{"id":16117297,"url":"https://github.com/nickbabcock/dness","last_synced_at":"2025-03-16T08:32:47.363Z","repository":{"id":34025649,"uuid":"163904346","full_name":"nickbabcock/dness","owner":"nickbabcock","description":"A dynamic dns client","archived":false,"fork":false,"pushed_at":"2024-04-15T11:44:25.000Z","size":1058,"stargazers_count":114,"open_issues_count":3,"forks_count":7,"subscribers_count":6,"default_branch":"master","last_synced_at":"2024-05-01T21:17:36.761Z","etag":null,"topics":["cloudflare","dns","dynamic-dns-client","dynu","godaddy","namecheap","porkbun"],"latest_commit_sha":null,"homepage":"","language":"Rust","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/nickbabcock.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE.txt","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},"funding":{"github":["nickbabcock"]}},"created_at":"2019-01-03T00:39:43.000Z","updated_at":"2024-05-20T12:50:36.084Z","dependencies_parsed_at":"2023-12-19T01:34:02.839Z","dependency_job_id":"5a9c87cb-79fe-41b0-8d0e-577403339740","html_url":"https://github.com/nickbabcock/dness","commit_stats":null,"previous_names":[],"tags_count":16,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nickbabcock%2Fdness","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nickbabcock%2Fdness/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nickbabcock%2Fdness/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nickbabcock%2Fdness/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nickbabcock","download_url":"https://codeload.github.com/nickbabcock/dness/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243807454,"owners_count":20350996,"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":["cloudflare","dns","dynamic-dns-client","dynu","godaddy","namecheap","porkbun"],"created_at":"2024-10-09T20:43:52.490Z","updated_at":"2025-03-16T08:32:46.890Z","avatar_url":"https://github.com/nickbabcock.png","language":"Rust","funding_links":["https://github.com/sponsors/nickbabcock"],"categories":[],"sub_categories":[],"readme":"# dness\n\n***Finesse with dness: a dynamic dns client***\n\n![ci](https://github.com/nickbabcock/dness/workflows/ci/badge.svg)\n\n---\n\n## Motivation\n\nWhen one has a server that is subjected to unpredictable IP address changes, such as at home or elsewhere, a change in IP address causes unexpected downtime. Instead of paying for a static IP address, one can employ a dynamic dns client on said server, which will update the [WAN](https://en.wikipedia.org/wiki/Wide_area_network) IP address on the dns server.\n\nThere are plenty of dynamic dns clients, including the venerable [ddclient](https://github.com/ddclient/ddclient), but troublesome installation + perl system dependency resolution, and cache format errors have left much to be desired. Other solutions fall short, so dness was created with the following goals:\n\n## Features:\n\n- ✔ Cross platform (Windows, Mac, Linux, ARM, BSD)\n- ✔ Zero dependencies (one can opt to dynamically link openssl when compiling from source)\n- ✔ A standard configuration ([TOML](https://github.com/toml-lang/toml)) that is similar to ddclient's\n- ✔ Support for multiple Dynamic DNS Services:\n   - [Cloudflare](#cloudflare)\n   - [GoDaddy](#godaddy)\n   - [Namecheap](#namecheap)\n   - [He.net](#henet)\n   - [No-IP](#no-ip)\n   - [Dynu](#dynu)\n   - [Porkbun](#porkbun)\n- ✔ Permissively licensed\n\n## Installation\n\nTo maximize initial flexibility, dness is not a daemon. Instead it relies on the host's scheduling (cron, systemd timers, windows scheduler).\n\n### Ubuntu / Debian (systemd + deb)\n\n- Download the [latest deb](https://github.com/nickbabcock/dness/releases/latest)\n\n```bash\ndpkg -i dness\u003cversion\u003e_amd64.deb\n\n# ensure it is working\n/usr/bin/dness\n\n# enable systemd timer\nsystemctl daemon-reload\nsystemctl start dness.timer\nsystemctl enable dness.timer\n\n# update configuration\n${EDITOR:-vi} /etc/dness/dness.conf\n\n# create the environment variables with sensitive info\n(umask 077; touch /etc/dness/dness.env)\n${EDITOR:-vi} /etc/dness/dness.env\n```\n\n### Windows\n\n- Download the [latest zip](https://github.com/nickbabcock/dness/releases/latest) with \"windows\" in its name\n- Unzip\n- Create configuration file (`dness.conf`)\n- Execute `dness.exe -c dness.conf` to verify behavior\n- If desired, use windows task scheduler to execute command at specific times\n\n### Other\n\nDownload the [latest appropriate target](https://github.com/nickbabcock/dness/releases/latest)\n\n## Configuration\n\nNo configuration file is necessary when only the WAN IP is desired.\n\n```bash\n./dness\n```\n\nSample output:\n\n```\n[INFO  trust_dns_proto::xfer::dns_exchange] sending message via: UDP(208.67.220.220:53)\n[INFO  dness] resolved address to 256.256.256.256 in 23ms\n[INFO  dness] processed all: (updated: 0, already current: 0, missing: 0) in 29ms\n```\n\n### Simple Configuration\n\nBut dness can do more than resolve one's WAN IP. Below is a simple configuration file (conventionally named `dness.conf`) that will update cloudflare records.\n\n```toml\n[[domains]]\ntype = \"cloudflare\"\ntoken = \"dec0de\"\nzone = \"example.com\"\nrecords = [\n    \"n.example.com\"\n]\n```\n\nExecute dness with the configuration:\n\n```\n./dness -c dness.conf\n```\n\n### Substitute Sensitive Values\n\nDness will substitute in values from the environment into the configuration so that sensitive values don't need to be specified in the config:\n\n```toml\n[[domains]]\ntype = \"cloudflare\"\ntoken = \"{{MY_CLOUDFLARE_TOKEN}}\"\nzone = \"example.com\"\nrecords = [\n    \"n.example.com\"\n]\n```\n\nThis is a great way to run dness in an unprivileged account but still have access to sensitive values.\n\n### Annotated Configuration\n\nBelow are the configuration options, but they've been annotated with comments.\n\n```toml\n[log]\n# How verbose the log is. Common values: Error, Warn, Info, Debug, Trace\n# The default level is info\nlevel = \"Debug\"\n\n[[domains]]\n# We denote that our domain is managed by cloudflare\ntype = \"cloudflare\"\n\n# Create Cloudflare token by using the use \"Edit zone DNS\" API token template.\n# Alternatively one can use email + key fields but the token is recommended as\n# it is more secure\ntoken = \"dec0de\"\n\n# The email address registered in cloudflare that is authorized to update dns\n# records. Only required when not using the token field\n# email = \"admin@example.com\"\n\n# The cloudflare key can be found in the domain overview, in \"Get your API key\"\n# and view \"Global API Key\". Required when \"email\" is used\n# key = \"deadbeef\"\n\n# The zone is the domain name\nzone = \"example.com\"\n\n# List of A records found under the DNS tab that should be updated\nrecords = [\n    \"n.example.com\"\n]\n\n# More than one domain can be specified in a config!\n[[domains]]\ntype = \"cloudflare\"\nemail = \"admin@example.com\"\nkey = \"deadbeef\"\nzone = \"example2.com\"\nrecords = [\n    \"n.example2.com\",\n    \"n2.example2.com\"\n]\n```\n\n### Supported Dynamic DNS Services\n\n#### Cloudflare\n\n```toml\n[[domains]]\n# We denote that our domain is managed by cloudflare\ntype = \"cloudflare\"\n\n# The email address registered in cloudflare that is authorized to update dns\n# records\nemail = \"admin@example.com\"\n\n# The cloudflare key can be found in the domain overview, in \"Get your API key\"\n# and view \"Global API Key\" (or another key as appropriate)\nkey = \"deadbeef\"\n\n# The zone is the domain name\nzone = \"example.com\"\n\n# List of A records found under the DNS tab that should be updated\nrecords = [\n    \"n.example.com\"\n]\n```\n\nCloudflare dynamic dns service works in three steps:\n\n1. Send GET to translate the zone (example.com) to cloudflare's id\n2. Send GET to find all the domains under the zone and their sub-ids\n   - Cloudflare paginates the response to handle many subdomains\n   - It is possible to query for individual domains but as long as more\n     than one desired domain in each page -- this methods cuts down requests\n3. Each desired domain in the config is checked to ensure that it is set to our address. In\n   this way cloudflare is our cache (to guard against nefarious users updating out of band)\n\n#### GoDaddy\n\n```toml\n[[domains]]\n# denote that the domain is managed by godaddy\ntype = \"godaddy\"\n\n# The GoDaddy domain: https://dcc.godaddy.com/domains/\ndomain = \"example.com\"\n\n# This is the api key, you can create one here:\n# https://developer.godaddy.com/keys\nkey = \"abc123\"\n\n# The password for the key, top secret!\nsecret = \"ef\"\n\n# The records to update. \"@\" = \"example.com\", \"a\" = \"a.example.com\"\nrecords = [ \"@\", \"a\" ]\n```\n\nGoDaddy dynamic dns service works as the following:\n\n1. Send a GET request to find all records in the domain\n2. Find all the expected records (and log those that are missing) and check their current IP\n3. Update the remote IP as needed, ensuring that original properties are preserved in the upload, so that we don't overwrite a property like TTL.\n\n#### Namecheap\n\n```toml\n[[domains]]\n# Namecheap requires that dynamic dns is enabled in their UI!\ntype = \"namecheap\"\ndomain = \"test-dness-1.xyz\"\nddns_password = \"super_secret_password\"\n\n# The records to update. Make sure they are listed as A + Dynamic DNS\n# \"@\" = \"test-dness-1.xyz\"\n# \"* = \"\u003cany-sub-domain\u003e.test-dness-1.xyz\"\n# \"sub = \"sub.test-dness-1.xyz\"\nrecords = [ \"@\", \"*\", \"sub\" ]\n```\n\nThe namecheap services requires dynamic dns enabled in their UI.\n\nUpdating the dns entry works as follows:\n\n- A dns query is sent to cloudflare to check the IP of the record\n- If the IP is different than WAN then a request is sent to namecheap to update it\n- If the IP is the same, no action is taken\n\nThis method suffers from natural flow of dns propagation. When namecheap receives the update, it may take up to an hour for cloudflare to see the new record. In the meantime, dness will keep updating namecheap servers with the WAN. This has no consequential side effects other than momentary confusion why updates are being sent to namecheap every 5 minutes. Future revisions of this provider may use another method (like API integration) if the current method proves deficient enough.\n\n#### He.net\n\n```toml\n[[domains]]\ntype = \"he\"\nhostname = \"test-dness-1.xyz\"\npassword = \"super_secret_password\"\nrecords = [ \"@\", \"sub\" ]\n```\n\n[he.net](http://he.net/) follows the same flow as Namecheap (check the current record via DNS and update if necessary).\n\n#### No-IP\n\n```toml\n[[domains]]\ntype = \"noip\"\nhostname = \"dnesstest.hopto.org\"\nusername = \"myemail@example.org\"\npassword = \"super_secret_password\"\n```\n\n#### Dynu\n\n```toml\n[[domains]]\ntype = \"dynu\"\nhostname = \"test-dness.camdvr.org\"\nusername = \"MyUserName\"\n\n# ip update password:\n# https://www.dynu.com/en-US/ControlPanel/ManageCredentials\npassword = \"IpUpdatePassword\"\n\n# The records to update.\n# \"@\" = \"test-dness.camdvr.org\"\n# \"sub = \"sub.test-dness.camdvr.org\"\nrecords = [ \"@\", \"sub\" ]\n```\n\n#### Porkbun\n\n```toml\n[[domains]]\n# denote that the domain is managed by porkbun\ntype = \"porkbun\"\n\n# The Porkbun domain: https://porkbun.com/account/domainsSpeedy\n# IMPORTANT: You must enable API Access for the domain at the above url.\ndomain = \"example.com\"\n\n# This is the api key, you can create one here:\n# https://porkbun.com/account/api\nkey = \"abc123\"\n\n# The password for the key, top secret! Only visible once when you create the key.\nsecret = \"ef\"\n\n# The records to update. \"@\" = \"example.com\", \"a\" = \"a.example.com\" \"*\" = \"*.example.com\"\n# Both \"@\" and \"\" are valid to configure root domain.\nrecords = [ \"@\", \"a\" ]\n```\n\nPorkbun dynamic dns service works similar to GoDaddy:\n\n1. Send a POST request to find all records in the domain\n2. Find all the expected records (and log those that are missing) and check their current IP\n3. Update the remote IP as needed, ensuring that original properties are preserved in the upload, so that we don't overwrite a property like TTL.\n\n### Supported WAN IP Resolvers\n\nThere are a couple different methods for dness to resolve the WAN IP address.\n\n#### OpenDNS\n\nThe default WAN IP address resolver queries OpenDNS. It resolves IPv4 addresses by querying \"myip.opendns.com\" against resolver1.opendns.com and resolver2.opendns.com.\n\nWhile it is the default, it can explicitly be specified by appending snippet below to the top of the config:\n\n```toml\nip_resolver = \"opendns\"\n```\n\n#### Ipify\n\nOpenDNS may not be available to all networks, so one can configure dness to use [Ipify](https://www.ipify.org/). Instead of using DNS, an HTTPs request will be sent. To opt into using Ipify, append the snippet below to the top of the config:\n\n```toml\nip_resolver = \"ipify\"\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnickbabcock%2Fdness","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnickbabcock%2Fdness","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnickbabcock%2Fdness/lists"}