Nir Adler
Piece by Piece

Follow

Piece by Piece

Follow
Cloudflare automatic DNS update for homelab

Photo by Jordan Harrison on Unsplash

Cloudflare automatic DNS update for homelab

Nir Adler's photo
Nir Adler
ยทMar 26, 2022
Play this article

First of all, I love Cloudflare, I think they have a great product, I use Cloudflare to manage all my DNS, anyone that has a homelab setup knows you need to figure out a way to keep Cloudflare IP update if your home IP is changed, there are many great solutions out there but I love to create my own tools, so I created cloudflaresync.

My home lab setup is a set of docker-compose files, everything is dockerized so this was the obvious choice, I'm trying to learn Golang so written in Go, and the code is very simple, but taylormade to my need.

# docker-compose
version: '3.4'

services:
  cloudflaresync:
    image: niradler/cloudflaresync
    env_file:
      - .env

The code is very straightforward, we get the configuration from a set of env vars, and configure a cron task to run every x time to update DNS records with new IP, I'm also using it to create new records when a new service is created.

// main.go
package main

import (
    ...

    "github.com/cloudflare/cloudflare-go"
    "github.com/joho/godotenv"
    "github.com/robfig/cron/v3"
)

....

func main() {
    err := godotenv.Load()
    if err != nil {
        log.Println("Error loading .env file")
    }
    updateRecords()
    log.Println("Start cron", time.Now())
    cronExpression, exist := os.LookupEnv("CRON")
    if !exist {
        cronExpression = "0 * * * *"
    }
    log.Println("cron:", cronExpression)
    c := cron.New()
    id, err := c.AddFunc(cronExpression, updateRecords)
    if err != nil {
        log.Fatal("cron AddFunc error:", err)
    }
    log.Println("cron id:", id)
    c.Start()
    log.Println("Cron Info: ", c.Entries())

    go forever()

    quitChannel := make(chan os.Signal, 1)
    signal.Notify(quitChannel, syscall.SIGINT, syscall.SIGTERM)
    <-quitChannel

    fmt.Println("done")
}

Supported env vars:

CLOUDFLARE_API_TOKEN=<key>
CLOUDFLARE_DOMAIN=example.com
CLOUDFLARE_SUB_DOMAINS=test,home
CRON=*/2 * * * *
PROXIED=true

Running example for raspberry pi.

docker run --name cloudflaresync --env CLOUDFLARE_API_TOKEN=<key> --env CLOUDFLARE_SUB_DOMAINS=<app,home> --env CLOUDFLARE_DOMAIN=<example.com> --restart unless-stopped niradler/cloudflaresync:armv7

Updated to automatically update record from container label, check out the repo for more details https://github.com/niradler/cloudflaresync

version: "3.5"

services:
  cloudflaresync:
    image: niradler/cloudflaresync:latest
    restart: unless-stopped
    environment:
      CLOUDFLARE_API_TOKEN: "${CLOUDFLARE_API_TOKEN}"
      CLOUDFLARE_DOMAIN: "${DOMAIN}"
      CLOUDFLARE_SUB_DOMAINS: "${SUB_DOMAINS}"
      DOCKER_DAEMON: 'true'
    labels:
      - homepage.show=true
      - homepage.description=cloudflaresync
      - homepage.title=cloudflaresync
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
version: "3.5"

services:
  adminer:
    image: adminer:latest
    labels:
      - cloudflaresync.name=adminer

will automatically create a record adminer.domain

ย 
Share this