Skip to main content
  1. Posts/

Nginx Proxy Manager - Reverse Proxy as simple as it gets

·7 mins· loading ·
Self-hosting Application
Timo
Author
Timo
Business Applications Architect, Network Engineer, Self-hosting Hobbyist.
Table of Contents

Nginx Proxy Manager is a tool for managing and configuring Nginx reverse proxies through a user-friendly web interface. It offers support for multiple domains, HTTPS/SSL certificates, and automatic Let’s Encrypt integration. Whether you are a technical user looking to set up and manage your own Nginx proxy server or a non-technical user looking for an easy way to get started with Nginx, Nginx Proxy Manager is a great choice.

Requirements
#

  • Public domain or at least a DynDNS domain (e.g. DuckDNS) pointing to your routers public interface
  • Port Forwarding for HTTP (80/tcp) and HTTPS (443/tcp) Traffic
  • Docker/Compose

Port Forwarding
#

For your Reverse Proxy to work it is necessary that any http(s) traffic
(e.g. https://myservice.domain.tld) is pointed to the host you’re running Nginx Proxy Manager on. This requires a public domain or at least a Dynamic DNS domain pointing to the public interface (in other words your public IP Address) of your router. Now all you have to do is forwarding the ports 80/tcp and 443/tcp to the host of Nginx Proxy Manager.

The way you do this depends on your router, just google something like
port forwarding <ROUTER_MODEL>.

Installation
#

Create a external docker network called reverse-proxy.
Adding our services and Nginx Proxy Manager to the same docker network later on makes sure, our Reverse Proxy can redirect to them without the need of exposing ports for every single service. More on that later.

docker network create reverse-proxy

Create a installation directory for Nginx Reverse Proxy.

mkdir /opt/nginx-reverse-proxy

Generate the docker-compose.yml.

version: "3"
services:
  app:
    image: 'jc21/nginx-proxy-manager:latest'
    restart: unless-stopped
    container_name: nginx-proxy-manager
    ports:
      # These ports are in format <host-port>:<container-port>
      - '80:80' # Public HTTP Port
      - '443:443' # Public HTTPS Port
      - '81:81' # Admin Web Port
      # Add any other Stream port you want to expose
      # - '21:21' # FTP
    environment:
      DB_MYSQL_HOST: "db"
      DB_MYSQL_PORT: 3306
      DB_MYSQL_USER: "npm"
      DB_MYSQL_PASSWORD: "password"
      DB_MYSQL_NAME: "npm"
      # Uncomment this if IPv6 is not enabled on your host
      # DISABLE_IPV6: 'true'
    volumes:
      - /opt/nginx-proxy-manager/data:/data
      - /opt/nginx-proxy-manager/letsencrypt:/etc/letsencrypt
    depends_on:
      - db

  db:
    image: 'jc21/mariadb-aria:latest'
    restart: unless-stopped
    container_name: nginx-proxy-manager_db
    environment:
      MYSQL_ROOT_PASSWORD: 'root'
      MYSQL_DATABASE: 'npm'
      MYSQL_USER: 'npm'
      MYSQL_PASSWORD: 'password'
    volumes:
      - /opt/nginx-proxy-manager/data/mysql:/var/lib/mysql

networks:
  default:
    external:
      name: reverse-proxy
Generate secure passwords for DB_MYSQL_PASSWORD / MYSQL_PASSWORD and MYSQL_ROOT_PASSWORD.
The networks block adds Nginx Proxy Manager to the earlier created docker network reverse-proxy.

Spin the container up with:

docker-compose up -d
Check if the containers are up and running with docker-compose ps.
In case of troubleshooting see the docker logs with: docker logs nginx-proxy-manager.

You now should be able to browse to http://<host_ip_address>:81 and log in with the default credentials:

Email:    admin@example.com
Password: changeme

Initial login with default credentials.
Initial login with default credentials.

Right after your first login you’ll be requested to change your account details and set a new password.

Edit user details.
Edit user details.
Change to a secure password.
Change to a secure password

You’re now able to start setting up your SSL certificates and create your first proxy hosts.

SSL Certificates
#

Why are we using a Reverse Proxy in the first place?
We want to access our services in a secure and trusted way, this is where SSL Certificates come into play to help us keep user data secure by verifying ownership of a website and therefor preventing Man-in-the-middle attacks.

With Nginx Proxy Manager and its integrated Certbot you can either create SSL Certificates per Proxy Host (like service.domain.tld) or implement a single Wildcard Certificate which can be used for all Proxy Hosts within your domain (like *.domain.tld). Since having a dedicated SSL Certificate for every service you’re running can get quite messy with time I recommend using a much more convinient Wildcard Certificate.

Wildcard Certificate (Cloudflare)
#

To do so we need to create an API Token from our DNS provider, in this case we are using Cloudflare.
Follow this link to your Cloudflare profile and click on Create Token and create a Custom Token.

Create a Token from Cloudflare.
Create a Token from Cloudflare.

This should generate an API Token you can use for Nginx Proxy Manager to interact with your Cloudflare account.

Now let’s create a Wildcard Certificate in Nginx Proxy Manager, to do so click Add SSL Certificate in the SSL Certificates tab.

Add a SSL Certificate in Nginx Proxy Manager.
Add a SSL Certificate in Nginx Proxy Manager.

Fill out all the necessary information and click on save.

Fill out the information to create a Wildcard Certificate from Cloudflare.
Fill out the information to create a Wildcard Certificate from Cloudflare.

This process can take a few minutes but if everything goes right your should be presented with your newly created Wildcard Certificate, which can be used for all future proxy hosts you create within your domain.

Newly generated Wildcard Certificate from Cloudflare.
Newly generated Wildcard Certificate from Cloudflare.

Restricting Access
#

Since the majority of your services for security reasons should not directly be published to the internet Nginx Proxy Manager allows to implement Access Lists. With these Access Lists we can restrict access by defining IP Address Whitelists and Blacklists or forcing Authorization.


Before publishing your services to the internet check the following post about WireGuard, set up your own VPN and securely access your self-hosted services…

Secure and Fast VPN with Wireguard
·5 mins· loading
Self-hosting Application
… and think about adding another layer of security with an authentication portal like Authelia.
Secure Access with Authelia
·5 mins· loading
Self-hosting Application


For your services to be reachable via a Proxy Host you need some kind of local DNS service pointing to Nginx Proxy Manager since you won’t create a public DNS record for them ( Pi-hole for example comes with local DNS too).

In this step we will create a Access List called local and therefor restrict access to local subnets by clicking on Add Access List in the Access Lists tab.

Add a Access List in Nginx Proxy Manager.
Add a Access List.

Fill in the details and whitelist the local subnets 10.0.0.0/8, 172.16.0.0/12 and 192.168.0.0/16.

Name your Access List in Nginx Proxy Manager.
Name your Access List.

Allow access by your local DNS provider.
Allow access by your local DNS provider.

You can now select this Access List when creating a Proxy Host.

Your first Proxy Host
#

We can finally create our first Proxy Host, click on Add Proxy Host in the tab Hosts –> Proxy Hosts.

Add your first Proxy Host in Nginx Proxy Manager.
Add your first Proxy Host.

Define the Domain Name and the destination (Hostname / IP Address and Port of your service).

Set up your first Proxy Host in Nginx Proxy Manager.
Set up your first Proxy Host.

Select the SSL Certificate we created earlier and click on Save.

Set up your first Proxy Host in Nginx Proxy Manager.
Set up your first Proxy Host.

We should now be able to browse our service securely via the defined URL https://uptime.dizzytech.de.

Access your newly created Proxy Host.
Access your newly created Proxy Host.

Pro Tip
#

As long as your instance of Nginx Proxy Manager and the service you want to create a Proxy Host for are running on the same host, you can join them in the same docker network and reach your service without the need of exposing ports.
To do so we have to join our service (in this case Uptime Kuma) the same docker network as Nginx Proxy Manager and comment out the port exposure.

Add the following code to join your service to the docker network called reverse-proxy:

networks:
 default:
   external:
     name: reverse-proxy

The finished docker-compose.yml should look something like this:

version: "3.8"

services:
  app:
    container_name: uptime-kuma
    image: louislam/uptime-kuma:1
    restart: unless-stopped
    volumes:
      - uptime-kuma:/app/data
    # ports:
      # - "50001:3001"

volumes:
  uptime-kuma:
    driver: local

networks:
 default:
   external:
     name: reverse-proxy
Don’t forget to define a container_name for your service too since this is the hostname Nginx Proxy Manager will be redirecting to.

Recreate the docker container with the following command:

docker compose up -d --force-recreate
If you are unsure about the container port you can always check with docker-compose ps or docker ps.

We can now adjust the Proxy Host for our service by entering the container_name as Forward Hostname / IP and the container port as Forward Port.

Adjust the Proxy Host of your service.
Adjust the Proxy Host of your service.

If everything works as expected you are now able to access your service without exposing any ports of the docker container.

Final Thoughts
#

Besides Nginx Proxy Manager there are many popular Reverse Proxy services out there, for example Traefik and Caddy just to name a few. The convinience of an easy-to-use Web GUI and the solid functionality never gave me a reason to consider changing to any other Reverse Proxy solution.
Nginx Proxy Manager is beginner-friendly and doesn’t leave you hanging even when your requirements might get more advanced, it’s all in all a great choice.

Consider leaving a ⭐ at the GitHub Repo if you like Nginx Proxy Manager.