From 57b71da78101a76242ea79f26f964a44d332f404 Mon Sep 17 00:00:00 2001 From: alexz Date: Mon, 18 May 2026 01:18:39 -0700 Subject: [PATCH] cfddns: rebuild on private fork with management web UI - Swap image from favonia/cloudflare-ddns:latest to git.alexzaw.dev/alexz/cloudflare-ddns:latest (private fork with cmd/manager binary that wraps the original ddns updater) - Expose web UI on internal port 8080, traefik-routable - Add CFDDNS_WEB_USER/CFDDNS_WEB_PASSWORD basic-auth form fields - Repurpose existing DOMAINS/PROXIED/UPDATE_CRON/TZ as first-run seed for the YAML config that the UI manages thereafter - Mount ${APP_DATA_DIR}/data:/config for persistent cfddns.yaml - Healthcheck on /healthz via 127.0.0.1 (alpine wget) - Bump tipi_version 7 -> 8 to trigger app update --- apps/cfddns/config.json | 61 +++++++++++++++++++---------- apps/cfddns/docker-compose.json | 44 +++++++++++---------- apps/cfddns/docker-compose.yml | 17 +++++++- apps/cfddns/metadata/description.md | 39 ++++++++++++++++++ 4 files changed, 119 insertions(+), 42 deletions(-) create mode 100644 apps/cfddns/metadata/description.md diff --git a/apps/cfddns/config.json b/apps/cfddns/config.json index f235322..487a16c 100644 --- a/apps/cfddns/config.json +++ b/apps/cfddns/config.json @@ -3,63 +3,84 @@ "name": "Cloudflare DDNS", "id": "cfddns", "available": true, - "exposable": false, + "port": 8533, + "exposable": true, "dynamic_config": true, - "no_gui": true, - "tipi_version": 7, - "version": "latest", + "no_gui": false, + "tipi_version": 8, + "version": "v1-ui1", "categories": [ "network", "utilities" ], - "description": "Automatically update Cloudflare DNS records with your current public IP. Supports multiple domains, IPv4/IPv6, and proxy toggle.", - "short_desc": "Dynamic DNS updater for Cloudflare", - "author": "favonia", - "source": "https://github.com/favonia/cloudflare-ddns", + "description": "Automatically updates Cloudflare DNS records with your current public IP. Manage domains, proxied state, schedule, API token, and view live status & logs from a built-in web UI. Fork of favonia/cloudflare-ddns with an added management binary.", + "short_desc": "Dynamic DNS for Cloudflare, with web UI", + "author": "alexz (fork of favonia/cloudflare-ddns)", + "source": "https://git.alexzaw.dev/alexz/cloudflare-ddns", + "website": "https://github.com/favonia/cloudflare-ddns", "form_fields": [ + { + "type": "text", + "label": "Web UI Username", + "env_variable": "CFDDNS_WEB_USER", + "required": true, + "default": "admin", + "min": 3, + "max": 50, + "hint": "Username for HTTP basic auth on the management UI" + }, + { + "type": "password", + "label": "Web UI Password", + "env_variable": "CFDDNS_WEB_PASSWORD", + "required": true, + "min": 8, + "hint": "Password for HTTP basic auth on the management UI" + }, { "type": "password", "label": "Cloudflare API Token", "env_variable": "CLOUDFLARE_API_TOKEN", "required": true, - "hint": "API token with DNS edit permissions" + "hint": "API token with Zone:DNS:Edit permissions. After first start the UI manages this." }, { "type": "text", - "label": "Domains (comma-separated)", + "label": "Initial Domains (comma-separated)", "env_variable": "DOMAINS", - "required": true, - "hint": "e.g. home.example.com,vpn.example.com" + "required": false, + "hint": "First-run seed only — managed by the web UI afterward. e.g. home.example.com,vpn.example.com" }, { "type": "boolean", - "label": "Proxied (Orange Cloud)", + "label": "Initial Proxied (Orange Cloud)", "env_variable": "PROXIED", "required": false, - "default": false + "default": false, + "hint": "First-run seed only — proxy state is managed per-domain by the UI afterward" }, { "type": "text", - "label": "Update Schedule", + "label": "Initial Update Schedule", "env_variable": "UPDATE_CRON", "required": false, "default": "@every 5m", - "hint": "Cron expression or @every Xm" + "hint": "First-run seed only — managed by the UI afterward. Cron expression or @every Xm." }, { "type": "text", - "label": "Timezone", + "label": "Initial Timezone", "env_variable": "TZ", "required": false, - "default": "UTC" + "default": "UTC", + "hint": "First-run seed only — managed by the UI afterward" } ], "supported_architectures": [ - "arm64", "amd64" ], "created_at": 1736974800000, - "updated_at": 1736974800000, + "updated_at": 1747555200000, "deprecated": false, "min_tipi_version": "4.5.0" } diff --git a/apps/cfddns/docker-compose.json b/apps/cfddns/docker-compose.json index 1837779..148a956 100644 --- a/apps/cfddns/docker-compose.json +++ b/apps/cfddns/docker-compose.json @@ -4,30 +4,34 @@ "services": [ { "name": "cfddns", - "image": "favonia/cloudflare-ddns:latest", + "image": "git.alexzaw.dev/alexz/cloudflare-ddns:latest", "isMain": true, + "internalPort": 8080, "environment": [ + { "key": "CFDDNS_LISTEN", "value": ":8080" }, + { "key": "CFDDNS_CONFIG_FILE", "value": "/config/cfddns.yaml" }, + { "key": "CFDDNS_WEB_USER", "value": "${CFDDNS_WEB_USER}" }, + { "key": "CFDDNS_WEB_PASSWORD", "value": "${CFDDNS_WEB_PASSWORD}" }, + { "key": "CLOUDFLARE_API_TOKEN", "value": "${CLOUDFLARE_API_TOKEN}" }, + { "key": "DOMAINS", "value": "${DOMAINS:-}" }, + { "key": "PROXIED", "value": "${PROXIED:-false}" }, + { "key": "UPDATE_CRON", "value": "${UPDATE_CRON:-@every 5m}" }, + { "key": "TZ", "value": "${TZ:-UTC}" } + ], + "volumes": [ { - "key": "CLOUDFLARE_API_TOKEN", - "value": "${CLOUDFLARE_API_TOKEN}" - }, - { - "key": "DOMAINS", - "value": "${DOMAINS}" - }, - { - "key": "PROXIED", - "value": "${PROXIED:-false}" - }, - { - "key": "UPDATE_CRON", - "value": "${UPDATE_CRON:-@every 5m}" - }, - { - "key": "TZ", - "value": "${TZ:-UTC}" + "hostPath": "${APP_DATA_DIR}/data", + "containerPath": "/config", + "readOnly": false } - ] + ], + "healthCheck": { + "test": "wget --spider -q http://127.0.0.1:8080/healthz || exit 1", + "interval": "30s", + "timeout": "5s", + "retries": 3, + "startPeriod": "10s" + } } ] } diff --git a/apps/cfddns/docker-compose.yml b/apps/cfddns/docker-compose.yml index acd6726..8062c13 100644 --- a/apps/cfddns/docker-compose.yml +++ b/apps/cfddns/docker-compose.yml @@ -1,13 +1,26 @@ services: cfddns: - image: 'favonia/cloudflare-ddns:latest' + image: 'git.alexzaw.dev/alexz/cloudflare-ddns:latest' environment: + - 'CFDDNS_LISTEN=:8080' + - 'CFDDNS_CONFIG_FILE=/config/cfddns.yaml' + - 'CFDDNS_WEB_USER=${CFDDNS_WEB_USER}' + - 'CFDDNS_WEB_PASSWORD=${CFDDNS_WEB_PASSWORD}' - 'CLOUDFLARE_API_TOKEN=${CLOUDFLARE_API_TOKEN}' - - 'DOMAINS=${DOMAINS}' + - 'DOMAINS=${DOMAINS:-}' - 'PROXIED=${PROXIED:-false}' - 'UPDATE_CRON=${UPDATE_CRON:-@every 5m}' - 'TZ=${TZ:-UTC}' + volumes: + - '${APP_DATA_DIR}/data:/config' + healthcheck: + test: ['CMD-SHELL', 'wget --spider -q http://127.0.0.1:8080/healthz || exit 1'] + interval: 30s + timeout: 5s + retries: 3 + start_period: 10s x-runtipi: is_main: true + internal_port: 8080 x-runtipi: schema_version: 2 diff --git a/apps/cfddns/metadata/description.md b/apps/cfddns/metadata/description.md new file mode 100644 index 0000000..5032f21 --- /dev/null +++ b/apps/cfddns/metadata/description.md @@ -0,0 +1,39 @@ +# Cloudflare DDNS + +Keeps your Cloudflare DNS A/AAAA records in sync with the public IP address of this server, with a web management UI for managing the domain list and settings. + +This is a private fork of [favonia/cloudflare-ddns](https://github.com/favonia/cloudflare-ddns) with an added `manager` binary that wraps the upstream updater. The manager: + +- Loads configuration from `cfddns.yaml` in the app data dir. +- Exposes a web UI (HTTP basic auth) for adding, editing, and removing domain entries, toggling proxy state per domain, editing the Cloudflare API token, and viewing live status and logs. +- Supervises the upstream `ddns` binary as a child process and restarts it cleanly when the configuration changes. + +## First install + +On first start the manager seeds `cfddns.yaml` from the `DOMAINS`, `PROXIED`, `UPDATE_CRON`, `TZ`, and `CLOUDFLARE_API_TOKEN` env vars (set via the install form). After that the YAML file is the source of truth and the env vars are ignored. + +If both `DOMAINS` and `CLOUDFLARE_API_TOKEN` are empty at first start, the manager will not launch the updater — it logs a warning and waits for you to configure domains via the web UI. + +## Web UI + +Open the app from the Runtipi dashboard. Log in with the username/password you set during install (`CFDDNS_WEB_USER` / `CFDDNS_WEB_PASSWORD`). + +The UI shows: + +- Current public IPv4/IPv6 (scraped from updater output) +- Last update time and status +- Updater process state and PID +- Domain table with add / edit / delete actions +- Per-domain proxied checkbox +- Cron schedule, timezone, and API token editor +- Live tail of the updater log +- "Refresh now" button that triggers an immediate update + +## Storage + +Configuration: `${APP_DATA_DIR}/data/cfddns.yaml` (mode 0600 — contains your API token). + +## Source + +- Fork: https://git.alexzaw.dev/alexz/cloudflare-ddns +- Upstream: https://github.com/favonia/cloudflare-ddns