commit e56ea087a8828555d083b02089fc17095d90d169 Author: padriano Date: Sat May 9 15:45:56 2026 +0100 Initial commit Home server Docker Compose stack with Forgejo, Home Assistant, DuckDNS, and Time Machine services. Co-authored-by: Cursor diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..a164a53 --- /dev/null +++ b/.env.example @@ -0,0 +1,16 @@ +# Required environment variables for docker-compose +# Copy this to .env and fill in the values before starting the stack. + +PUID=1000 +PGID=1000 +TZ=Etc/UTC + +DUCKDNS_SUBDOMAINS=ha-padriano,padrianoha,padriano +DUCKDNS_TOKEN=replace-with-your-duckdns-token + +TM_UID=1000 +TM_GID=1000 +TM_GROUPNAME=timemachine +TM_USERNAME=timemachine +TIMEMACHINE_PASSWORD=replace-with-your-timemachine-password +TIMEMACHINE_VOLUME_LIMIT=500G diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..539f63f --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.env +notes.txt diff --git a/README.md b/README.md new file mode 100644 index 0000000..c267917 --- /dev/null +++ b/README.md @@ -0,0 +1,188 @@ +# Docker Compose — Home Server + +## Services + +| Container | Image | Purpose | +|-----------|-------|---------| +| `duckdns` | `lscr.io/linuxserver/duckdns` | Dynamic DNS — keeps `*.duckdns.org` pointed at the home IP | +| `homeassistant` | `homeassistant/home-assistant` | Home automation, reachable at `:8123` | +| `timemachine` | `mbentley/timemachine:smb` | Time Machine backup server over SMB | +| `forgejo` | `codeberg.org/forgejo/forgejo` | Self-hosted Git server, web UI at `:3000`, SSH at `:2222` | + +## Initial Setup + +1. Copy and fill in the environment file: + + ```bash + cp .env.example .env + nano .env + ``` + +2. Create the Forgejo data directory if it doesn't exist: + + ```bash + mkdir -p /home/padriano/projects/forgejo + ``` + +3. Bring the full stack up: + + ```bash + cd /home/padriano/projects/composer + docker compose up -d + ``` + +--- + +## Common Docker Compose Commands + +### Stack management + +```bash +# Start all services (detached) +docker compose up -d + +# Stop all services (containers remain) +docker compose stop + +# Stop and remove all containers (data volumes are preserved) +docker compose down + +# Restart all services +docker compose restart + +# Restart a single service +docker compose restart homeassistant +``` + +### Viewing status and logs + +```bash +# Show running containers and their status +docker compose ps + +# Follow logs for all services +docker compose logs -f + +# Follow logs for a single service +docker compose logs -f forgejo + +# Show last 50 lines for a service +docker compose logs --tail=50 timemachine +``` + +### Updating images + +```bash +# Pull latest images for all services +docker compose pull + +# Pull for a single service +docker compose pull forgejo + +# Recreate containers that have a newer image +docker compose up -d --pull always + +# Recreate a single service after pulling +docker compose up -d --force-recreate forgejo +``` + +### Inspecting containers + +```bash +# Open a shell inside a running container +docker exec -it homeassistant bash +docker exec -it forgejo sh # alpine-based, use sh not bash + +# Show resource usage (CPU, RAM, network) +docker stats + +# Inspect container configuration +docker inspect forgejo +``` + +--- + +## Service Notes + +### duckdns + +- Config stored at `/home/padriano/projects/duckdns/config` +- Uses `network_mode: host` — required for Avahi/mDNS broadcast +- Domains managed: `ha-padriano`, `padrianoha`, `padriano` (all `.duckdns.org`) + +### homeassistant + +- Config stored at `/home/padriano/projects/ha/config` +- Web UI: `http://192.168.1.116:8123` or `http://ha-padriano.duckdns.org` +- Uses `network_mode: host` for device discovery (mDNS, Zigbee, etc.) +- Has a healthcheck — status shows `(health: starting)` for ~60s on first boot + +### timemachine + +- Backup data stored at `/home/padriano/backup/timemachine` +- Uses `network_mode: host` and a fixed `hostname: timemachine` — the stable hostname prevents macOS from losing the backup destination after container restarts +- On your Mac: **System Settings → General → Time Machine → Add Backup Disk** + +### forgejo + +- All data (repos, config, SQLite DB) stored at `/home/padriano/projects/forgejo` +- Backing up this single directory is sufficient for a full restore + +#### First-run setup + +Visit `http://192.168.1.116:3000` on first start and complete the install wizard: + +- **Base URL**: `http://padriano.duckdns.org:3000` +- **SSH domain**: `padriano.duckdns.org` +- **SSH port**: `2222` + +#### Access + +| Method | Local network | External (via DuckDNS) | +|--------|---------------|------------------------| +| Web UI | `http://192.168.1.116:3000` | `http://padriano.duckdns.org:3000` | +| Git SSH | `ssh://git@192.168.1.116:2222` | `ssh://git@padriano.duckdns.org:2222` | + +For external access, forward these ports on your router to `192.168.1.116`: + +- TCP `3000` → Forgejo web UI +- TCP `2222` → Forgejo SSH + +#### Git remote URL examples + +```bash +# Add remote via HTTP +git remote add origin http://padriano.duckdns.org:3000/padriano/my-repo.git + +# Add remote via SSH +git remote add origin ssh://git@padriano.duckdns.org:2222/padriano/my-repo.git + +# Clone via SSH +git clone ssh://git@192.168.1.116:2222/padriano/my-repo.git +``` + +--- + +## Disk Space + +```bash +# Free space on the main filesystem +df -h / + +# Free space on all mounted filesystems +df -h + +# Space used by each service's data directory +du -sh /home/padriano/projects/* /home/padriano/backup/* +``` + +--- + +## Data & Backup Summary + +| Service | Host path | Notes | +|---------|-----------|-------| +| `duckdns` | `/home/padriano/projects/duckdns/config` | Token cache, not critical | +| `homeassistant` | `/home/padriano/projects/ha/config` | All HA config and automations | +| `timemachine` | `/home/padriano/backup/timemachine` | Mac backup sparsebundles | +| `forgejo` | `/home/padriano/projects/forgejo` | All repos, DB, config | diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..39a877d --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,75 @@ +services: + duckdns: + image: lscr.io/linuxserver/duckdns:36a2e3a3-ls78 + container_name: duckdns + restart: unless-stopped + environment: + - PUID=${PUID} + - PGID=${PGID} + - TZ=${TZ} + - SUBDOMAINS=${DUCKDNS_SUBDOMAINS} + - TOKEN=${DUCKDNS_TOKEN} + - UPDATE_IP=ipv4 + - LOG_FILE=true + volumes: + - /home/padriano/projects/duckdns/config:/config + + homeassistant: + image: homeassistant/home-assistant:2024.5.4 + container_name: homeassistant + restart: unless-stopped + network_mode: host + depends_on: + - duckdns + environment: + - TZ=${TZ} + volumes: + - /home/padriano/projects/ha/config:/config + healthcheck: + test: ["CMD", "curl", "-fsSL", "http://localhost:8123/api/"] + interval: 30s + timeout: 10s + retries: 5 + start_period: 60s + + forgejo: + image: codeberg.org/forgejo/forgejo:10 + container_name: forgejo + hostname: forgejo + restart: unless-stopped + ports: + - "3000:3000" + - "2222:22" + environment: + - USER_UID=${PUID} + - USER_GID=${PGID} + volumes: + - /home/padriano/projects/forgejo:/data + - /etc/timezone:/etc/timezone:ro + - /etc/localtime:/etc/localtime:ro + + timemachine: + image: mbentley/timemachine:smb-20260503 + container_name: timemachine + hostname: timemachine + restart: unless-stopped + network_mode: host + tmpfs: + - /run/samba + ulimits: + nofile: + soft: 65536 + hard: 65536 + environment: + - TM_UID=${TM_UID} + - TM_GID=${TM_GID} + - TM_GROUPNAME=${TM_GROUPNAME} + - TM_USERNAME=${TM_USERNAME} + - PASSWORD=${TIMEMACHINE_PASSWORD} + - SET_PERMISSIONS=false + - VOLUME_SIZE_LIMIT=${TIMEMACHINE_VOLUME_LIMIT} + - CUSTOM_SMB_CONF=true + volumes: + - /home/padriano/backup/timemachine:/opt/timemachine + - /home/padriano/projects/composer/timemachine/avahi-daemon.conf:/etc/avahi/avahi-daemon.conf:ro + - /home/padriano/projects/composer/timemachine/smb.conf:/etc/samba/smb.conf:ro diff --git a/timemachine/avahi-daemon.conf b/timemachine/avahi-daemon.conf new file mode 100644 index 0000000..cae965a --- /dev/null +++ b/timemachine/avahi-daemon.conf @@ -0,0 +1,69 @@ +# This file is part of avahi. +# +# avahi is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. +# +# avahi is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +# License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with avahi; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA. + +# See avahi-daemon.conf(5) for more information on this configuration +# file! + +[server] +#host-name=foo +#domain-name=local +#browse-domains=0pointer.de, zeroconf.org +use-ipv4=yes +use-ipv6=yes +allow-interfaces=enp0s31f6 +#deny-interfaces=eth1 +#check-response-ttl=no +#use-iff-running=no +#enable-dbus=yes +#disallow-other-stacks=no +#allow-point-to-point=no +#cache-entries-max=4096 +#clients-max=4096 +#objects-per-client-max=1024 +#entries-per-entry-group-max=32 +ratelimit-interval-usec=1000000 +ratelimit-burst=1000 + +[wide-area] +#enable-wide-area=no + +[publish] +#disable-publishing=no +#disable-user-service-publishing=no +#add-service-cookie=no +#publish-addresses=yes +publish-hinfo=no +publish-workstation=no +#publish-domain=yes +#publish-dns-servers=192.168.50.1, 192.168.50.2 +#publish-resolv-conf-dns-servers=yes +#publish-aaaa-on-ipv4=yes +#publish-a-on-ipv6=no + +[reflector] +#enable-reflector=no +#reflect-ipv=no +#reflect-filters=_airplay._tcp.local,_raop._tcp.local + +[rlimits] +#rlimit-as= +#rlimit-core=0 +#rlimit-data=8388608 +#rlimit-fsize=0 +#rlimit-nofile=768 +#rlimit-stack=8388608 +#rlimit-nproc=3 diff --git a/timemachine/smb.conf b/timemachine/smb.conf new file mode 100644 index 0000000..8dd93a2 --- /dev/null +++ b/timemachine/smb.conf @@ -0,0 +1,49 @@ +[global] + workgroup = WORKGROUP + server role = standalone server + security = user + ntlm auth = no + + server min protocol = SMB2_10 + server max protocol = SMB3 + + server signing = auto + smb encrypt = desired + + load printers = no + printing = bsd + printcap name = /dev/null + disable spoolss = yes + show add printer wizard = no + + logging = file + log file = /var/log/samba/log.%m + max log size = 1000 + log level = 1 auth:3 vfs:1 + + smb ports = 445 + + vfs objects = catia fruit streams_xattr + + fruit:aapl = yes + fruit:nfs_aces = no + fruit:copyfile = no + fruit:model = TimeCapsule8,119 + fruit:metadata = stream + fruit:veto_appledouble = no + fruit:posix_rename = yes + fruit:zero_file_id = yes + fruit:wipe_intentionally_left_blank_rfork = yes + fruit:delete_empty_adfiles = yes + + spotlight backend = noindex + +[TimeMachine] + path = /opt/timemachine + browseable = yes + read only = no + inherit permissions = no + valid users = timemachine + vfs objects = catia fruit streams_xattr + fruit:time machine = yes + fruit:time machine max size = 500G