In many self-hosting setups, a single public IP address often has to handle dozens of services. Managing all these services using plain Nginx means writing and maintaining numerous server blocks, proxy rules, and route maps that are prone to misconfiguration as services grow. The main challenge is not only the complexity of configuration files, but also managing TLS/SSL certificates for each domain, handling automatic renewals, and dealing with port conflicts.
What is Nginx Proxy Manager (NPM)?
Nginx Proxy Manager (NPM) is a container-based application that wraps Nginx with a web User Interface to manage reverse proxies, hosts, SSL/TLS certificates, redirections, and TCP/UDP streams. NPM provides a dashboard that allows users to add or modify proxy hosts, connect hostnames to backends, and request Let's Encrypt certificates without manually editing Nginx configuration files.
Why Choose NPM?
- Free & Open Source: A free solution with an active community.
- User Friendly UI: Suitable for users who prefer not to edit configurations manually.
- Automatic SSL: Direct integration with Let's Encrypt for automatic certificate issuance and renewal.
- Quick Comparison:
- Plain Nginx: Flexible but requires manual configuration and is prone to human error.
- NPM: Focuses on ease of operation and centralized certificate management.
1. Preparation & Installation
Minimum Server Specifications
- CPU: 1 vCPU
- RAM: 1 GB (2 GB recommended if running multiple containers)
- Disk: 10 GB free space
- Network: Inbound access on ports 80, 443, and 81
Docker Installation
Use the official Docker installation script. Run the following command:
sudo sh -c "curl -fsSL https://get.docker.com/ | sh"
Docker Compose
Create the npm directory:
mkdir npm
cd npmCreate the compose.yml file:
nano compose.ymlInsert the following configuration, make sure to change the password in the environment section:
services:
npm:
image: jc21/nginx-proxy-manager:2.14.0
container_name: nginx-proxy-manager
restart: unless-stopped
ports:
- "80:80"
- "81:81"
- "443:443"
environment:
DB_MYSQL_HOST: "db"
DB_MYSQL_PORT: 3306
DB_MYSQL_USER: "npm"
DB_MYSQL_PASSWORD: "npm_password_here"
DB_MYSQL_NAME: "npm"
volumes:
- ./data:/data
- ./letsencrypt:/etc/letsencrypt
depends_on:
- db
db:
image: 'jc21/mariadb-aria:latest'
container_name: mariadb-nginx-proxy-manager
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: "root_password_here"
MYSQL_DATABASE: "npm"
MYSQL_USER: "npm"
MYSQL_PASSWORD: "npm_password_here"
volumes:
- ./data/mysql:/var/lib/mysql
networks:
default:
name: npm_networkExplanation:
- Services: npm (Reverse Proxy)
- Ports:
- 80:80 & 443:443: Main entry points for HTTP and HTTPS traffic.
- 81:81: Port to access the NPM Admin Dashboard.
- Environment: Connects NPM to the MariaDB database using the same credentials as the db service.
- Volumes:
- ./data: Stores host configurations and user settings.
- ./letsencrypt: Stores SSL certificates so they persist even after container restarts.
- Ports:
- Services: db (Database)
- Image (mariadb-aria): A database version optimized for NPM to be lighter and faster.
- Volumes (./data/mysql): Critical to ensure tables and proxy user data are permanently stored on the host disk.
- Networks
- name: npm_network: Creates a dedicated network. Other containers can join this network and be recognized by NPM simply by their container name.
Running & First Login
Start the containers:
sudo docker compose up -dVerify the docker compose result:
sudo docker compose psExample output:
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
mariadb-nginx-proxy-manager jc21/mariadb-aria:latest "/scripts/run.sh" db 37 seconds ago Up 36 seconds 3306/tcp
nginx-proxy-manager jc21/nginx-proxy-manager:latest "/init" npm 37 seconds ago Up 36 seconds 0.0.0.0:80-81->80-81/tcp, [::]:80-81->80-81/tcp, 0.0.0.0:443->443/tcp, [::]:443->443/tcpAccess the admin panel on port 81 (e.g., http://server-ip:81). Proceed to create an admin account.
2. Usage Scenarios
a. Reverse Proxy for Docker Containers
An application running inside a Docker container is to be accessed via the subdomain docker-app.domain.com through NPM on the same host, with both containers connected to the same network (npm_network) to ensure smooth internal communication.
Topology:
User → Internet → NPM (80/443) → Container (container_name:80)Run the container to be connected with NPM:
sudo docker run -d --name nginx-app --network npm_network -p 127.0.0.1:8080:80 --restart always nginx:alpine
Steps to Create Proxy:
- Hosts → Proxy Hosts. Add Proxy Hosts.
- Details:
- Domain Names = e.g., docker-app.domain.com.
- Scheme = http.
- Forward Hostname / IP = nginx-app (since it is on the same network, just use the container name)
- Forward Port = 80.
- SSL:
- Request a new Certificate
- Force SSL
- HTTP/2 Support
- HSTS Enabled
- Then Save.

b. Reverse Proxy for Different Hosts
In this scenario, the application is hosted on a different machine than NPM, so access is done using the application server's IP address rather than a container name.
Topology:
User → Internet → NPM (10.130.0.2) → App (10.130.0.3:8080)Steps to Create Proxy:
- Hosts → Proxy Hosts. Add Proxy Hosts.
- Details:
- Domain Names = e.g., other-app.domain.com.
- Scheme = http.
- Forward Hostname / IP = application server IP, e.g., 10.130.0.3.
- Forward Port = application port, e.g., 8080.
- SSL:
- Request a new Certificate
- Force SSL
- HTTP/2 Support
- HSTS Enabled
- Then Save.
3. Custom SSL Certificate
If you prefer not to use SSL from Let's Encrypt, Nginx Proxy Manager supports custom SSL certificates.
Adding an SSL Certificate:
- Certificates → Add Certificate → Custom Certificate.
- Give the certificate a name and upload the certificate key file, certificate file, and intermediate certificate (optional).
- Save.
Changing an SSL Certificate:
- Edit Proxy Host → SSL tab.
- Under SSL Certificate, select the name of the SSL certificate you have added.
- Save.
Conclusion
Nginx Proxy Manager simplifies reverse proxy and SSL management through a GUI, making it ideal for self-hosters who want a quick solution without manually editing configuration files. For highly dynamic infrastructures or large-scale orchestration, other solutions may be more suitable. However, for ease of operation and centralized management, NPM is an excellent choice.




