# hk2.chans.xyz | Item | Value | |------|--------| | Role | PowerDNS Authoritative (ns1) + Poweradmin / Traefik | | SSH | `ssh -4 windy@hk2.chans.xyz` (prefer IPv4 from WSL) | | IPv4 | `154.36.174.161` | | Hostname (OS) | `C20210714091792` (Debian 13 trixie) | | Also DNS | `ns1.wsvc.info` → this host | | Secondary NS | `ns2.wsvc.info` → `202.91.35.141` (`us1.wsvc.info`, PowerDNS Auth **5.0.5**) | | Install path | `/opt/pdns` | | Compose | `/opt/pdns/compose.yml` | | Env file | `/opt/pdns/.env` (secrets — **never commit**) | | TZ | `Asia/Shanghai` | Upstream docs / config checklist: [docs/pdns-upstream.md](../docs/pdns-upstream.md) ## PowerDNS Authoritative **Status: operational** (auth + db healthy, API **5.0.6**, DNS on :53 — last config audit 2026-08-01 21:40 CST). | Item | Value | |------|--------| | Image | `powerdns/pdns-auth-50:5.0.6` (pinned) | | Container | `pdns-auth` | | Config | `/opt/pdns/auth/pdns.conf` + `auth/templates.d/secrets.j2` → `pdns.d/secrets.conf` | | Backend | PostgreSQL 16 (`launch=gpgsql`, DB name `pdns`) | | DNS ports | host `53/tcp` + `53/udp` | | API | host `127.0.0.1:8081` only; `webserver-allow-from` private ranges | | Mode | `primary=yes`; `also-notify` / AXFR ACL → `202.91.35.141`; `only-notify=` empty | | DNSSEC | `gpgsql-dnssec=yes`; CSK ECDSAP256SHA256 | | SOA-EDIT | `default-soa-edit(-signed)=INCEPTION-INCREMENT` | | Poweradmin | `PDNS_VERSION=50`; Traefik Host(`pdns.wsvc.info`) | | Advisories | 2026-06 + 2026-07 cleared by 5.0.6 | ### Zones (authoritative) | Zone | Kind | DNSSEC | Zone metadata | |------|------|--------|---------------| | `windy.me` | Master | yes | `ALLOW-AXFR-FROM` + `TSIG-ALLOW-AXFR=mykey.` | | `wsvc.info` | Master | yes | same | | `chans.xyz` | Master | yes | same | NS set: `ns1.wsvc.info` / `ns2.wsvc.info`. Dig SOA may differ from backend serial (SOA-EDIT) — expected. ### Intended auth config (sanitized) See full shape in [docs/pdns-upstream.md](../docs/pdns-upstream.md). Live secrets only in `.env` / generated drop-in on the server. ### Stack | Container | Service | Status | Image | |-----------|---------|--------|-------| | `pdns-auth` | auth | Up (healthy) | `powerdns/pdns-auth-50:5.0.6` | | `pdns-db` | db | Up (healthy) | `postgres:16` | | `poweradmin` | poweradmin | Up (healthy) | `poweradmin/poweradmin:stable` | | `pdns_pgweb` | pgweb | Up | `sosedoff/pgweb:0.16.2` | | `pdns-backup` | backup | Up | `postgres:16` (scheduler) | > Legacy PDA UI container `powerdns-admin` (orphan, Exited) was removed 2026-08-12 (W1N-59). ### Network model | Network | Purpose | |---------|---------| | `backend` | Internal (`internal: true`) — DB + service API | | `edge` | Host-published DNS `:53` and loopback API `:8081` | | `frontend` (`traefik`) | External Traefik network for web UIs | ### Public / management URLs | URL | Backend | Notes | |-----|---------|-------| | https://pdns.wsvc.info | `poweradmin` via Traefik | DNS admin UI | | https://pgweb.wsvc.info | `pgweb` via Traefik | DB browser (HTTP basic) | | DNS `ns1.wsvc.info:53` | `pdns-auth` | Public authoritative | ## Config audit (vs official docs) **Functional primary/secondary config: OK** after 5.0.6 upgrade + `only-notify=` / `domains.master` cleanup. | Item | Verdict | |------|---------| | `primary` + MASTER zones + gpgsql DNSSEC | OK | | `also-notify` + empty `only-notify` | OK (docs-recommended pattern) | | API bind / host port publish | OK | | SOA-EDIT with PowerDNS secondary | OK | | API key / DB password hygiene | **Deferred** — weak, plaintext, reused | | TSIG `mykey` | **Deferred** — any holder can AXFR (bypasses IP ACL) | ## Backup | Item | Value | |------|--------| | Service | `pdns-backup` | | Schedule | `CRON_SCHEDULE=0 3 * * *` (03:00 Asia/Shanghai) | | Retention | `RETENTION_DAYS=7`, `MAX_BACKUPS=3` | | Output | `/opt/pdns/backup/pdns_*.sql.gz` (+ optional `roles_*.sql`) | | Scheduler | `scripts/backup-scheduler.sh` (daily `M H * * *` only) | | Manual | `cd /opt/pdns && ./scripts/manual-backup.sh` | **Quirk:** `backend` is internal — backup must not use Alpine + runtime `apk`/`crond`. Uses `postgres:16` + `backup-scheduler.sh` (fixed 2026-08-01). ## RustDesk Server **Status: operational** (hbbs + hbbr Up; image pinned `1.1.14`; relay address fixed 2026-08-12, W1N-59). | Item | Value | |------|--------| | Install path | `/opt/rustdesk` | | Compose | `/opt/rustdesk/compose.yml` | | Containers | `hbbs` (rendezvous), `hbbr` (relay) | | Image | `rustdesk/rustdesk-server:1.1.14` (pinned) | | Relay (hbbr) | `hk2.chans.xyz:21117` — advertised to clients via `hbbs -r` | | Rendezvous (hbbs) | `21115/tcp` (NAT test), `21116/tcp+udp`, `21118/tcp` (ws) | | Relay (hbbr) | `21117/tcp`, `21119/tcp` (ws) | | Public IP | `154.36.174.161` | | Health | [runbooks/rustdesk-health.md](../runbooks/rustdesk-health.md) | **Note:** the relay hostname in `hbbs -r` must resolve to this host's public IP (`154.36.174.161`). `hk2.chans.xyz` resolves correctly; the previously used `hk2.wsvc.info` had **no DNS record** and broke relay connectivity for clients (fixed 2026-08-12, W1N-59). ## Other software on this host (confirmed 2026-08-12) Verified live via `docker ps` / port scan. Each runs as a separate compose project under `/opt/` and is fronted by Traefik where noted. | Service | Path | Container(s) | Image | Ports / notes | |---------|------|--------------|-------|---------------| | Traefik | `/opt/traefik` | `traefik` | `traefik:v3.6.2` | `80`, `443` (TLS entry), `8080` (dashboard) | | AdGuard Home | `/opt/adguard` | `adguardhome` | `adguard/adguardhome:latest` | DoH `5443`, DoT `853` (bridge; no LAN `:53`) | | Remark42 | `/opt/remark42` | `remark42` | `ghcr.io/umputun/remark42:latest` | no host ports; via Traefik (in-container `8080`) | ### Traefik dashboard auth | Item | Value | |------|-------| | Dashboard URL | `https://npm.chans.xyz` (Traefik `api@internal` router), also host `:8080` | | Auth | HTTP Basic via Traefik `basicauth` middleware (label `dashboard-auth`) | | User | `windy` — stored as a **bcrypt** hash (plaintext never stored) | | Hash generator | `/opt/traefik/generate-dashboard-auth.sh` (bcrypt; auto `$`→`$$` compose escaping) | | Config | `/opt/traefik/compose.yml` (label `traefik.http.middlewares.dashboard-auth.basicauth.users`) | **Password rotated 2026-08-12** from apr1/MD5 to bcrypt via the generator script; the plaintext lives only in the operator's password manager, never in this repo. To rotate again: `cd /opt/traefik && ./generate-dashboard-auth.sh windy`, paste the printed label into `compose.yml`, then `docker compose up -d --force-recreate traefik`. `/opt/nginx-manager` was a leftover (compose + `data/` + `letsencrypt/`, no running container) and was **removed 2026-08-12**; pre-deletion backup: `/opt/backups/nginx-manager-20260812.tar.gz`. Health coverage: these auxiliary services are checked by the `hk2aux` health-check profile (`ansible/roles/healthcheck`). Run: `cd ansible && ansible-playbook playbooks/health-report.yml --limit powerdns`. ## Ops / runbooks - [pdns-health](../runbooks/pdns-health.md) - [pdns-upstream docs](../docs/pdns-upstream.md) ```bash cd ansible ansible-playbook playbooks/health-report.yml --limit powerdns # after reviewed auth config / secret-template / environment changes: ansible-playbook playbooks/compose-reconcile.yml --limit powerdns \ -e '{"service_reconcile_confirm": true, "service_reconcile_targets": ["auth"]}' ``` Direct SSH remains appropriate for streaming incident logs or running the on-server, intentionally imperative manual backup command: ```bash ssh -4 windy@hk2.chans.xyz 'cd /opt/pdns && ./scripts/manual-backup.sh' ``` ```bash dig @154.36.174.161 NS windy.me +short dig @154.36.174.161 SOA wsvc.info +short # compare secondary: dig @202.91.35.141 SOA wsvc.info +short ``` On-server docs: `/opt/pdns/README.md`, `CHANGELOG.md`. ## Verified Last checked: **2026-08-01 21:40 CST** — operational; docs audit recorded. - Auth **5.0.6** healthy; no Mandatory security banner - Zones Master + DNSSEC; SOA in sync with ns2 (served serial) - `only-notify=` + `also-notify=202.91.35.141`; MASTER `domains.master` cleared - https://pdns.wsvc.info → **302**; https://pgweb.wsvc.info → **401** - Hardening backlog: API/DB credential rotation + TSIG rotate (see upstream doc)