Skip to main content

Configure Dynamic DNS for IPv6 Addresses with Cloudflare

Thursday, December 1, 2022
Reading time 8 minutes

In another of my adventures with the Mini PC I converted into a server, I’ve found an interesting situation regarding its use from outside the home network. At first, I only used the services I installed locally, but as time went by, I found things somewhat difficult to do from my work. For example, I thought about allowing only local access to the services running on the Mini PC, but time and some situations made me think about hosting the GitLab instance I use for developments at MCV Software on said server. That GitLab is practically a single-user instance, as the vast majority of projects that are open there are also in our GitHub organization. A week after finishing the initial implementation, I can simply say it has been working excellently. Of course, you should never forget to make backups, but that’s always recommended, no matter where the server is hosted.

One of the main inconveniences with the server I have at home is that the internet provider, which is Izzi, assigns IPv4 addresses under a CG-NAT scheme. This means that a single IPv4 address, which are the most used until now, and which have already run out, according to news, is shared among many residential connections. It’s certainly impossible to say the number of users sharing the same IP address. This is especially difficult for users who require having open ports on a Router, like those who play on consoles, use WiFi cameras, or some other so-called Internet of Things devices. You simply can’t open ports on the router, because the provider has no way of knowing if the port you need will be required later by another of your IP address neighbors. So, to avoid these types of situations, they prefer to share several hundred clients with a single address, and prevent them from accessing open ports, configuring bridge modes on the router, and other things that would have come in very handy in this adventure.

But here’s the thing. If CG-NAT prevents people from playing, how can Izzi sell anything? The answer is in IPv6.

When IPv4 addresses ran out, IPv6 addresses began to be distributed, which has many more spaces to assign devices and it’s estimated that all humanity, with its countless devices, will never exhaust the address space, as did happen with IPv4. Currently, the IPv6 standard is being slowly adopted by providers and services, who see that implementing this new protocol is cheaper (address blocks, which control which provider can assign each address, are notably cheaper and offer more available addresses). This in turn causes providers in Mexico to be implementing systems with CG-NAT for sites that don’t yet support IPv6, but at the same time assign a fully usable IPv6 address for any device that requires it. This has been my case, and my biggest surprise when verifying that I can connect to my small home server from any place that has a valid IPv6 address. To do this it was necessary to configure a couple of aspects in the Izzi Router, mainly to allow traffic from IPv6 addresses into the local network, but once that was done, it was an immediate success.

Now, to give a name to our IPv6 address, which can normally change from time to time (although, I must say that in the time I’ve had it configured, I haven’t seen a single change, even after router restarts), I decided to use Cloudflare services as a dynamic DNS. Ah, Cloudflare, that service that normally works very well, but when it falls, makes half the internet go down with it. I like it more and more, to tell the truth, and today won’t be the exception, as I’ve found a Docker container that allows setting up the configuration for a dynamic DNS. That way, I’ll always have a subdomain that points to my IPv6 address, regardless of whether this address changes at some point. As long as the container is active, the address will remain updated.

Requirements

The first thing to keep in mind, naturally, is that since this is a Docker container, you need docker and docker compose installed on the host machine. For that, you can refer to the Docker installation documentation, for various operating systems. In my case, the host is a Debian 11, although the configuration shouldn’t be different for other types of hosts. It’s also evident that you’ll need a domain already pointed to Cloudflare’s DNS servers, so it can create the necessary subdomains.

Getting data from Cloudflare

Since the container needs to write and read information from Cloudflare systems, we’ll need two important pieces of data: the zone ID, which allows us to identify each domain in Cloudflare, and an API token, which allows performing actions on behalf of the user who owns the DNS zone.

Creating API token

  1. Access the API Tokens section within your Cloudflare profile, and select the button called “create token”.
  2. The first screen allows us to select a permissions template. This is useful as it configures the permissions used for most cases. The template we’re interested in is the first one, called “Edit Zone DNS”. To use it, simply press the button called “use template” in the right column.
  3. Once the template is selected, you have to configure some permissions related to it. By default, the type of permission given to the template is edit, which should be left as is. In the “Zone Resources” section, you’re allowed to decide if the Token has permission to modify all zones or a specific zone. This is configured in the field called “Specific zone”, which can be manipulated like a combo box, with the caveat that to select an option you must press Enter. If you’ve chosen to allow working only on a specific zone, you must select the zone in the next section, called “Select”. The rest of the options should remain as they’re configured by default, so what follows is pressing the button called “Continue to summary”.
  4. Once in the token summary, simply press the “Create token” button to finish the process. Cloudflare should display a token that will allow access to its API. Copy that code and save it for later use.

Getting the zone ID

Copying the zone ID is very simple. You just have to access the site for which you want to create subdomains, this on the Cloudflare Profile page, and look for a heading titled “Zone ID”. Below this is our zone ID. As with the API token, copy this value and save it for later.

Configuring the container

  1. Create a directory to save the container configuration and the docker-compose file:
mkdir cloudflare-ddns
  1. Create a file called config.json, with options similar to the following. To see the reference configuration, you can consult it directly in the repository:
{
  "cloudflare": [
    {
      "authentication": {
        "api_token": "V_XXXXXXXX",
        "api_key": {
          "api_key": "",
          "account_email": ""
        }
      },
      "zone_id": "XXXXXXXXXX",
      "subdomains": [
        {
          "name": "subdomain",
          "proxied": false
        },
        {
          "name": "another_subdomain",
          "proxied": true
        }
      ]
    }
  ],
  "a": false,
  "aaaa": true,
  "purgeUnknownRecords": false,
  "ttl": 300
}
  • Replace the values for api_token and zone_id with those you copied previously in the earlier phases.
  • Pay attention that when creating the subdomains, it’s not necessary to put the full domain in the “name” section. That is, if your domain is example.com, and you need to make a subdomain called test.example.com, you only place the word test in the subdomain name.
  • The proxied parameter indicates whether Cloudflare should redirect the subdomain through its proxy system or not. Setting it to true makes it so only port 443 can be used, so if you have software running on other ports it might be better not to set proxied to true.
  • The “a” and “aaaa” parameters control whether records should be created for the IPv4 address (a) and for IPv6 (aaaa). In my case, since my IPv4 is behind a NAT, I’ve disabled it.
  • “purgeUnknownRecords” deletes records that aren’t configured in this file.
  • ttl controls how much time in seconds will pass before the container updates the IP address. Addresses are updated only when they change, so the 5 minutes configured by default seems like a good idea.
  1. Create a docker-compose.yml file, with the following:
version: "3.7"
services:
  cloudflare-ddns:
    image: timothyjmiller/cloudflare-ddns:latest
    container_name: cloudflare-ddns
    security_opt:
      - no-new-privileges:true
    network_mode: "host"
    environment:
      - PUID=1000
      - PGID=1000
    volumes:
      - ./config.json:/config.json
    restart: unless-stopped
  1. To start running the container, simply execute the corresponding command:
sudo docker compose up -d
  1. After downloading and starting the service, you can check its logs to verify it’s already updating the DNS records with the following command:
sudo docker compose logs --tail 20

Conclusion

If everything went as expected, the command logs should indicate that IP addresses are being updated every x number of seconds, where X is the number specified as ttl. It should also be possible to ping the subdomain, and see that the service responds correctly. If any of this doesn’t work, you can start diagnosing the ports on the router, the firewall status, and try to access the address directly (without using the subdomain) to identify where the problem might be.

Linux Administration NAS Tutorials

NAS cloudflare IPv6 NAT CG-NAT DDNS