Self-hosted infrastructure for mfilipe.eu on hopper (Debian / ZFS / Docker). Architecture and rationale: DESIGN.md.
| Dir | Service | Endpoint |
|---|---|---|
caddy/ | Reverse proxy + TLS for all *.mfilipe.eu | — |
immich/ | Photos | img.mfilipe.eu |
memos/ | Notes | notes.mfilipe.eu |
blog/ | Hugo site, served static from blog/site/ | blog.mfilipe.eu |
jellyfin/ | Media (systemd) | tv.mfilipe.eu |
monitoring/ | VictoriaMetrics + Grafana + Telegraf + vmagent | graf. / metrics.mfilipe.eu |
iot/ | Zigbee2MQTT + Mosquitto | internal |
llm/ | Local LLM via llama-swap (systemd); see llm/AGENTS.md | internal |
ddns/ | Dynamic DNS updater (systemd timer) | — |
fail2ban/ | IP banning | — |
git clone git@github.com:msf/selfhost.git /srv/selfhost &&cd /srv/selfhost
./deploy.sh # decrypt secrets.tar.age → */env (needs ~/.age-key.txt)- Docker:
docker compose up -din each dir with a compose file (caddy,immich,memos,monitoring,monitoring/telegraf,monitoring/vmagent,iot). - Systemd:
jellyfin,ddns.timer,fail2ban. LLM stack viallm/install.sh, fail2ban viafail2ban/install.sh.
git pull && ./deploy.sh
docker compose restart # in the changed dir# or: sudo systemctl restart <unit>env files are gitignored; the tracked .env are symlinks to them. The encrypted
bundle is secrets.tar.age (age).
./encrypt-secrets.sh # */env → secrets.tar.age
./deploy.sh # secrets.tar.age → */envdocker ps
docker logs <name>
systemctl status jellyfin ddns fail2ban
sudo fail2ban-client status