NGINX Proxy Manager – How-To Installation and Configuration

If you’re searching for a small and easy-to-set-up reverse proxy with a beautiful UI, you’re at the right place. In this tutorial, I will show you how to install the NGINX proxy manager in a docker container on Linux.

Prerequisites

For this tutorial, you need a Linux server that has docker and docker-compose installed. Docker-Compose is simple and easy to manage containers with static configuration files. But you could also deploy NGINX proxy manager in other container management systems if you want. If you want to know how to install docker on Linux, just have a look at the official docker documentation and docker-compose documentation.

What is NGINX proxy manager

NGINX proxy manager is a reverse proxy management system, that is based on NGINX with a nice and clean web UI. You can also obtain trusted SSL certificates, manage several proxies with individual configs, customizations, and intrusion protection. It is open-source and maintained GitHub. It’s perfect for small environments like home labs or small server environments. You can easily expose any web service or application with it. It includes a free SSL certificate management by letsencrypt that can also be used to obtain wildcard certs. To deploy the NGINX proxy manager you need a small MySQL database container and the NGINX container. Let’s have a look at how to deploy this easily with docker-compose.

Deploy NGINX proxy manager in docker how-to

Now we need to create our docker-compose file. I will create a new project folder in the /opt directory called “nginxproxymanager”. Then I create a docker-compose.yaml file with the following template.

version: '3'
services:
  app:
    image: 'jc21/nginx-proxy-manager:latest'
    ports:
      - '80:80'
      - '81:81'
      - '443:443'
    environment:
      DB_MYSQL_HOST: "db"
      DB_MYSQL_PORT: 3306
      DB_MYSQL_USER: "npm"
      DB_MYSQL_PASSWORD: "npm"
      DB_MYSQL_NAME: "npm"
    volumes:
      - ./data:/data
      - ./letsencrypt:/etc/letsencrypt
  db:
    image: 'jc21/mariadb-aria:10.4'
    environment:
      MYSQL_ROOT_PASSWORD: 'npm'
      MYSQL_DATABASE: 'npm'
      MYSQL_USER: 'npm'
      MYSQL_PASSWORD: 'npm'
    volumes:
      - ./data/mysql:/var/lib/mysql

Start the NGINX proxy manager stack with the following command.

docker-compose up -d

Login to the web UI of NGINX proxy manager

Now we can log in to the web UI. Simply use your browser to connect to your server by using the IP address or an FQDN and connect on port “81”. Log in with the username “admin@example.com” and the password “changeme”. Next, you should change your username and password, and that’s it!

You can create proxy hosts, obtain trusted SSL certificates, manage access control lists and much more. First let’s add a new domain on our DNS server, that we’re able to obtain a new SSL certificate.

Create a DNS A record for your domain that points to your server

I create a new A record on my server that is called “research.the-digital-life.com” that points to the public IP of my cloud server. I’m using DigitalOcean as my DNS provider because their DNS management is completely free and very easy. If you want to try out DigitalOcean use this link to get 100$ for 60-days for free!

Obtain trusted SSL certificates for your services

Next, we need to obtain our SSL certs in the NGINX proxy manager UI. Go to “SSL certificates” and enter your details. Note, if you want to use a wildcard cert like “*.the-digital-life.com”, you will need to enable the “Use a DNS Challenge” method. Select your DNS provider and follow the instructions, based on your provider’s documentation. But in this example, I won’t use a DNS challenge, because I want to obtain an SSL cert for the subdomain “research.the-digital-life.com”.

Once you click on “Save”, the NGINX proxy manager tries to obtain your trusted SSL cert. If everything is successful, you should see your cert in the list.

Expose a simple unsecured web application

To expose a simple web application that is running on our server, we will create a new “Proxy Host”. In this example, I will expose a docker container that is running “nextcloud”.

Note, it’s very important to understand how networking works in docker. Because docker networks are isolated from each other, you need to make sure that the app you want to expose is connected to the NGINX proxy manager network “nginxproxymanager_default”. I’m doing this by running the following command. Alternatively, you could also add more services in the docker-compose.yaml file.

docker run --network nginxproxymanager_default --name=nextcloud nextcloud

Create a new proxy host

Now we can create a new “Proxy Host”. Make sure you select the “Scheme” “HTTP” if you want to expose any unsecured application that doesn’t use HTTPS. This is the protocol of the destination. Fill in the “domain names”, which should match all domains in your SSL cert. When you enter the Forward Hostname/IP you can simply enter the name of the docker “service” you want to expose. If your app is not running in a docker container, you could also simply add the IP address.

By enabling “Block Common Exploits” we also add some protection features to our app. Next select the SSL cert we’ve just created and enable force SSL, HTTP/2, and HSTS if you want to.

Now, we will test if everything works fine. Simply connect to the domain and you should see that your app is accessible now. But I know there can be some errors, let’s also talk about what could go wrong.

Common error: Bad Gateway 502

