cloudflare-ddns/README.md
2024-12-04 23:55:11 -08:00

151 lines
No EOL
4.9 KiB
Markdown

# DDNS for Cloudflare
Small binary to update Cloudflare DNS entries via a config file.
## How does it work
This system is split into two portions, the binary itself and an external timer
that periodically executes the binary.
To install the binary, either build your own `.deb` file or find a release. More
distro support is appreciated but not currently promised.
An external timer can be a system provided one or something like `crontab`.
For convenience, a `systemd` system and timer file is provided that activates it
on an hourly interval. This is automatically installed if you use the `.deb`.
The binary contains various subcommands:
|Subcommand|Description|
|----------|-----------|
|`run`|Reads from a config file and calls into Cloudflare's API|
|`list`|Read the config file to list information about your zones|
This binary must be activated at your preferred interval via an external timer.
This only supports updating one IP address to any number of zones and DNS
entries. For another IP address, install and run this on the machine with
different IP address.
## Installation
First, create an initial file at `/etc/cloudflare-ddns.toml`. Set the permissions
so that it is readable and writable by `root` only:
```
# sudo touch /etc/cloudflare-ddns.toml
# chmod 600 /etc/cloudflare-ddns.toml
```
Populate it with the following:
```toml
[account]
email = "your@email.com"
api_key = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
[ip_reflector]
ipv4 = "https://what.is.my.ipv4.example"
ipv6 = "https://what.is.my.ipv6.example"
[zone."example.com"]
id = "deadbeefdeadbeefdeadbeefdeadbeef"
```
### `account` section
The `email` should be the email associated with your Cloudflare account.
The `api_key` field should be populated with your Global API Key. This is found
at on your [account profile].
[account profile]: https://dash.cloudflare.com/profile/api-tokens
### `ip_reflector` section
The `ipv4` and `ipv6` fields should be populated with a URL that when provided
a `GET` request, returns the IP address in the body as a string, without a
newline.
For example, `curl` should return something similar to this:
```
$ curl https://what.is.my.ipv4.example
1.2.3.4%
```
The `%` is added by `curl` to indicate no line ending.
### `zone` section
Each zone subsection should contain a website registered to your account. Each
zone needs an `id`, which can be found on the Overview tab of the respective
website.
Once you've populated all fields, run `cloudflare-ddns list` to list the ids of
each DNS entry:
```
example.com (deadbeefdeadbeefdeadbeefdeadbeef)
+--------------------+------+--------------------------+---------+----------------------------------+
| Name | Type | IP Address | Proxied | Id |
+--------------------+------+--------------------------+---------+----------------------------------+
| example.com | A | 6.6.6.6 | false | fefefefefefefefefefefefefefefefe |
+--------------------+------+--------------------------+---------+----------------------------------+
| irys.example.com | A | 6.6.6.6 | true | c0ffeec0ffeec0ffeec0ffeec0ffeec0 |
+--------------------+------+--------------------------+---------+----------------------------------+
| suisei.example.com | AAAA | 1111:11::1111 | true | 1337c0d31337c0d31337c0d31337c0d3 |
+--------------------+------+--------------------------+---------+----------------------------------+
```
This lists all relevant data necessary for dynamically updating each DNS entry.
For each DNS entry for `example.com` you want to dynamically update, create an
entry as follows:
```toml
[[zone."example.com".record]]
name = "@" # Use @ for the root domain
id = "fefefefefefefefefefefefefefefefe"
proxy = false
type = "A"
[[zone."example.com".record]]
name = "irys"
id = "c0ffeec0ffeec0ffeec0ffeec0ffeec0"
proxy = true
type = "A"
[[zone."example.com".record]]
name = "suisei"
id = "1337c0d31337c0d31337c0d31337c0d3"
proxy = true
type = "AAAA"
```
A full example config can be found in the repo.
At this point, you can run `cloudflare-ddns run` to verify that everything
works. If you run into issues, you can provide `--log=debug` or `--log=trace`
for more information.
If successful, attempt to trigger it via the external timer. If that is
successful, installation is complete.
## Building packages
A `.deb` package is created via [`cargo-deb`].
[`cargo-deb`]: https://github.com/kornelski/cargo-deb
## Security
This project attempts to take security seriously. Please note the following
hardening notes applied by default.
### Hardened `systemd` service configuration
In principle, this service needs very little access to a host, and needs access
to the internet. As a result, the default `systemd` service configuration
aggressively restricts the capabilities of the binary to a minimum set of
features, namely access to the internet and dependency to do so. If you believe
more directives could be provided, please create a PR.