What it is
Nginx Proxy Manager is a friendly web UI sitting on top of nginx. You point it at upstreams, give them hostnames, attach SSL certificates, and it generates and reloads the nginx config for you. It's the kind of tool that becomes invisible once it's working — which is the highest compliment I can pay infrastructure software.
Why I run it
The catalog you're reading has 33 public service entries. Without a reverse proxy, each one is "remember which port runs on which IP," and adding HTTPS means hand-editing nginx config and managing certificates per host. NPM collapses both problems: one entry per service, dropdown menu for the certificate, websockets toggle, done.
I picked NPM over raw nginx specifically because the GUI keeps me honest. When I see a list of every proxied service in one screen, I notice the ones that have grown stale. A YAML file in a repo hides that.
How I use it
Every internal hostname in this homelab flows through NPM:
- AdGuard Home holds a single wildcard DNS rewrite that points every
*.labname at NPM. - The browser sends the request to NPM with the hostname in the
Hostheader. - NPM matches the header against its proxy host list and forwards to the right upstream.
Adding a new service to the catalog is now a single NPM entry — no new DNS record per name, no nginx file. The wildcard does the resolution; NPM does the routing.
The site you're on (jhinx.dev) is the recent change here. In May 2026, I moved new service hostnames toward Let's Encrypt-backed *.jhinx.dev certs instead of self-signed *.lab certs that had to be trusted on every device. The *.lab setup is still alive in NPM as a compatibility path, but new services go straight to the real domain.
Setup notes
- Host: a Docker LXC alongside the rest of my edge infrastructure (AdGuard Home, Uptime Kuma, Homepage).
- TLS termination: NPM terminates HTTPS; upstreams are mostly plain HTTP on the internal network. The few that aren't (Portainer, Proxmox Backup Server, Nextcloud) get
proxy_ssl_verify off;in NPM's Advanced tab so it accepts their self-signed certs. - Websockets: required for almost every modern app — Home Assistant, Immich, Nextcloud, n8n, Open WebUI, Vaultwarden. I now turn the toggle on by default and only revisit it if something specifically doesn't need it.
- Backups: the
data/directory holds NPM's SQLite database with every proxy host and certificate; included in the PBS schedule for the host LXC. - Update cadence: manual, alongside other infra updates. Watchtower is not allowed near it.
Runbook
- Healthy looks like: NPM admin loads, the proxy host list shows every entry as green ("Online"), Uptime Kuma probes against
*.jhinx.devURLs are passing. 502 Bad Gateway: upstream is down or the port changed. Confirm by hitting the upstream IP and port directly — NPM is almost never the actual problem.- Hostname doesn't resolve: the wildcard DNS rewrite in AdGuard was removed or disabled. AdGuard → Filters → DNS rewrites.
- Cert errors on HTTPS upstream: NPM is verifying the upstream's self-signed cert. Add
proxy_ssl_verify off;in the Advanced tab. - Subtle lesson — UI loads but data widgets stay empty: I hit this with Proxmox Backup Server's frontend. PBS uses
Securecookies and a few APIs that silently fail outside a secure context, so over plain HTTP the static UI loads but every authenticated call returns nothing. Fix: serve through HTTPS, not HTTP. This same pattern bites Vaultwarden's web vault too — its Subtle Crypto API only works in a secure context. The rule I now follow: anything cookie-heavy gets HTTPS even on a "trusted" internal network. - Where logs live:
docker logs nginx-proxy-managerfor the proxy itself, the per-host access logs in the NPM UI for individual upstreams.