1"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[8630],{16132:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>a,default:()=>p,frontMatter:()=>r,metadata:()=>o,toc:()=>l});const o=JSON.parse('{"id":"dns/providers/scripting","title":"DNS Scripting","description":"To provide your own script to update DNS you need to create (or source) a Windows (CMD) batch file which expects the following sequence of arguments and update a corresponding TXT record in your DNS zone:","source":"@site/docs/dns/providers/scripting.md","sourceDirName":"dns/providers","slug":"/dns/providers/scripting","permalink":"/docs/dns/providers/scripting","draft":false,"unlisted":false,"editUrl":"https://github.com/webprofusion/certify-docs/edit/master/docs/dns/providers/scripting.md","tags":[],"version":"current","frontMatter":{"id":"scripting","title":"DNS Scripting"}}');var i=t(74848),s=t(28453);const r={id:"scripting",title:"DNS Scripting"},a=void 0,c={},l=[{value:"Calling a Python or node script",id:"calling-a-python-or-node-script",level:2}];function d(e){const n={code:"code",em:"em",h2:"h2",li:"li",p:"p",pre:"pre",ul:"ul",...(0,s.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.p,{children:"To provide your own script to update DNS you need to create (or source) a Windows (CMD) batch file which expects the following sequence of arguments and update a corresponding TXT record in your DNS zone:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["Target Domain (e.g. ",(0,i.jsx)(n.code,{children:"example.com"}),")"]}),"\n",(0,i.jsxs)(n.li,{children:["Record Name (e.g. ",(0,i.jsx)(n.code,{children:"_acme-challenge.example.com"}),")"]}),"\n",(0,i.jsxs)(n.li,{children:["Record Value (e.g. ",(0,i.jsx)(n.code,{children:"ABCBD123456789"}),")"]}),"\n",(0,i.jsxs)(n.li,{children:["Zone Id (e.g. ",(0,i.jsx)(n.code,{children:"OptionalZoneId"}),", this is often useful to match the specific zone to update)"]}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["e.g. given a script at ",(0,i.jsx)(n.em,{children:"C:\\customscripts\\UpdateDNS.bat"}),", this will be executed as:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:"C:\\customscripts\\UpdateDNS.bat example.com _acme-challenge.example.com ABCBD123456789 OptionalZoneId\n"})}),"\n",(0,i.jsx)(n.p,{children:"Important Notes:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Your script will run as the background service user (local system), not as your account."}),"\n",(0,i.jsx)(n.li,{children:"You should assume the working directory of the process will not be the same as the script."}),"\n",(0,i.jsxs)(n.li,{children:["When an 'apex domain' like ",(0,i.jsx)(n.code,{children:"example.com"})," is included in the certificate request for a wildcard (e.g. ",(0,i.jsx)(n.code,{children:"*.example.com"}),") both TXT records will have the same name but different values, so updates need to add to the TXT record values. For this reason it's also a good idea to provide a (well tested!) delete script to clean up the TXT record once the request has completed, otherwise your TXT record values will grow with every validation attempt."]}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"calling-a-python-or-node-script",children:"Calling a Python or node script"}),"\n",(0,i.jsxs)(n.p,{children:["To use a Python script (or similarly Node etc) start with a .bat file which can then forward all the arguments as required to your script using ",(0,i.jsx)(n.code,{children:"%*"})," (or you could pass specific arguments if you needed). Note also the fully qualified path to the python exe (or node) as your script will run as local system (using the apps background service) and the path environment variable settings may be different:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bat",children:"REM This script would be called with the parameters <target domain> <record name> <record value> <zone id (optionally)>\n\nREM this example then calls a custom python script forwarding all the arguments\n\nc:\\python27\\python.exe create_dns_txt_example.py %*\n"})}),"\n",(0,i.jsxs)(n.p,{children:["In the following Python example the args are available in the ",(0,i.jsx)(n.code,{children:"sys.argv"})," list. This example passes that list to a function called ",(0,i.jsx)(n.code,{children:"main"})," and logs some example stuff (",(0,i.jsx)(n.code,{children:"create_dns_txt_example.py"})," logging to ",(0,i.jsx)(n.code,{children:"dns_create_test.log"}),")."]}),"\n",(0,i.jsx)(n.p,{children:"Your real script would use your DNS providers API or a library such as Apache libcloud."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-python",children:'# Example\n\nimport sys\nimport os\nimport getopt\nimport logging\n\n# TODO: added module for DNS updates (libcloud etc)\n\n\ndef main(argv):\n\n # init logging etc\n logging.basicConfig(filename=\'dns_create_test.log\',\n filemode=\'a\', level=logging.INFO)\n\n logging.info("Example Python DNS helper.")\n\n # TODO: setup your DNS provider (apache libcloud etc)\n\n # TODO: add/append the txt record\n\n logging.info("args: " + " ".join(sys.argv))\n\n logging.info(\n "If this script did anything it would create a TXT record called " + sys.argv[2]\n + " with the value " + sys.argv[3]\n + " you could optionally use the domain ("+sys.argv[1]+") "\n + " or zoneId ("+sys.argv[4]+") in your python script")\n\n\n#########################################\nif __name__ == "__main__":\n main(sys.argv)\n\n'})}),"\n",(0,i.jsx)(n.p,{children:"When the script runs that app will call the .bat file like:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:"ExampleDNSCreatePython.bat mydomain.com _acme-challenge.mydomain.com ABCD1234 myoptionalZoneId\n"})}),"\n",(0,i.jsx)(n.p,{children:"Which in turn (based on the above example .bat) will call the python script as :"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:"python create_dns_txt_basic.py.bat mydomain.com _acme-challenge.mydomain.com ABCD1234 myoptionalZoneId\n"})})]})}function p(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(d,{...e})}):d(e)}},28453:(e,n,t)=>{t.d(n,{R:()=>r,x:()=>a});var o=t(96540);const i={},s=o.createContext(i);function r(e){const n=o.useContext(s);return o.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:r(e.components),o.createElement(s.Provider,{value:n},e.children)}}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.