Nginx Proxy Manager puts a friendly web UI on top of Nginx: point domain names at your containers and it handles SSL certificates, redirect rules, and access lists.
Prerequisites
- Docker Engine + Compose plugin (see the Compose guide)
- A domain name you control, with DNS you can edit — needed for the SSL step
1. Create the project folder
sudo mkdir -p /opt/npm
cd /opt/npm
2. Write the Compose file
services:
npm:
image: jc21/nginx-proxy-manager:latest
container_name: npm
restart: unless-stopped
ports:
# These two MUST be public — the proxy's whole job is answering
# HTTP/HTTPS requests from the internet
- "80:80"
- "443:443"
# Admin UI bound to localhost only; reach it via SSH tunnel
- "127.0.0.1:81:81"
volumes:
- npm-data:/data
- npm-etc:/etc/letsencrypt
volumes:
npm-data:
npm-etc:
3. Start it and open the admin UI
sudo docker compose up -d
On your own computer, tunnel to the admin interface:
ssh -L 8081:localhost:81 your-user@your-server-ip
# then open http://localhost:8081
The documented default login is admin@example.com with password changeme — the UI forces you to set a new email and password on first login. Do that immediately.
4. Point a domain at your first app
- In your DNS provider, create an
Arecord:app.example.com → your server IP. Wait for it to resolve (dig +short app.example.comon your machine shows the IP). - In NPM: Hosts → Proxy Hosts → Add. Domain =
app.example.com, forward to your app (for a Compose app on the same server: the container name and port, e.g.uptime-kuma:3001, which works because Compose puts containers on a shared network — add NPM to your app's compose network for this). - On the SSL tab choose "Request a new SSL certificate", enable "Force SSL". NPM completes the Let's Encrypt challenge automatically.
5. Updates and backups
cd /opt/npm
sudo docker compose pull && sudo docker compose up -d
Everything that matters lives in the two volumes (npm-data, npm-etc — hosts, and your certificates). Stop the stack and archive both, or fold them into the automated routine in the backups guide.
Troubleshooting
- SSL challenge fails: DNS not propagated yet, or port 80 blocked. Verify the record resolves publicly and that your provider's firewall (if any) passes port 80.
- 502 Bad Gateway to a Compose app: NPM can't reach the container — join it to the same Docker network as the app (a
networks:block shared by both compose files) or forward to the host IP instead of the container name. - Locked out of the UI: you can reset the admin password by following the official docs' database-reset procedure — another reason the admin volume belongs in your backups.
Official documentation: Nginx Proxy Manager setup guide