Metadata-Version: 2.4
Name: dnsync
Version: 0.1.0
Summary: DevNomads dynamic DNS updater - keep an A/AAAA record on your public IP
Author-email: DevNomads <support@devnomads.nl>
License: MIT
Keywords: dyndns,dynamic-dns,ddns,dns,devnomads
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: httpx>=0.27
Dynamic: license-file

# dnsync

Keep a domain name pointed at your home or office internet connection, even
when your provider changes your IP address. This is "dynamic DNS" (the same
idea as DynDNS or No-IP), but for domains you host at
[DevNomads](https://devnomads.nl).

Say you want `home.example.com` to always reach the computer in your living
room. Most home connections get an IP address that changes from time to
time, which would normally break that. `dnsync` checks your connection's
current public IP and updates the DNS record for you, so the name keeps
working. Run it once, from cron, or leave it running in the background.

It handles IPv4 (`A` records), IPv6 (`AAAA` records), or both.

## Install

```sh
pip install dnsync
```

Or, to install it as a standalone command without touching your system
Python (recommended on servers and workstations):

```sh
uv tool install dnsync      # or: pipx install dnsync
```

Either way you get a `dnsync` command on your `PATH`.

## 1. Add your API key

Create an API key in the
[DevNomads portal](https://portal.devnomads.nl) under
**Profiel -> API Sleutels**.

The easiest way to store it is with the companion tool
[`dnctl`](https://pypi.org/project/dnctl/), which `dnsync` shares
credentials with:

```sh
pip install dnctl
dnctl configure        # paste your API key when asked
```

That's it - `dnsync` will find the key automatically.

Prefer not to install `dnctl`? You have two other options:

- Set an environment variable:

  ```sh
  export DN_API_KEY="your-devnomads-api-key"
  ```

- Or, for an unattended server, write the key to
  `/etc/dnsync/credentials`:

  ```ini
  [default]
  api_key = your-devnomads-api-key
  ```

## 2. Run it

Point a hostname at your current IPv4 address:

```sh
dnsync home.example.com
```

That's the whole thing. `dnsync` looks up your public IP, finds the right
zone automatically from the domains your key can manage, and updates the
record only if it actually changed.

Want IPv6 too, or instead?

```sh
dnsync -6 home.example.com        # only the AAAA record (IPv6)
dnsync -4 -6 home.example.com     # both A and AAAA
```

You can list more than one hostname, and use `--dry-run` to see what would
happen without changing anything:

```sh
dnsync --dry-run home.example.com vpn.example.com
```

## 3. Keep it up to date automatically

Your IP can change at any time, so you'll usually want `dnsync` to run on
its own. Pick whichever fits your setup.

### With cron (simple and reliable)

Run it every five minutes. `--quiet` keeps it silent unless something
changes or goes wrong, so cron only emails you when it matters:

```cron
*/5 * * * * dnsync --quiet home.example.com
```

### As a background service (daemon)

Leave it running and let it re-check on a timer (300 seconds below):

```sh
dnsync --daemon --interval 300 home.example.com
```

Under systemd, a minimal service looks like:

```ini
[Unit]
Description=dnsync dynamic DNS
After=network-online.target
Wants=network-online.target

[Service]
ExecStart=/usr/local/bin/dnsync --daemon --interval 300 home.example.com
Restart=on-failure

[Install]
WantedBy=multi-user.target
```

### With Docker

If you already run [Docker](https://www.docker.com/) (for example on a NAS
or a small home server), there's a ready-made image that keeps your record
updated for you. You don't need Python or anything else installed - the
image has everything inside it.

Start it with this one command. Replace the two values in quotes with your
own API key and hostname; leave the rest as-is:

```sh
docker run -d --name dnsync --restart unless-stopped \
  -e DN_API_KEY="your-devnomads-api-key" \
  -e DNSYNC_HOSTNAMES="home.example.com" \
  -e DNSYNC_INTERVAL=300 \
  infrapod/dnsync
```

What the parts mean:

- `-d` runs it quietly in the background; `--restart unless-stopped` brings
  it back after a reboot, so you can set it and forget it.
- `DN_API_KEY` is your DevNomads API key (from step 1).
- `DNSYNC_HOSTNAMES` is the name you want kept up to date. List more than
  one with spaces, like `"home.example.com vpn.example.com"`.
- `DNSYNC_INTERVAL` is how often it checks, in seconds. `300` is every five
  minutes, which is plenty.

By default it updates the IPv4 (`A`) record. To also update IPv6, add
`-e DNSYNC_IPV6=true`; for IPv6 only, add `-e DNSYNC_IPV4=false` as well.

To see that it's working, check its log:

```sh
docker logs dnsync
```

You'll see a line each time it runs - either that nothing changed, or that
it updated your record to a new IP.

#### Docker Compose

Prefer a Compose file? Save this as `docker-compose.yml`:

```yaml
services:
  dnsync:
    image: infrapod/dnsync
    restart: unless-stopped
    environment:
      DN_API_KEY: your-devnomads-api-key
      DNSYNC_HOSTNAMES: home.example.com
      DNSYNC_INTERVAL: "300"
      # DNSYNC_IPV6: "true"   # uncomment to also update the IPv6 record
```

Then start it from the same folder with:

```sh
docker compose up -d
```

## Settings without typing them every time

Anything you can pass on the command line can also come from environment
variables or a config file, so a service doesn't need a long command. The
order of precedence is: command line, then environment, then config file.

Environment variables:

| Variable           | Meaning                                 |
| ------------------ | --------------------------------------- |
| `DNSYNC_HOSTNAMES` | hostnames to update (space-separated)   |
| `DNSYNC_IPV4`      | `true`/`false` - update the A record    |
| `DNSYNC_IPV6`      | `true`/`false` - update the AAAA record |
| `DNSYNC_TTL`       | record TTL in seconds (default 60)      |
| `DNSYNC_INTERVAL`  | daemon poll interval in seconds         |

Config file (`/etc/dnsync/config`, or pass `--config path`):

```ini
[dnsync]
hostnames = home.example.com vpn.example.com
ipv4 = true
ipv6 = true
ttl = 60
interval = 300
```

With that file in place, the service command is simply:

```sh
dnsync --daemon
```

## Troubleshooting

- **"no API key found"** - you haven't stored a key yet; see step 1.
- **"no hostname given"** - tell `dnsync` which name to update, on the
  command line or in a config file.
- **"API rejected the key"** - the key is wrong, or it isn't allowed to
  edit this domain. Check it in the DevNomads portal.
- **"no DevNomads zone found"** - the domain isn't hosted at DevNomads, or
  this key can't see it.
- **"could not determine public IP"** - the machine couldn't reach the IP
  lookup service. For the IPv6 (`AAAA`) record your connection needs
  working IPv6; if it doesn't have any, stick to IPv4.

## License

MIT - see [LICENSE](LICENSE). Use it freely.
