Cloudflare CNAME automation

Curious if anyone has found a way to automate Cloudflare CNAME records from either docker labels or caddy config. I see there is a traefik-cloudflare-companion app that does this, but I have not come across a solution for caddy.

It’s unclear what you’re asking for here. Why do you need to automate CNAME records?

Please fill out the help topic template, it’s important for us to understand the full context of your question.

Cloudflare does not proxy wildcards so CNAME records must be created to proxy a service. There is a traefik companion app that automates this from docker labels. Hoping to find something similar for Caddy so as to not have to manually manage CNAME records for all of my services.

What in the template would be helpful? Not sure what to show since this functionality does not exist that I am aware of; hence, the question. I also use caddy-docker-proxy which no longer has the ability to show CaddyFile.

It does, it gets output in the logs.

Well, I don’t understand what the shape of your config looks like, so I have to make assumptions based on the very little you’ve said. Showing your config would help me understand what you mean.

I’m still not clear on what you’re expecting to happen.

But I can say pretty confidently nothing like this exists yet, but it might not be too difficult to write a Caddy plugin to do this, using the libdns plugin for Cloudflare. It would be a Caddy app (see the caddy-exec plugin for an example of how a Caddy app is configured via global options).

I would like to be able to add a label to a container like caddy.service.cname=servicename and servicename gets added as a CNAME to Cloudflare eliminating the step of logging into the CloudFlare portal and creating it manually. I am already using labels to automate the caddy config, caddy-auth-portal, and a dasboard. Would be nice to be able to do the same with CNAMES. Was hoping since someone figured it out for traefik, that maybe someone had a similiar solution for caddy,

Thanks for the info. I will look into it to see if I can come up with something.

Here is the output from the logs of the caddy config for what it is worth. It is logged as a bug/enhancement request that CaddyFile format is no longer available with caddy-docker-proxy.

