How to Set Up Nginx Proxy Manager (Reverse Proxy and HTTPS with a Web Interface)

Nginx Proxy Manager: reverse proxy by clicking — Same Nginx. A form instead of a file.

Tutorial 28 built a reverse proxy by writing Nginx server blocks. Nginx Proxy Manager is the same Nginx with a web page in front: add a host, type the app's address, tick "Request a new SSL certificate", save. If you add apps often, or someone else in the house needs to, this is the version they can use.

Quick reference

TaskWhat
Folder~/docker/npm/compose.yaml
Admin pagehttp://server-ip:81
Default loginadmin@example.com / changeme (change immediately)
Add an appHosts → Proxy Hosts → Add
HTTPSSSL tab → Request a new SSL certificate
WildcardSSL Certificates → Add → Use a DNS challenge

1. The compose file

Stop a host-installed Nginx or Caddy first — this needs ports 80 and 443.

mkdir -p ~/docker/npm && cd ~/docker/npm
nano compose.yaml

services:
npm:
image: jc21/nginx-proxy-manager:latest
container_name: npm
ports:
- "80:80"
- "443:443"
- "127.0.0.1:81:81"
volumes:
- ./data:/data
- ./letsencrypt:/etc/letsencrypt
restart: unless-stopped

Port 81 is the admin page, bound to localhost — reach it over an SSH tunnel or from inside the VPN by opening it to your LAN instead ("81:81" plus a UFW rule from your subnet).

docker compose up -d
sudo ufw allow 80/tcp && sudo ufw allow 443/tcp

2. First login

Open http://192.168.1.50:81, log in with the default credentials, and it immediately asks you to set your own name, email and password.

3. Add a proxy host

Hosts → Proxy Hosts → Add Proxy Host:

Thirty seconds later https://status.example.com works with a padlock. Repeat per app.

4. A wildcard certificate

One certificate for *.example.com saves a request per app and works for internal names that aren't reachable from the internet:

SSL Certificates → Add SSL Certificate → Let's Encrypt, domain names *.example.com and example.com, tick Use a DNS Challenge, pick your DNS provider (Cloudflare, DuckDNS and many others), paste the API token. Then in each proxy host's SSL tab, choose that certificate from the list instead of requesting a new one.

5. Access lists

Access Lists → Add: give it a name, add a username and password under Authorization, or allow only your LAN under Access (192.168.1.0/24). Then pick the list on any proxy host's Details tab. Handy for Portainer or the Syncthing UI.

Custom Nginx

Each host has an Advanced tab for raw Nginx config — client_max_body_size 10G; for Nextcloud, proxy_buffering off; for Jellyfin.

Troubleshooting

"Internal Error" when requesting a certificate. Port 80 isn't reachable from the internet, or DNS doesn't point at you yet. Check docker compose logs npm for the Let's Encrypt message.

502 Bad Gateway. NPM can't reach the forward address. From the server, curl http://192.168.1.50:3001. If the app is bound to 127.0.0.1, NPM in Docker can't see it — bind it to the LAN IP or put them on the same Docker network.

Lost the admin password. docker compose exec npm sqlite3 /data/database.sqlite "UPDATE user SET is_deleted=0" then reset via the default login route — or simply delete ./data and start over, re-adding hosts.

Admin page on 81 reachable from outside. Don't. Keep it on localhost or LAN only.

Wrapping up

One container, a form per app, a tick box for HTTPS, a wildcard certificate via DNS for everything internal. Everything Nginx can do, with the config written for you.

Call us