Nginx Proxy Manager Lab:
Reverse Proxy & SSL the Easy Way (Docker + Portainer)
Why Nginx Proxy Manager?
Nginx Proxy Manager (NPM) provides a friendly web UI on top of Nginx so you can reverse proxy multiple self‑hosted services behind a single public IP with HTTPS certificates from Let’s Encrypt. In this lab, I deployed NPM with Docker via Portainer and configured proxy hosts, SSL, access control, and advanced routes.
Lab Setup Overview
- Hardware: Raspberry Pi 4 (or any Docker host), reliable power, Ethernet.
- Network: Public port forward
80&443to the Docker host; DNS A/AAAA records for your domain/subdomains. - Software: Docker Engine, Portainer CE,
jc21/nginx-proxy-manager, test services (e.g., whoami, Home Assistant).
Install Docker & Portainer
Same base as my other labs—quick recap:
# Docker (Pi OS / Debian)
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER
# Portainer
sudo docker volume create portainer_data
sudo docker run -d \
-p 8000:8000 -p 9443:9443 \
--name portainer \
--restart=always \
-v /var/run/docker.sock:/var/run/docker.sock \
-v portainer_data:/data \
portainer/portainer-ce:latest
Deploy Nginx Proxy Manager via Portainer
Use a Stack for a tidy, repeatable deployment.
# portainer stack: npm
version: "3.8"
services:
app:
image: jc21/nginx-proxy-manager:latest
container_name: nginx-proxy-manager
restart: unless-stopped
ports:
- "80:80" # HTTP
- "81:81" # Admin UI
- "443:443" # HTTPS
volumes:
- ./data:/data
- ./letsencrypt:/etc/letsencrypt
- Portainer → Stacks → Add stack, paste the YAML, then Deploy the stack.
- Open
http://<host-ip>:81. Default login:admin@example.com/changeme→ change email & password immediately.
Create Your First Proxy Host
- In your DNS, point
app.example.com→ your public IP. - NPM → Hosts → Proxy Hosts → Add Proxy Host:
- Domain Names:
app.example.com - Forward Hostname / IP:
192.168.1.50(or container name) - Forward Port:
3000 - Scheme:
http(orhttpsif upstream serves TLS) - Websockets Support: enabled if your app uses it
- Block Common Exploits: enabled
Under SSL:
- Request a new SSL Certificate → Let’s Encrypt
- Enter a valid email, agree to TOS, and Force SSL
- Ensure ports
80/443are reachable from the internet (for HTTP challenge)
Save. Browse to https://app.example.com — you should see your app through NPM with a valid certificate.
Other Useful Host Types
Redirection Hosts
Handy for permanent moves (301) or vanity domains. Example: redirect status.example.com → https://status.newdomain.com with Force SSL.
404 Hosts
Catch-all handler for unknown subdomains—useful to avoid leaking your origin or to display a simple branded page.
Streams (TCP/UDP)
NPM can proxy TCP/UDP to internal services (e.g., a lightweight game server). Use sparingly and only when you understand the security implications; not all protocols are proxy‑friendly.
Custom Locations & Path‑Based Routing
Under a Proxy Host you can add Custom locations to split traffic by path to different upstreams. Example: serve / from a static site and /api from an API container.
Maintenance & Backups
- Back up volumes:
./dataand./letsencryptcontain your config and certs. - Updates: pull the latest image and redeploy the stack; NPM will migrate config automatically.
- Certificates: Let’s Encrypt renewals are automated; ensure port
80remains reachable, or use a DNS challenge if your environment blocks HTTP validation.