Docker Networks and Nginx Proxy Manager

Docker Networks and Nginx Proxy Manager

A part of my home lab configuration is the existence of Nginx Proxy Manager. What NPM does is it takes an incoming request, usually a domain and forwards it to the correct service. In the example about you can see that the request for the website domain.cxx is searched DNS magic, for now, forwards that request to your domains IP address. If you're self-hosting a blog for example on your network, the IP address would typically be your public IP. You can find out what your IP is by going here.

From there your domain would point to your IP and then your router would see what it should do with a request for that IP and port, often 80 for http and 443 for https. The server that has your services and NPM would have its ports open for 80 and 443. NPM would take the request now in the form of domain.cxx:443 and forward that to the correct service and port on your network. Then you would get the content. Now this is a highly simplified take on what happens to request and NPM, but it helps me understand it better.

Because NPM is a reverse proxy manager it means you don't have to expose multiple ports for many services and some services even use the same ports. NPM will just 1st forward the request to the service at the correct port. That's a pretty nice thing to have, reverse proxy that is, because we don't need to expose more ports than we have too, so it hides are network behind a proxy.

Another thing that I do for security is to keep my databases on their own docker network and are only reachable by their docker container app that is on the same docker network. For example a configuration of Ghost that I would use for production would have two parts, the docker app ghost-app and the docker database ghost-db. ghost-app would be two networks as it needs to be able to access ghost-db, a frontend docker network that is external would be used with backend network that only ghost-db would be a part of, no other networks. This in my opinion is much better for security and while it's the end all to threats it makes me feel a little better. How a docker compose would look like with my principles:

version: '3'

networks:
  frontend:
    external: true
  backend: <---

services:
  ghost-app:
    image: blah:latest
    container_name: nginx-app
    environment:
      - blah:blah
    volumes:
      - /blah:/blah
    networks:
      - frontend
      - backend <---

  ghost-db:
    image: mysqlblah:latest
    restart: always
    container_name: ghost-db
    environment:
    - blah:blah
    volumes:
      - blah:/var/lib/mysql
    networks:
      - backend <---

Please don't use this gibberish

As you can see the frontend network is external and sits in the same network as Nginx Proxy Manager, so that they are able to communicate with each other. backend is left without the modification of external: true because we want Docker to create an isolated Docker network that would be ghost-backend where the ghost-app and ghost-db sit inside so that they can communicate with each other. This is that's important because Ghost will not work in production mode unless It's paired with a MySQL database. With that now all said there is the Docker compose that I would use:

version: '3'

networks:
  frontend:
    external: true
  backend:

services:
  npm-app:
    image: jc21/nginx-proxy-manager:latest
    container_name: nginx-app
    depends_on: 
      - npm-db
    restart: always
    ports:
      - "80:80"
      - "81:81"
      - "443:443"
    environment:
      - DB_MYSQL_HOST=npm-db
      - DB_MYSQL_PORT=3306
      - DB_MYSQL_USER=npm
#make sure you change this to a secure password!
      - DB_MYSQL_PASSWORD=yoursecurepassword 
      - DB_MYSQL_NAME=npm
    volumes:
      - /your/path/nginx/data:/data
      - /your/path/nginx/ssl:/etc/letsencrypt
    networks:
      - frontend
      - backend

  npm-db:
    image: jc21/mariadb-aria:latest
    restart: always
    container_name: nginx-db
    environment:
#make sure to change this to a secure root password!
      - MYSQL_ROOT_PASSWORD=rootyoursecurepassword
      - MYSQL_DATABASE=npm
      - MYSQL_USER=npm
#make sure this is the same as above in npm-app
      - MYSQL_PASSWORD=yoursecurepassword
    volumes:
      - /your/path/nginx/db:/var/lib/mysql
    networks:
      - backend

With that up and running with the command docker compose up -d in your favourite terminal you should now have NPM running. Visit your local host on port 81 or 443 to configure NPM.