Skip to main content
Proxy Basics

How to Setup Nginx Proxy Manager: The Ultimate 2026 Guide

8 min read

How to Setup Nginx Proxy Manager: The Ultimate 2025 Guide

Nginx Proxy Manager (NPM) is a critical tool for network engineers, developers, and homelab enthusiasts. It acts as a frontend for the powerful Nginx web server, simplifying the management of reverse proxies, SSL termination, and access control lists through a web-based GUI. Instead of writing cryptic Nginx configuration files by hand, NPM allows you to manage traffic routing with a few clicks.

This guide provides a technical, deep-dive approach to setting up and configuring Nginx Proxy Manager in 2025, covering Docker deployment, security hardening, and integration with proxy rotation for scraping tasks.

---

Part 1: Prerequisites and Docker Deployment

While NPM can be run on bare metal or as a Node.js application, the most stable and recommended deployment method is via Docker. This ensures isolation of dependencies and easier updates.

1.1 System Requirements

Before starting, ensure your host system meets the following criteria:

  • OS: Ubuntu 20.04/22.04 LTS, Debian 11+, or CentOS Stream (Windows/Mac via Docker Desktop is also supported).
  • RAM: Minimum 1GB (2GB recommended).
  • Network: Static IP address assigned to the host.
  • Domain: A registered domain (e.g., example.com) with A Records pointing to your host's public IP. *
  • 1.2 Docker & Docker Compose Installation

    If you do not have Docker installed, execute the following commands on a Debian/Ubuntu system:

    curl -sSL https://get.docker.com | sh
    

    sudo usermod -aG docker $USER

    Log out and back in for group changes to take effect

    1.3 The Directory Structure

    Create a dedicated directory to house your NPM configuration and database data. Persistence is key here to ensure you don't lose your proxy configurations during container updates.

    mkdir -p ~/npm/data
    

    mkdir -p ~/npm/letsencrypt

    1.4 Creating the docker-compose.yml

    Navigate to your new directory and create the docker-compose.yml file.

    cd ~/npm
    

    nano docker-compose.yml

    Paste the following configuration. This setup includes NPM and a MariaDB database container. Note that we are exposing ports 80, 443, and 81.

    version: '3'
    

    services: app: image: 'jc21/nginx-proxy-manager:latest' restart: unless-stopped ports: - '80:80' # Public HTTP - '81:81' # Administration Dashboard - '443:443' # Public HTTPS environment: DB_SQLITE_FILE: "/data/database.sqlite" # Uncomment below if using MySQL/MariaDB instead of SQLite # DB_MYSQL_HOST: "db" # DB_MYSQL_USER: "npm" # DB_MYSQL_PASSWORD: "npm" # DB_MYSQL_NAME: "npm" volumes: - ./data:/data - ./letsencrypt:/etc/letsencrypt # Uncomment the 'db' service below if using MySQL/MariaDB # db: # image: 'jc21/mariadb-aria:latest' # restart: unless-stopped # environment: # MYSQL_ROOT_PASSWORD: 'npm' # MYSQL_DATABASE: 'npm' # MYSQL_USER: 'npm' # MYSQL_PASSWORD: 'npm' # volumes: # - ./data/mysql:/var/lib/mysql

    *Note: The default SQLite database is sufficient for most users handling fewer than 100 sites. For enterprise setups involving thousands of proxies, switch to the MariaDB configuration provided in the comments.*

    1.5 Launching the Stack

    Deploy the containers using Docker Compose:

    docker-compose up -d
    

    Verify that the containers are running:

    docker ps
    

    ---

    Part 2: Initial Configuration and Access

    2.1 Accessing the Admin UI

    Once the containers are running, open your browser and navigate to:

    http://:81

    You will be greeted by the login screen.

    2.2 Default Credentials

    NPM ships with default credentials that must be changed immediately upon login.

  • Email: admin@example.com
  • Password: changeme
  • Upon first login, you will be prompted to change your name and email, and set a new, strong password.

    ---

    Part 3: Configuring Reverse Proxies (The "How-To")

    The primary function of NPM is to route incoming traffic to a specific backend service based on the domain name requested.

    3.1 Understanding the Flow

    1. Client requests https://app.mydomain.com. 2. DNS resolves app.mydomain.com to your NPM Server IP. 3. NPM (listening on port 443) receives the request. 4. NPM checks its config for app.mydomain.com. 5. NPM forwards the traffic to the internal IP (e.g., 192.168.1.50:3000).

    3.2 Step-by-Step Proxy Host Creation

    1. Navigate to the "Hosts" tab > "Proxy Hosts". 2. Click "Add Proxy Host". 3. Fill in the following details: * Domain Names: subdomain.yourdomain.com (e.g., plex.mydomain.com). * Scheme: http (or https if your internal app uses SSL). * Forward Hostname / IP: The internal IP of the service (e.g., 192.168.1.55). * Forward Port: The port of the service (e.g., 8096 for Plex). 4. Advanced Features: * Cache Assets: Enable this to improve load times for static sites. * Block Common Exploits: Highly recommended to enable. * Websockets Support: Required for apps like Nextcloud, guac, or Omada. 5. Click Save.

    3.3 SSL Certificate Management

    One of NPM's strongest features is its integration with Let's Encrypt.

    1. In the "Proxy Host" edit screen, click the SSL tab. 2. Select "Request a new SSL Certificate". 3. Select "Let's Encrypt" from the dropdown. 4. Accept the Terms of Service. 5. Click Save.

    NPM will now perform a challenge (usually HTTP-01) to verify you own the domain and issue the certificate. It will also create a Cron job inside the container to auto-renew this certificate before it expires.

    ---

    Part 4: Advanced Configuration and Custom Nginx Config

    Sometimes the GUI isn't enough for complex routing logic. NPM allows you to inject raw Nginx configuration.

    4.1 Adding Custom Headers (CORS)

    If you are running an API or a frontend that needs to talk to a backend on a different port, you may need CORS headers.

    1. Go to "Proxy Hosts" > Edit your host. 2. Go to the "Custom" tab. 3. In the "Custom Nginx Configuration" box:

    Allow CORS for specific origin

    add_header 'Access-Control-Allow-Origin' 'https://my-frontend.com' always; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always; add_header 'Access-Control-Allow-Headers' 'Authorization, Content-Type' always;

    Handle Pre-flight requests

    if ($request_method = 'OPTIONS') { return 204; }

    4.2 Nginx Proxy Manager for Scraping

    As a scraping expert, you can use NPM to route traffic through rotating residential proxies if you host your scraping dashboard locally, or simply to manage your scraping tools (like Scrapy, Scrapoxy, or Zyte). You can also use NPM to *act* as the proxy manager for a network of internal scrapers.

    However, typically when people ask about "scraping" in the context of NPM, they want to route specific outgoing traffic. Since NPM is an *Ingress* controller (incoming traffic), it is not designed to change the *outgoing* proxy settings of your Python scripts.

    Example: Python scraping script configuration (This usually happens on the *client* side, not the NPM side).

    import requests
    

    proxies = { "http": "http://user:pass@your-residential-proxy-ip:8000", "https": "http://user:pass@your-residential-proxy-ip:8000", }

    response = requests.get("http://httpbin.org/ip", proxies=proxies) print(response.json())

    In this scenario, NPM would be used to host the dashboard that displays these scraping results, accessible only to you via an Access List.

    4.3 Access Lists (Security)

    NPM allows you to password protect specific sites (Basic Auth) or limit access to specific IPs.

    1. Go to "Access Lists". 2. Create a new list. 3. Select "Basic Authorization" for a simple username/password prompt. 4. Go back to your Proxy Host > Access tab. 5. Apply the newly created Access List.

    This is useful for staging sites or admin dashboards (like Portainer or Pi-hole) that you don't want exposed to the public internet.

    ---

    Part 5: Troubleshooting Common Issues

    "502 Bad Gateway"

    This is the most common error. It means NPM is running, but it cannot reach the backend service.

  • Check: Is the backend container running? (docker ps)
  • Check: Is the IP and Port in the Proxy Host configuration correct?
  • Check: Do you have a firewall on the backend server blocking the NPM IP?
  • "SSL Challenge Failed"

  • Check: Does your domain A record actually point to the NPM server IP? (Use dig domain.com to verify).
  • Check: Is port 80 open to the world? Let's Encrypt validation requires port 80.

---

Conclusion

Nginx Proxy Manager transforms the complex art of Nginx configuration into a user-friendly, dashboard-driven experience. By deploying it via Docker, you ensure a robust, resilient system capable of managing SSL certificates, securing internal services with Access Lists, and routing traffic efficiently. Whether you are setting up a homelab dashboard or securing production applications, NPM is the industry standard for 2025.

Share: