A complete self-hosted services stack — Docker compose files for a production home server, one wildcard certificate, eight services.
The actual production stack behind a personal home server: Nextcloud, Vaultwarden, WireGuard (wg-easy), SFTPGo, RustDesk, Uptime Kuma, Netdata and Watchtower — every service currently running in production, packaged as clean docker-compose files.
Each service lives in its own directory with its own compose file, so you can adopt just the pieces you need.
| Service | What it does | Web UI | Compose dir |
|---|---|---|---|
| Nextcloud | Files, calendar, contacts (+ MariaDB, Redis) | 8082 | services/nextcloud/ |
| Vaultwarden | Password manager, Bitwarden-compatible | 8080 | services/vaultwarden/ |
| wg-easy | WireGuard VPN with web admin | 51821 | services/wireguard/ |
| SFTPGo | Managed SFTP/HTTP file transfers | 8090 | services/sftpgo/ |
| RustDesk | Self-hosted remote desktop (hbbs/hbbr) | — | services/rustdesk/ |
| Uptime Kuma | Status pages + uptime monitoring | 3001 | services/uptime-kuma/ |
| Netdata | Real-time system monitoring | 19999 | services/netdata/ |
| Watchtower | Automatic nightly image updates | — | services/watchtower/ |
See docs/ARCHITECTURE.md for the full service map, network diagram and security decisions.
# 1. Configure secrets (NEVER commit real ones — .env is git-ignored)
cp .env.example services/nextcloud/.env
cp .env.example services/vaultwarden/.env
cp .env.example services/wireguard/.env
# ... edit each .env with real values
# 2. Start a service
cd services/nextcloud && docker compose up -d
# 3. Expose it through the reverse proxy
# copy proxy/service.duckdns.org.conf.example to your Apache/Nginx,
# point ServerName at your subdomain, adjust the container portGenerate the hashed secrets:
# Vaultwarden admin token
docker run vaultwarden/server /vaultwarden hash
# wg-easy web UI password
docker run ghcr.io/wg-easy/wg-easy wgpw your-password- One service per directory — adopt what you need, nothing more.
- Secrets via .env only — the original stack had hardcoded DB passwords and admin tokens; this repo ships the fixed form.
- One wildcard certificate —
*.example.duckdns.orgvia Lets Encrypt DNS-01, every subdomain on the same cert. No cert sprawl. - No port clashes — each service publishes a distinct host port, mapped in the architecture doc.
- Self-maintaining — Watchtower updates images nightly, Uptime Kuma watches the endpoints, Netdata watches the host.
The proxy/ folder has the production Apache vhost pattern: wildcard
certificate, HSTS, Nextcloud .well-known redirects and ProxyPass to
the container port. It works identically with Nginx (proxy_pass to the
same 127.0.0.1:<port>).
If you use UFW on the host, keep Docker networking alive:
sudo ufw default allow routed # CRITICAL — deny breaks containers
sudo ufw allow 22,80,443/tcp
sudo ufw allow 51820/udp # WireGuard
sudo ufw allow from 10.8.0.0/24 # VPN subnet → internal serviceslinuxserver/wireguard— superseded by wg-easy (kept the same10.8.0.0/24subnet so client configs survived the migration)pyload-ng— download manager, removed
MIT © 2026 Vasileios Antonopoulos