Why install Nginx Proxy Manager on your VPS
As soon as you host several services on a VPS (an API, an admin panel, a Portainer, an n8n…), you have to route each domain to the right container and manage an SSL certificate for each one. Doing it by hand with Nginx configuration files and Certbot is tedious and error-prone. Nginx Proxy Manager solves this problem: from a web interface, you create a “Proxy Host” by specifying a domain and an internal target (IP:port), and NPM automatically generates the Let's Encrypt certificate. It also handles redirects, custom headers, access lists and wildcard certificates. Unlike a PaaS, NPM does not deploy applications: it is an infrastructure building block dedicated to HTTP/HTTPS routing, ideally placed in front of all your other containers.
What Nginx Proxy Manager brings
- Creation of reverse proxies in a few clicks, without editing an Nginx file.
- Automatic Let's Encrypt certificates, including wildcard via DNS challenge.
- Centralized management of all your domains and subdomains from a single interface.
- Access Lists to protect a service by password or by IP.
- Redirects, 404 hosts and custom headers configurable visually.
- Access and error logs viewable per host, useful for debugging.
Prerequisites for Nginx Proxy Manager
Nginx Proxy Manager is very lightweight: a VPS with 1 GB of RAM and 1 vCPU is amply sufficient, since NPM only routes traffic to your other containers. Plan for 15 GB of SSD disk for certificates, the SQLite database and logs. Docker and Docker Compose must be installed. Crucial point: NPM must be the only service listening on ports 80 and 443 of the VPS, since it serves as the single entry point for all web traffic. Port 81 is used for the administration interface and must never be exposed directly on the Internet. Point your DNS records (an A record for each domain, or a wildcard for the DNS challenge) to the VPS IP before generating the certificates.
Nginx Proxy Manager versus Traefik
| Criterion | Nginx Proxy Manager | Traefik |
|---|---|---|
| Configuration | Visual web interface, no file to edit | YAML files and Docker labels |
| Learning curve | Low, accessible to beginners | Steeper, DevOps-oriented |
| Let's Encrypt SSL | Automatic via the interface, wildcard possible | Automatic via configuration |
| Service discovery | Manual (entering IP:port) | Automatic via Docker labels |
| Ideal for | A few manually managed services | Dynamic environments and numerous containers |
| RAM consumption | Very low | Low |
| Logs per host | Viewable in the interface | Via an external log stack |
| Access management | Built-in Access Lists (IP, password) | Middlewares to configure |
Install Nginx Proxy Manager and create a proxy
Prepare the docker-compose
On the VPS, create a /opt/npm folder and a docker-compose.yml file declaring the jc21/nginx-proxy-manager:latest image, mapping ports 80, 443 and 81, with volumes for ./data and ./letsencrypt.
Launch the container
Run docker compose up -d. NPM starts with a default SQLite database. The administration interface becomes accessible at http://IP_DU_VPS:81.
Log in and secure the admin account
Log in with the default credentials ([email protected] / changeme), then immediately change the email and password. This is a non-negotiable security step before any exposure.
Create a Proxy Host
In “Proxy Hosts”, add a host: domain app.mydomain.com, target Forward Hostname (the container name or the internal IP) and port. Enable “Block Common Exploits” and WebSocket support if needed.
Enable automatic SSL
In the Proxy Host's SSL tab, choose “Request a new SSL Certificate”, accept the Let's Encrypt terms and enable “Force SSL”. NPM obtains and installs the certificate; your service is now accessible over HTTPS.
Protect the administration interface
Close port 81 at the firewall and create a dedicated Proxy Host to access the admin via an HTTPS domain, protected by an Access List. Never leave port 81 open on the Internet.
To obtain a wildcard certificate *.mydomain.com and cover all your subdomains at once, use the DNS challenge: in the SSL tab, select your DNS provider and provide an API key. Then connect all your containers (Portainer, n8n, your applications) to the same Docker network as NPM, in order to target each service by its container name rather than by an IP: the configuration stays stable even if the internal addresses change on restart.