From 3db67677d275ee073453d977b643ac60949e384a Mon Sep 17 00:00:00 2001 From: Faisal Memon Date: Mon, 16 Feb 2026 20:20:39 -0800 Subject: [PATCH] Allow interval to be configurable --- Jenkinsfile | 2 +- README.md | 8 +++-- readme-vars.yml | 4 ++- root/app/duck.sh | 1 + root/defaults/abc.tmpl | 2 ++ root/etc/crontabs/abc | 2 -- root/etc/s6-overlay/s6-rc.d/init-duckdns/run | 37 +++++++++++++++++++- 7 files changed, 49 insertions(+), 7 deletions(-) create mode 100644 root/defaults/abc.tmpl delete mode 100644 root/etc/crontabs/abc diff --git a/Jenkinsfile b/Jenkinsfile index b070a94..9093516 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -281,7 +281,7 @@ pipeline { -v ${WORKSPACE}:/mnt \ -e AWS_ACCESS_KEY_ID=\"${S3_KEY}\" \ -e AWS_SECRET_ACCESS_KEY=\"${S3_SECRET}\" \ - ghcr.io/linuxserver/baseimage-alpine:3 s6-envdir -fn -- /var/run/s6/container_environment /bin/bash -c "\ + ghcr.io/linuxserver/baseimage-alpine:3.23 s6-envdir -fn -- /var/run/s6/container_environment /bin/bash -c "\ apk add --no-cache python3 && \ python3 -m venv /lsiopy && \ pip install --no-cache-dir -U pip && \ diff --git a/README.md b/README.md index a585a1d..4c8d11e 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ The architectures supported by this image are: - Go to the [duckdns website](https://duckdns.org/), register your subdomain(s) and retrieve your token. - Create a container with your subdomain(s) and token. If you own `user.duckdns.org`, you set `SUBDOMAINS=user`. You would NOT set a sub subdomain like `overseerr` from `overseerr.user.ducksdns.org`. -- It will update your IP with the DuckDNS service every 5 minutes (with a random jitter). +- It will update your IP with the DuckDNS service at a configurable interval (default: every 5 minutes, with a random jitter). Use the `UPDATE_INTERVAL` environment variable to customize the update frequency. ## Notice regarding automatic detection @@ -76,7 +76,7 @@ This image can be run with a read-only container filesystem. For details please To help you get started creating a container from this image you can either use docker-compose or the docker cli. >[!NOTE] ->Unless a parameter is flaged as 'optional', it is *mandatory* and a value must be provided. +>Unless a parameter is flagged as 'optional', it is *mandatory* and a value must be provided. ### docker-compose (recommended, [click here for more info](https://docs.linuxserver.io/general/docker-compose)) @@ -94,6 +94,7 @@ services: - SUBDOMAINS=subdomain1,subdomain2 - TOKEN=token - UPDATE_IP=ipv4 #optional + - UPDATE_INTERVAL=5m #optional - LOG_FILE=false #optional volumes: - /path/to/duckdns/config:/config #optional @@ -112,6 +113,7 @@ docker run -d \ -e SUBDOMAINS=subdomain1,subdomain2 \ -e TOKEN=token \ -e UPDATE_IP=ipv4 `#optional` \ + -e UPDATE_INTERVAL=5m `#optional` \ -e LOG_FILE=false `#optional` \ -v /path/to/duckdns/config:/config `#optional` \ --restart unless-stopped \ @@ -131,6 +133,7 @@ Containers are configured using parameters passed at runtime (such as those abov | `-e SUBDOMAINS=subdomain1,subdomain2` | multiple subdomains allowed, comma separated, no spaces, if your domain is user.duckdns.org you put user, not a sub-subdomain | | `-e TOKEN=token` | DuckDNS token | | `-e UPDATE_IP=ipv4` | Set to `ipv6` or `ipv4` to update **only** your public IPv4/6 address. Set to `both` to update IPv6 and IPv4 address. This variable makes use of a [third-party service](#notice-regarding-automatic-detection). Omitting this variable uses DuckDNS for detection and only supports IPv4. `both` and `ipv6` modes needs [host networking](#networking-net). | +| `-e UPDATE_INTERVAL=5m` | Set the update interval. Format: `[number][m|h]` where `m` is minutes (5-60) or `h` is hours (1-24). Examples: `5m` (every 5 minutes), `30m` (every 30 minutes), `2h` (every 2 hours). Default is `5m`. | | `-e LOG_FILE=false` | Set to `true` to log to file (also need to map /config). | | `-v /config` | Persistent config files. Also set `LOG_FILE=true` to keep address history. | | `--read-only=true` | Run container with a read-only filesystem. Please [read the docs](https://docs.linuxserver.io/misc/read-only/). | @@ -299,6 +302,7 @@ Once registered you can define the dockerfile to use with `-f Dockerfile.aarch64 ## Versions +* **18.02.26:** - Add configurable update interval via UPDATE_INTERVAL environment variable. * **27.07.25:** - Rebase to Alpine 3.22. * **27.01.25:** - Rebase to Alpine 3.21. * **24.06.24:** - Rebase to Alpine 3.20. diff --git a/readme-vars.yml b/readme-vars.yml index 86ff292..622c8ca 100644 --- a/readme-vars.yml +++ b/readme-vars.yml @@ -25,6 +25,7 @@ param_env_vars: opt_param_usage_include_env: true opt_param_env_vars: - {env_var: "UPDATE_IP", env_value: "ipv4", desc: "Set to `ipv6` or `ipv4` to update **only** your public IPv4/6 address. Set to `both` to update IPv6 and IPv4 address. This variable makes use of a [third-party service](#notice-regarding-automatic-detection). Omitting this variable uses DuckDNS for detection and only supports IPv4. `both` and `ipv6` modes needs [host networking](#networking-net).", env_options: ["", "ipv4", "ipv6", "both"]} + - {env_var: "UPDATE_INTERVAL", env_value: "5m", desc: "Set the update interval. Format: `[number][m|h]` where `m` is minutes (5-60) or `h` is hours (1-24). Examples: `5m` (every 5 minutes), `30m` (every 30 minutes), `2h` (every 2 hours). Default is `5m`.", env_options: ["5m", "30m", "1h", "2h"]} - {env_var: "LOG_FILE", env_value: "false", desc: "Set to `true` to log to file (also need to map /config).", env_options: ["false", "true"]} opt_param_usage_include_vols: true opt_param_volumes: @@ -36,7 +37,7 @@ app_setup_block_enabled: true app_setup_block: | - Go to the [duckdns website]({{project_url}}), register your subdomain(s) and retrieve your token. - Create a container with your subdomain(s) and token. If you own `user.duckdns.org`, you set `SUBDOMAINS=user`. You would NOT set a sub subdomain like `overseerr` from `overseerr.user.ducksdns.org`. - - It will update your IP with the DuckDNS service every 5 minutes (with a random jitter). + - It will update your IP with the DuckDNS service at a configurable interval (default: every 5 minutes, with a random jitter). Use the `UPDATE_INTERVAL` environment variable to customize the update frequency. ## Notice regarding automatic detection @@ -85,6 +86,7 @@ init_diagram: | "duckdns:latest" <- Base Images # changelog changelogs: + - {date: "18.02.26:", desc: "Add configurable update interval via UPDATE_INTERVAL environment variable."} - {date: "27.07.25:", desc: "Rebase to Alpine 3.22."} - {date: "27.01.25:", desc: "Rebase to Alpine 3.21."} - {date: "24.06.24:", desc: "Rebase to Alpine 3.20."} diff --git a/root/app/duck.sh b/root/app/duck.sh index 2b03fc5..99c0f48 100755 --- a/root/app/duck.sh +++ b/root/app/duck.sh @@ -7,6 +7,7 @@ if [[ "${LOG_FILE,,}" = "true" ]]; then touch /config/logrotate.status chmod 640 /config/logrotate.status /usr/sbin/logrotate -s /config/logrotate.status /config/logrotate.conf + echo "duck.sh invoked at $(date)" >> "${DUCK_LOG}" else DUCK_LOG="/dev/null" fi diff --git a/root/defaults/abc.tmpl b/root/defaults/abc.tmpl new file mode 100644 index 0000000..96196f5 --- /dev/null +++ b/root/defaults/abc.tmpl @@ -0,0 +1,2 @@ +# min . hour day month weekday command +${MINUTES} ${HOURS} * * * sleep $((60 + $RANDOM % 230)); /app/duck.sh 2>&1 \ No newline at end of file diff --git a/root/etc/crontabs/abc b/root/etc/crontabs/abc deleted file mode 100644 index d998d8c..0000000 --- a/root/etc/crontabs/abc +++ /dev/null @@ -1,2 +0,0 @@ -# min hour day month weekday command -*/5 * * * * sleep $((60 + $RANDOM % 230)); /app/duck.sh 2>&1 diff --git a/root/etc/s6-overlay/s6-rc.d/init-duckdns/run b/root/etc/s6-overlay/s6-rc.d/init-duckdns/run index 4ff26cd..c7fda1c 100755 --- a/root/etc/s6-overlay/s6-rc.d/init-duckdns/run +++ b/root/etc/s6-overlay/s6-rc.d/init-duckdns/run @@ -1,12 +1,47 @@ #!/usr/bin/with-contenv bash # shellcheck shell=bash -#Check to make sure the subdomain and token are set +# Check to make sure the subdomain and token are set if [ -z "${SUBDOMAINS}" ] || [ -z "${TOKEN}" ]; then echo "Please pass both your subdomain(s) and token as environment variables in your docker run command. See the readme for more details." sleep infinity fi +# Render template into real crontab with default interval if not provided +UPDATE_INTERVAL=${UPDATE_INTERVAL:-5m} +if [[ ! "$UPDATE_INTERVAL" =~ ^[0-9]+[mh]?$ ]]; then + echo "Invalid interval format: \"$UPDATE_INTERVAL\", expected format \"[0-9]+[mh]?\"" + exit 1 +fi + +case "$UPDATE_INTERVAL" in + *h) + HOURS=${UPDATE_INTERVAL%h} + if (( HOURS < 1 || HOURS > 24 )); then + echo "Update interval must be between 1-24 hours" + exit 1 + fi + HOURS="*/$HOURS" + + # We want a single run per selected hour, with the template's jitter handling + # the exact seconds. + MINUTES="0" + ;; + *) + MINUTES=${UPDATE_INTERVAL%m} + if (( MINUTES < 5 || MINUTES > 60 )); then + echo "Update interval must be between 5-60 minutes" + exit 1 + fi + MINUTES="*/$MINUTES" + + HOURS="*" + ;; +esac + +sed "s|\${MINUTES} \${HOURS}|$MINUTES $HOURS|g" < /defaults/abc.tmpl > /etc/crontabs/abc +chmod 644 /etc/crontabs/abc + if [[ ! -f /config/logrotate.conf ]]; then cp /defaults/logrotate.conf /config/logrotate.conf chmod 640 /config/logrotate.conf