HomeLab : Cloudflare DDNS Setup for Kubernetes

Thomas K
6 min readMar 17, 2024

--

How to connect your HomeLab Cluster with DNS

In the previous article, we went through the process of setting up a Kubernetes cluster. Now, let’s explore how to ensure stable access to this HomeLab cluster from outside of your home. Specifically, we will learn how to install Cloudflare DDNS on the existing K8s cluster and set it up according to your domain.

At the end of the post, we are going to see the cluster as shown in below (black dotted-lines)

HomeLab K8s Cluster Setup Cloudflare DNS deployment

Note: Internet Service Providers (ISPs) assign dynamic IP addresses to residential internet connections, which means that the assigned IP address to you can change at any time. Consequently, relying on accessing your services via the IP address from external sources does not guarantee a stable service. Additionally, to apply SSL HTTPS security (using SSL certificates), you need to utilize an internet domain that you own or have administrative control over. From this point forward, we assume that you have your own domain.

DDNS (Dynamic DNS)

As a solution to the frequently changing IP address of your residential connection, we use Dynamic DNS (DDNS). DDNS is a service that periodically (typically every few minutes) updates the domain registration information with the currently accessible IP address by detecting changes in the actual IP address (public IP address) provided by your ISP. The operation of DDNS is based on the method defined in the ACME (Automatic Certificate Management Environment) RFC8555 standard, many domain registrars (or DNS service providers) may use slightly different implementation methods, but essentially they follow the same RFC standard.

How ACME works
How ACME works in a nutshell (https://www.keyfactor.com/blog/what-is-acme-protocol-and-how-does-it-work/)

First, check if your domain registrar or DNS service provider supports Dynamic DNS. Many domain registrars offer support for DDNS. GoDaddy, Cloudflare, and Google Domains, etc.

Note: Google no longer offers domain registration not only for DDNS, because they sold the business to Squarespace, And Squarespace won’t allow DDNS currently.

To ensure secure usage of your cluster, it is now considered standard practice to use encrypted HTTPS based on TLS certificates. If you currently do not have a domain to use, I’d recommended to have your own top-level domain for around $15 per year as one of your digital identity (The following explanation will be based on Cloudflare, which is being used as an example).

Cloudflare Dynamic DNS

Cloudflare is a well-known company in the industry, primarily recognized for its CDN and other network-related services. However, as a domain registrar, it also offers convenient and useful features to end users (even in their free tier), such as basic DDoS protection, proxy services, and DDNS functionality.

Cloudflare main menu
Cloudflare website main menu
  1. First, let’s generate and record the API Token to be used for Cloudflare DDNS (My Profile -> API Tokens -> Create Token).
Cloudflare Create API token

2. Set the DNS setup on the Cloudflare website to ‘Full’.

3. Select ‘Always Use HTTPS’ and configure it to use a minimum TLS 1.2 or higher.

4. Finally, verify and record the Zone ID (required in the next step)

Now, let’s deploy the Cloudflare DDNS container to your cluster and configure it to automatically update your IP address changes to Cloudflare.

My First Container, Cloudflare DDNS

Cloudflare DDNS will be the first container used in your K8s cluster.

Almost all Kubernetes operations start with working with YAML (*.yml, *.yaml) files. YAML files are designed to allow hierarchical representation of various configurations.

First, create the configuration file (config.json) for Cloudflare DDNS and populate it with your domain-related information.

# to write my own configuration file 
$ nano config.json

Let’s assume that we have two hostname as www.cavecafe.app and api.cavecafe.app. The configuration will be like the followings.

{
"cloudflare": [
{
"authentication": {
"api_token": "r5nY........ REDACTED .........wdzEDZ"
},
"zone_id": "1043........ REDACTED ........b605",
"subdomains": [
{
"name": "",
"proxied": true
},
{
"name": "www",
"proxied": true
},
{
"name": "api",
"proxied": true
}
]
}
],
"a": true,
"aaaa": false,
"purgeUnknownRecords": false,
"ttl": "Auto"
}

Now, encode the above config.json as base64 format to be used in the next step.

# now encode the config.json as base64 format 
$ cat config.json | base64
ewogICJjbG.................................
...........................................
...........................................
...........................................
...........................................
.....................................8iCn0K
the configuration will be like the followings

Next, let’s create the cloudflare-ddns.yaml file and copy the previously created config.json in base64 format into the config.json section.

---
# create namespace for Cloudflare DDNS container as 'cloudflare-ddns'
apiVersion: v1
kind: Namespace
metadata:
name: cloudflare-ddns
---
# create Secret for Cloudflare DDNS container
# The value for 'config.json' can be produced by the following shell command
# cat config.json | base64
# copy & paste into the section
apiVersion: v1
data:
config.json: ewogICJjbG...... REDACTED ...........8iCn0K
kind: Secret
metadata:
creationTimestamp: null
name: cloudflare-ddns
namespace: cloudflare-ddns
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: cloudflare-ddns
namespace: cloudflare-ddns
spec:
selector:
matchLabels:
app: cloudflare-ddns
template:
metadata:
labels:
app: cloudflare-ddns
secret-name: cloudflare-ddns
spec:
containers:
- name: cloudflare-ddns
image: timothyjmiller/cloudflare-ddns:latest
resources:
limits:
memory: '32Mi'
cpu: '50m'
env:
- name: CONFIG_PATH
value: '/etc/cloudflare-ddns/'
volumeMounts:
- mountPath: '/etc/cloudflare-ddns'
name: cloudflare-ddns
readOnly: true
volumes:
- name: cloudflare-ddns
secret:
secretName: cloudflare-ddns

After applying the YAML file to the actual cluster, let’s verify if it is running correctly.

# apply cloudflare-ddns.yml
$ kubectl apply -f cloudflare-ddns.yml
namespace cloudflare-ddns created
secret cloudflare-ddns created
deployment cloudflare-ddns created

# verify the cloudflare-ddns applied and runnnig
$ kubectl get pods -n cloudflare-ddns
NAME READY STATUS RESTARTS AGE
cloudflare-ddns-58dfd9b747-8wx48 1/1 Running 0 1m

After a few moments (up to 5 minutes), if you check the DNS records on the Cloudflare website, you should see the newly added hostnames (www, api) listed as follows:

Finally, if you enter www.cavecafe.app in a web browser and see the following error screen, it means everything is ‘working’ correctly (you have successfully reached Cloudflare DNS, but the actual website does not exist):

In this article, we have briefly explored how to set up Dynamic DNS using Cloudflare. In the next article, we will proceed to deploy and test our actual API service (Spring Boot or .NET Core API) to see it in action.

--

--

Thomas K

Software engineer (working on Android, iOS and API design), system engineer on Windows, Linux, Mac and still love programming in embedded OSes with no boundary