Homelab Configs
Docker Compose files and configuration for homelab infrastructure. All stacks are managed via Portainer at http://192.168.88.27:9000 (or https://portainer.jgitta.com).
Portainer Access
| Item | Value |
|---|---|
| URL | http://192.168.88.27:9000 |
| External URL | https://portainer.jgitta.com |
| API Token | ptr_1cThi+cjOKeICslJbSzCtUhORF06xUOykbAWPUoTyMU= |
Note: The API token above is for automation/scripting. Keep it private. To call the Portainer API:
curl -H "X-API-Key: <token>" http://192.168.88.27:9000/api/stacks
Important — Volume Paths: All volume mounts in Portainer stacks must use absolute paths (e.g.
/srv/docker/myapp/data:/app/data). Relative paths (e.g../data) resolve to Portainer's internal/data/compose/<id>/directory and will lose data if the stack is redeployed with a different ID. This was audited and corrected on 2026-05-07.
Hosts
| Host | IP | Role | Portainer Endpoint ID | Docker Version |
|---|---|---|---|---|
| siklos | 192.168.88.27 | Main Docker server (VM 112 on Proxmox) | 3 (local) | 26.1.5 |
| jellyfin | 192.168.88.10 | Media server | 4 (agent) | 26.1.5 |
| jgpc | 192.168.88.41 | Workstation / Ollama / AI | 5 (agent) | 29.4.2 |
Stack Inventory
siklos (192.168.88.27) — 20 stacks
| Stack | Port(s) | Data Path | URL | Notes |
|---|---|---|---|---|
| actual-budget | 5006 | /srv/docker/actual-budget | budget.jgitta.com | Budget tracking |
| beszel | 8085 | /srv/docker/beszel | beszel.jgitta.com | Beszel hub — all-in-one monitoring (replaced Prometheus/Grafana/cAdvisor) |
| dashboard | 8096 | /srv/docker/dashboard | dashboard.jgitta.com | Custom homepage |
| dashy | 8081 | /srv/docker/dashy | dashy.jgitta.com | Dashboard |
| gitea | 3002, 2222 | /srv/docker/gitea/data | gitea.jgitta.com | Git server — this repo |
| glances | 61208 | — | glances.jgitta.com | System monitoring |
| goldengames | 3030 | /srv/docker/goldengames | goldengamer.org | (built locally) |
| guacamole | 8080 | /srv/docker/guacamole | apache.jgitta.com | Apache Guacamole — remote desktop gateway |
| homarr | 7575 | /srv/docker/homarr/.homarr/appdata | homarr.jgitta.com | Dashboard |
| karakeep | 3010 | /srv/docker/karakeep | notes.jgitta.com | Bookmarks / read-later |
| kopia | 51515 | /srv/docker/kopia | kopia.jgitta.com | Backup tool (backs up to TrueNAS) |
| linkwarden | 3015 | /srv/docker/linkwarden/pgdata | links.jgitta.com | Link manager |
| litellm | 4000 | /srv/docker/litellm | — | LLM API gateway |
| meshcentral | 444 | /srv/docker/meshcentral | mesh.jgitta.com | Remote management |
| onlyoffice | 8880 | /srv/docker/onlyoffice | office.jgitta.com | Office document server (replaced Collabora) |
| pihole | host network | /srv/docker/pihole | pihole.jgitta.com | DNS ad blocker |
| portainer | 9000, 9443 | /srv/docker/portainer | portainer.jgitta.com | Container management UI |
| uptime-kuma | 3001 | /srv/docker/uptime-kuma/data | status.jgitta.com | Uptime monitoring |
| watchtower | — | — | — | Auto-updates containers |
| wordpress | 8095 | /srv/docker/wordpress | jgitta.com | WordPress site |
jellyfin (192.168.88.10) — 3 stacks
| Stack | Port(s) | Data Path | Notes |
|---|---|---|---|
| arr-stack | various | /srv/docker | Radarr, Sonarr, Prowlarr, Flaresolverr, Watchtower |
| beszel-agent | 45876 | — | Beszel agent (systemd binary, not Docker) |
| portainer-agent | 9001 | — | Portainer agent (fully managed) |
jgpc (192.168.88.41) — 4 stacks
| Stack | Port(s) | Data Path | Notes |
|---|---|---|---|
| frigate | 5000, 8554, 8555 | /srv/docker/frigate | NVR / camera AI |
| open-webui | 3000 | /srv/docker/open-webui | Ollama web UI |
| portainer-agent | 9001 | — | Portainer agent (shows "limited" — expected, see notes) |
| stirling-pdf | 8081 | /srv/docker/stirling-pdf | PDF tools |
| beszel-agent | 45876 | — | Beszel agent (systemd binary, not Docker) |
Caddy Reverse Proxy
Caddy runs on a dedicated VM at 192.168.88.110 (alias: caddy) as a systemd service.
It handles all HTTPS termination and reverse proxying for *.jgitta.com subdomains.
TLS certificates are obtained automatically via Cloudflare DNS challenge (Let's Encrypt).
Config location: /etc/caddy/ on the caddy VM.
File Structure
| File | Purpose |
|---|---|
Caddyfile |
Main file — sets global options, imports snippets and sites |
snippets.caddy |
Reusable blocks: web_secure, internal_only, proxy_timeouts, etc. |
sites/infrastructure.caddy |
Management/tool services (portainer, kopia, beszel, pihole, etc.) |
sites/media.caddy |
Media and automation stack (jellyfin, sonarr, radarr, next, etc.) |
sites/homenet.caddy |
Internal .homenet HTTP-only domains (no TLS) |
sites/goldengamer.caddy |
goldengamer.org external domain |
Key Snippets
internal_only— Blocks requests from outside192.168.88.0/24and192.168.2.0/24viaabort. Used on sensitive services (portainer, pihole, proxmox, etc.).web_secure— Standard security headers + gzip compression.proxy_timeouts— 90s read/write timeouts on upstream connections.
DNS Notes
- Internal services use MikroTik DNS (
192.168.88.1) to resolve*.jgitta.com→192.168.88.110. - Browsers with DNS-over-HTTPS (DoH) enabled (e.g. Brave) bypass MikroTik DNS and use public resolvers, which have no record of internal-only subdomains. Disable DoH in browser settings or ensure Cloudflare DNS has grey-cloud records pointing to the WAN IP for all subdomains.
- Public-facing services use Cloudflare DNS (grey cloud) → WAN IP → MikroTik port-forwards 443 → Caddy VM.
internal_onlyservices should use grey-cloud Cloudflare records (not orange/proxied) — orange cloud sends traffic from Cloudflare's IPs whichinternal_onlywill abort, causing a 520 error.
Data Directory Convention
All stack data is stored under /srv/docker/<stack-name>/ on each host.
All Portainer volume mounts must use absolute paths — relative paths break on stack redeploy.
Old compose files were renamed to .bak after migration to Portainer.
Kopia Backup Notes (updated 2026-05-07)
Kopia backs up Nextcloud data (VM 103) and other sources to TrueNAS NFS.
- Cache limit set to 4 GB content + 512 MB metadata (
kopia cache set) /tmpand/app/logsare bind-mounted out of the container to prevent overlay2 growth- After-snapshot hook pings Uptime Kuma heartbeat at
status.jgitta.comafter each backup - If disk fills up again, check
/srv/docker/kopia/tmp/for leftover verify/restore artifacts - Ignore policy active for
/data/.claudein the Nextcloud data source
Portainer Agent Notes
Portainer agents run on jellyfin and jgpc, allowing the central Portainer instance on siklos to manage all three Docker hosts from one UI.
- jellyfin agent: Fully managed by Portainer (Stack ID 36)
- jgpc agent: Shows as "limited" in Portainer UI — this is expected and harmless.
The portainer-agent cannot redeploy itself through its own proxy (catch-22). The agent
is stable and the endpoint is fully functional. Agent data is persisted in the
portainer_agent_dataDocker named volume so TLS certs survive restarts.
Proxmox / Infrastructure Notes
| Item | Details |
|---|---|
| Proxmox host | 192.168.88.25 |
| PBS | 192.168.88.60 |
| TrueNAS | 192.168.88.24 |
| Nextcloud VM | VM 103 (192.168.88.62) |
| OCIS VM | VM 114 (192.168.88.63) — cloud.jgitta.com |
| Docker server VM | VM 112 = siklos (192.168.88.27) |
| Caddy proxy VM | 192.168.88.110 |