The constraint
I wanted one machine that could host the things I use every day without becoming a second job. That meant a hard rule up front: every service had to be reproducible from a file in Git, and every piece of state had to have a restore path.
The host is a single mini PC running Proxmox. It is not a production cluster, and it is not meant to be. It is a place to make mistakes where the blast radius is my own uptime.
What runs on it
Five services cover most of what I need:
- Caddy terminates TLS and routes by hostname. Certificates renew automatically, and the config is one readable file.
- Forgejo holds my private repositories and mirrors the public ones.
- Prometheus and Grafana collect and display the metrics I care about: disk, memory, container restarts, and certificate expiry.
- Uptime Kuma checks the endpoints from outside the box.
- Restic writes encrypted backups to object storage every night.
Each service runs in its own container with a bind-mounted config directory. The compose files live in a single repository, so rebuilding the host is a matter of installing Docker, cloning, and restoring the data volumes.
The part that matters: restore
A backup you have never restored is a hope, not a backup. Once a quarter I delete a container's volume, run the restore command, and check that the service comes back with its data intact.
restic snapshots --tag forgejo
restic restore latest --target /srv/restore --tag forgejo
docker compose up -d forgejoThe first time I did this, the restore worked but the file ownership did not. Forgejo started, then failed to write to its repository directory. That one detail is now in the runbook, and the restore script sets ownership before the container starts.
What I would change
The current setup is deliberately single-node. That is fine for a homelab, but it means a dead power supply takes everything with it. The next step is not a second server — it is making the recovery time honest: measure how long a full rebuild actually takes, write it down, and decide whether that number is acceptable.