Homelab Networking (Cloudflare, NGINX, & Split DNS)

In previous posts, I’ve written about how you can use Cloudflare Zero Trust & WARP to protect your network resources, focusing primarily on configuring the VPN and identity providers. In this post I want to go over my entire homelab networking setup, including how I setup dynamic DNS, automatically expose my services to Cloudflare Access, generate SSL certificates, restrict ingress traffic, and use split DNS to access resources both on my local network and on external networks through Cloudflare Access.

This setup allows me to add new homelab services without any changes in Cloudflare DNS / Zero Trust, and gives me a direct connection to my services when on my local network, allowing me to utilize my full internal network connection through the same domain name that’s routed through Cloudflare.

Prerequisites & Software

Before we get started, you should already have a domain registered and setup with Cloudflare, as well as a Cloudflare Access account. For a guide on how to setup Cloudflare Access, check out my previous post below.

Additionally, I will be using dynv6, NGINX Proxy Manager, and NextDNS for this tutorial. While you can replicate this setup with a different dynamic DNS provider, reverse proxy, and DNS server, I’ve found that these are the easiest to use and work well for me.

For this tutorial, I will be using the root level domain home.lab as an example, dedicated specifically to my home lab. While it is possible to use a domain that is hosting other (non-homelab) services or even a subdomain, you may run into issues and will need to adjust some of the steps below.

Part One: Dynamic DNS

In order to access our homelab services on external networks, we will need to know the IP address of our home network. If you have a static IP address, you can simply create an “A” record in Cloudflare pointing to your home IP, but often you will have a dynamic IP that can change at the will of your internet service provider.

To make sure that we always have a hostname pointing to our current home IP address, we will be using dynamic DNS which will create a hostname that updates every time our router detects a new IP address.

While there are many services that offer dynamic DNS (No-IP, DuckDNS, Cloudflare API), we will be using dynv6, a free service that lets you use your own hostname and has many APIs for updating your IP address. While dynv6 works well for me on a Ubiquiti router, you may need to use a different service if your router doesn’t support dynv6, or write a script to call the REST API rather than relying on your network router to push DDNS updates.

To use dynv6, first create an account, then head to “My Domains”. Enter a subdomain of your homelab’s domain (e.g. ddns.home.lab) and click “Add Domain”.

Head to the Cloudflare Zone for your domain. Add three “NS” records for the subdomain you just added, pointing to ns1.dynv6.com, ns2.dynv6.com, and ns3.dynv6.com.

Next, head back to the zone for your new DDNS domain in dynv6, and open the “Instructions” tab. To configure our router to use dynv6, we will be using the credentials under the “ddclient” section. Copy the password from this section to use in the next step.

On a Ubiquiti UniFi router, head to your internet settings page, then select the WAN port with the IP address you would like to use. Under “Dynamic DNS”, click “Create New Dynamic DNS”.

Set the service to “dynv6”, enter your DDNS hostname (ddns.home.lab), set the username to “none” (yes, literally none), and paste the password you copied from the dynv6 instructions page. Finally, set the server to the following string which will fill in the hostname and password you set in the fields above: dynv6.com/api/update?hostname=%h&token=%p&ipv4=%i

Head back to dynv6 and switch to the “Status” tab. Within a few seconds, you should see that your IP address has been updated.

Part Two: Wildcard DNS

Now that we have a hostname pointing to our home network, we need to setup the DNS records for our services. While you can create a separate DNS record for each service, we will be using a wildcard record to automatically point all subdomains to our homelab.

Before we can add the DNS record, double check that your Cloudflare zone is set to Full or Full (strict) under SSL/TLS -> Overview. You may run into issues later if this is not configured.

Back in your DNS records, add a new CNAME record pointing “*” to your new DDNS hostname (ddns.home.lab). Make sure the orange cloud (proxy mode) is enabled, otherwise Cloudflare Access will not work properly.

Part Three: Cloudflare Zero Trust Network Access

Once our DNS records are created, we can configure Cloudflare Access. Head to the Cloudflare One dashboard (one.dash.cloudflare.com), then head to Access -> Applications.

