Initial commit
Home server Docker Compose stack with Forgejo, Home Assistant, DuckDNS, and Time Machine services. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
commit
e56ea087a8
6 changed files with 399 additions and 0 deletions
16
.env.example
Normal file
16
.env.example
Normal file
|
|
@ -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
|
||||||
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
.env
|
||||||
|
notes.txt
|
||||||
188
README.md
Normal file
188
README.md
Normal file
|
|
@ -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 |
|
||||||
75
docker-compose.yml
Normal file
75
docker-compose.yml
Normal file
|
|
@ -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
|
||||||
69
timemachine/avahi-daemon.conf
Normal file
69
timemachine/avahi-daemon.conf
Normal file
|
|
@ -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
|
||||||
49
timemachine/smb.conf
Normal file
49
timemachine/smb.conf
Normal file
|
|
@ -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
|
||||||
Loading…
Add table
Reference in a new issue