duckdns: Proper Support for Single-TXT Domains & Fix Let's Encrypt Rate-Limit#4126
Conversation
… (such as DuckDNS) - Revise run to use the new parameters for dehydrated - Version bump - Updated Changelogs
📝 WalkthroughWalkthroughUpdates dehydrated source and version, bumps add-on version to 1.26.0, and revises the renewal script to invoke dehydrated once with aggregated domain arguments instead of per-domain passes and a final combine. Documentation (CHANGELOG) updated accordingly. No public interfaces changed. Changes
Sequence Diagram(s)sequenceDiagram
participant s6 as s6 service
participant run as duckdns/run
participant dehydrated as dehydrated
participant LE as Let's Encrypt ACME
s6->>run: start
run->>run: Build domain_args from domains + aliases
run->>dehydrated: --cron --separate-challenges ${domain_args}
dehydrated->>LE: Perform ACME challenges/renewals
LE-->>dehydrated: Challenge results/certificates
dehydrated-->>run: Exit status
run-->>s6: Complete (update timestamp if renewed)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Tip 🔌 Remote MCP (Model Context Protocol) integration is now available!Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats. ✨ Finishing Touches🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 0
🔭 Outside diff range comments (3)
duckdns/rootfs/etc/s6-overlay/s6-rc.d/duckdns/run (3)
31-35: Alias extraction is incorrect; jq builds an alias→domain map but looks up by domain key.
This returns no aliases. Select aliases by value (domain) instead.Apply this diff:
- for domain in ${domains}; do - for alias in $(jq --raw-output --exit-status "[.aliases[]|{(.alias):.domain}]|add.\"${domain}\" | select(. != null)" /data/options.json) ; do - aliases+=("${alias}") - done - done + for domain in ${domains}; do + # Collect aliases whose "domain" matches the current domain + while IFS= read -r alias; do + [[ -n "$alias" ]] && aliases+=("$alias") + done < <(jq -r --arg domain "$domain" '.aliases // [] | .[] | select(.domain == $domain) | .alias' /data/options.json) + done
37-39: Make domain array construction robust to whitespace and quoting.
Rely on newline-delimited expansion from bashio rather than generic word-splitting to avoid accidental concatenation.Apply this diff and update the loop at Line 31 accordingly:
- domains=$(bashio::config 'domains') + # Produce a newline-delimited list for safe array parsing + mapfile -t domainsarray < <(bashio::config 'domains | join($"\n")') @@ - for domain in ${domains}; do + for domain in "${domainsarray[@]}"; do @@ - readarray -t domainsarray <<< "$domains" # line-separated list of domains into an array + # domainsarray already populated above
100-102: DuckDNS domain sanitization: block wildcard aliases & handle case sensitivityOur current regex will pull in domains from wildcard entries (e.g.
*.bad.duckdns.org→bad.duckdns.org) and ignores any uppercase input. To tighten this up:• Exclude any entry beginning with
*.before extracting domains
• Normalize to lowercase (or, if you must preserve case, add-itogrep)
• Only match a single-label DuckDNS host (no deeper subdomains)Proposed pipeline (bash-compliant, avoids look-arounds):
duckdnsDomains=$( echo "$DOMAINS" \ | tr '[:upper:]' '[:lower:]' \ | tr ' ,>' '\n' \ | grep -v '^\*\.' \ | grep -E '^[a-z0-9-]+\.duckdns\.org$' \ | sort -u \ | paste -sd, )This will:
- Lowercase everything (so
GOOD.DUCKDNS.ORGis captured)- Split on spaces, commas or
>- Drop any line starting with
*.- Match only exactly one-label subdomains of
duckdns.org- Deduplicate and rejoin with commas
🧹 Nitpick comments (3)
duckdns/CHANGELOG.md (1)
5-6: Tighten grammar for clarity and subject-verb agreement.
Use “that handle” (plural) and remove filler.Apply this diff:
-- Updated dehydrated fork with support for single-txt domains -- Use the new dehydrated script parameters which handles individual domain processing now +- Updated dehydrated fork with support for single TXT domains +- Use the new dehydrated script parameters that handle individual-domain processingduckdns/Dockerfile (1)
8-8: Harden curl invocation & pin script versionTo improve reliability when fetching the Dehydrated script:
• In duckdns/Dockerfile, change the curl flags to fail fast on network issues:
- && curl -s -o /usr/bin/dehydrated \ + && curl -fsSL -o /usr/bin/dehydrated \ "https://raw.githubusercontent.com/Xebozone/dehydrated/${DEHYDRATED_VERSION}/dehydrated" \ + && chmod a+x /usr/bin/dehydrated• (Optional, but recommended) Pin to a commit SHA to avoid surprises if a tag is moved:
ARG DEHYDRATED_COMMIT=<commit-sha> RUN curl -fsSL -o /usr/bin/dehydrated \ "https://raw.githubusercontent.com/Xebozone/dehydrated/${DEHYDRATED_COMMIT}/dehydrated" \ && chmod a+x /usr/bin/dehydratedSince
DEHYDRATED_VERSIONis declared without a default value, please build the image with a concrete version (or provide a default in the Dockerfile) and verify that:curl -sSfI "https://raw.githubusercontent.com/Xebozone/dehydrated/${DEHYDRATED_VERSION}/dehydrated"returns HTTP 200 before merging.
duckdns/rootfs/etc/s6-overlay/s6-rc.d/duckdns/run (1)
49-55: Guard against empty domain_args and avoid masking failures.
Skip dehydrated when no domains/aliases were found and surface errors instead of swallowing them.Apply this diff:
- for domain in "${domainsAndAliases[@]}"; do - domain_args+=("--domain" "${domain}") - done + for domain in "${domainsAndAliases[@]}"; do + domain_args+=("--domain" "${domain}") + done @@ - # Do the certificate renewals - dehydrated --cron --separate-challenges --algo "${ALGO}" --hook /root/hooks.sh --challenge dns-01 "${domain_args[@]}" --out "${CERT_DIR}" --config "${WORK_DIR}/config" || true + # Do the certificate renewals + if [ ${#domain_args[@]} -eq 0 ]; then + bashio::log.warning "No domains or aliases found; skipping certificate renewal" + return 0 + fi + if ! dehydrated --cron --separate-challenges --algo "${ALGO}" --hook /root/hooks.sh --challenge dns-01 "${domain_args[@]}" --out "${CERT_DIR}" --config "${WORK_DIR}/config"; then + bashio::log.warning "dehydrated run failed" + fi
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge Base: Disabled due to data retention organization setting
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (5)
duckdns/CHANGELOG.md(1 hunks)duckdns/Dockerfile(1 hunks)duckdns/build.yaml(1 hunks)duckdns/config.yaml(1 hunks)duckdns/rootfs/etc/s6-overlay/s6-rc.d/duckdns/run(1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
*/**(html|markdown|md)
⚙️ CodeRabbit Configuration File
*/**(html|markdown|md): - For instructional content in documentation, use a direct and authoritative tone. Avoid expressions of politeness such as 'may' or 'please', and ensure the goal of the instruction is fronted.
- Apply the Microsoft Style Guide to ensure documentation maintains clarity and conciseness.
- In step-by-step instructions, front the location phrase in the instructional sentence.
- In step-by-step instructions, front the 'goal' in the instructional sentence.
- In step-by-step instructions, if in doubt what to front, front the 'goal' before the location phrase in the instructional sentence.
- do not hyphenate terms like 'top-right' or 'bottom-left' with 'corner'
*/**(html|markdown|md): - Use bold to mark UI strings.
If "" are used to mark UI strings, replace them by bold.
Be brief in your replies and don't add fluff like "thank you for..." and "Please let me know if"
Use sentence-style capitalization also in headings.
do not comment on HTML used for icons
Avoid flagging inline HTML for embedding videos in future reviews for this repository.
Files:
duckdns/build.yamlduckdns/Dockerfileduckdns/config.yamlduckdns/CHANGELOG.md
🔇 Additional comments (2)
duckdns/config.yaml (1)
2-2: Version bump looks correct and consistent with PR scope.
Matches CHANGELOG and associated Dehydrated update across the PR.duckdns/build.yaml (1)
12-12: Confirmed DEHYDRATED_VERSION Tag Resolves Correctly
The raw URL for DEHYDRATED_VERSION 0.8.0 returns HTTP 200 OK, so the non-prefixed tag is valid. No changes needed.
Summary by CodeRabbit
New Features
Chores
Documentation