Similar to the DNS records, while we could create a separate entry for each service we want to protect, we will be creating a catch-all record so all homelab services are automatically protected. You can still individually add services if you need to apply specific settings to different services, and you can add bypass rules to your services if they should be open to the public, but this rule will ensure that by default, all of your applications are protected.

Create a new application, then select “Self Hosted”. Enter a name like “Homelab” For the subdomain, enter “*”, then select the desired domain.

Assign an access policy and configure your identity providers as desired. If you’d like to automatically allow any of your registered users using the WARP VPN client, follow the instructions from the post below.

Finally, save your application. Try opening any subdomain of your homelab’s domain (e.g. test.home.lab) in an incognito window / with WARP disabled. You should see your Cloudflare Access login page.

Part Four: NGINX Proxy Manager

At this point we have everything we need to access our homelab from external networks and we can start to configure the internal networking. For our homelab, we will be using NGINX Proxy Manager as our reverse proxy, routing all of our services to the proper internal IP addresses.

Follow the instructions here to install NGINX Proxy Manager: https://nginxproxymanager.com/setup/. Once installed, make sure that NGINX Proxy Manager has a static IP and ports 80/443 exposed, then forward ports 80/443 on your router to your NGINX Proxy Manager container. Below is my configuration on a UniFi router, but again, this process may look different depending on your router.

Next, head to your NGINX Proxy Manager instance at port 81 (admin interface) and login. By default the username is [email protected] and the password is changeme.

First we will setup a wildcard SSL certificate using a Cloudflare DNS challenge. This will require us creating an API key in Cloudflare. Head back to your Cloudflare Zone, then go to Manage Account -> Account API Tokens.

Create a new token, then choose the “Edit Zone DNS” template. Give your token a descriptive name, then select the desired zone (home.lab) under “Zone Resources”.

Save the token, then copy the token value on the next page.

Back in NGINX Proxy Manager, head to the “SSL Certificates” tab and add a new Let’s Encrypt certificate. For the domain name, enter your wildcard domain (e.g. *.home.lab). Select “Use a DNS Challenge”, select Cloudflare as your DNS provider, then paste your API token after dns_cloudflare_api_token=. Accept the terms of service and save your certificate.

Next, we’ll set up our access control list. In order to ensure that requests to our reverse proxy only come from authorized sources (Cloudflare’s proxy network or our internal network), we’ll use an access list with IP rules. Head to the “Access Lists” tab and create a new access list.

Enter a name for your access list, and check the “Satisfy Any” box.

Leave the “Authorization” list empty. This is used to set htpasswd / basic authentication credentials, but we don’t need this as we’re using Cloudflare Access for authorization. Finally, head to the “Access” tab and enter the IP / subnets you want to allow to access your homelab. To start I’ll add my primary home network subnet, 192.168.1.0/24, then I’ll add entries for each subnet on Cloudflare’s IP Ranges list: https://www.cloudflare.com/ips/.

Save the access list.

Part Five: Split DNS

Now that authentication is setup for external networks, let’s setup split DNS so we can bypass authentication when on our local network.

If you haven’t signed up already, you can create a free account at NextDNS, then follow the setup guide for your device, browser, or router. NextDNS offers many different configuration methods that are compatible with any device. You can even use the Dynamic DNS hostname we configured earlier if you need to use NextDNS’ IPv4 servers.

Once NextDNS has been configured on your network or device, open the “Settings” tab, then scroll down to the “Rewrites” section. Enter your top level domain, and the IP address of your NGINX server. This will rewrite DNS requests to your server for all hostnames under your top level domain.

Part Six: Enable your Services

Our configuration is complete! All that’s left to do is to enable your services in NGINX Proxy Manager.

In NGINX Proxy Manager, simply add a new proxy host for your service, give it a domain name under your root domain, set the access list to the “Cloudflare & Local Network” list we created earlier, then set your SSL certificate to the wildcard certificate we generated earlier.

Once added, you should immediately be able to access your service with no additional changes in Cloudflare. When accessing your service from the internet you should be prompted to login through Cloudflare Zero Trust, but when accessing your service from your local network you should bypass the login prompt and reach your service directly while still using the same domain name and SSL certificate as before.

The best part of all, when on your local network your services will utilize the full bandwidth of your network connection, eliminating ISP bottlenecks and latency!