# Runbook: Standalone Unbound internal DNS

## Purpose

Operate the standalone Unbound DNS service for internal homelab `dropcutstud.io` records.

## Current Service

- Host: CTID 106 `unbound`
- IP: `192.168.0.124` via DHCP
- Proxmox node: `buntbox01`
- Exposure: LAN-only current; intended LAN + Tailscale later
- Config: `/etc/unbound/unbound.conf.d/homelab.conf`
- Snapshot: `post-unbound-internal-dns-mvp`

## Safety Notes

- DNS can break service access. Keep direct IP fallback documented.
- Do not point router DHCP clients at this DNS service until the IP is stable/reserved and rollback is documented.
- Do not expose DNS publicly.
- Router/OPNsense DHCP/DNS changes require explicit confirmation.

## Current Internal Records

```text
dns.dropcutstud.io      -> 192.168.0.124
unbound.dropcutstud.io  -> 192.168.0.124
proxy.dropcutstud.io    -> 192.168.0.137
dashboard.dropcutstud.io -> 192.168.0.137
search.dropcutstud.io   -> 192.168.0.137
vw.dropcutstud.io       -> 192.168.0.238
nc.dropcutstud.io       -> 192.168.0.110
opn.dropcutstud.io      -> 192.168.0.1
```

## DHCP / LAN DNS

As of 2026-06-07, OPNsense DHCP advertises `192.168.0.124` as the LAN DNS server via DNSmasq. LAN clients resolve `*.dropcutstud.io` names automatically without manual configuration.

## Add or Update a Record

1. SSH to `unbound-dns` or administer via Proxmox console.
2. Edit:

   ```sh
   sudoedit /etc/unbound/unbound.conf.d/homelab.conf
   ```

3. Add/update `local-data` lines:

   ```text
   local-data: "service.dropcutstud.io. 300 IN A 192.168.0.x"
   ```

4. Validate and reload:

   ```sh
   sudo unbound-checkconf
   sudo systemctl restart unbound
   ```

## Verification

From a LAN host:

```sh
dig @192.168.0.124 search.dropcutstud.io +short
dig @192.168.0.124 proxy.dropcutstud.io +short
dig @192.168.0.124 example.com +short
```

Expected for current MVP:

```text
search.dropcutstud.io -> 192.168.0.137
proxy.dropcutstud.io  -> 192.168.0.137
```

Check service:

```sh
systemctl is-active unbound
sudo ss -lunpt | grep ':53'
```

Check reverse-proxy route using Unbound's answer:

```sh
IP=$(dig @192.168.0.124 search.dropcutstud.io +short | head -1)
curl -k --resolve search.dropcutstud.io:443:$IP https://search.dropcutstud.io/ -I
```

## Backups / Restore

- Backup class: `standard`
- Backup status: configured, verified, and restore-tested on 2026-06-07
- Backup scope: `/etc/unbound/unbound.conf` and `/etc/unbound/unbound.conf.d/`
- Guest-local destination: `/var/backups/unbound/`
- Off-guest destination: `/home/piagent/backups/unbound/` on Nimrod LXC 104
- Encryption: not currently required for internal DNS config; switch to an approved encrypted path if sensitive upstream credentials, private keys, or access tokens are added.
- Schedule: manual only during bootstrap
- Retention: manual/no pruning until the broader backup destination/retention policy is selected
- Restore test required: yes for standard class; latest restore test: 2026-06-07 using artifact `unbound-20260607T044755Z.tar.gz` restored into a temporary Unbound process bound to `127.0.0.1:1053` on CT 106; verified `search`, `proxy`, and `dashboard` records

Backup script source of truth in this repo: `ansible/files/unbound-backup`.

Install/update the script with Ansible from Nimrod:

```sh
ansible unbound-dns -i ansible/inventories/homelab/hosts.yml \
  -m copy \
  -a 'src=ansible/files/unbound-backup dest=/usr/local/sbin/unbound-backup owner=root group=root mode=0755'
```

Manual backup command on `unbound-dns`:

```sh
sudo /usr/local/sbin/unbound-backup
```

Verification on `unbound-dns`:

```sh
cd /var/backups/unbound
sudo sha256sum -c <latest>.sha256
systemctl is-active unbound
```

Off-guest copy from Nimrod:

```sh
mkdir -p /home/piagent/backups/unbound
scp unbound-dns:/var/backups/unbound/<artifact>.tar.gz /home/piagent/backups/unbound/
scp unbound-dns:/var/backups/unbound/<artifact>.sha256 /home/piagent/backups/unbound/
cd /home/piagent/backups/unbound && sha256sum -c <artifact>.sha256
```

Restore/rebuild outline:

1. Provision or choose an isolated test target with Unbound installed.
2. Extract the backup artifact into a temporary directory.
3. Restore `etc/unbound/unbound.conf` and `etc/unbound/unbound.conf.d/` to `/etc/unbound/` on the target.
4. Run `sudo unbound-checkconf`.
5. Start/restart Unbound on the target.
6. Verify representative records such as `search.dropcutstud.io` and public recursion such as `example.com`.
7. Do not overwrite production DNS config during restore testing.

## Rollback / Recovery

For one bad record:

1. Revert the line in `/etc/unbound/unbound.conf.d/homelab.conf`.
2. Run `sudo unbound-checkconf`.
3. Restart Unbound.
4. Use direct service IP fallback.

For service failure:

1. Stop using `192.168.0.124` as resolver in any clients/router settings.
2. Use existing router/upstream DNS.
3. Revert CT 106 to snapshot `post-unbound-internal-dns-mvp` or repair config.

## Related Files / Systems

- Ticket: `tickets/active/2026-06-07-standalone-unbound-internal-dns.md`
- DNS/Tailscale ticket: `tickets/active/2026-06-06-internal-dns-and-tailscale-naming.md`
- Registry: `infra/proxmox-registry.yaml`
- Inventory: `systems/inventory.md`
- Change log: `docs/server-change-log.md`
