Setting up a reverse proxy for HTTPS with a custom domain using Nginx Proxy Manager, AdGuard Home and Cloudflare
I've used a reverse proxy to access my self-hosted apps and services for years, and used Pi-Hole as my home network DNS for even longer, but recently switched to AdGuard Home. That meant redoing all my DNS records within AdGuard so I could get my reverse proxy back up and running, and I decided to write down the steps I took. When done, we'll be able to access our apps and services through a custom domain, with unique sub-domains for each app or service, with full HTTPS and accessible only locally.
Sections
- Pre-Requisites and Caveats
- Setting up AdGuard Home as network DNS server
- Adding DNS rewrites in AdGuard Home
- Add a domain in Cloudflare
- Install and configure Nginx Proxy Manager
- References
Pre-Requisites and Caveats
I wrote previously about how to set this up using Pi-Hole, but I recently bought a GL.iNet Flint 2 router which has AdGuard Home built-in, so it seemed a waste not to use it. (Also for as great as Pi-Hole is, I have had to redo it multiple times over the years due to database errors or just a dead mini SD card or USB drive, etc.) So, this guide will be mostly based on my old one, with just the parts dealing with Pi-Hole replaced with AdGuard Home, since setting up Nginx Proxy Manager and Cloudflare work the same as always.
This guide uses specific third-party services, namely Cloudflare, AdGuard Home and Nginx Proxy Manager to set up a secure local-only reverse proxy. The same is possible with other tools, apps and services including Pi-Hole (which as I mentioned, I previously used for many years) or NextDNS instead of AdGuard Home, Caddy or Traefik instead of Nginx, any other DNS provider instead of Cloudflare, etc. I’m only writing about my preferred tools that I’ve used multiple times to set everything up and keep it running for over a year.
This guide will require a owned custom top-level domain (TLD), such as a .com
or .cc
or .xyz
, etc. Certain TLDs can be bought for super cheap on Namecheap or Porkbun, but be aware in most cases after the first year or two, the price will see a steep jump. I again prefer Cloudflare for purchasing domains, since they always price domains at cost, so you won’t see any surprise price hike one year to the next. An alternative I won’t be getting into is using dynamic DNS, as I’ve not had to use it myself, so I honestly wouldn’t even know how to begin to set that up.
Setting up AdGuard Home as network DNS server
In my case, AdGuard Home already comes installed and ready to use on the GL.iNet Flint 2 router, requiring only toggling it on from the router’s web admin UI to activate. If you want to run it bare metal on a server, see their getting started guide. If you want to run AdGuard Home in a Docker container, this compose.yaml
should work for you as a base.
![]()
Please note, I have never run AdGuard Home in a Docker container myself, I’m just using common sense defaults to get up and running fast. Using
network_mode: host
allows all necessary network ports, including53
for DNS (which must be available for DNS resolution to work), port3000
for the web UI, ,853
for DNS over TLS, etc.Check out the Docker Hub page for AdGuard Home if you want to expose specific ports, or want to make other changes not covered here.
services:
adguardhome:
image: adguard/adguardhome
container_name: adguardhome
network_mode: host
restart: unless-stopped
volumes:
- /local/path/adguardhome/work:/opt/adguardhome/work
- /local/path/adguardhome/conf:/opt/adguardhome/conf
When ready, use command docker compose up -d
to download and run the container as a daemon in the background. (If you’re already running a stack of containers, you can add the above to your existing compose file.)
Next you’ll need to set the IP address of AdGuard Home as the DNS server in your router. (If you’re setting this up on the Flint 2, skip this part because it’s automatically configured.) Each router is different, but generally you’re looking for the DNS server setting, usually located within a router’s DHCP settings. If your router lets you set a custom DNS server, enter the IP address of the machine running AdGuard Home here, e.g. 192.168.0.50
.
However, not all routers let you set a custom DNS server (this is especially common in ISP-provided routers), in which case you are out of luck — you will have to manually set the AdGuard Home IP address as the DNS in network settings on a per-device basis. If this is undesirable or unfeasable, and if your router lets you turn off it’s DHCP server, you might consider using Pi-Hole instead since it can act as a DHCP server for your network.
Once AdGuard Home is being broadcast as the network’s DNS server by the router, your devices will gradually begin querying it as they renew their DHCP leases. You can usually force a renew by restarting a device, or just reboot the router and it should propagate the changes to all devices.
Add DNS rewrites in AdGuard Home
Next, we’ll go into the AdGuard Home web UI and add the DNS rewrites we need for Nginx Proxy Manager. The web UI should be accessible via your browser at http://<ip-address>:3000
.
-
In the AdGuard Home web UI, click on Filters on the navigation bar at the top, and choose DNS Rewrites from the dropdown menu.
-
Click on the Add DNS rewrite button.
-
Add a your domain as a wildcard like
*.domain.com
, and under that the IP address of the server running your services, e.g.192.168.0.50
, then click on Save.
![]()
If you want to proxy services from more than one server, create specific entries for each one rather than using a wildcard — for example,
service1.domain.com
would point to192.168.0.50
,service2.domain.com
would point to192.168.0.100
, etc.This is also the case you want to proxy something straight to
domain.com
rather than a sub-domain, make sure to create a specific DNS rewrite for it, e.g.domain.com
pointing to192.168.0.200
.
That’s all you have to do with AdGuard Home. Next, we’ll be using Cloudflare to get the TLS certificates for our custom domain.
Add a domain in Cloudflare
You’ll need to create a free account on Cloudflare. (Feel free to use another DNS provider if you prefer.) You can add a domain bought from another registrar to Cloudflare by following the below instructions, or if you purchase a domain on Cloudflare it will automatically be configured and you can skip this section.
To add an existing domain to Cloudflare:
- On the Cloudflare dashboard Account Home, click the + Add a domain button.
-
Enter your domain, leave Quick scan for DNS records selected, and click Cotinue.
-
Click on the Free plan at the bottom and click Continue.
- You’ll see your DNS records, if there are any. Don’t worry about this right now and click on the Continue to activate button.
- You’ll see a pop-up window saying you should set your DNS records now, click on Confirm.
-
You’ll be provided some instructions to update the nameservers on your domain’s registrar, open a new tab and follow those instructions. Once you’ve added the Cloudflare nameservers at your registrar, go back to Cloudflare and click on Continue.
-
Now you’ll have to wait a few minutes for the changes to propagate, then click on Check nameservers and reload the page. If it’s still shows Pending next to the domain at the top, just keep waiting. In the meantime, we need to do some additional setup.
-
From your domain’s Overview scroll down and you’ll see a section at the bottom-right called API with a Zone ID and Account ID. Under that, click on Get your API token.
-
Click the button Create Token, then click the Use template button next to Edit DNS Zone.
-
Under Permissions, leave the first entry as is, click on +Add more.
-
For the new Permission, choose in order from the dropdown menus Zone, Zone and Read.
-
Under Zone Resources, leave the first two dropdown menus as is, and in the final dropdown all the way to the right, select your domain. Scroll past everything else,without changing anything else, click on Continue to summary, and finally on the Create Token button.
-
On the next page you’ll see your API token, make sure to save it somewhere because it will not be shown again. We will need this API token for to provision the TLS certificates in Nginx Proxy Manager.
-
Once your domain is Active in Cloudflare, you can move on to the next section.
Install and congifure Nginx Proxy Manager
If you don’t have Docker installed already and need to do it from scratch, I suggest using Docker’s own install script by running the command curl -fsSL get.docker.com | sudo sh
. I’ll be using docker compose
to install and run Nginx Proxy Manager, it’s the easiest way to run long-term containers.
Create a compose.yml
file, use the below as a base. (If you are also running AdGuard Home as a container, I’d suggest putting them both on one compose file.)
services:
nginx-proxy-manager:
container_name: nginx-proxy-manager
image: "jc21/Nginx-proxy-manager:latest"
ports:
- 81:81 # web UI port
- 80:80
- 443:443
volumes:
- /opt/docker/nginx:/data
- /opt/docker/letsencrypt:/etc/letsencrypt
restart: unless-stopped
![]()
Make sure that ports
80
and443
are available on your server and not being used by anything else! Nginx Proxy Manager needs port80
for HTTP and port443
for HTTPS.
This compose file uses bind mounts to store container data in specific directories on the host, as I find this easier to migrate than volumes. (If you save your site on GitHub you can just clone it and install it anywhere.)
Be sure to type in your own local path to where you want the data from Nginx Proxy Manager to live in your server, e.g. /home/bob/docker/..
etc. and run the following command within the same directory where the compose file is located:
docker compose up -d
If you are running Portainer and want to create the container(s) from within it’s UI — rather than creating the compose file and using commands in the terminal — do the following:
-
In the Portainer web UI, go into your environment and click Stacks from the sidebar.
-
Click the + Add Stack button at the top-left. Name the stack, copy and paste the contents of the
compose.yaml
above into the web editor. -
Once done, scroll down and click the Deploy the stack button.
Whichever method you use, wait a few moments while the image is downloaded and the container is created. Once it’s up and running we can login to the Nginx Proxy Manager web UI at http://<ip-address>:81
where the IP is the server running Nginx Proxy Manager.
Go into the Nginx Proxy Manager web UI at http://<your-ip-address>:81
, login with the default email [email protected]
and password changeme
, and as soon as you login go to Users on the nav bar, and change (ideally) both the email and password of the administrator account.
To add proxy hosts click on Hosts on the navigation bar at the top, then click the Add Proxy Host button.
We’ll create an entry for Plex first, which is running as a container on the same host at port 32400. You’ll begin in the Details tab.
-
Under Domain Names type in
*.domain.com
and click theAdd *.domain.com
dropdown that appears. Make sure to include the*
as this will create a wildcard certificate for use with all subdomains. -
Leave Scheme as
http
. -
For Forward Hostname/IP type in your server IP.
-
For Forward Port type in
32400
. -
Toggle on Websockets Support and Block Common Exploits, but leave caching off.
-
Go to the SSL tab, click under SSL Certificate and select Request a new SSL Certificate from the dropdown.
-
HTTPS should work with Force SSL toggled off, but feel free to toggle it on if you prefer.
-
Toggle on Use a DNS Challenge, then under DNS Provider choose
Cloudflare
from the dropdown. -
Under Credentials File Content you’ll see see
dns_cloudflare_api_token=
followed by numbers. Replace these numbers with your Cloudflare API token. -
At the bottom, type an email address (you’ll get emails when your certificate is about to expire), toggle on that you agree to the Let’s Encrypt TOS, and click Save.
Assuming you set up and entered your Cloudflare API token correctly, after a minute or two an SSL certificate will be provisioned and the proxy host will be created. Now you should be able to go to https://plex.domain.com
and see your Plex UI with full HTTPS.
To add additional proxy hosts, repeat the process as above (changing the forward port to the one used by each specific app you are proxying), but when you get to the SSL tab choose your now existing *.domain.com
certificate from the dropdown, then proceed to choose Cloudflare as DNS provider and enter the API token. This process has to be done each time you add a new proxy host.
Always make sure the full URL you want to use (subdomain.domain.com
) is added to the CNAME Records in Pi-Hole (or whatever DNS server you use in your home network) pointing to the server running Nginx Proxy Manager as target.
If something does not work as intended (503 error or the like), fiddle with the proxy host options — try both http
and https
scheme, try toggling Force SSL on and off, double-check your API token is correct, etc. You can also check the Nginx Proxy Manager container logs with the terminal command docker logs nginx-proxy-manager
. (Or whatever container_name
you used in the compose file when creating the container.)
Barring any errors, once you set up all your proxy hosts in Nginx Proxy Manager you should have full HTTPS when going to your services via https://subdomain.domain.com
.
![]()
One last thing, if you want to want to access the AdGuard Home web UI via HTTPS as well, be sure to use its default HTTPS network port 3001 in Nginx Proxy Manager.