This error happens when the reverse proxy can’t connect to the destination host, or doesn’t get a response. Most likely, in docker setups, the containers are not on the same network, or the destination is not correct. Make sure you’re accessing the correct IP/hostname and the NGINX proxy manager can reach this target.

Also note, that the NGINX proxy manager is running in a docker container, so using the IP address 127.0.0.1 will NOT refer to the host OS IP address, but the container’s internal address.

Another common issue is that the communication between the NGINX proxy manager and the target can’t be established because the protocol version is incorrect. Make sure you’re using the correct Scheme “HTTP” for unsecured destination sites, and “HTTPS” for secured destination sites that use a self-signed cert!

I hope this was helpful, but if you have other problems and you’re searching for help, just have a look at our Discord community.

30 thoughts on “NGINX Proxy Manager – How-To Installation and Configuration”

  1. Hi Christian,
    DB initalisation in Docker failed:
    2020-12-08 8:08:30 0 [Note] InnoDB: Starting shutdown…

    2020-12-08 8:08:30 0 [ERROR] Plugin ‘InnoDB’ init function returned error.

    2020-12-08 8:08:30 0 [ERROR] Plugin ‘InnoDB’ registration as a STORAGE ENGINE failed.

    2020-12-08 8:08:30 0 [Note] Plugin ‘FEEDBACK’ is disabled.

    2020-12-08 8:08:30 0 [ERROR] Could not open mysql.plugin table. Some plugins may be not loaded

    2020-12-08 8:08:30 0 [ERROR] Unknown/unsupported storage engine: InnoDB

    2020-12-08 8:08:30 0 [ERROR] Aborting

    :###
    ich benutze dein docker-compose.yml ohne Änderung
    Hast du eine Idee ?

    Reply
  2. CentOS 7 on a Virual Server. httpd is down.
    I used this docker-compose.yml

    [version: ‘3’
    services:
    app:
    image: ‘jc21/nginx-proxy-manager:latest’
    ports:
    – ’80:80′
    – ’81:81′
    – ‘443:443’
    environment:
    DB_MYSQL_HOST: “db”
    DB_MYSQL_PORT: 3306
    DB_MYSQL_USER: “npm”
    DB_MYSQL_PASSWORD: “npm”
    DB_MYSQL_NAME: “npm”
    volumes:
    – ./data:/data
    – ./letsencrypt:/etc/letsencrypt
    db:
    image: ‘jc21/mariadb-aria:10.4.12’
    environment:
    MYSQL_ROOT_PASSWORD: ‘npm’
    MYSQL_DATABASE: ‘npm’
    MYSQL_USER: ‘npm’
    MYSQL_PASSWORD: ‘npm’
    volumes:
    – ./data/mysql:/var/lib/mysql
    ](url)
    When I start docker-compose.yml without -d to see all errors. I get this error

    app_1 | ❯ Enabling IPV6 in hosts: /data/nginx
    app_1 | [1/2/2021] [3:50:42 PM] [Global ] › ℹ info Generating MySQL db configuration from environment variables
    app_1 | [1/2/2021] [3:50:42 PM] [Global ] › ℹ info Wrote db configuration to config file: ./config/production.json
    db_1 | 2021-01-02 15:50:43 3 [Warning] Access denied for user ‘npm’@’172.18.0.3’ (using password: YES)
    app_1 | [1/2/2021] [3:50:43 PM] [Global ] › ✖ error ER_ACCESS_DENIED_ERROR: Access denied for user ‘npm’@’172.18.0.3’ (using password: YES)
    db_1 | 2021-01-02 15:50:44 4 [Warning] Access denied for user ‘npm’@’172.18.0.3’ (using password: YES)

    Reply
  3. I need your help to analyze an error that is happening to me when I try to install NGINX proxy manager.

    When I follow the steps according to your tutorial it throws me a port error in which it says : 0.0.0.0:443 and 0.0.0.0:80 are already assigned…

    Note: I have installed mailcow and within the pack is Nginx alpine with that range of ports assigned … for that reason the NGINX proxy manager only works by port 81.

    What do I do?

    Reply
  4. I need your help to analyze an error that is happening to me when I try to install NGINX proxy manager.

    When I follow the steps according to your tutorial it throws me a port error in which it says : 0.0.0.0:443 and 0.0.0.0:80 are already assigned…

    Note: I have installed mailcow and within the pack is Nginx alpine with that range of ports assigned … for that reason the NGINX proxy manager only works by port 81.

    What do I do?

    Reply
  5. Hallo wie kann man Webseiten einbinden die lokal auf den host System liegen?

    Da Nginx Proxy Manager ja im Container lauft und zb. nur mit den Gateway 172.17.0.1 kommuniziert.

    Was müsste man bei ADD Host eintragen um eine lokale Webseite zb. Nextcloud einzubinden welche auf den Gastgebersystem installiert ist?

    Reply
    • Dazu müsstest du den netwerkmodus auf “host” modus in der docker-compose datei vom Nginx proxy Manager umschalten und die lokale IP addresse und den Port ansprechen.

      Reply
  6. Thank you for the excellent guide, is there a way in nginx proxy manager to map to a directory instead of a subdomain? for example how to turn:
    container1.domain.com ==> container1:8080
    container2.domain.com ==> container2:753
    container3.domain.com ==> container3:59880
    into:
    docker.domain.com/container1 ==> container1:8080
    docker.domain.com/container2 ==> container2:753
    docker.domain.com/container3 ==> container3:59880

    Reply
  7. Hello
    Thank you for the great instructions
    I am struggling with Nextcloud.
    Is there a way to show me step by step how to configure Nextcloud to be accessed remotely using NPM?

    Here is what I have done so far
    1-I am able to get nextcloud to work internally
    2-I have NPM working and functioning with home assistant so I know it is working
    3-I need instructions on how to set up NPM host proxy for nextcloud
    4-I need instructions on how to modify the config.php of nextcloud to work with NPM

    Thank you in advance

    Reply
  8. Thank you for the awesome guide, is there a way in NGINX Proxy Manager to reverse proxy to folder? Instead of container.domain.com mapping to internal host:port it’s domain.com/container to internal host:port?

    Thank you

    Reply
  9. Thank you for the awesome article, is there a way to reverse proxy to a subfolder instead of a sub domain?
    For example:
    sub.domain.com/some_folder1 maps to internal_IP1:port
    sub.domain.com/some_folder2 maps to internal_IP2:port
    Etc…

    Thank you for creating all these informative guides.

    Reply
  10. Hola @Christian

    I was having some trouble in order to enable UFW and NPM container in order to access to other containers outside of their docker network
    I tried to use the flag network_mode: “host” for “app” service, but, obviously, the “db” get inaccesible,
    so, after several trial/fails, I decide to mount NPM without any database, well, in fact with sqlite3, but without any other “service” in the docker-compose:
    https://github.com/jc21/nginx-proxy-manager/issues/200
    After that, I add the flag (network host) now I am able to reach to another containers using 127.0.0.1

    Is ther a better way to do this?

    Reply
    • What I do is, connect all containers to the NPM network, OR I connect NPM to all networks of the containers. You can easily connect them to more than one network, so that’s working for me very well.

      Reply
  11. Hallo!
    Ich bekomme immer einen internen Error, wenn ich ein SSL Zertifikat erzeugen lassen will.
    Woran kann das liegen? NPM Version ist 2.8.0

    Reply
  12. Hallo Christian,

    vielen Dank für diese Anleitung und den zugehörigen Video. Ich habe es mit festem IPv4 Anschluss ausprobiert und es hat wunderbar funktioniert. Leider bekomme ich nun einen DSlite Anschluss mit fester IPv6 Adresse. Deshalb würde ich gerne wissen, wie NPM mit IPv6 arbeitet. Leider findet sich darüber arg wenig bis nichts im Internet. Hast Du dazu eventuell Informationen oder könntest Du die Voraussetzungen für diesen Fall beschreiben – IPv6 Konfiguration von Docker, Docker Compose und NPM? Könnte mir vorstellen, dass mit IPv6 sich auch viele andere jetzt und zukünftig beschäftigen müssen.

    Viele Grüße

    Torsten

    Reply
    • Since MySQL was taken over by Oracle, senior engineers created mariaDB as a fork of MySQL. Since then a lot of things have been changed, newer versions of MySQL are a bit different than the older MySQL versions or mariadb. It’s hard to do a 1 by 1 comparison, however, I like using mariadb most of the time 🙂

      Reply
  13. Hallo Christian,
    I have installed successfully and using with no problem at all.
    Only thing annoying is renewing certificates. the expiration date on the SSL certificates from Let’s Encrypt comes with 180 days expiration time as default. is there a way to change the default to 1,800 day for example?

    Thanks

    Reply
  14. This is a very cool solution I am using only a raspberry pi with rasbian os – it works fine.
    Only problem is when i reboot the computer the the docker-compose stuff is not running but I not sure if this need some create command to know how to start the docker-compose.yml file.
    I can cd to my /opt directory and run docker-compose start but I am new to this docker compose solution.

    Reply
  15. Hallo Christain! cooler Beitrag – leider scheitere ich schon im 3. Schritt – “Create a DNS A record for your domain that points to your server” … in welchen der 4 Menüpunkte (Proxy Host etc.) muss ich diesen Schritt ausführen?

    Danke und VG!

    Reply
  16. I installed it on my Windows computer and everything worked perfectly right from the start. Since I do not want that computer running 24/7, I deleted the container and installed this on my Ubuntu computer. Changed ports 80 and 443 in the router to the Ubuntu computer. It works, but as soon as I use SSL for one of my domains, I get Bad Gateway 502. Without SSL, everything works. Any ideas what might be wrong?

    Reply

Leave a Comment

I accept the Privacy Policy