{"id":15413440,"url":"https://github.com/cromefire/fritzbox-cloudflare-dyndns","last_synced_at":"2025-05-10T23:30:11.179Z","repository":{"id":54399797,"uuid":"199613995","full_name":"cromefire/fritzbox-cloudflare-dyndns","owner":"cromefire","description":"Slim WAN IP updater for AVM FRITZ!Box devices, pushing updates towards Cloudflare DNS using push and poll strategies.","archived":false,"fork":false,"pushed_at":"2024-10-25T17:49:24.000Z","size":3230,"stargazers_count":41,"open_issues_count":0,"forks_count":14,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-05-10T23:30:02.574Z","etag":null,"topics":["avm","dyndns","fritzbox","golang","soap"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cromefire.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-07-30T08:55:10.000Z","updated_at":"2025-04-16T13:27:12.000Z","dependencies_parsed_at":"2024-10-21T14:36:26.537Z","dependency_job_id":null,"html_url":"https://github.com/cromefire/fritzbox-cloudflare-dyndns","commit_stats":{"total_commits":134,"total_committers":7,"mean_commits":"19.142857142857142","dds":0.3880597014925373,"last_synced_commit":"4dfeaa33edffc40c641643422da39d4e3c53b90a"},"previous_names":["adrianrudnik/fritzbox-cloudflare-dyndns"],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cromefire%2Ffritzbox-cloudflare-dyndns","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cromefire%2Ffritzbox-cloudflare-dyndns/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cromefire%2Ffritzbox-cloudflare-dyndns/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cromefire%2Ffritzbox-cloudflare-dyndns/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cromefire","download_url":"https://codeload.github.com/cromefire/fritzbox-cloudflare-dyndns/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253497296,"owners_count":21917683,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["avm","dyndns","fritzbox","golang","soap"],"created_at":"2024-10-01T16:57:05.544Z","updated_at":"2025-05-10T23:30:11.155Z","avatar_url":"https://github.com/cromefire.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# AVM FRITZ!Box Cloudflare DNS-service\n\nThis project has some simple goals:\n\n- Offer a slim service without any additional service requirements\n- Allow for two different combined strategies: Polling (through FRITZ!Box SOAP-API) and Pushing (FRITZ!Box Custom-DynDns\n  setting).\n- Allow multiple domains to be updated with new A (IPv4) and AAAA (IPv6) records\n- Push those IP changes directly to Cloudflare DNS\n- Deploy in docker compose\n\nIf this fits for you, skim over the CNAME workaround if this is a better solution for you, otherwise feel free to visit\nthe appropriate strategy section of this document and find out how to configure it correctly.\n\n## CNAME record workaround\n\nBefore you try this service evaluate a cheap workaround, as it does not require dedicated hardware to run 24/7:\n\nHave dynamic IP updates by using a CNAME record to your myfritz address, found in `Admin \u003e Internet \u003e MyFRITZ-Account`.\nIt should look like `[hash].myfritz.net`.\n\nThis basic example of a BIND DNS entry would make `intranet.example.com` auto update the current IP:\n\n```\n$TTL 60\n$ORIGIN example.com.\nintranet IN CNAME [hash].myfritz.net\n```\n\nBeware that this will expose your account hash to the outside world and depend on AVMs service availability.\n\n## Strategies\n\n### FRITZ!Box pushing\n\nYou can use this strategy if you have:\n\n- access to the admin panel of the FRITZ!Box router.\n- this services runs on a public interface towards the router.\n\nIn your `.env` file or your system environment variables you can be configured:\n\n| Variable name               | Description                                                                                                                          |\n|-----------------------------|--------------------------------------------------------------------------------------------------------------------------------------|\n| DYNDNS_SERVER_BIND          | required, network interface to bind to, i.e. `:8080`.                                                                                |\n| DYNDNS_SERVER_USERNAME      | optional, username for the DynDNS service.                                                                                           |\n| DYNDNS_SERVER_PASSWORD      | optional, password for the DynDNS service.                                                                                           |\n| DYNDNS_SERVER_PASSWORD_FILE | optional, path to a file containing the password for the DynDNS service. It's recommended to use this over `DYNDNS_SERVER_PASSWORD`. |\n\nNow configure the FRITZ!Box router to push IP changes towards this service. Log into the admin panel and go to\n`Internet \u003e Shares \u003e DynDNS tab` and setup a  `Custom` provider:\n\n| Property   | Description / Value                                                                    |\n|------------|----------------------------------------------------------------------------------------|\n| Update-URL | http://[server-ip]/ip?v4=\\\u003cipaddr\\\u003e\u0026v6=\\\u003cip6addr\\\u003e\u0026prefix=\\\u003cip6lanprefix\\\u003e             |\n| Domain     | Enter at least one domain name so the router can probe if the update was successfully. |\n| Username   | Enter '_' if  `DYNDNS_SERVER_USERNAME` is unset.                                       |\n| Password   | Enter '_' if `DYNDNS_SERVER_PASSWORD` and `DYNDNS_SERVER_PASSWORD_FILE` are unset.     |\n\nIf you specified credentials you need to append them as additional GET parameters into the Update-URL\nlike `\u0026username=\u003cusername\u003e\u0026password=\u003cpass\u003e`.\n\n### FRITZ!Box polling\n\nYou can use this strategy if you have:\n\n- no access to the admin panel of the FRITZ!Box router.\n- for whatever reasons the router can not push towards this service, but we can poll from it.\n- you do not trust pushing\n\nIn your `.env` file or your system environment variables you can be configured:\n\n| Variable name              | Description                                                                                            |\n|----------------------------|--------------------------------------------------------------------------------------------------------|\n| FRITZBOX_ENDPOINT_URL      | optional, how can we reach the router, i.e. `http://fritz.box:49000`, the port should be 49000 anyway. |\n| FRITZBOX_ENDPOINT_TIMEOUT  | optional, a duration we give the router to respond, i.e. `10s`.                                        |\n| FRITZBOX_ENDPOINT_INTERVAL | optional, a duration how often we want to poll the WAN IPs from the router, i.e. `120s`.               |\n\nYou can try the endpoint URL in the browser to make sure you have the correct port, you should receive\nan `404 ERR_NOT_FOUND`.\n\n_Because `FRITZBOX_ENDPOINT_URL` is set by default on the docker image, you have to explicitly set it to an empty string\nto disable polling_\n\n## Cloudflare setup\n\nTo get your API Token do the following: Login to the cloudflare dashboard, go\nto `My Profile \u003e API Tokens \u003e Create Token \u003e Edit zone DNS`, give to token some good name (e.g. \"DDNS\"), add all zones\nthat the DDNS should be used for, click `Continue to summary` and `Create token`. Be sure to copy the token and add it\nto the config, you won't be able to see it again.\n\nIn your `.env` file or your system environment variables you can be configured:\n\n| Variable name             | Description                                                                                                                                                 |\n|---------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| CLOUDFLARE_API_TOKEN      | required if `CLOUDFLARE_API_TOKEN_FILE` is unset, your Cloudflare API Token.                                                                                |\n| CLOUDFLARE_API_TOKEN_FILE | required if `CLOUDFLARE_API_TOKEN` is unset, path to a file containing your Cloudflare API Token. It's recommended to use this over `CLOUDFLARE_API_TOKEN`. |\n| CLOUDFLARE_ZONES_IPV4     | comma-separated list of domains to update with new IPv4 addresses.                                                                                          |\n| CLOUDFLARE_ZONES_IPV6     | comma-separated list of domains to update with new IPv6 addresses.                                                                                          |\n| CLOUDFLARE_API_EMAIL      | deprecated, your Cloudflare account email.                                                                                                                  |\n| CLOUDFLARE_API_KEY        | deprecated, your Cloudflare Global API key.                                                                                                                 |\n| CLOUDFLARE_API_KEY_FILE   | deprecated, path to a file containing your Cloudflare Global API key. It's recommended to use this over `CLOUDFLARE_API_KEY`.                               |\n\nThis service allows to update multiple records, an advanced example would be:\n\n```env\nCLOUDFLARE_ZONES_IPV4=ipv4.example.com,ip.example.com,server-01.dev.local\nCLOUDFLARE_ZONES_IPV6=ipv6.example.com,ip.example.com,server-01.dev.local\n```\n\nConsidering the example call `http://192.168.0.2:8080/ip?v4=127.0.0.1\u0026v6=::1` every IPv4 listed zone would be updated to\n`127.0.0.1` and every IPv6 listed one to `::1`.\n\n## Register IPv6 for another device (port-forwarding)\n\nIPv6 port-forwarding works differently and so if you want to use it you have to add the following configuration.\n\nWarning: `FRITZBOX_ENDPOINT_URL` has to be set for this to work.\n\nTo access a device via IPv6 you need to add it's global IPv6 address to cloudflare, for this to be calculated you need\nto find out the local part of it's IP.\nYou can find out the local part of a device's IP, by going to the device's settings and looking at\nthe `IPv6 Interface-ID`.\nIt should look something like this: `::1234:5678:90ab:cdef`.\nSometimes the FritzBox seems to use a subnet, so you might need to add change it from something\nlike `::1234:5678:90ab:cdef` to `::1:1234:5678:90ab:cdef`\n\n| Variable name             | Description                                     |\n|---------------------------|-------------------------------------------------|\n| DEVICE_LOCAL_ADDRESS_IPV6 | required, enter the local part of the device IP |\n\n## Docker compose setup\n\nHere is an example `docker-compose.yml` with all features activated:\n\n```\nversion: '3.7'\n\nservices:\n  updater:\n    image: ghcr.io/cromefire/fritzbox-cloudflare-dyndns:1\n    network_mode: host\n    # build:\n    #   context: .\n    environment:\n      - FRITZBOX_ENDPOINT_URL=http://fritz.box:49000\n      - FRITZBOX_ENDPOINT_TIMEOUT=30s\n      - FRITZBOX_ENDPOINT_INTERVAL=3s\n      - CLOUDFLARE_API_EMAIL=max@example.com\n      - CLOUDFLARE_API_KEY=demo\n      - CLOUDFLARE_ZONES_IPV4=test.example.com\n      - CLOUDFLARE_ZONES_IPV6=test.example.com\n```\n\nNow we could configure the FRITZ!Box\nto `http://[docker-host-ip]:49000/ip?v4=\u003cipaddr\u003e\u0026v6=\u003cip6addr\u003e\u0026prefix=\u003cip6lanprefix\u003e` and it should trigger the update\nprocess.\n\n## Docker build\n\nA pre-built docker image is also available on this\nGitHub [repository](https://github.com/cromefire/fritzbox-cloudflare-dyndns/pkgs/container/fritzbox-cloudflare-dyndns)\nas `ghcr.io/cromefire/fritzbox-cloudflare-dyndns:\u003cversion\u003e`.\nThe version is something like `1.2` (you can leave out the patch version), please don't use `latest` directly, as it may\nbreak at any point with a major release.\n\nYou can use it with compose like this:\n\n```yaml\nname: \"dyndns\"\nservices:\n  updater:\n    image: \"ghcr.io/cromefire/fritzbox-cloudflare-dyndns:\u003cversion\u003e\"\n    env_file: ./updater.env\n    restart: unless-stopped\n    ports:\n      - \"8080/tcp\"\n```\n\nWith your secret configure in the `updater.env` file next to it (as `SOME_VARIABLE=\u003cvalua\u003e`).\n\nThe more raw approach would be to build and run it yourself:\n\n```\ndocker build -t fritzbox-cloudflare-dyndns .\ndocker run --rm -it -p 8888:8080 fritzbox-cloudflare-dyndns\n```\n\nIf you leave `CLOUDFLARE_*` unconfigured, pushing to Cloudflare will be disabled for testing purposes, so try to\ntrigger it by calling `http://127.0.0.1:8888/ip?v4=127.0.0.1\u0026v6=::1` and review the logs.\n\n## Passing secrets\n\nAs shown above, secrets can be passed via environment variables.\nIf passing secrets via environment variables does not work for your use case, it's also possible to pass them via the filesystem.\nIn order to pass a secret via a file, append `_FILE` to the respective environment variable name and configure it to point to the file containing the secret.\nFor example in order to pass the Cloudflare API token via a file, configure an environment variable with name `CLOUDFLARE_API_TOKEN_FILE` with the absolute path to a file containing the secret.\n\nHere is an example `docker-compose.yml` passing the file `cloudflare_api_key.txt` from the host to the docker container using docker compose secrets:\n\n```yaml\nname: \"dyndns\"\nservices:\n  updater:\n    image: ghcr.io/cromefire/fritzbox-cloudflare-dyndns:1\n    network_mode: host\n    environment:\n      - DYNDNS_SERVER_BIND=:8080\n      - CLOUDFLARE_API_TOKEN_FILE=/run/secrets/cloudflare_api_token\n      - DYNDNS_SERVER_PASSWORD_FILE=/run/secrets/fb_server_password\n      - CLOUDFLARE_ZONES_IPV4=test.example.com\n      - CLOUDFLARE_ZONES_IPV6=test.example.com\n    secrets:\n      - cloudflare_api_token\n      - fb_server_password\n\nsecrets:\n  cloudflare_api_token:\n    file: ./cloudflare_api_token.txt\n  fb_server_password:\n    file: ./fb_server_password.txt\n```\n\nSee https://docs.docker.com/compose/how-tos/use-secrets/ for more information about docker compose secrets.\n\n## Metrics and Health Check\n\nIf you want to check whether the service is running correctly, you can configure these with the following variables:\n\n| Variable name      | Description                                                                                                                                   |\n|--------------------|-----------------------------------------------------------------------------------------------------------------------------------------------|\n| METRICS_BIND       | required, network interface to bind to, i.e. `:9876`                                                                                          |\n| METRICS_TOKEN      | token that has to be passed to the endpoints to authenticate                                                                                  |\n| METRICS_TOKEN_FILE | path ot a file containing a token that has to be passed to the endpoints to authenticate.  It's recommended to use this over `METRICS_TOKEN`. |\n\nThe endpoint for prometheus-compatible metrics is `/metrics`, the endpoint for the health check is `/healthz` and the\nendpoint for liveness is `/liveness` on the configured network bind.\nIf you chose to use a token, you'll have to append it using the query like `/metrics?token=123456`.\n\nThe difference between the liveness and the health endpoint is that the health endpoint will return `503` if any\nsubsystem has an issue and `200` if not, while the liveness endpoint will always return `204` as long as the HTTP server\nis able to respond.\n\n## History \u0026 Credit\n\nMost of the credit goes to [@adrianrudnik](https://github.com/adrianrudnik), who wrote and maintained the software for\nyears. After he moved on I stepped in at a later point when the repository was transferred to me to continue its basic\nmaintenance should it be required.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcromefire%2Ffritzbox-cloudflare-dyndns","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcromefire%2Ffritzbox-cloudflare-dyndns","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcromefire%2Ffritzbox-cloudflare-dyndns/lists"}