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.

Nginx Proxy Manager dashboard
Clean overview of proxy hosts, SSL certificates, and access lists.

Lab Setup Overview

  • Hardware: Raspberry Pi 4 (or any Docker host), reliable power, Ethernet.
  • Network: Public port forward 80 & 443 to 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
  1. Portainer → StacksAdd stack, paste the YAML, then Deploy the stack.
  2. Open http://<host-ip>:81. Default login: admin@example.com / changeme → change email & password immediately.
Portainer stack showing NPM
NPM running with persistent volumes for config and certificates.

Create Your First Proxy Host

  1. In your DNS, point app.example.com → your public IP.
  2. 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 (or https if upstream serves TLS)
  • Websockets Support: enabled if your app uses it
  • Block Common Exploits: enabled

Under SSL:

  • Request a new SSL CertificateLet’s Encrypt
  • Enter a valid email, agree to TOS, and Force SSL
  • Ensure ports 80/443 are 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.

Add Proxy Host form
Proxy Host: domain, upstream target, SSL, and common protections.

Other Useful Host Types

Redirection Hosts

Handy for permanent moves (301) or vanity domains. Example: redirect status.example.comhttps://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.

Custom locations routing
Path‑based routing lets one domain front multiple backends.

Maintenance & Backups

  • Back up volumes: ./data and ./letsencrypt contain 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 80 remains reachable, or use a DNS challenge if your environment blocks HTTP validation.