Launching Nginx Proxy Manager

Nginx Proxy Manager is what I use to manage all the reverse proxies to different web apps. It also handles my ssl certificates. Now I will tell you how to get it running.

Launching Nginx Proxy Manager
Photo by Joey Kyber / Unsplash

In my first blog post I mentioned Nginx Proxy Manager. This is what I use to manage all the reverse proxies to different web apps. It also handles my ssl certificates. Now I will tell you how to get it running.

Docker Network

To make life easier (and more secure), we're going to create a seperate docker network for our service. We will attach NPM (Nginx Proxy Manager) and all services we want to expose to this network. Putting them in the same network allows NPM to act as a reverse proxy for those services, without those services having to expose their ports to the host.

We will be creating a simple bridge network. The command is simple:

root@jveweb:/opt/DockerStacks# docker network create npm_network

You can get an overview of your networks with following command:

root@jveweb:/opt/DockerStacks# docker network ls
NETWORK ID     NAME                 DRIVER    SCOPE
082aeb477221   bridge               bridge    local
37c59c54a11b   host                 host      local
e483949bc0d2   none                 null      local
f0eecf642da8   npm_network          bridge    local

The bridge, host and none networks are default. For more information on those read this stackoverflow entry. If you want more detail about any of those networks you can issue the docker network inspect <NETWORK_NAME> command.

The Files

docker-compose.yml

I will be using docker(-compose) to get NPM up and running. Create a folder with two files: docker-compose.yml and .env. The first part of the docker-compose.yml file looks very similar as the one in my post about setting up ghost.

version: '3'

networks:
  default:
    external:
      name: npm_network

The version tag defines the syntax version of docker-compose we will be using. The external npm_network (the one we just created) will be the default network for the containers in this compose file.


The next part describes the services we will be using. Apart from Nginx Proxy Manager itself, we will also need a MariaDB service. Both of those containers are build and maintained by the creator of NPM jc21. He has his own version of the MariaDB container as he needed to force it to use the aria storage engine.

services:
  npm-app:
    image: 'jc21/nginx-proxy-manager:latest'
    restart: unless-stopped
    ports:
      - '80:80'
      - '443:443'
      - '81:81'
    depends_on:
      - npm-db
    environment:
      DB_MYSQL_HOST: "npm-db"
      DB_MYSQL_PORT: 3306
      DB_MYSQL_USER: "${MYSQL_USER}"
      DB_MYSQL_PASSWORD: "${MYSQL_PW}"
      DB_MYSQL_NAME: "${MYSQL_DB}"
    volumes:
      - ${DATADIR}/npm/data:/data
      - ${DATADIR}/npm/letsencrypt:/etc/letsencrypt
  npm-db:
    image: 'jc21/mariadb-aria:latest'
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: "${MYSQL_ROOTPW}"
      MYSQL_DATABASE: "${MYSQL_DB}"
      MYSQL_USER: "${MYSQL_USER}"
      MYSQL_PASSWORD: "${MYSQL_PW}"
    volumes:
      - ${DATADIR}/db/data:/var/lib/mysql

Service npm-db describes the MariaDB instance. The environment variables will be filled at runtime using the .env file we created. The variables are self-explanatory, but if you want more information check the GitHub repository or the DockerHub page of the upstream image. The volume is where MariaDB will store its database files, the ${DATADIR} variable will be set in the .env file.

For the npm-app service; we reuse the same MYSQL_* variables to create the connection to the database. As DB_MYSQL_HOST we will set the name of the MariaDB service: npm-db. That will be the hostname of that container in the npm_network. The DB_MYSQL_PORT points to the default port 3306. As this container needs the database service, we use depends_on. It makes sure the database container is running before starting NPM.

As the outside world will connect using http and https to this application we have to expose those ports through the host. We also expose port 81 to get to the admin interface of NPM.

.env

The contents of the .env file are as follows:

DATADIR=/media/docker/npm
MYSQL_USER=*****
MYSQL_PW=*****
MYSQL_ROOTPW=*****
MYSQL_DB=*****

Replace the ***** values with your values.

Now you can run docker-compose config to see how it will look:

root@jveweb:/opt/DockerStacks/npm2# docker-compose config
networks:
  default:
    external:
      name: npm_network
services:
  npm-app:
    depends_on:
    - npm-db
    environment:
      DB_MYSQL_HOST: npm-db
      DB_MYSQL_NAME: '*****'
      DB_MYSQL_PASSWORD: '*****'
      DB_MYSQL_PORT: 3306
      DB_MYSQL_USER: '*****'
    image: jc21/nginx-proxy-manager:latest
    restart: unless-stopped
    volumes:
    - /media/docker/npm2/npm/data:/data:rw
    - /media/docker/npm2/npm/letsencrypt:/etc/letsencrypt:rw
  npm-db:
    environment:
      MYSQL_DATABASE: '*****'
      MYSQL_PASSWORD: '*****'
      MYSQL_ROOT_PASSWORD: '*****'
      MYSQL_USER: '*****'
    image: jc21/mariadb-aria:latest
    restart: unless-stopped
    volumes:
    - /media/docker/npm2/db/data:/var/lib/mysql:rw
version: '3.0'

Launch

Now run docker-compose up -d in the folder and all will be launched in the background. Now you can browse to <YOUR_SERVER_IP>:81 and start setting up your reverse proxies. More information about configuring NPM itself can be found on the official page.

Now you can also launch the Ghost container we created in the previous post.

Considerations

If you want you can create a reverse proxy inside NPM to his own admin page. This would allow you to stop exposing port 81. But I like to keep it open, as a failsafe. The port is blocked by a firewall, so only people with a VPN connection can connect to it anyway.

The database container does not have to be in the same network. It could be on its own network. This would mean other services can't connect to it by accident. But this would also mean we would need to attach an extra network to the NPM container.