Dynamic DNS using Cloudflare
  • Go 85.8%
  • Makefile 9.9%
  • Dockerfile 4.3%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
enid 59f591d281
All checks were successful
cf-dyndns Workflow / Build and publish OCI image (push) Successful in 11s
feat: move workflow to forgejo
feat: move workflow to forgejo
2026-09-12 16:38:17 +02:00
.forgejo feat: move workflow to forgejo 2026-09-12 16:38:17 +02:00
cmd/cf-dyndns [feat] add megalinter, binary releases and dependabot 2024-07-26 14:41:57 +02:00
internal Update config.go 2024-09-06 18:47:51 +01:00
vendor [feat] migrate from self-hosted forgejo 2024-07-17 11:46:27 +02:00
.dockerignore [feat] add megalinter, binary releases and dependabot 2024-07-26 14:41:57 +02:00
.gitignore [chore] cleanup, update and fix megalinter 2024-10-17 11:17:34 +02:00
.mega-linter.yml [chore] cleanup, update and fix megalinter 2024-10-17 11:17:34 +02:00
Dockerfile feat: move workflow to forgejo 2026-09-12 16:38:17 +02:00
go.mod [chore] upgrade Docker build image, update go version 2024-10-07 10:53:40 +02:00
go.sum [feat] migrate from self-hosted forgejo 2024-07-17 11:46:27 +02:00
LICENSE [feat] migrate from self-hosted forgejo 2024-07-17 11:46:27 +02:00
Makefile [chore] cleanup, update and fix megalinter 2024-10-17 11:17:34 +02:00
README.adoc doc: use adoc syntax 2025-01-27 19:28:01 +00:00
revive.toml [chore] cleanup, update and fix megalinter 2024-10-17 11:17:34 +02:00

= cf-dyndns

Dynamic DNS using Cloudflare

== How it works

cf-dyndns is available as an OCI image or executable for Windows, Linux and macOS (both amd64 and arm64).

Internally, it runs as a daemon and (should) only fatally crash in the case of something going wrong during startup.

If no Cron schedule is set (see xref:#cron-schedule[]) it will update the defined Cloudflare entry every five minutes.

The actual process works by grabbing the current IP via a call to the anysrc API (https://anysrc.net). The IP from that is then set as the IP which the defined Cloudflare DNS entry is pointing to.

NOTE: Currently, only IPv4 addresses/A records are supported.

== Releases

Releases can be found here:

* link:https://github.com/enidisepic/cf-dyndns/pkgs/container/cf-dyndns[OCI Image]
* link:https://github.com/enidisepic/cf-dyndns/actions[Binaries]
1. Click on latest run
2. Binary artifacts can be found near the bottom


== Usage

=== Deployment

==== Docker (with Compose)

Example:

[source,yaml]
----
services:
  server:
    image: ghcr.io/enidisepic/cf-dyndns:latest
    restart: unless-stopped
    environment:
      - CRON_SCHEDULE=@every 1h
      - CF_API_KEY=<your API key>
      - CF_ZONE_ID=<your zone ID>
      - CF_ENTRY_NAME=<your DNS entry name>
      - CF_ENTRY_ID=<your DNS entry's ID>
      - CF_PROXIED='1'
----

==== Kubernetes

This assumes you have created a namespace, and have created the secret (example provided).

Secret:

[source,yaml]
----
apiVersion: v1
kind: Secret
metadata:
  name: cf-api-secret

  # This namespace must match your Deployment!
  namespace: dyndns
type: Opaque
data:
  # Secrets must be base64 encoded
  api-key: "<your base64 encoded API key>"
----

Deployment

[source,yaml]
----
apiVersion: apps/v1
kind: Deployment
metadata:
  name: dyndns
  namespace: dyndns
spec:
  selector:
    matchLabels:
      app: dyndns
  template:
    metadata:
      labels:
        app: dyndns
    spec:
      # Override Dockerfile "USER" directive to a user that exists
      securityContext:
        runAsUser: 1000
      containers:
      # If you require more than 1 domain in sync, you can add more containers to the pod
      # clone the container as shown below into another entry, changing the entry name & ID as relevant
      - name: dyndns
        image: ghcr.io/enidisepic/cf-dyndns:latest
        env:
          - name: CRON_SCHEDULE
            value: '@every 1h'
          - name: CF_ZONE_ID
            value: '<your zone ID>'
          - name: CF_ENTRY_NAME
            value: '<your DNS entry name>'
          - name: CF_ENTRY_ID
            value: '<your DNS entry ID>'
          - name: CF_PROXIED
            value: '1'
          - name: CF_API_KEY
            valueFrom:
              secretKeyRef:
                name: cf-api-secret
                key: api-key
        resources:
          limits:
            cpu: '100m'
            memory: '128Mi'
----

=== Environment Variables

These environment variables can be defined directory or in a `.env` file in the same directory as the daemon itself.

WARNING: Environment variables musn't be quoted once they reach the application, it will not unquote them itself.
This can cause the API requests to fail without a good explanation as to why.

[#cron-schedule]
==== `CRON_SCHEDULE`

Optional. The cron schedule at which to update the DNS entry (default `@every 5m`)

==== `CF_API_KEY`

The Cloudflare API key. To generate one follow these steps:

1. Go to your link:https://dash.cloudflare.com[Cloudflare dashboard]
2. Click on the user icon in the top right
3. Press "My Profile"
4. Under "API Tokens" create a new one
5. Use the "Edit zone DNS" template
6. Under "Zone Resources" select the zone in which your DynDns entry will reside
7. Click on "Continue to summary", then "Create Token"

==== `CF_ZONE_ID`

The Cloudflare zone ID of the zone the DynDNS entry will be in. You can find this in the right-side information view when looking at your zone's DNS entries in the dashboard.

==== `CF_ENTRY_NAME`

The FQDN of your DynDNS entry. You can create this now and use a placeholder as the IP address it points to. Must be an A record.

==== `CF_ENTRY_ID`

The ID of the DynDNS entry. To find this open your browser's developer tools and navigate to the "Networking" tab. After that, update the IP address the entry points to (can be any placeholder or real IP address).

In the networking tab there should now be a request to `https://dash.cloudflare.com/api/v4/zones/<zone ID>/dns_records/<entry ID>`. Copy the entry ID from this URL.

==== `CF_PROXIED`

Whether the record should be created as "Proxied". If the variable has any non empty value, it is treated as true, which will set the status to Proxied.

== To Do

* Automatic retrieval of zone and entry ID