← Library
runbook

Nginx Proxy Manager: Adding a New Service with SSL

nginx, proxy, ssl, reverse-proxy, docker

Purpose

Route a new subdomain to a containerized service through Nginx Proxy Manager (NPM), with SSL termination handled either by NPM or an upstream provider like Cloudflare.

Prerequisites

Procedure

1. Verify the Service is Reachable

Before touching NPM, confirm the service responds from the host:

curl -I http://localhost:<service-port>

If the service is in a Docker container on macOS, NPM (also in Docker) needs to reach it via host.docker.internal:<port>, not localhost. This is the single most common source of "502 Bad Gateway" in a Mac-based lab.

On Linux, use the Docker bridge IP (usually 172.17.0.1) or put both containers on the same Docker network.

2. Create the Proxy Host

  1. Open NPM admin UI at http://<server-ip>:81
  2. Go to Hosts > Proxy Hosts > Add Proxy Host
  3. Fill in:
Field Value
Domain Names service.lab.example.com
Scheme http
Forward Hostname / IP host.docker.internal (macOS) or container name (same network)
Forward Port The service's internal port
Block Common Exploits On
Websockets Support On (if the app uses WebSockets — n8n, Grafana, etc.)

3. SSL Configuration

This depends on your setup:

Option A: Cloudflare handles SSL (recommended with tunnels)

Option B: NPM handles SSL with Let's Encrypt

4. Forward Auth (Optional — for SSO)

If you run an identity provider (Authentik, Authelia, etc.), add forward auth:

  1. In the proxy host, go to the Advanced tab
  2. Add the forward auth snippet. For Authentik:
location / {
    auth_request     /outpost.goauthentik.io/auth/nginx;
    error_page       401 = @goauthentik_proxy_signin;
    auth_request_set $auth_cookie $upstream_http_set_cookie;
    add_header       Set-Cookie $auth_cookie;

    proxy_pass       http://host.docker.internal:<port>;
    proxy_set_header Host $http_host;
}

Critical: The proxy_set_header Host $http_host line must be present. Without it, the SSO provider can't construct the correct redirect URL after authentication, and you'll get redirect loops or land on the wrong page.

5. Test the Route

# Should return 200 (or 302 if behind auth)
curl -I https://service.lab.example.com

# Check NPM logs for errors
docker logs nginx-proxy-manager --tail 50

6. Reload if Needed

NPM usually picks up changes automatically, but if routing seems stale:

docker exec nginx-proxy-manager nginx -s reload

Common Issues

502 Bad Gateway — NPM can't reach the backend. Check: is the forward hostname correct? Is the service actually running? Is the port right? On macOS, is it host.docker.internal?

504 Gateway Timeout — The service is reachable but slow to respond. Increase proxy timeout in the Advanced tab:

proxy_read_timeout 300;
proxy_connect_timeout 300;
proxy_send_timeout 300;

Mixed content warnings — Your app thinks it's running on HTTP but the browser loaded HTTPS. Set the X-Forwarded-Proto header in NPM's advanced config, and configure your app to trust the proxy.

Verification Checklist

Running StdOut? Contribute a sanitized doc from your knowledge base — or get started:

Self-Host $149