Archived
Polish KarlDNS production UI and docs
This commit is contained in:
1 parent
ca92dc211a
commit
5beee0e5c6
61 files changed
+1566
-523
No files matched your search
@@ -1,8 +1,8 @@
|
||||
# KarlDNS
|
||||
|
||||
**Self-hosted DynDNS for FRITZ!Box, OpenWrt, pfSense, OPNsense, UniFi, MikroTik, and any router that can call a custom DDNS update URL.**
|
||||
**Self-hosted Dynamic DNS (DynDNS / DDNS) for FRITZ!Box, OpenWrt, pfSense, OPNsense, UniFi, MikroTik, Linux cron jobs, and any router that can call a custom DDNS update URL.**
|
||||
|
||||
KarlDNS is the friendly name for `karldns`: a small FastAPI Dynamic DNS provider you can run on your own VPS. It gives users FRITZ!Box-ready DynDNS credentials, keeps public A/AAAA records updated through Cloudflare or RFC 2136, provides generated hostnames that work as CNAME targets, and supports verified custom domains with DNS TXT ownership checks.
|
||||
KarlDNS is the friendly name for `karldns`: a small FastAPI Dynamic DNS provider you can run on your own VPS. It gives users accountless private update URLs, FRITZ!Box-ready DynDNS fields, public A/AAAA records through Cloudflare or RFC 2136, generated hostnames that work as CNAME targets, and verified custom domains with DNS TXT ownership checks.
|
||||
|
||||
If you want a lightweight DuckDNS / Dynu / No-IP style service that you control yourself, KarlDNS is built for that use case.
|
||||
|
||||
@@ -21,7 +21,7 @@ If you want a lightweight DuckDNS / Dynu / No-IP style service that you control
|
||||
|
||||
## Screenshots
|
||||
|
||||
### Generate Router Credentials
|
||||
### Create Router Credentials
|
||||
|
||||

|
||||
|
||||
@@ -29,6 +29,19 @@ If you want a lightweight DuckDNS / Dynu / No-IP style service that you control
|
||||
|
||||

