[{"data":1,"prerenderedAt":673},["ShallowReactive",2],{"article-cloudflare-hermes-integration":3},{"id":4,"title":5,"body":6,"date":657,"description":658,"extension":659,"meta":660,"navigation":344,"path":661,"readingTime":662,"seo":663,"stem":664,"tags":665,"__hash__":672},"articles\u002Fblog\u002Fcloudflare-hermes-integration.en.md","Hermes + Cloudflare: DNS and Deployment Automation from the Terminal",{"type":7,"value":8,"toc":641},"minimark",[9,13,17,20,25,28,47,50,54,64,90,93,128,131,135,140,143,193,196,234,241,245,287,291,315,319,322,390,393,453,463,467,474,480,483,487,490,495,498,512,515,519,522,545,548,552,558,564,607,613,627,631,634,637],[10,11,5],"h1",{"id":12},"hermes-cloudflare-dns-and-deployment-automation-from-the-terminal",[14,15,16],"p",{},"I have dozens of subdomains: blogs, landing pages, APIs, notification services. Managing all of this through the Cloudflare Dashboard is painful. Logging in every time, finding the right record, clicking around, waiting...",[14,18,19],{},"The solution is to hand it off to an AI agent. Hermes Agent can work with Cloudflare via CLI and API. Here's how I set up this pipeline.",[21,22,24],"h2",{"id":23},"why-does-an-agent-need-cloudflare","Why Does an Agent Need Cloudflare?",[14,26,27],{},"A typical scenario: I deploy a new service on a VPS and want it accessible over HTTPS on its own subdomain. It used to be:",[29,30,31,35,38,41,44],"ol",{},[32,33,34],"li",{},"Log into the Cloudflare Dashboard",[32,36,37],{},"Create a DNS record",[32,39,40],{},"Wait for propagation",[32,42,43],{},"Verify SSL",[32,45,46],{},"Configure Caddy\u002Fnginx",[14,48,49],{},"Now I just tell Hermes: \"Set up ntfy on the notify subdomain and proxy it through Cloudflare.\" The agent handles everything itself.",[21,51,53],{"id":52},"tool-flarectl","Tool: flarectl",[14,55,56,63],{},[57,58,62],"a",{"href":59,"rel":60},"https:\u002F\u002Fgithub.com\u002Fcloudflare\u002Fcloudflare-go\u002Ftree\u002Fmain\u002Fcmd\u002Fflarectl",[61],"nofollow","flarectl"," is the official CLI utility from Cloudflare. Installation:",[65,66,71],"pre",{"className":67,"code":68,"language":69,"meta":70,"style":70},"language-bash shiki shiki-themes github-light catppuccin-mocha","go install github.com\u002Fcloudflare\u002Fcloudflare-go\u002Fcmd\u002Fflarectl@latest\n","bash","",[72,73,74],"code",{"__ignoreMap":70},[75,76,79,83,87],"span",{"class":77,"line":78},"line",1,[75,80,82],{"class":81},"siMrf","go",[75,84,86],{"class":85},"sG7gF"," install",[75,88,89],{"class":85}," github.com\u002Fcloudflare\u002Fcloudflare-go\u002Fcmd\u002Fflarectl@latest\n",[14,91,92],{},"Authentication via environment variables:",[65,94,96],{"className":67,"code":95,"language":69,"meta":70,"style":70},"export CF_API_TOKEN=your-api-token\nexport CF_ACCOUNT_ID=your-account-id\n",[72,97,98,115],{"__ignoreMap":70},[75,99,100,104,108,112],{"class":77,"line":78},[75,101,103],{"class":102},"saXKZ","export",[75,105,107],{"class":106},"slTIY"," CF_API_TOKEN",[75,109,111],{"class":110},"s_Q3D","=",[75,113,114],{"class":106},"your-api-token\n",[75,116,118,120,123,125],{"class":77,"line":117},2,[75,119,103],{"class":102},[75,121,122],{"class":106}," CF_ACCOUNT_ID",[75,124,111],{"class":110},[75,126,127],{"class":106},"your-account-id\n",[14,129,130],{},"The token is created in Dashboard → My Profile → API Tokens. Required permissions: Zone:DNS:Edit, Zone:Zone:Read.",[21,132,134],{"id":133},"basic-operations","Basic Operations",[136,137,139],"h3",{"id":138},"creating-a-dns-record","Creating a DNS Record",[14,141,142],{},"A record (subdomain → server IP):",[65,144,146],{"className":67,"code":145,"language":69,"meta":70,"style":70},"flarectl dns create --zone example.com \\\n  --type A --name myservice --content 203.0.113.1 --proxied\n",[72,147,148,169],{"__ignoreMap":70},[75,149,150,152,155,158,162,165],{"class":77,"line":78},[75,151,62],{"class":81},[75,153,154],{"class":85}," dns",[75,156,157],{"class":85}," create",[75,159,161],{"class":160},"soLUO"," --zone",[75,163,164],{"class":85}," example.com",[75,166,168],{"class":167},"s_VIv"," \\\n",[75,170,171,174,177,180,183,186,190],{"class":77,"line":117},[75,172,173],{"class":160},"  --type",[75,175,176],{"class":85}," A",[75,178,179],{"class":160}," --name",[75,181,182],{"class":85}," myservice",[75,184,185],{"class":160}," --content",[75,187,189],{"class":188},"sNSVI"," 203.0.113.1",[75,191,192],{"class":160}," --proxied\n",[14,194,195],{},"CNAME (subdomain → Cloudflare Pages project):",[65,197,199],{"className":67,"code":198,"language":69,"meta":70,"style":70},"flarectl dns create --zone example.com \\\n  --type CNAME --name blog --content my-project.pages.dev --proxied\n",[72,200,201,215],{"__ignoreMap":70},[75,202,203,205,207,209,211,213],{"class":77,"line":78},[75,204,62],{"class":81},[75,206,154],{"class":85},[75,208,157],{"class":85},[75,210,161],{"class":160},[75,212,164],{"class":85},[75,214,168],{"class":167},[75,216,217,219,222,224,227,229,232],{"class":77,"line":117},[75,218,173],{"class":160},[75,220,221],{"class":85}," CNAME",[75,223,179],{"class":160},[75,225,226],{"class":85}," blog",[75,228,185],{"class":160},[75,230,231],{"class":85}," my-project.pages.dev",[75,233,192],{"class":160},[14,235,236,237,240],{},"The ",[72,238,239],{},"--proxied"," flag enables the orange cloud — Cloudflare caches, protects against DDoS, and terminates SSL.",[136,242,244],{"id":243},"updating-records","Updating Records",[65,246,248],{"className":67,"code":247,"language":69,"meta":70,"style":70},"flarectl dns update --zone example.com \\\n  --id RECORD_ID --type A --name myservice --content 203.0.113.2\n",[72,249,250,265],{"__ignoreMap":70},[75,251,252,254,256,259,261,263],{"class":77,"line":78},[75,253,62],{"class":81},[75,255,154],{"class":85},[75,257,258],{"class":85}," update",[75,260,161],{"class":160},[75,262,164],{"class":85},[75,264,168],{"class":167},[75,266,267,270,273,276,278,280,282,284],{"class":77,"line":117},[75,268,269],{"class":160},"  --id",[75,271,272],{"class":85}," RECORD_ID",[75,274,275],{"class":160}," --type",[75,277,176],{"class":85},[75,279,179],{"class":160},[75,281,182],{"class":85},[75,283,185],{"class":160},[75,285,286],{"class":188}," 203.0.113.2\n",[136,288,290],{"id":289},"deleting","Deleting",[65,292,294],{"className":67,"code":293,"language":69,"meta":70,"style":70},"flarectl dns delete --zone example.com --id RECORD_ID\n",[72,295,296],{"__ignoreMap":70},[75,297,298,300,302,305,307,309,312],{"class":77,"line":78},[75,299,62],{"class":81},[75,301,154],{"class":85},[75,303,304],{"class":85}," delete",[75,306,161],{"class":160},[75,308,164],{"class":85},[75,310,311],{"class":160}," --id",[75,313,314],{"class":85}," RECORD_ID\n",[21,316,318],{"id":317},"cloudflare-pages-deploying-static-sites","Cloudflare Pages: Deploying Static Sites",[14,320,321],{},"For Nuxt, Astro, Next.js, and other SSG\u002FSSR frameworks, Cloudflare Pages offers free hosting with a CDN. Deployment via the wrangler CLI:",[65,323,325],{"className":67,"code":324,"language":69,"meta":70,"style":70},"npm install -g wrangler\n\n# Authentication\nwrangler login\n\n# Deploy from dist\u002F folder\nwrangler pages deploy dist --project-name=my-blog\n",[72,326,327,340,346,353,362,367,373],{"__ignoreMap":70},[75,328,329,332,334,337],{"class":77,"line":78},[75,330,331],{"class":81},"npm",[75,333,86],{"class":85},[75,335,336],{"class":160}," -g",[75,338,339],{"class":85}," wrangler\n",[75,341,342],{"class":77,"line":117},[75,343,345],{"emptyLinePlaceholder":344},true,"\n",[75,347,349],{"class":77,"line":348},3,[75,350,352],{"class":351},"skkvY","# Authentication\n",[75,354,356,359],{"class":77,"line":355},4,[75,357,358],{"class":81},"wrangler",[75,360,361],{"class":85}," login\n",[75,363,365],{"class":77,"line":364},5,[75,366,345],{"emptyLinePlaceholder":344},[75,368,370],{"class":77,"line":369},6,[75,371,372],{"class":351},"# Deploy from dist\u002F folder\n",[75,374,376,378,381,384,387],{"class":77,"line":375},7,[75,377,358],{"class":81},[75,379,380],{"class":85}," pages",[75,382,383],{"class":85}," deploy",[75,385,386],{"class":85}," dist",[75,388,389],{"class":160}," --project-name=my-blog\n",[14,391,392],{},"A custom domain is attached via the API:",[65,394,396],{"className":67,"code":395,"language":69,"meta":70,"style":70},"curl -s -X POST \\\n  \"https:\u002F\u002Fapi.cloudflare.com\u002Fclient\u002Fv4\u002Faccounts\u002F$CF_ACCOUNT_ID\u002Fpages\u002Fprojects\u002Fmy-blog\u002Fdomains\" \\\n  -H \"Authorization: Bearer *** \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  --data '{\"name\": \"blog.example.com\"}'\n",[72,397,398,414,427,438,448],{"__ignoreMap":70},[75,399,400,403,406,409,412],{"class":77,"line":78},[75,401,402],{"class":81},"curl",[75,404,405],{"class":160}," -s",[75,407,408],{"class":160}," -X",[75,410,411],{"class":85}," POST",[75,413,168],{"class":167},[75,415,416,419,422,425],{"class":77,"line":117},[75,417,418],{"class":85},"  \"https:\u002F\u002Fapi.cloudflare.com\u002Fclient\u002Fv4\u002Faccounts\u002F",[75,420,421],{"class":106},"$CF_ACCOUNT_ID",[75,423,424],{"class":85},"\u002Fpages\u002Fprojects\u002Fmy-blog\u002Fdomains\"",[75,426,168],{"class":167},[75,428,429,432,435],{"class":77,"line":348},[75,430,431],{"class":160},"  -H",[75,433,434],{"class":85}," \"Authorization: Bearer *** ",[75,436,437],{"class":167},"\\\n",[75,439,440,443,446],{"class":77,"line":355},[75,441,442],{"class":85},"  -H \"Content-Type:",[75,444,445],{"class":85}," application\u002Fjson\" ",[75,447,437],{"class":167},[75,449,450],{"class":77,"line":364},[75,451,452],{"class":85},"  --data '{\"name\": \"blog.example.com\"}'\n",[454,455,456],"blockquote",{},[14,457,458,459,462],{},"Wrangler v4.94+ may not support ",[72,460,461],{},"wrangler pages domain add",". Use the API directly.",[21,464,466],{"id":465},"ssl-flexible-vs-full","SSL: Flexible vs Full",[14,468,469,473],{},[470,471,472],"strong",{},"SSL:Flexible"," — Cloudflare terminates SSL at its edge; plain HTTP goes to your origin. No certificate needed on the server. Ideal for services that don't natively support HTTPS.",[14,475,476,479],{},[470,477,478],{},"SSL:Full"," — Cloudflare terminates SSL at the edge, but also uses SSL to connect to the origin. A certificate is required on the server (you can use a free Cloudflare Origin CA certificate).",[14,481,482],{},"For self-hosted services on a single VPS, Flexible is usually sufficient. However, if the service transmits sensitive data, use Full.",[21,484,486],{"id":485},"automation-via-hermes","Automation via Hermes",[14,488,489],{},"Here's how it works in real life. Hermes Agent has terminal access and can execute commands. I say:",[454,491,492],{},[14,493,494],{},"\"Set up Grafana on monitor.example.com\"",[14,496,497],{},"The agent:",[29,499,500,503,506,509],{},[32,501,502],{},"Checks that Grafana is installed",[32,504,505],{},"Creates a DNS A record via flarectl",[32,507,508],{},"Configures the Caddy reverse proxy",[32,510,511],{},"Verifies HTTPS",[14,513,514],{},"All in one conversation, without switching to the Dashboard.",[136,516,518],{"id":517},"cron-monitoring","Cron Monitoring",[14,520,521],{},"Hermes can check DNS records on a schedule:",[65,523,525],{"className":67,"code":524,"language":69,"meta":70,"style":70},"flarectl dns list --zone example.com --type A\n",[72,526,527],{"__ignoreMap":70},[75,528,529,531,533,536,538,540,542],{"class":77,"line":78},[75,530,62],{"class":81},[75,532,154],{"class":85},[75,534,535],{"class":85}," list",[75,537,161],{"class":160},[75,539,164],{"class":85},[75,541,275],{"class":160},[75,543,544],{"class":85}," A\n",[14,546,547],{},"If a record has changed or disappeared, the agent sends a notification.",[21,549,551],{"id":550},"pitfalls","Pitfalls",[14,553,554,557],{},[470,555,556],{},"Proxy status."," If a record is not proxied (grey cloud), Cloudflare won't terminate SSL or cache. For services that should be behind a CDN, always use proxied.",[14,559,560,563],{},[470,561,562],{},"Cache purge."," After deploying a new build, Cloudflare might serve the old cache. To purge:",[65,565,567],{"className":67,"code":566,"language":69,"meta":70,"style":70},"curl -s -X POST \\\n  \"https:\u002F\u002Fapi.cloudflare.com\u002Fclient\u002Fv4\u002Fzones\u002F$ZONE_ID\u002Fpurge_cache\" \\\n  -H \"Authorization: Bearer *** \\\n  --data '{\"purge_everything\":true}'\n",[72,568,569,581,594,602],{"__ignoreMap":70},[75,570,571,573,575,577,579],{"class":77,"line":78},[75,572,402],{"class":81},[75,574,405],{"class":160},[75,576,408],{"class":160},[75,578,411],{"class":85},[75,580,168],{"class":167},[75,582,583,586,589,592],{"class":77,"line":117},[75,584,585],{"class":85},"  \"https:\u002F\u002Fapi.cloudflare.com\u002Fclient\u002Fv4\u002Fzones\u002F",[75,587,588],{"class":106},"$ZONE_ID",[75,590,591],{"class":85},"\u002Fpurge_cache\"",[75,593,168],{"class":167},[75,595,596,598,600],{"class":77,"line":348},[75,597,431],{"class":160},[75,599,434],{"class":85},[75,601,437],{"class":167},[75,603,604],{"class":77,"line":355},[75,605,606],{"class":85},"  --data '{\"purge_everything\":true}'\n",[14,608,609,612],{},[470,610,611],{},"Rate limits."," The Cloudflare Free plan has API call limits. This is rarely an issue for automation, but if the agent makes dozens of requests per minute, it might hit a 429 error.",[14,614,615,618,619,622,623,626],{},[470,616,617],{},"DNS propagation."," After creating a record, DNS propagates within 1-5 minutes. Hermes verifies via ",[72,620,621],{},"dig"," or ",[72,624,625],{},"flarectl dns list"," before considering the task complete.",[21,628,630],{"id":629},"conclusion","Conclusion",[14,632,633],{},"Cloudflare Free + Hermes Agent = full infrastructure automation from the terminal. No Dashboard, no manual clicking. The agent manages DNS, deploys static sites, configures SSL, and monitors records.",[14,635,636],{},"For self-hosted projects, this is the ideal stack: free, reliable, and entirely CLI-driven.",[638,639,640],"style",{},"html pre.shiki code .siMrf, html code.shiki .siMrf{--shiki-light:#6F42C1;--shiki-light-font-style:inherit;--shiki-dark:#89B4FA;--shiki-dark-font-style:italic}html pre.shiki code .sG7gF, html code.shiki .sG7gF{--shiki-light:#032F62;--shiki-dark:#A6E3A1}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .saXKZ, html code.shiki .saXKZ{--shiki-light:#D73A49;--shiki-dark:#CBA6F7}html pre.shiki code .slTIY, html code.shiki .slTIY{--shiki-light:#24292E;--shiki-dark:#CDD6F4}html pre.shiki code .s_Q3D, html code.shiki .s_Q3D{--shiki-light:#D73A49;--shiki-dark:#94E2D5}html pre.shiki code .soLUO, html code.shiki .soLUO{--shiki-light:#005CC5;--shiki-dark:#A6E3A1}html pre.shiki code .s_VIv, html code.shiki .s_VIv{--shiki-light:#005CC5;--shiki-dark:#F5C2E7}html pre.shiki code .sNSVI, html code.shiki .sNSVI{--shiki-light:#005CC5;--shiki-dark:#FAB387}html pre.shiki code .skkvY, html code.shiki .skkvY{--shiki-light:#6A737D;--shiki-light-font-style:inherit;--shiki-dark:#9399B2;--shiki-dark-font-style:italic}",{"title":70,"searchDepth":117,"depth":117,"links":642},[643,644,645,650,651,652,655,656],{"id":23,"depth":117,"text":24},{"id":52,"depth":117,"text":53},{"id":133,"depth":117,"text":134,"children":646},[647,648,649],{"id":138,"depth":348,"text":139},{"id":243,"depth":348,"text":244},{"id":289,"depth":348,"text":290},{"id":317,"depth":117,"text":318},{"id":465,"depth":117,"text":466},{"id":485,"depth":117,"text":486,"children":653},[654],{"id":517,"depth":348,"text":518},{"id":550,"depth":117,"text":551},{"id":629,"depth":117,"text":630},"2026-05-24","How the Hermes AI agent manages DNS records, deploys static sites to Cloudflare Pages, and configures SSL — all via CLI, without the Dashboard.","md",{},"\u002Fblog\u002Fcloudflare-hermes-integration.en",null,{"title":5,"description":658},"blog\u002Fcloudflare-hermes-integration.en",[666,667,668,669,670,671],"hermes","cloudflare","dns","devops","automation","cli","nvPKwgwqsfvRT1G5f-mr-qS-d4WldqKgG6CkTcUxQbQ",1780777846249]