NGINX Proxy Manager for Self Hosting

NGINX is a free, open-source, high-performance HTTP server, reverse proxy, and IMAP/POP3 proxy server. NGINX is known for its high performance and stability, free SSL with Let’s Encrypt, a rich feature set, simple configuration, and low resource consumption. NGINX  is perfect for home networks and scales in all directions.

A Specific Use Case

I wanted to point a domain and subdomains to my home server and offer services without opening up many ports on my home router. Opening up ports makes you susceptible to security threats and managing it can be painful. Instead, I forward all HTTP/HTTPS traffic to my NGINX proxy server, which will determine the traffic destination based on the sub-domain specified.

In my home lab, I am running a remote access gateway (Apache Guacamole), this blog site (WordPress), a password database manager (Bitwarden), a personal cloud server (NextCloud), a private messaging service via RocketChat, an audiobook server, and an open-source VoIP server (Increabable PBX). I use the free tier from Cloudflare to host my DNS and proxy my IP address to increase security. NGINX distributes the HTTP/HTTPS traffic to each of my services in one convenient and secure location.

Setting up NGINX can be done in many different methods and across the various OS. It does not matter if you set it up using a Windows machine, macOS, Linux, etc., or containerizing it in Docker. Here is what I would recommend, whatever platform you decide on, ensure it will run on a machine that will always be on, so it can direct your traffic as you need it. NGNIX is lightweight, and I am running it on a RaspberryPi in a docker container. You don’t have to do this, but it will be an example you can use on any Linux machine running Docker, Portainer, or Yacht.

Setting up the Docker Container

For some clarity, I am setting this up on a RaspberryPi 4B with open media vault (OMV) installed. You do not have to do this as the example extends beyond OMV and considers a Linux OS and Docker. I use OMV to store all of my data and config files in a central location on my network server. I used various servers for my home lab and wanted to centralize where I stored these files so I could move services and remap the locations easier. I also use Portainer as an easy graphical interface for Docker. Again, you don’t have to install this over the top of OMV or use Portainer.

First: Install Docker:

Update the repository:

sudo apt update

Install Docker:

sudo apt install docker
sudo apt install docker-compose

Docker install

Create a directory and move into it:

mkdir nginx
cd nginx
Make Dir

Now create a file called docker-compose.yml

NGINX is a free, open-source, high-performance HTTP server, reverse proxy, and IMAP/POP3 proxy server. NGINX is known for its high performance and stability. Free SSL with Let’s Encrypt. Perfect for home networks. NGINX has a rich feature set, simple configuration, and low resource consumption. NGINX scales in all directions.

nano docker-compose.yml

Paste the following into the file and save (CTL+X, Y, Enter):

version: "3"
    image: 'jc21/nginx-proxy-manager:latest'
    restart: always
      # Public HTTP Port:
      - '80:80'
      # Public HTTPS Port:
      - '443:443'
      # Admin Web Port:
      - '81:81'
      # These are the settings to access your db
      DB_MYSQL_HOST: "db"
      DB_MYSQL_PORT: 3306
      DB_MYSQL_USER: "changeuser"
      DB_MYSQL_PASSWORD: "changepass"
      DB_MYSQL_NAME: "npm"
      # If you would rather use Sqlite uncomment this
      # and remove all DB_MYSQL_* lines above
      # DB_SQLITE_FILE: "/data/database.sqlite"
      # Uncomment this if IPv6 is not enabled on your host
      DISABLE_IPV6: 'true'
      - ./data/nginx-proxy-manager:/data
      - ./letsencrypt:/etc/letsencrypt
      - db
    image: 'yobasystems/alpine-mariadb:10.4.17-arm32v7'
    restart: unless-stopped
      PUID: 998
      PGID: 100
      TZ: "America/Denver"
      MYSQL_ROOT_PASSWORD: "changeme"
      MYSQL_DATABASE: "npm"
      MYSQL_USER: "changeuser"
      MYSQL_PASSWORD: "changepass"
      - ./data/mariadb:/config

I left comments in the docker-compose stack that were useful when I copied it over. Leaving the comments to help understand what the compose stack is doing.

This container’s build shows that the app is:

  • Pulling a specific image from Docker Hub
  • Using ports 80,81, and 443
  • Naming the database host, port, username, and password for the database
  • Where it will map volumes to save data.

The container’s build shows that the database is:

  • Named db and the same as what the app is calling on
  • Identifying the PUID and PGID for authorized users
  • Determining time zone and set root password, database name, user, and password
  • Mapping the volumes to a config folder