"caddyfile":"{\n\thttps_port 443\n\thttp_port 80\n\torder jwt before reverse_proxy\n\torder authp before jwt\n\temail user@mydomain.net\n\tdebug\n\tlog {\n\t\toutput file /data/caddy.log\n\t\tlevel warn\n\t\tformat json\n\t}\n}\n(geofilter) {\n\t@mygeofilter {\n\t\tmaxmind_geolocation {\n\t\t\tdb_path /data/GeoLite2-City.mmdb\n\t\t\tallow_countries US\n\t\t\tallow_subdivisions MO\n\t\t\tallow_metro_codes 609\n\t\t}\n\t}\n\tlog {\n\t\toutput file /data/access.log\n\t\tformat json\n\t}\n}\nauth.mydomain.mydnsprovider.org {\n\timport geofilter\n\troute /* {\n\t\tauthp {\n\t\t\tcrypto default token lifetime 3600\n\t\t\tcrypto key sign-verify <redacted>\n\t\t\tcookie domain mydomain.mydnsprovider.org\n\t\t\tcookie lifetime 86400\n\t\t\tbackends {\n\t\t\t\tlocal_backend {\n\t\t\t\t\tmethod local\n\t\t\t\t\tpath /config/caddy/users.json\n\t\t\t\t\trealm local\n\t\t\t\t}\n\t\t\t}\n\t\t\ttransform user {\n\t\t\t\tmatch origin local\n\t\t\t\taction add role authp/admin\n\t\t\t\trequire mfa\n\t\t\t}\n\t\t\tui {\n\t\t\t\tlinks {\n\t\t\t\t\t\"My Identity\" /whoami icon \"las la-star\"\n\t\t\t\t\t\"My Settings\" /settings icon \"las la-cog\"\n\t\t\t\t\tAdguard https://adguard.mydomain.mydnsprovider.org target_blank\n\t\t\t\t\tAdminer /adminer icon \"las la-tools\" target_blank\n\t\t\t\t\tBazarr /bazarr icon \"las la-clipboard\" target_blank\n\t\t\t\t\tcAdvisor /cadvisor/ icon \"las la-chart-line\" target_blank\n\t\t\t\t\t\"Calibre Content Server\" /calibre icon \"las la-book\" target_blank\n\t\t\t\t\t\"Calibre GUI\" /calibre-gui icon \"las la-book\" target_blank\n\t\t\t\t\t\"Calibre Web\" /calibre-web icon \"las la-book\" target_blank\n\t\t\t\t\tCloud9 https://cloud9.mydomain.mydnsprovider.org target_blank\n\t\t\t\t\tContainer-web-tty /webtty icon \"las la-cog\" target_blank\n\t\t\t\t\tCrontab-UI /crontabui icon \"las la-cog\" target_blank\n\t\t\t\t\tddns-updater /ddns-updater/ icon \"las la-record-vinyl\" target_blank\n\t\t\t\t\tDozzle /dozzle icon \"las la-file-alt\" target_blank\n\t\t\t\t\tFilebrowser /filebrowser icon \"las la-file-alt\" target_blank\n\t\t\t\t\tGaps /gaps icon \"las la-film\" target_blank\n\t\t\t\t\tGhost /blog icon \"las la-sticky-note\" target_blank\n\t\t\t\t\t\"Ghost Admin\" /blog/ghost/#/signin icon \"las la-sticky-note\" target_blank\n\t\t\t\t\tGoaccess /goaccess icon \"las la-file-alt\" target_blank\n\t\t\t\t\tGotify /gotify icon \"las la-file-alt\" target_blank\n\t\t\t\t\tGrafana /grafana icon \"las la-calculator\" target_blank\n\t\t\t\t\tHoobs https://hoobs.mydomain.mydnsprovider.org target_blank\n\t\t\t\t\tHubitat https://hubitat.mydomain.mydnsprovider.org target_blank\n\t\t\t\t\tKomga /komga icon \"las la-book\" target_blank\n\t\t\t\t\tLidarr /lidarr icon \"las la-music\" target_blank\n\t\t\t\t\tLogs /logs icon \"las la-file-alt\" target_blank\n\t\t\t\t\tMagazines /magazines icon \"las la-book\" target_blank\n\t\t\t\t\tMylar3 /mylar icon \"las la-book\" target_blank\n\t\t\t\t\tNavidrome /navidrome icon \"las la-music\" target_blank\n\t\t\t\t\tNetdata /netdata icon \"las la-calculator\" target_blank\n\t\t\t\t\tOmbi /ombi icon \"las la-search\" target_blank\n\t\t\t\t\tOrganizr https://organizr.mydomain.mydnsprovider.org target_blank\n\t\t\t\t\tOpenbooks /openbooks/ icon \"las la-book\" target_blank\n\t\t\t\t\tOverseerr https://overseerr.mydomain.mydnsprovider.org target_blank\n\t\t\t\t\tPidgin pidgin icon \"las la-phone-square\" target_blank\n\t\t\t\t\tPigallery2 https://pigallery2.mydomain.mydnsprovider.org target_blank\n\t\t\t\t\tPiwigo https://piwigo.mydomain.mydnsprovider.org target_blank\n\t\t\t\t\tPlex https://plex.mydomain.mydnsprovider.org target_blank\n\t\t\t\t\tPodgrab https://podgrab.mydomain.mydnsprovider.org target_blank\n\t\t\t\t\tPortainer https://portainer.mydomain.mydnsprovider.org target_blank\n\t\t\t\t\tPosterr /posterr icon \"las la-film\" target_blank\n\t\t\t\t\tProwlarr /prowlarr icon \"las la-search\" target_blank\n\t\t\t\t\tqBittorrent https://qbt.mydomain.mydnsprovider.org target_blank\n\t\t\t\t\tRadarr /radarr icon \"las la-film\" target_blank\n\t\t\t\t\tReadarr /readarr icon \"las la-book\" target_blank\n\t\t\t\t\tRemmina /remmina icon \"las la-tools\" target_blank\n\t\t\t\t\tRequestrr /requestrr icon \"las la-search\" target_blank\n\t\t\t\t\tSABnzbd /sabnzbd icon \"las la-arrow-down\" target_blank\n\t\t\t\t\tSonarr /sonarr icon \"las la-tv\" target_blank\n\t\t\t\t\tSqlitebrowser /sqlitebrowser icon \"las la-tools\" target_blank\n\t\t\t\t\tStatping /statping icon \"las la-tools\" target_blank\n\t\t\t\t\tSyncthing /syncthing/ icon \"las la-tools\" target_blank\n\t\t\t\t\tTautulli /tautulli icon \"las la-chalkboard\" target_blank\n\t\t\t\t\tWebtop /webtop icon \"las la-laptop-code\" target_blank\n\t\t\t\t\tWikijs https://wikijs.mydomain.mydnsprovider.org target_blank\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\troute /navidrome* {\n\t\tjwt {\n\t\t\tbypass uri prefix /navidrome/rest\n\t\t\tacl rule {\n\t\t\t\tmatch role user admin authp/admin authp/user\n\t\t\t\tallow stop log debug\n\t\t\t}\n\t\t\tacl default deny\n\t\t}\n\t\treverse_proxy @mygeofilter 192.168.1.104:4533\n\t}\n\troute /magazines/* {\n\t\tjwt {\n\t\t\tprimary yes\n\t\t\tcrypto key verify <redacted>\n\t\t\tset auth url https://auth.mydomain.mydnsprovider.org/\n\t\t\tallow roles authp/admin authp/user authp/guest\n\t\t\tallow roles superadmin\n\t\t}\n\t\turi strip_prefix /magazines\n\t\tencode gzip\n\t\troot * /magazines\n\t\tfile_server browse\n\t}\n\tredir /magazines /magazines/\n\troute /logs/* {\n\t\tjwt\n\t\turi strip_prefix /logs\n\t\tencode gzip\n\t\troot * /docker\n\t\tfile_server browse\n\t}\n\tredir /logs /logs/\n\troute /goaccess/* {\n\t\tjwt\n\t\turi strip_prefix /goaccess\n\t\tencode gzip\n\t\troot * /docker/goaccess\n\t\tfile_server browse\n\t}\n\tredir /goaccess /goaccess/\n\troute {\n\t\tredir https://{hostport}/login/ 302\n\t}\n\tredir /gotify /gotify/\n\tredir /netdata /netdata/\n\troute /adminer* {\n\t\tjwt\n\t\treverse_proxy @mygeofilter 192.168.1.104:8106\n\t}\n\troute /bazarr* {\n\t\tjwt\n\t\treverse_proxy @mygeofilter 192.168.1.104:8096\n\t}\n\troute /blog* {\n\t\tjwt\n\t\treverse_proxy @mygeofilter 192.168.1.104:8120\n\t}\n\troute /cadvisor/* {\n\t\tjwt\n\t\treverse_proxy @mygeofilter 192.168.1.104:8104\n\t}\n\troute /calibre* {\n\t\tjwt\n\t\treverse_proxy @mygeofilter 192.168.1.104:8091\n\t}\n\troute /calibre-gui* {\n\t\tjwt\n\t\treverse_proxy @mygeofilter 192.168.1.104:8098\n\t}\n\troute /calibre-web* {\n\t\tjwt\n\t\treverse_proxy @mygeofilter 192.168.1.104:8089 {\n\t\t\theader_up X-Script-Name /calibre-web\n\t\t}\n\t}\n\troute /crontabui* {\n\t\tjwt\n\t\treverse_proxy @mygeofilter 192.168.1.104:8127\n\t}\n\troute /ddns-updater/* {\n\t\tjwt\n\t\treverse_proxy @mygeofilter 192.168.1.104:8103\n\t}\n\troute /dozzle* {\n\t\tjwt\n\t\treverse_proxy @mygeofilter 192.168.1.104:8888\n\t}\n\troute /filebrowser* {\n\t\tjwt\n\t\treverse_proxy @mygeofilter 192.168.1.104:8090\n\t}\n\troute /gaps* {\n\t\tjwt\n\t\treverse_proxy @mygeofilter 192.168.1.104:8135\n\t}\n\troute /gotify* {\n\t\tjwt\n\t\turi strip_prefix /gotify\n\t\treverse_proxy @mygeofilter 192.168.1.104:8132\n\t}\n\troute /grafana* {\n\t\tjwt\n\t\treverse_proxy @mygeofilter 192.168.1.104:3000\n\t}\n\troute /komga* {\n\t\tjwt\n\t\treverse_proxy @mygeofilter 192.168.1.104:8116\n\t}\n\troute /lidarr* {\n\t\tjwt\n\t\treverse_proxy @mygeofilter 192.168.1.104:8686\n\t}\n\troute /mylar* {\n\t\tjwt\n\t\treverse_proxy @mygeofilter 192.168.1.104:8115\n\t}\n\troute /netdata* {\n\t\tjwt\n\t\turi strip_prefix /netdata\n\t\treverse_proxy @mygeofilter 192.168.1.104:19999\n\t}\n\troute /ombi* {\n\t\tjwt\n\t\treverse_proxy @mygeofilter 192.168.1.104:3579\n\t}\n\troute /openbooks/* {\n\t\tjwt\n\t\treverse_proxy @mygeofilter @mygeofilter 192.168.1.104:8107\n\t}\n\troute /posterr* {\n\t\tjwt\n\t\treverse_proxy @mygeofilter 192.168.1.104:9876\n\t}\n\troute /prowlarr* {\n\t\tjwt\n\t\treverse_proxy @mygeofilter 192.168.1.104:9696\n\t}\n\troute /radarr* {\n\t\tjwt\n\t\treverse_proxy @mygeofilter 192.168.1.104:8095\n\t}\n\troute /readarr* {\n\t\tjwt\n\t\treverse_proxy @mygeofilter 192.168.1.104:8094\n\t}\n\troute /remmina* {\n\t\tjwt\n\t\treverse_proxy @mygeofilter 192.168.1.104:8124\n\t}\n\troute /requestrr* {\n\t\tjwt\n\t\treverse_proxy @mygeofilter 192.168.1.104:4545\n\t}\n\troute /sabnzbd* {\n\t\tjwt\n\t\treverse_proxy @mygeofilter 192.168.1.104:8080\n\t}\n\troute /sonarr* {\n\t\tjwt\n\t\treverse_proxy @mygeofilter 192.168.1.104:8079\n\t}\n\troute /sqlitebrowser* {\n\t\tjwt\n\t\treverse_proxy @mygeofilter 192.168.1.104:8109\n\t}\n\troute /syncthing* {\n\t\turi strip_prefix /syncthing\n\t\treverse_proxy @mygeofilter 192.168.1.104:8384\n\t\tjwt\n\t}\n\troute /tautulli* {\n\t\tjwt\n\t\treverse_proxy @mygeofilter 192.168.1.104:8099\n\t}\n\troute /webtop* {\n\t\tjwt\n\t\treverse_proxy @mygeofilter 192.168.1.104:8141\n\t}\n\troute /webtty* {\n\t\tjwt\n\t\treverse_proxy @mygeofilter 192.168.1.104:8105\n\t}\n}\nhttp://osu.logs {\n\tencode gzip\n\troot * /docker\n\tfile_server browse\n}\nhttp://osu.magazines {\n\tencode gzip\n\troot * /magazines\n\tfile_server browse\n}\nhttp://osu.goaccess {\n\tencode gzip\n\troot * /docker/goaccess\n\tfile_server browse\n}\nhubitat.mydomain.mydnsprovider.org {\n\timport geofilter\n\tjwt\n\treverse_proxy @mygeofilter 192.168.1.157:80\n}\nadguard.mydomain.mydnsprovider.org {\n\timport geofilter\n\tjwt\n\treverse_proxy @mygeofilter 192.168.1.103:80\n}\ncloud9.mydomain.mydnsprovider.org {\n\timport geofilter\n\tjwt\n\treverse_proxy @mygeofilter 192.168.1.104:8123\n}\nhoobs.mydomain.mydnsprovider.org {\n\timport geofilter\n\tjwt\n\treverse_proxy @mygeofilter 192.168.1.104:8102\n}\noverseerr.mydomain.mydnsprovider.org {\n\timport geofilter\n\treverse_proxy @mygeofilter 192.168.1.104:5055\n\troute {\n\t\tjwt\n\t}\n}\npigallery2.osuhickeys.net {\n\timport geofilter\n\troute {\n\t\treverse_proxy @mygeofilter 192.168.1.104:8146\n\t}\n}\npiwigo.mydomain.mydnsprovider.org {\n\timport geofilter\n\treverse_proxy @mygeofilter 192.168.1.104:8085\n\troute {\n\t\tjwt\n\t}\n}\nplex.mydomain.mydnsprovider.org {\n\timport geofilter\n\treverse_proxy @mygeofilter 192.168.1.104:32400\n\troute {\n\t\tjwt\n\t}\n}\npodgrab.mydomain.mydnsprovider.org {\n\timport geofilter\n\treverse_proxy @mygeofilter 192.168.1.104:8134\n\troute {\n\t\tjwt\n\t}\n}\nportainer.mydomain.mydnsprovider.org {\n\timport geofilter\n\treverse_proxy @mygeofilter 192.168.1.104:9000\n\troute {\n\t\tjwt\n\t}\n}\nqbt.mydomain.mydnsprovider.org {\n\timport geofilter\n\tjwt\n\treverse_proxy @mygeofilter 192.168.1.104:8113\n}\n"}

That is the Caddyfile, just with newlines/tabs encoded in the JSON string. You can toss that text into a tool like Free Online JSON Escape / Unescape Tool - FreeFormatter.com to get it without the escaped newlines etc.

I’d say this is a pretty niche thing to want. Haven’t seen anyone ask for anything similar in the past 1.5 years since Caddy v2 was released.

You’ll probably need to take a shot at writing it yourself.