{"id":317,"date":"2025-07-16T10:53:07","date_gmt":"2025-07-16T17:53:07","guid":{"rendered":"https:\/\/www.cmsws.com\/blog\/?p=317"},"modified":"2025-07-16T10:53:07","modified_gmt":"2025-07-16T17:53:07","slug":"create-bind9-hook-script-for-use-with-acme-sh","status":"publish","type":"post","link":"https:\/\/www.cmsws.com\/blog\/create-bind9-hook-script-for-use-with-acme-sh\/","title":{"rendered":"Create Bind9 &#8220;hook&#8221; script for use with acme.sh"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Add_%E2%80%9Chook%E2%80%9D_processing_file_for_acmesh\"><\/span>Add &#8220;hook&#8221; processing file for acme.sh<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Create_the_file_%E2%80%98acmeshdns_bind9sh\"><\/span>Create the file <strong><em>&#8216;~\/.acme.sh\/dns_bind9.sh&#8217;<\/em><\/strong><span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p>Add the following to this file:<\/p><div id=\"ez-toc-container\" class=\"ez-toc-v2_0_82_2 ez-toc-wrap-right counter-hierarchy ez-toc-counter ez-toc-grey ez-toc-container-direction\">\n<div class=\"ez-toc-title-container\">\n<span class=\"ez-toc-title-toggle\"><\/span><\/div>\n<nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/www.cmsws.com\/blog\/create-bind9-hook-script-for-use-with-acme-sh\/#Add_%E2%80%9Chook%E2%80%9D_processing_file_for_acmesh\" >Add &#8220;hook&#8221; processing file for acme.sh<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/www.cmsws.com\/blog\/create-bind9-hook-script-for-use-with-acme-sh\/#Create_the_file_%E2%80%98acmeshdns_bind9sh\" >Create the file &#8216;~\/.acme.sh\/dns_bind9.sh&#8217;<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/www.cmsws.com\/blog\/create-bind9-hook-script-for-use-with-acme-sh\/#Set_file_as_executable\" >Set file as executable<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/www.cmsws.com\/blog\/create-bind9-hook-script-for-use-with-acme-sh\/#Create_Bind9_update_script_%E2%80%98usrlocalbinupdate_bind9_txtsh\" >Create Bind9 update script &#8216;\/usr\/local\/bin\/update_bind9_txt.sh&#8217;<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/www.cmsws.com\/blog\/create-bind9-hook-script-for-use-with-acme-sh\/#Set_file_as_executable-2\" >Set file as executable<\/a><\/li><\/ul><\/li><\/ul><\/nav><\/div>\n\n\n\n\n<pre class=\"wp-block-code\"><code>#!\/bin\/bash\n# acme.sh DNS API hook for BIND9\n\nBIND_UPDATE_SCRIPT=\"\/usr\/local\/bin\/update_bind9_txt.sh\"\n\ndns_bind9_add() {\n    fulldomain=\"$1\"\n    txtvalue=\"$2\"\n\n    _debug \"dns_bind9_add: $fulldomain = $txtvalue\"\n\n    \"$BIND_UPDATE_SCRIPT\" \"ADD\" \"$fulldomain\" \"$txtvalue\" || return 1\n\n    return 0\n}\n\ndns_bind9_rm() {\n    fulldomain=\"$1\"\n    txtvalue=\"$2\"\n\n    _debug \"dns_bind9_rm: $fulldomain (value $txtvalue)\"\n\n    \"$BIND_UPDATE_SCRIPT\" \"DEL\" \"$fulldomain\" \"$txtvalue\" || return 0\n\n    return 0\n}\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Set_file_as_executable\"><\/span>Set file as executable<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>chmod +x ~\/.acme.sh\/dns_bind9.sh<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Create_Bind9_update_script_%E2%80%98usrlocalbinupdate_bind9_txtsh\"><\/span>Create Bind9 update script <em>&#8216;\/usr\/local\/bin\/update_bind9_txt.sh&#8217;<\/em><span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>Add the following to this file:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#!\/bin\/bash\n\n# Must be run as root\nif &#91;&#91; $EUID -ne 0 ]]; then\n    echo \"This script must be run as root.\"\n    exit 1\nfi\n\nACTION=\"$1\"       # ADD or DEL\nRECORD=\"$2\"       # Full domain (_acme-challenge.sub.example.com)\nTXT_VALUE=\"$3\"\n\nZONE_DIR=\"\/etc\/bind\/zones\"\n\nif &#91;&#91; -z \"$ACTION\" || -z \"$RECORD\" || ( \"$ACTION\" == \"ADD\" &amp;&amp; -z \"$TXT_VALUE\" ) ]]; then\n    echo \"Usage: $0 ADD|DEL full.domain.name txt-value\"\n    exit 1\nfi\n\n# Function to extract zone name from domain\nfind_zone_name() {\n    domain=\"$1\"\n    while &#91;&#91; \"$domain\" == *.* ]]; do\n        zone_candidate=\"$domain\"\n        zone_file=\"$ZONE_DIR\/$zone_candidate.zone\"\n        if &#91;&#91; -f \"$zone_file\" ]]; then\n            echo \"$zone_candidate\"\n            return\n        fi\n        domain=\"${domain#*.}\"\n    done\n    echo \"\"\n}\n\nZONE_NAME=\"$(find_zone_name \"$RECORD\")\"\n\nif &#91;&#91; -z \"$ZONE_NAME\" ]]; then\n    echo \"Zone file for $RECORD not found in $ZONE_DIR\"\n    exit 1\nfi\n\nZONE_FILE=\"$ZONE_DIR\/$ZONE_NAME.zone\"\n\n# Backup\nTIMESTAMP=$(date +%Y%m%d_%H%M%S)\ncp \"$ZONE_FILE\" \"$ZONE_FILE.bak_$TIMESTAMP\" || exit 1\n\n# Function to increment SOA serial\nincrement_serial() {\n    sed -i -E \"\/; serial\/ {\n        s\/(&#91;0-9]{10})\/\\1 + 1\/e\n    }\" \"$ZONE_FILE\"\n}\n\n# Build relative name for zone file (strip zone from record)\nREL_NAME=\"${RECORD%.$ZONE_NAME}\"\nREL_NAME=\"${REL_NAME%.}\"  # remove trailing dot if present\n\nif &#91;&#91; -z \"$REL_NAME\" || \"$REL_NAME\" == \"$RECORD\" ]]; then\n    REL_NAME=\"@\"\nfi\n\ncase \"$ACTION\" in\n    ADD)\n        echo \"$REL_NAME. 300 IN TXT \\\"$TXT_VALUE\\\"\" &gt;&gt; \"$ZONE_FILE\"\n        ;;\n    DEL)\n        sed -i \"\\|^$REL_NAME&#91;&#91;:space:]].*IN&#91;&#91;:space:]]TXT&#91;&#91;:space:]]\\\"$TXT_VALUE\\\"|d\" \"$ZONE_FILE\"\n        ;;\n    *)\n        echo \"Unknown action: $ACTION\"\n        exit 1\n        ;;\nesac\n\nincrement_serial\n\n# Reload the zone\nrndc reload \"$ZONE_NAME\" || {\n    echo \"Failed to reload zone $ZONE_NAME\"\n    exit 1\n}\n\necho \"Successfully updated $ZONE_NAME for record $REL_NAME\"\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Set_file_as_executable-2\"><\/span>Set file as executable<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>chmod +x \/usr\/local\/bin\/update_bind9_txt.sh<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Add &#8220;hook&#8221; processing file for acme.sh Create the file &#8216;~\/.acme.sh\/dns_bind9.sh&#8217; Add the following to this file: Set file as executable Create Bind9 update script &#8216;\/usr\/local\/bin\/update_bind9_txt.sh&#8217; Add the following to this file: Set file as executable<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-317","post","type-post","status-publish","format-standard","hentry","category-misc"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.cmsws.com\/blog\/wp-json\/wp\/v2\/posts\/317","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.cmsws.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.cmsws.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.cmsws.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.cmsws.com\/blog\/wp-json\/wp\/v2\/comments?post=317"}],"version-history":[{"count":0,"href":"https:\/\/www.cmsws.com\/blog\/wp-json\/wp\/v2\/posts\/317\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.cmsws.com\/blog\/wp-json\/wp\/v2\/media?parent=317"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.cmsws.com\/blog\/wp-json\/wp\/v2\/categories?post=317"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.cmsws.com\/blog\/wp-json\/wp\/v2\/tags?post=317"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}