146 lines
8.2 KiB
Markdown
146 lines
8.2 KiB
Markdown
# 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 |
|
|
| photos | 192.168.88.32 | Photos VM (VM 113) — Immich | 8 (agent) | — |
|
|
|
|
## 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 |
|
|
| authentik | 9011 | /srv/docker/authentik | auth.jgitta.com | SSO / identity provider (stack 58; secrets stored as Portainer env vars) |
|
|
| 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 |
|
|
| 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 |
|
|
| beszel | 8085 | /srv/docker/beszel | beszel.jgitta.com | Beszel hub — all-in-one monitoring (replaced Prometheus/Grafana/cAdvisor) |
|
|
| 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 + faster-whisper + open-webui |
|
|
| 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 |
|
|
| ntfy | 2586 | /srv/docker/ntfy | ntfy.jgitta.com | Push notifications (replaces Telegram); topic: homelab-alerts; Caddy needs `transport http { versions 1.1 }` for WebSocket |
|
|
| searxng | 8092 | /srv/docker/searxng | search.jgitta.com | Private search engine |
|
|
| watchtower | — | — | — | Auto-updates containers |
|
|
| wordpress | 8095 | /srv/docker/wordpress | jgitta.com | WordPress site |
|
|
|
|
### photos (192.168.88.32) — 1 stack
|
|
|
|
| Stack | Port(s) | Data Path | URL | Notes |
|
|
|---|---|---|---|---|
|
|
| immich | 2283 | /mnt/immich-photos (uploads), /srv/docker/immich/postgres (DB) | pictures.jgitta.com | Stack 45; postgres needs `shared_preload_libraries=vectors.so,vchord.so` (unquoted, list-form command) |
|
|
|
|
### jellyfin (192.168.88.10) — 3 stacks
|
|
|
|
| Stack | Port(s) | Data Path | Notes |
|
|
|---|---|---|---|
|
|
| arr-stack | various | /srv/docker | Radarr, Sonarr, Prowlarr, Flaresolverr, Bindery (8787, binder.jgitta.com), Audiobookshelf (13378, books.jgitta.com), Watchtower |
|
|
| beszel-agent | 45876 | — | Beszel agent (systemd binary, not Docker) |
|
|
| portainer-agent | 9001 | — | Portainer agent (fully managed) |
|
|
|
|
### jgpc (192.168.88.41) — 3 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) |
|
|
| 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, 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 outside `192.168.88.0/24` and `192.168.2.0/24` via `abort`. 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_only` services should use grey-cloud Cloudflare records (not orange/proxied) — orange cloud sends traffic from Cloudflare's IPs which `internal_only` will 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.
|
|
|
|
**2026-07-03 — external stacks converted to Portainer:** authentik (stack 58), beszel (57), searxng (56) were created in Portainer; watchtower (18), karakeep (21), frigate (31), immich (45) were redeployed so Portainer owns the running containers. Frigate and immich stack definitions were updated to match the newer host compose files (frigate: cpuset pinning + 8G memory limit; immich: /mnt/immich-photos path + vectorchord postgres image). Host compose files renamed to `.bak`. Do not run `docker compose up` from /srv/docker — deploy via Portainer only.
|
|
|
|
## 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_data` Docker 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 |
|