Skip to content
appsgit

Deploy guide

How to self-host Nginx Proxy Manager with Docker Compose

Install Nginx Proxy Manager with Docker Compose: ports 80, 443 and 81, first admin setup, free Let's Encrypt certificates, proxy hosts, backups and upgrades.

  • Updated
  • Beginner
  • About 10 minutes

You will need

  • 1 vCPU / 512 MB RAM
  • Docker + Docker Compose v2
  • Ports 80 and 443 free and reachable from the internet
  • A domain name with DNS records pointing at the server

What is Nginx Proxy Manager?

Nginx Proxy Manager is a web interface for running Nginx as a reverse proxy, with free SSL certificates from Let's Encrypt. It is open source under the MIT license and lets you point domains at your self-hosted apps, add HTTPS, set up redirects and protect services with access lists, all without writing Nginx configuration by hand.

Requirements

  • A Linux server with 1 vCPU and 512 MB of RAM.
  • Docker Engine and Docker Compose v2.
  • Ports 80 and 443 not used by anything else on the host, and open in your firewall (and forwarded on your router for home servers).
  • One or more domain names with A or AAAA records pointing at the server.

Step 1: Prepare the server

This guide assumes Ubuntu 24.04 with Docker installed. If you need Docker, follow the official install guide. Check that nothing else is listening on ports 80 and 443:

sudo ss -ltnp | grep -E ':(80|443)\s'

Then create a folder and a shared Docker network that your apps can join:

mkdir -p ~/npm && cd ~/npm
docker network create proxy

Step 2: Create the Docker Compose file

Save this as docker-compose.yml:

services:
  app:
    image: jc21/nginx-proxy-manager:2
    container_name: nginx-proxy-manager
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
      - "127.0.0.1:81:81"
    environment:
      TZ: "Europe/London"
      # Uncomment if IPv6 is not enabled on your host:
      # DISABLE_IPV6: "true"
    volumes:
      - ./data:/data
      - ./letsencrypt:/etc/letsencrypt
    networks:
      - proxy

networks:
  proxy:
    external: true

Nginx Proxy Manager uses a built-in SQLite database by default, which is fine for almost every setup. It needs no secrets in the Compose file; you create the admin account in the browser.

The admin port 81 is bound to 127.0.0.1. The admin UI controls every domain and certificate on the server, so it should not be open to the internet. Reach it through an SSH tunnel (Step 3), or proxy it through NPM itself with an access list. The 2 tag tracks the current 2.x release; pin a specific version such as 2.16.0 from the releases page if you prefer.

Step 3: Start and open the app

docker compose up -d
docker compose logs -f app

The first start generates keys and initialises the database, which can take a minute. From your own computer, open an SSH tunnel:

ssh -L 8181:127.0.0.1:81 user@YOUR_SERVER_IP

Then browse to http://localhost:8181. Current versions show a setup screen where you create the first admin user with your email and a strong password. Enable two-factor authentication in your profile if your version offers it.

Step 4: Put it behind HTTPS

Nginx Proxy Manager is itself the HTTPS layer, so this step is about adding your first site. Click "Add Proxy Host" and fill in:

  • Domain Names: app.example.com
  • Forward Hostname / IP: the container name of your app on the proxy network, such as uptime-kuma
  • Forward Port: the app's internal port, such as 3001
  • Websockets Support: on, for apps with live updates

On the SSL tab, choose "Request a new SSL Certificate", enable "Force SSL" and "HTTP/2 Support", and save. The equivalent in Caddy, for comparison, is just:

app.example.com {
    reverse_proxy uptime-kuma:3001
}

To make an app reachable by name, add networks: [proxy] to its service and declare proxy as an external network in its Compose file. You can then remove the app's own ports: mapping so it is reachable only through the proxy.

Backups and upgrades

Back up both folders: ./data (database, proxy host configuration, access lists and logs) and ./letsencrypt (certificates and account keys). Stop the container for a consistent copy:

docker compose stop && tar czf npm-$(date +%F).tgz data letsencrypt && docker compose start

Upgrade with:

docker compose pull && docker compose up -d

Troubleshooting

  • Certificate request fails: the DNS record does not point at this server yet, or port 80 is blocked. Let's Encrypt HTTP validation needs port 80 open from the internet. For servers behind CGNAT, use a DNS challenge instead.
  • 502 Bad Gateway: NPM cannot reach the upstream. Use the container name on a shared network, not localhost, which refers to the NPM container itself.
  • Container fails with "address already in use": another web server, often Apache or Nginx from the OS, is using port 80 or 443. Stop and disable it.
  • Uploads fail with 413: add client_max_body_size 1G; under the proxy host's Advanced tab.

Next steps

Add access lists for admin tools, create redirection hosts for old domains, set up a wildcard certificate with a DNS challenge, and put every self-hosted app behind NPM on the shared proxy network.

Spotted something out of date? Tell us and we will update the guide.

FAQ

Nginx Proxy Manager questions

Still curious? Email info@appsgit.com.

What ports does Nginx Proxy Manager use?

Nginx Proxy Manager uses port 80 for HTTP and Let's Encrypt validation, port 443 for HTTPS, and port 81 for its admin web interface.

Is Nginx Proxy Manager free?

Yes. Nginx Proxy Manager is free and open source under the MIT license.

What is the default Nginx Proxy Manager login?

Current versions show a setup screen on first launch where you create the admin account yourself. Older releases used admin@example.com with the password changeme, which you had to change at first login.

How do I proxy to other Docker containers with Nginx Proxy Manager?

Put Nginx Proxy Manager and the app on the same Docker network, then use the container name and internal port as the forward hostname and port, for example vaultwarden and 80.

Nginx Proxy Manager vs Caddy vs Traefik?

Nginx Proxy Manager is configured through a web UI, which suits people who prefer clicking over config files. Caddy uses a short config file with automatic HTTPS, and Traefik reads Docker labels, which suits larger, automated setups.