Kituwa IT · Self-hosting guides

Install Nginx Proxy Manager with Docker Compose

Reverse proxy and automatic Let's Encrypt certificates

reverse proxyTLSlets encrypt

Nginx Proxy Manager is a web UI in front of Nginx: create a hostname, point it at a container, tick "Request a new SSL certificate", done. For a home server with fifteen services it replaces an afternoon of hand-editing config files with a form.

Category
Network & proxy
License
MIT
Needs
MariaDB + Docker socket
Image
jc21/nginx-proxy-manager

What it is

A management layer over Nginx with automatic Let's Encrypt certificates, access lists, streams and redirects, plus a Docker-aware service list. Every self-hosted app that says "put it behind a reverse proxy" ends up here.

Before you start

  • Ports 80 and 443 must be free on the host, and DNS must already point at it. Let's Encrypt HTTP-01 validation needs to reach port 80 from the internet.
  • It mounts the Docker socket to read container names and IPs. That's a privilege you should be comfortable granting — it is effectively root on the host.
  • Every app it proxies should bind its host port to 127.0.0.1. If an app listens on 0.0.0.0 it's directly reachable, and the proxy's certificate and access controls mean nothing.

1 — Create the directory

Command / configuration
mkdir -p ~/services/nginx-proxy-manager/{data,db}
cd ~/services/nginx-proxy-manager

2 — Write the compose file

Command / configuration
services:
  app:
    image: jc21/nginx-proxy-manager:latest
    container_name: nginx-proxy-manager
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
      - "81:81"
    volumes:
      - ./data:/data
      - ./db:/database
      - /var/run/docker.sock:/var/run/docker.sock:ro
    healthcheck:
      test: ["CMD", "/bin/check-health"]
      interval: 30s
      timeout: 5s
      retries: 3

Port 81 is the initial setup UI. Once you've created your admin account and added a proxy host, close it with docker exec nginx-proxy-manager sh -c "touch /data/nginx-proxy-manager-initial" && docker restart nginx-proxy-manager.

3 — Start it

Command / configuration
docker compose up -d
docker compose logs -f app | grep -i "listen\|error"

4 — First-run setup

  1. Open http://yourhost:81 and create the admin account. The defaults are admin@example.com / changeme — change them before anything else.
  2. Add a proxy host. Scheme http, forward to the container name and port (e.g. nextcloud and 80). Add both hostnames (docs.example.com and www.example.com).
  3. SSL tab → Request a new SSL certificate → tick "Force SSL", "HTTP/2" and "HSTS". Save. The certificate appears in about ten seconds if DNS is right.
  4. Advanced tab → add the WebSocket support snippet if your app needs it (Mattermost, n8n, Uptime Kuma). It's a custom location block with the Upgrade/Connection headers.

5 — The bit everyone misses

Command / configuration
# give the proxy a stable LAN address for upstreams
# and set the container name as the forward hostname, not localhost
Locating containers vs DNSBy default NPM resolves service names through Docker's DNS on a shared network. If your app is on a different network and NPM can't see it, either attach both to one external network, or forward to the host's 127.0.0.1 with the app's published port. A 502 Bad Gateway here is 90% of the time a networking mismatch, not an app problem.

Help when you need it

Want help getting this running?

We can help with a supported Linux host, application setup, migration or troubleshooting. Contact us to confirm the software, scope and scheduling before ordering.

Related guides

← Browse all 30 guides · Back to top