Nginx Proxy Manager: Reverse Proxy and SSL in the GUI - 夜莺博客

Nginx Proxy Manager: Reverse Proxy and SSL in the GUI

Nginx Proxy Manager is the pragmatic choice when you want nginx and free certificates but do not want to hand-write server blocks. It is a container that manages nginx and Certbot for you, wrapped in a web UI: define a proxy host, pick a domain, tick the SSL box, and you have TLS termination in a couple of minutes. This guide covers the deployment, the certificate workflow, websocket and large-upload settings, and the two failure modes that generate most of the community questions.

Deploy It

services:
  app:
    image: 'jc21/nginx-proxy-manager:2.16.0'
    restart: unless-stopped
    environment:
      TZ: "Asia/Shanghai"
    ports:
      - '80:80'      # public HTTP (ACME HTTP-01 challenge + redirect)
      - '81:81'      # admin UI - never expose this to the internet
      - '443:443'    # public HTTPS
    volumes:
      - ./data:/data
      - ./letsencrypt:/etc/letsencrypt
docker compose up -d
docker compose logs -f
# Default login: admin@example.com / changeme  -- change it immediately

The admin interface on port 81 holds the certificates and the reverse-proxy configuration. Restrict it to your management network, an IP allowlist, or a VPN. Anyone who reaches it can point your domains anywhere.

Get a Certificate First

Create the certificate before creating the proxy host — it makes debugging considerably easier.

  1. SSL Certificates → Add SSL Certificate → Let's Encrypt.
  2. Enter the domain (and wildcard *.example.com if required).
  3. For a wildcard you must use the DNS challenge: add the provider's credentials / API token. Without an API token the wildcard will fail.
  4. Accept the terms and save. NPM asks the CA to validate, then stores the certificate and sets it to renew automatically.

Port 80 must be reachable from the internet for the HTTP-01 challenge, and your DNS A record must already point at the server. Validation failures here are almost always DNS propagation or a firewall in front of port 80.

Create the Proxy Host

Hosts → Proxy Hosts → Add Proxy Host:

  • Domain Names — the FQDN you issued the certificate for.
  • Scheme — http or https to the backend.
  • Forward Hostname / IP — 10.10.10.50 or the container name if on the same Docker network.
  • Forward Port — for example 8080.
  • Block Common Exploits — on.
  • Websockets Support — on if the app uses them (most modern dashboards do; a missing websocket upgrade shows up as a UI that loads and then never updates).

Then on the SSL tab select your certificate, enable Force SSL, HTTP/2 Support and HSTS Enabled.

Advanced Tab: The Lines You Will Need

# Large uploads (Nextcloud, Immich, media apps)
client_max_body_size 16G;
proxy_request_buffering off;

# Long-running requests / streaming
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;

# Client IP and scheme delivered to the backend
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;

# Websocket upgrade (if the toggle alone is not enough for a non-standard app)
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $http_upgrade;

The client_max_body_size default of 1 MB is the classic “uploads fail with 413” cause, and it must be raised both in NPM and in the application's own PHP/Node limits.

Access Lists and External Authentication

Use Access Lists to require HTTP basic auth or an IP allowlist on any host you do not want public — an admin panel, a router UI, a Proxmox interface. It is not authentication for real users; it is a fence that keeps scanners out, and it is far better than nothing.

Two Failure Modes to Know

Certificates stop renewing

Renewal happens inside the container on a schedule. If the container was down during the renewal window, or port 80 was closed, the certificate expires and users see a warning. Check SSL Certificates for the renewal date, and keep the container running — a stopped NPM cannot renew.

Redirect loop behind another proxy

If NPM sits behind a CDN or cloud load balancer, forcing SSL on both layers produces an infinite redirect. Terminate TLS at exactly one layer, or configure the outer layer to pass X-Forwarded-Proto: https and the inner layer to trust it.

Backups

Everything that matters lives in ./data and ./letsencrypt. Back up both directories together: the proxy host definitions and the certificates are useless apart. A restore is a container restart with those volumes in place — which is exactly why this pattern, rather than hand-written nginx configs, survives a disk failure with far less drama.

Related Reading

Deeper dives on the same topics from our archive:

原文链接:https://nginxproxymanager.com/guide/