Set up a free Dynamic DNS service with ddclient on Kubernetes
Tags: raspberrypi, dns, technology, docker
Published: 2020-07-01 18:05:15

---
title: Set up a free Dynamic DNS service with ddclient on Kubernetes
published: true
date: 2020-05-12 03:48:41 UTC
tags: raspberrypi, dns, technology, docker
canonical_url: https://medium.com/@joycelin.codes/ddclient-c9a6ac1d8f81
---

#### Don’t gamble on accessing self-hosted services on a Raspberry Pi when you’re away from home and your IP changes

![](https://cdn-images-1.medium.com/max/1024/1*d0GwB2WDaVx_5vZO2ssDOQ.jpeg)<figcaption>Photo by <a href="https://unsplash.com/@nasa?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">NASA</a> on <a href="https://unsplash.com/s/photos/internet?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></figcaption>

Most internet service providers (ISPs) give residential customers a dynamic IP address. They pull from a pool of IP addresses and allocate one to a home.

Since the IP address might change in a few months or even in a few hours, it can be hard to consistently access your personal computer when you’re away from home.

Setting up a **dynamic DNS (DDNS)** service gives you reliable access to self-hosted services, like a personal website, a Minecraft server, or just your home computer. If you point a hostname to your home network, you can have Kubernetes update the DNS record when your IP inevitably changes.

### What is Dynamic DNS?

Since most residential customers have dynamic IPs, there’s a few options to manage a changing IP address.

- **Static IP** : if your ISP offers this option, get a dedicated IP address so it never changes
- **Router** : if your router has a dynamic DNS option, configure DDNS on your router to always maintain an active connection
- **DDNS services** : [Cloudflare recommends a few options](https://support.cloudflare.com/hc/en-us/articles/360020524512-Manage-dynamic-IPs-in-Cloudflare-DNS-programmatically), such as updating your IP using a dynamic DNS client application

Making sure your IP is up to date, or remains fixed, guarantees reliable access to your self-hosted services.

![](https://cdn-images-1.medium.com/max/1024/1*fKLKnlGhom5pDw3Sg1YqKQ.jpeg)<figcaption>Don’t gamble on accessing your self-hosted services when you’re away from home</figcaption>

For example, I have a self-hosted Minecraft server on a Raspberry Pi at home. I want to set up DDNS so that I can access this game server even if the IP changes while I’m out of town.

### How can we run a dynamic DNS service?

Let’s use a dynamic DNS client application called [ddclient](https://ddclient.net/). Services like these keep an eye on your IP address. When the IP changes, the service automatically updates your DNS record using the DNS provider’s API.

![](https://cdn-images-1.medium.com/max/1024/1*Mq-zfyYS7bKktDUXKE_pHw.jpeg)<figcaption>DDNS client apps like <a href="https://ddclient.net/">ddclient</a> periodically check your public IP for changes</figcaption>

If you’d like to learn how to set up your DNS records, take a spin through [this very good tutorial](https://blog.jswart.xyz/posts/cloudflare-dynamic-dns) that walks through how to register a domain and run ddclient using Docker on its own.

In this tutorial, let’s run ddclient on Kubernetes.

> **_Wait, wait… You’re using_ Kubernetes _to run a self-hosted app?!_**

> **_Isn’t this overkill?_**

> **_— anyone reading this_**

### Why use Kubernetes in addition to Docker?

Docker containers are useful for packaging and running software in a way that’s predictable and consistent. While I’ve previously talked about using Kubernetes [to reduce the complexity of managing containers and to scale services](https://dev.to/loopdelicious/deploying-a-scalable-web-application-with-docker-and-kubernetes-4op9), we can also use Kubernetes to simplify the deployment process.

![](https://cdn-images-1.medium.com/max/1024/1*djdP5D3VdmsE0dwjFjuhWg.jpeg)<figcaption>Docker for packaging software, and Kubernetes for deploying it</figcaption>

My self-hosted apps will never have Netflix- or Slack-level traffic. But if we can use Kubernetes to ease the pain of deployment, for free, then why not?

There’s a bit of a learning curve with Kubernetes, but a bunch of new tools are making it easier than ever to get started.

Let’s forge ahead.

### Where can I deploy a Kubernetes cluster?

When I think about deploying on Kubernetes, I imagine working with a managed cloud service, like when we [previously deployed a cluster on Amazon EKS](https://dev.to/loopdelicious/learn-how-your-kubernetes-clusters-respond-to-failure-using-gremlin-and-grafana-2l76).

But Kubernetes can also run on a local machine, like a Raspberry Pi at home.

> **_You can deploy a Kubernetes cluster on a local machine, cloud, on-prem datacenter; or choose a managed Kubernetes cluster. You can also create custom solutions across a wide range of cloud providers, or bare metal environments._**

> **_—_** [**_Kubernetes docs_**](https://kubernetes.io/docs/setup/)

A cluster running on a self-hosted Raspberry Pi server is perfect for my own DDNS and gaming needs. Setting up Kubernetes on a local machine is also a great way to learn Kubernetes without racking up cloud costs.

Let’s deploy ddclient on Kubernetes running on a local Raspberry Pi. To do this, we’ll use [KubeSail](https://kubesail.com/resources), which can deploy on any type of cluster.

### A recipe for deploying ddclient on Kubernetes with KubeSail

![](https://cdn-images-1.medium.com/max/1024/1*IrEmA5rumJnlR7vrjEQncg.png)<figcaption>automatically update IP using ddclient</figcaption>

The ddclient app keeps an eye on our IP address. When the IP changes, ddclient automatically updates our DNS record using the Cloudflare API. Ddclient works with [a bunch of DNS providers](https://github.com/ddclient/ddclient) to keep DNS records up to date, but we’ll use [Cloudflare](https://www.cloudflare.com/).

- Step 0 — [Pre-requisites](#a036)
- Step 1 — [Add a cluster to the Raspberry Pi](#8e66)
- Step 2 — [Fork a public template](#b373)
- Step 3 — [Update your DNS secrets](#36c0)
- Step 4 — [Update the deployment details](#9cc3) (skip)
- Step 5 — [Deploy on Kubernetes](#675e)

Let’s get started.

### 0 | Pre-requisites

Do this stuff first.

#### **KubeSail**

Sign up for a [free KubeSail account](https://kubesail.com/) — we’ll use their tools to manage the apps on our Raspberry Pi.

#### **DNS server**

You’ll need to own your own domain and be able [to change your domain’s nameservers](https://support.cloudflare.com/hc/en-us/articles/205195708-Changing-your-domain-nameservers-to-Cloudflare). I’m using a [free Cloudflare account](https://www.cloudflare.com/) to route my web traffic through the Cloudflare network.

#### **Kubernetes**

Decide where to run your Kubernetes cluster. I’m using a Raspberry Pi. The DDNS application should be running on the same home network as your self-hosted services, since the app works by checking its own network IP.

### 1 | Add a cluster to the Raspberry Pi

I’m using a [Raspberry Pi 4](https://www.raspberrypi.org/products/raspberry-pi-4-model-b/) to run my Kubernetes cluster. [This very good tutorial](https://kubesail.com/blog/microk8s-raspberry-pi) shows us how to set up a cluster on a new Raspberry Pi.

- Flash an operating system onto an SD card — I used [Ubuntu](https://ubuntu.com/desktop)
- Enable [Secure Shell (SSH)](https://www.ssh.com/ssh/server) to operate a headless Raspberry Pi — or use a separate keyboard and monitor
- Enable Wi-Fi also on the SD card — or I plugged directly into ethernet
- Insert the SD card into the Raspberry Pi
- Log in to the Raspberry Pi using SSH
- Install [MicroK8s](https://microk8s.io/) — a lightweight Kubernetes recommended for IOT apps, so your commands will use `microk8s.kubectl` instead of just `kubectl`

To connect the Raspberry Pi to KubeSail, apply the configuration file to your namespace from the Raspberry Pi’s command line.

```
$ sudo microk8s.kubectl apply -f [https://byoc.kubesail.com/<your-kubesail-username>.yaml](https://byoc.kubesail.com/loopdelicious.yaml)
```

The Raspberry Pi is now a single-node Kubernetes cluster!

![](https://cdn-images-1.medium.com/max/1024/1*pEBYRRcql8s8UYkUJVFBag.jpeg)

![](https://cdn-images-1.medium.com/max/1024/1*jco0544_9XaqHssEga8wgQ.png)<figcaption>The Raspberry Pi is now a single-node Kubernetes cluster!</figcaption>

The Raspberry Pi also appears in the [KubeSail clusters dashboard](https://kubesail.com/clusters). In the dashboard under **Clusters** , select the new cluster, and then select **Namespaces** from the sub-menu. This is where you can add a new [Kubernetes namespace](https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/), or use a default namespace called default.

So now we have a cluster, a namespace, and a user —all the parameters required for our [Kubernetes context](https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/#context).

### **2 | Fork a public template**

I previously talked about[the basic concepts behind Docker and Kubernetes](https://dev.to/loopdelicious/deploying-a-scalable-web-application-with-docker-and-kubernetes-4op9). [YAML](https://yaml.org/) is used to write instructions to deploy and manage your containers.

If you’re just learning Kubernetes, or getting started with a new project, KubeSail lists [community examples](https://kubesail.com/templates). You can browse these examples, and cobble together relevant YAML samples to customize your own Kubernetes apps.

Under **Templates** , I made this one [for ddclient](https://kubesail.com/template/loopDelicious/ddclient).

> [**ddclient**](https://kubesail.com/template/loopDelicious/ddclient) : ddclient for dynamic DNS updating for self-hosted services at a residential network 🌐

The ddclient template has two kinds of Kubernetes resources.

- [Secret](https://kubernetes.io/docs/concepts/configuration/secret/) — to store your confidential information
- [Deployment](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/) — to describe how your application is deployed

[![](https://cdn-images-1.medium.com/max/1024/1*2BquP5uGnBzjqZgSemFTuA.png)](https://kubesail.com/template/loopDelicious/ddclient)<figcaption>fork the ddclient template</figcaption>

Fork the template on [this page](https://kubesail.com/template/loopDelicious/ddclient). Then toggle the new template’s setting to **Private** because we’ll add our secrets in the next step.

### **3 | Update your DNS secrets**

If you haven’t already done so, add an A record to Cloudflare that points to your home network. For now, this can point to any IP, such as `1.1.1.1` because ddclient will update the IP to the correct address when we deploy it later.

![](https://cdn-images-1.medium.com/max/1024/1*cBtm5ixrpBvntGkCg48bUQ.png)<figcaption>add an A record for the home network</figcaption>

Here’s the data you need from Cloudflare.

- `zone` — your domain name like `example.com`
- `login` — your Cloudflare account email address
- `password` — your global API key from under **API Tokens** on [your Cloudflare profile](https://dash.cloudflare.com/profile)
- the line beneath `password` — full domain name to keep updated, including subdomain like `home.example.com`

Back in your new private KubeSail template, click the **Edit Yaml** button to open the YAML editor on the right side of the page.

There’s a couple ways [to decouple Kubernetes configuration details](https://kubernetes.io/docs/concepts/configuration/overview/). Using a [Kubernetes Secret](https://kubernetes.io/docs/concepts/configuration/secret/) will store your confidential data, and inject the data into your containers only when it’s needed.

Find the `Secret` document tab in the YAML editor, and update your Cloudflare credentials beneath `ddclient.conf`.

![](https://cdn-images-1.medium.com/max/1024/1*UBl759a5fWC3zxfrE7D4Fw.png)<figcaption>Update your Cloudflare credentials in the `Secret` document</figcaption>

Here’s some other interesting details in the ddclient.conf.

- **`daemon`**: ddclient will run this process every 300 seconds (five minutes)
- **`web`**: dclient will check if the IP address has changed, using this web service: [https://domains.google.com/checkip](https://domains.google.com/checkip)

When you’re done, save the template.

### 4 | Update the deployment details (skip)

You don’t have to do anything here, but it’s helpful to understand some of the underlying YAML for this resource.

#### The YAML explained

Find the `Deployment` document tab in the YAML editor, and notice the interesting bits.

- [**`volumes`**](https://kubernetes.io/docs/concepts/storage/volumes/): there’s a single [Kubernetes volume](https://kubernetes.io/docs/concepts/storage/volumes/), or data store, that points to our secrets from the last step
- [**`image`**](https://kubernetes.io/docs/concepts/containers/images/): the base Docker image for our containerized application is [`linuxserver/ddclient`](https://hub.docker.com/r/linuxserver/ddclient) from the smart people at Linux Server
- [**`resources`**](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/): the request for how much CPU or memory a container needs to run ddclient as a fairly lightweight Perl program

![](https://cdn-images-1.medium.com/max/1024/1*EqQje-DfIaAvyhxaunxXjw.png)<figcaption>Review the deployment details</figcaption>

If you make any changes, remember to save the template.

### **5 | Deploy on Kubernetes**

We’re ready to deploy our app on Kubernetes! This part is easy peasy lemon squeezy since we already added a Kubernetes cluster and namespace in [the first step](#8e66).

In the dropdown menu next to the **Launch Template** button, select a [Kubernetes context](https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/#context) to deploy our app.

![](https://cdn-images-1.medium.com/max/1024/1*yNrcXP57Z4gJzsj4wWF2vA.png)

Hit **Launch Template** , and KubeSail will deploy ddclient.

In the example below, I deploy to the `default` namespace on my `Raspberry Pi` cluster.

![](https://cdn-images-1.medium.com/max/600/1*Ln-Ki0bZ1VhFKxOYhgxgFQ.gif)<figcaption>deploy to the `default` namespace on the `Raspberry Pi` cluster</figcaption>

You can see success notifications and logs under your deployment details.

#### Verify ddclient is working

Once your app is finished deploying, return to Cloudflare to verify that ddclient updated `1.1.1.1` to our actual network IP. Every five minutes, ddclient will check if our network IP has changed.

Besides the initial update, there’s one more check to verify that ddclient is working correctly. Once again, change the IP of your home network’s A record in Cloudflare to `1.1.1.1`. Turn off your internet router long enough to ensure your ISP allocates a new IP address. I left my router unplugged overnight. In the morning when I powered up my router, I verified that ddclient updated my IP in Cloudflare.

In summary, we deployed ddclient on Kubernetes. Every five minutes, ddclient will check the IP address of the Raspberry Pi. If there’s been a change to the IP, ddclient will update our DNS record using the Cloudflare API.

Doing this, allows me to continue playing Minecraft on my Raspberry Pi when I’m away from home, and my ISP changes my IP unexpectedly.

> _🤓_ **_Fun Fact:_** _The Raspberry Pi at home hosts both ddclient and my Minecraft server. While both servers don’t need to run on the same cluster, they should be in the same home network since ddclient works by checking its own network IP. Stay tuned to learn how to set up a Minecraft server on Raspberry Pi using Kubernetes._

### Final thoughts on deploying on Kubernetes

![I don’t always deploy on kubernetes, but when i do, it’s a real cluster](https://cdn-images-1.medium.com/max/500/1*pULNsjk0XORr3P9Gkipi2w.jpeg)

#### Kubernetes for simplifying deployments

Deploying projects is something I do very rarely. So when I do, it takes a while to dust off the cobwebs, and it’s pretty slow going.

Even though Kubernetes is best known for complex container orchestration at massive scale, it can also **_simplify_** modest deployments.

#### Share your templates

I’m new to Kubernetes. So as a n00b does, I hack on something until it works. For this project, starting with other people’s YAML examples was super helpful. This [great blog post](https://blog.jswart.xyz/posts/cloudflare-dynamic-dns/), other [public templates](https://kubesail.com/templates), and [these code samples](https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/#create-a-configmap) saved me a ton of time.

If you come up with something that works for you, share it with the rest of us as a [public template](https://kubesail.com/templates) 🙏