Services: What Runs Where and How It’s Exposed
Concrete list of what I run, which host/VM it’s on, and how nginx and TLS are configured.
Reverse proxy (nginx) — HA pair
- Primary: Ubuntu VM on Host 1. Fixed IP + keepalived VIP. Runs nginx, certbot, keepalived (MASTER), and an inotify-based sync that pushes config and cert changes to the secondary. Dynamic DNS updater runs on a systemd timer.
- Secondary: Ubuntu VM on Host 2. Fixed IP only; keepalived BACKUP. Runs nginx (same config as primary), keepalived, and receives synced config/certs from the primary. Also runs its own DDNS updater.
- Config: Single include file (
conf.d/reverse-proxy.conf) with all upstreams and allserver { ... }blocks. I don’t split vhosts into separate files; one file keeps ordering and maintenance simple. Main nginx.conf only does process/events/http, TLS defaults (1.2/1.3, modern ciphers), andinclude conf.d/*.conf. - Sync: When I change the config or certbot renews, the primary runs a script that rsyncs to the secondary. So both nodes always have the same reverse-proxy.conf and the same Let’s Encrypt dir. Reload is manual or via a small service that triggers on file change.
nginx documentation · keepalived
DNS — Pi-hole × 3
- Instance 1: Ubuntu VM on Host 1 (Pi-hole’s web admin is proxied at e.g.
pihole1.detellem.com, LAN-only via nginxallow/deny). - Instance 2: TrueNAS Scale app on Host 3 (same IP as the NAS, different port). Proxied at e.g.
pihole2.detellem.com, LAN-only. - Instance 3: Ubuntu VM on Host 2. Proxied at e.g.
pihole3.detellem.com, LAN-only.
All three are in the DHCP “DNS servers” list so clients get redundancy. I don’t expose the Pi-hole admin to the internet; nginx returns 403 for those hostnames unless the request is from the LAN subnet.
Main landing — Homepage
- Where: Docker container on the Docker VM (Host 1).
- Role: Dashboard with links to all my services (Plex, Bitwarden, Mealie, etc.). Served at the root domain and at
www,home,dashboard,homepagesubdomains (one nginx server block, same backend). - Config: YAML for widgets and services; I version the config in the homelab repo and mount it into the container.
Plex
- Where: Host 2 (Windows), not in a VM. Uses the host’s GPU for transcoding; media libraries point at SMB shares on TrueNAS (Host 3).
- Exposed as:
plex.detellem.comvia nginx. WebSocket and large body size enabled in the nginx location block for Plex. - Port: One backend port; nginx proxies to Host 2’s IP and that port.
Bitwarden (self-hosted)
- Where: Docker Compose stack on the Docker VM (Host 1). Multiple containers (nginx, api, identity, web, mssql, etc.); the Bitwarden “nginx” container is the internal front door, and my nginx reverse proxy forwards to it.
- Exposed as:
bitwarden.detellem.com. Client max body size increased in nginx for attachments. - Data: Persistent volumes for database and attachments; backups are manual/scheduled outside the container.
Mealie (recipes)
- Where: Single Docker container on the Docker VM. One port (e.g. 9000) mapped on the host.
- Exposed as:
recipes.detellem.comandmealie.detellem.com(same server block). - Data: Docker volume; backup as needed.
Donetick (chores)
- Where: Docker container on the Docker VM.
- Exposed as:
chores.detellem.comanddonetick.detellem.com.
Donetick (or current repo)
IT-Tools
- Where: Docker container on the Docker VM. Stateless.
- Exposed as:
it-tools.detellem.com.
ConvertX (file conversion)
- Where: Docker container on the Docker VM. Needs a larger
client_max_body_sizein nginx for uploads (e.g. 1G). - Exposed as:
xconvert.detellem.comandconvertx.detellem.com.
c4illin/convertx (or current)
TrueNAS (storage)
- Where: Host 3. Not exposed through the reverse proxy to the internet. I access the web UI from the LAN only. SMB shares are used by Host 1, Host 2 (Plex), and other devices. Datasets hold media, backups, and app data as needed.
Summary table
| Service | Host/VM | Exposed as | Notes |
|---|---|---|---|
| Homepage | Docker VM (H1) | detellem.com, www, home… | Main dashboard |
| Plex | Host 2 | plex.detellem.com | Host process, GPU |
| Bitwarden | Docker VM (H1) | bitwarden.detellem.com | Compose stack |
| Mealie | Docker VM (H1) | recipes / mealie | Single container |
| Donetick | Docker VM (H1) | chores / donetick | Single container |
| IT-Tools | Docker VM (H1) | it-tools.detellem.com | Stateless |
| ConvertX | Docker VM (H1) | xconvert / convertx | Large uploads |
| Pi-hole 1–3 | H1 VM, H3 app, H2 VM | pihole1/2/3.detellem.com | LAN-only in nginx |
| nginx | H1 VM (primary), H2 VM (secondary) | — | VIP, TLS, proxy to all above |