You do not have to use the same MariaDB image I do, but I found that the alpine-mariadb listed above was the only image that consistently worked for me building this on my RaspberryPi. Also, finding your PUID and PGID is very simple. SSH into your NGINX server and type in the command: ‘id username’ (no quotes and the username will be what you used to SSH into the machine). You can also find your username by typing the command: whoami

UUID Example

Now bring the container up:

sudo docker-compose up -d

Now, let us check the status!


NGINX is a free, open-source, high-performance HTTP server, reverse proxy, and IMAP/POP3 proxy server. NGINX is known for its high performance and stability. Free SSL with Let’s Encrypt. Perfect for home networks. NGINX has a rich feature set, simple configuration, and low resource consumption. NGINX scales in all directions.

docker ps

After running the above docker command, you should see the containers and their status. It will list the Container ID, Image Name when the container was created, and even assigned ports.


Now open a browser and navigate to the IP Address assigned to the NGINX server.

Test Screen NGINX

You should route to a screen indicating that NGINX is running. NGINX is now ready to be configured.

Configuring NGINX for the First Time

Log in by navigating to the admin portal. The portal address is the IP Address of the NGINX server and port 81 (ex.


Your default credentials are:

User Name: [email protected]
Password: changeme

Once logged in, you will get prompted to change your credentials right away; you need to do this. When you change your information, this will take you to the user screen, and now you’re ready to start pointing URLs to your different containers and servers.


As previously mentioned, I have many different servers and applications hosted on my home network. To access them over the public internet is bought a domain name (CHEAP) and used Cloudflare’s free tier to host my DNS and forward my domain and subdomain traffic to my home.

Gone are the days when you need to have a static IP to do this. Cloudflare has a docker container that will continually update your Cloudflare account with your IP Address should it change (assuming you have a dynamic IP as I do). DuckDNS also offers a similar update process, but it was via a CRON process (which is fine, too).

Once you have your domain pointed to your home IP, you will want to ensure you have forwarded all HTTP/HTTPS traffic on your home router to your NGINX server.

Port Forwarding

Most home internet service providers leave you with the Gateway IP Address and credentials to access your home router. Depending on the manufacturer, your screens and options will be different. You will want to navigate to the firewall or port forwarding section of your router to forward port 80 and port 443 to the internal IP address of your NGINX server. Also, take the time to either ensure your NGINX server has a static IP assignment, or you have set the dynamic IP to a preferred (fixed) IP assignment, as many routers offer today.

Port Forwarding

NGNIX Routing and Let’s Encrypt

Setting up routing with NGNIX is super easy, barely an inconvenience!

Please note that if you are using Cloudflare to host your DNS, you will want to ensure that you turn off proxy IP in Cloudflares DNS management until AFTER you have validated the redirect from your NGINX server. Once traffic is routed as you desire, mask your public IP by enabling proxy IP in Cloudflare once again.

Cloudflare DNS Mngmnt

To add a URL to forward to your container or router, select ADD PROXY HOST on the proxy page. This will pop up a window where you will enter the details of the domain name (or subdomain) you want to forward. Enter the domain name, scheme (HTTP), forward hostname (I use IP addresses), the port you want it to go to, and move the slider to “block common exploits.” Before saving, select the SSL shield at the top of the box. Select “request a new SSL Certificate with Let’s Encrypt” in the SSL Certificate box. Slide the force SSL and HTTP/2 Support radials to activate them. Enter an email address for Let’s Encrypt and agree to the Terms of Service, then Save. It may take a min to register, but your redirect and new SSL cert will be active and working.

For those not aware, Let’s Encrypt is a Certificate Authority (CA) that offers SSL certificates that are just as secure as paid certificates but does so at no charge.

Proxy Hosts ViewNew Proxy DetailsProxy Host SSLThere is not much more to it. Once NGINX is up and running, you almost forget about it until you are adding more applications that you are making available outside your network. NGINX can do much more than just what I have written about here. You can dive in deeper and set up customer 404, authentication for no login applications, and a reverse proxy to support domains on your home network.

As examples, I have included posts below for specific blogs on project applications I host outside my home network.

Additional Resources:
How-to’s on Hosted Services mentioned in this post:

1 thought on “NGINX Proxy Manager for Self Hosting

  1. E says:

    Great information! I love the step-by-step examples you provided.


Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.