|
||||
|
||||
## Logo And Social Preview
|
||||
|
||||
KarlDNS ships web-ready brand assets so self-hosted instances and shared links look clean out of the box:
|
||||
|
||||
| Asset | Purpose |
|
||||
| --- | --- |
|
||||
| `router_dyndns/assets/logo-nav.webp` | Small navigation logo. |
|
||||
| `router_dyndns/assets/logo.webp` | Optimized homepage logo. |
|
||||
| `router_dyndns/assets/logo-192.png` and `logo-512.png` | PWA, app icon, and manifest icons. |
|
||||
| `router_dyndns/assets/favicon.ico`, `favicon-16x16.png`, `favicon-32x32.png`, `apple-touch-icon.png` | Browser and mobile icons. |
|
||||
| `router_dyndns/assets/social-preview.png` | Open Graph and Twitter large-card preview for reliable crawlers. |
|
||||
| `router_dyndns/assets/social-preview.webp` | Optimized WebP social preview for modern clients. |
|
||||
|
||||
## What It Does
|
||||
|
||||
KarlDNS lets you host your own managed DynDNS service:
|
||||
@@ -107,6 +120,7 @@ For an internet-facing DynDNS service, run behind HTTPS and require a real DNS b
|
||||
```bash
|
||||
export DDNS_ADMIN_PASSWORD='replace-with-a-long-random-value'
|
||||
export DDNS_ADMIN_PATH='/admin'
|
||||
export DDNS_DASHBOARD_COOKIE_SECRET='replace-with-a-32-plus-character-random-value'
|
||||
export DDNS_PUBLIC_BASE_URL='https://karldns.de'
|
||||
export DDNS_HOSTNAME_SUFFIX='karldns.de'
|
||||
export DDNS_DATABASE='/data/ddns.sqlite3'
|
||||
@@ -146,7 +160,7 @@ KarlDNS also shows optional compatibility fields for routers that insist on sepa
|
||||
- `Benutzername` (optional)
|
||||
- `Kennwort` (optional)
|
||||
|
||||
Copy the router password and one-box update URL when they are generated or rotated. They are intentionally not recoverable from the dashboard later.
|
||||
Copy the router password and full update URL when they are generated or rotated. They are intentionally not recoverable from the dashboard later.
|
||||
|
||||
The generated FRITZ!Box URL uses the native placeholders:
|
||||
|
||||
@@ -156,7 +170,7 @@ https://karldns.de/u/<random-update-slug>?myip=<ipaddr>&myipv6=<ip6addr>
|
||||
|
||||
FRITZ!Box replaces `<ipaddr>` and `<ip6addr>` with the current WAN IPv4/IPv6 address and sends an HTTP GET request to that URL whenever it detects an address change. KarlDNS returns DynDNS-style responses such as `good 203.0.113.10`, `nochg 203.0.113.10`, `badauth`, or `nohost`.
|
||||
|
||||
This URL is enough for routers that only expose a single update URL field and do not send separate credentials. KarlDNS also shows a `One-box update URL` that embeds `hostname`, `username`, and `password` as query parameters for clients that require credential-style DynDNS URLs but do not expose separate credential fields. Treat both URLs as secrets.
|
||||
This URL is enough for routers that only expose a single update URL field and do not send separate credentials. KarlDNS also shows a `Full update URL` that embeds `hostname`, `username`, and `password` as query parameters for clients that require credential-style DynDNS URLs but do not expose separate credential fields. Treat both URLs as secrets.
|
||||
|
||||
The compatibility endpoint is also available:
|
||||
|
||||
@@ -268,7 +282,7 @@ curl -fsSL https://karldns.de/install.sh | sudo sh -s -- --ipv6 off
|
||||
|
||||
## Use Your Own Subdomain With CNAME
|
||||
|
||||
Most users do not need domain verification. Generate a KarlDNS hostname first, then create a CNAME at your DNS provider:
|
||||
Most users do not need domain verification. Create a KarlDNS hostname first, then create a CNAME at your DNS provider:
|
||||
|
||||
```dns
|
||||
home.example.com. CNAME a1b2c3d4.karldns.de.
|
||||
@@ -278,7 +292,7 @@ Put the KarlDNS `Update-URL`, `Domainnamen`, `Benutzername`, and `Kennwort` into
|
||||
|
||||
Use a subdomain such as `home.example.com`. Root/apex domains like `example.com` usually cannot be plain CNAME records unless your DNS provider supports CNAME flattening or ALIAS/ANAME records.
|
||||
|
||||
The generated hostname is not a secret. Treat it like any public DNS name. The update URL slug, router password, private status page URL, and domain claim link are the secrets. Dashboard forms use CSRF tokens, and dashboard password unlock cookies last 24 hours by default unless the user chooses the 30-day stay-unlocked option.
|
||||
The generated hostname is not a secret. Treat it like any public DNS name. The update URL slug, router password, private dashboard URL, and domain claim link are the secrets. Dashboard forms use CSRF tokens, and dashboard password unlock cookies last 24 hours by default unless the user chooses the 30-day stay-unlocked option.
|
||||
|
||||
## Custom Domain Flow
|
||||
|
||||
@@ -325,7 +339,7 @@ cp .env.example .env
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
The example environment is intentionally short: admin password/path, public URL, managed hostname suffix, Cloudflare token, Cloudflare zone ID, and the SQLite path. The app creates the SQLite parent directory and all tables on first run. Re-running the container or starting the app twice is idempotent; schema creation uses `CREATE TABLE IF NOT EXISTS`, and the cleanup scheduler keeps a single durable task row.
|
||||
The example environment is intentionally short: admin password/path, dashboard cookie signing secret, public URL, managed hostname suffix, Cloudflare token, Cloudflare zone ID, and the SQLite path. The app creates the SQLite parent directory and all tables on first run. Re-running the container or starting the app twice is idempotent; schema creation uses `CREATE TABLE IF NOT EXISTS`, and the cleanup scheduler keeps a single durable task row.
|
||||
|
||||
The image and compose file default `DDNS_DATABASE` to `/data/ddns.sqlite3`, and the compose volume persists `/data`.
|
||||
|
||||
@@ -338,6 +352,7 @@ The default container command runs one Uvicorn worker. Keep that deployment shap
|
||||
- Run behind HTTPS.
|
||||
- Keep `.env` out of git.
|
||||
- Use a long random value for `DDNS_ADMIN_PASSWORD`.
|
||||
- Use a separate long random value for `DDNS_DASHBOARD_COOKIE_SECRET` on public instances.
|
||||
- Change `DDNS_ADMIN_PATH` if you do not want the operator UI at `/admin`.
|
||||
- Use a least-privilege DNS API token or TSIG key.
|
||||
- Set `DDNS_TRUSTED_HOSTS` only when the app should answer for hostnames beyond `DDNS_PUBLIC_BASE_URL`.
|
||||
@@ -346,7 +361,7 @@ The default container command runs one Uvicorn worker. Keep that deployment shap
|
||||
- Leave cleanup enabled. The cleanup scheduler is stored in SQLite with a task row, next run time, status, last error, and a database lease so only one app process runs a due cleanup job.
|
||||
- Back up `/data/ddns.sqlite3`.
|
||||
- Run one Uvicorn worker with SQLite unless you have tested your deployment under load. Scheduled cleanup is lease-protected across workers, but rate-limit state and per-host update locks are process-local.
|
||||
- Keep Uvicorn access logs disabled unless your reverse proxy redacts query strings. Update URLs, dashboard URLs, and domain claim links are bearer secrets and may appear in request paths or query strings.
|
||||
- Keep Uvicorn access logs disabled. Use `DDNS_REDACTED_ACCESS_LOG=1` or `karldns serve --access-log` only for KarlDNS' built-in redacted access log, which masks bearer URL paths and query strings.
|
||||
|
||||
Security and cleanup defaults:
|
||||
|
||||
@@ -356,6 +371,8 @@ Security and cleanup defaults:
|
||||
| `DDNS_ADMIN_RATE_LIMIT_PER_MINUTE` | `20` | Admin/operator requests allowed per source IP and path. |
|
||||
| `DDNS_MAX_REQUEST_BODY_BYTES` | `16384` | Maximum accepted request body for form/API endpoints. |
|
||||
| `DDNS_ADMIN_PATH` | `/admin` | Private operator UI path. Admin routes are hidden from OpenAPI and require Basic auth. |
|
||||
| `DDNS_DASHBOARD_COOKIE_SECRET` | `DDNS_ADMIN_PASSWORD` fallback | HMAC signing secret for dashboard unlock cookies. Use a separate 32+ character random value in production. |
|
||||
| `DDNS_REDACTED_ACCESS_LOG` | `0` | Enable KarlDNS request logs with bearer paths and update query strings redacted. |
|
||||
| `DDNS_TRUSTED_HOSTS` | from `DDNS_PUBLIC_BASE_URL` | Host header allowlist. Add every public hostname that should serve the app. |
|
||||
| `DDNS_CLEANUP_CHALLENGE_HOURS` | `72` | Delete unverified DNS TXT claims after this many hours. |
|
||||
| `DDNS_CLEANUP_UNUSED_ACCOUNT_HOURS` | `1080` | Delete generated hostnames that never received a router update after this many hours. |
|
||||
|
||||
Reference in new issue
Block a user