I’ve been in the process of setting up Home Labs for both myself and my parents. One surprisingly annoying issue has been accessing these servers externally (for VPN access and enabling webhooks for things like Home Assistant). I am documenting the steps I took mostly for myself, but hopefully it helps a few folks as well.

Note: for folks using just Home Assistant standalone, I would use the DuckDNS integration. I am doing this because I have multiple containers that need reverse proxy access.

Why?

When you have a Home Lab behind a consumer internet connection, your public IP changes, which makes it hard for other services like a VPN client or 3rd party webhook to ping your server.

What?

We’re going to dynamically update DNS entries on Cloudflare so sub.yourdomain.com will always point to your public IP address.

How?

Domain on Cloudfront

You will need to have a domain on Cloudfront (or any other service that ddclient can update). I’m assuming you have one already.

Then you need to get an API Token before you set up ddclient. You can do that on Cloudflare by:

  1. In the top right, click on My Profile
  2. On the side navigation, click on API Tokens
  3. Click on Create Token and use the Edit Zone Template
  4. Under Zone Resources make sure you update it to the domain you purchased.

You then need to create the subdomain that will point to your homelab. You can do that by going to your domain and clicking on DNS on the side navigation and clicking on Add Record. You can set the IPv4 address to whatever, since it’ll be updated later.

MAKE SURE YOU UNCHECK PROXY STATUS otherwise you will have issues with configuring things like VPNs later.

Setting up ddclient

I have an existing debian instance running a few cron jobs already, so I’m re-using that.

I highly suggest using the latest version of Debian (I’m using 12.2). I’ve run into issues with Debian 10 and Ubuntu 22 installing old versions of ddclient that end up not working.

You can start by install ddclient by running the following command:

apt-get install ddclient

This will start the setup process:

  1. For Dynamic DNS Provider, select Cloudflare
  2. For username enter in the word token
  3. For password enter the token you created above
  4. For the comma-separated FQDN enter the full domain (including subdomain) you created
  5. For method select Web-based IP discovery service

Now we need to edit /etc/ddclient.conf and add zone=. The file should look something like this:

# Configuration file for ddclient generated by debconf
#
# /etc/ddclient.conf

protocol=cloudflare \
use=web, web=https://api.ipify.org/ \
login=token \
password='xxxxxxxxxxxxxxxxxxxxxxx' \
zone=yourdomain.com
sub.yourdomain.com

You can now test with:

ddclient -query

And then see if it worked:

ddclient status

Which should say something like:

SUCCESS:  updating sub.domain.com: IPv4 address set to xx.xxx.xx.xxx

Great success!

Make it a service

Update /etc/default/ddclient so the file looks like this:

# generated from debconf on Mon Jan 15 05:32:36 UTC 2024
#
# /etc/default/ddclient

# Set to "true" if ddclient should be run every time DHCP client ('dhclient'
# from package isc-dhcp-client) updates the systems IP address.
run_dhclient="false"

# Set to "true" if ddclient should be run every time a new ppp connection is
# established. This might be useful, if you are using dial-on-demand.
run_ipup="false"

# Set the time interval between the updates of the dynamic DNS name in seconds.
# This option only takes effect if the ddclient runs in daemon mode.
daemon_interval="5m"

run_daemon="true"

And then you need to run the following commands:

systemctl start ddclient.service
update-rc.d ddclient enable

And now this should run every 5 minutes to update your domain to point to your public IP address. You can now set up port forwarding on your router, and have this sort of mapping:

http://subdomain.domain.com:<external-port> -> 192.168.xxx.xxx:<internal-port>