from __future__ import annotations from ..settings import DdnsSettings from .components import _code_window, _example_update_ips, _message_band from .html_utils import escape, trusted from .layout import _page, _top_nav from .templates_public_sections import _linux_installer_section def _render_public_home( settings: DdnsSettings, message: str | None, request_ip: str | None = None, ) -> str: base_url = settings.public_base_url.rstrip("/") hostname_suffix = settings.hostname_suffix or "your KarlDNS suffix" suffix = escape(hostname_suffix) demo_update_url = escape(f"{base_url}/api/v1/router/update/?myip=") example_ipv4, _ = _example_update_ips(request_ip) create_demo_command = f"curl -sS '{base_url}/api/v1/router/update/?myip={example_ipv4}'" create_demo = f"{create_demo_command}\ngood {example_ipv4}" manual_demo = "\n".join( [ "# explicit IPv4", f"curl -sS '{base_url}/api/v1/router/update/?myip={example_ipv4}'", "# source IP fallback", f"curl -sS '{base_url}/api/v1/router/update/'", ] ) message_html = _message_band(message) if message else "" description = "KarlDNS is a free self-hosted Dynamic DNS service for FRITZ!Box routers, generated KarlDNS hostnames, Linux cron jobs, and home networks." return _page( "KarlDNS", trusted(f"""
{_top_nav()}

Dynamic DNS for home routers.

{demo_update_url}

KarlDNS gives you a generated DynDNS hostname under {suffix}. Add the private update URL to your router, or use it from a script.

Manual updates
{message_html}

How it works

No account needed.

Create a hostname, save the private values, register it, done.

  1. CreateRandom hostname and private links.
  2. SaveCopy the secrets while they are shown.
  3. RegisterActivate the hostname when you are ready.
  4. UpdateRouter, cron, or CNAME can use it.
{_code_window(create_demo, copy_label="update example", class_name="mt-4", copy_value=create_demo_command)}

Update from a router or script.

Works with FRITZ!Box, curl, cron, Home Assistant, OpenWrt, pfSense, OPNsense, UniFi, MikroTik, and custom tools.

{_code_window(manual_demo, copy_label="manual update examples", class_name="manual-code text-start mt-4")}
{_linux_installer_section(base_url)}
"""), description=description, preload_logo=True, canonical_url=f"{base_url}/", image_url=f"{base_url}/social-preview.png", image_alt="KarlDNS landing page with private Dynamic DNS update URL", structured_data={ "@context": "https://schema.org", "@type": "SoftwareApplication", "name": "KarlDNS", "applicationCategory": "NetworkingApplication", "operatingSystem": "Linux", "url": f"{base_url}/", "description": description, "image": f"{base_url}/social-preview.png", "offers": {"@type": "Offer", "price": "0", "priceCurrency": "EUR"}, "featureList": [ "Dynamic DNS for FRITZ!Box routers", "Accountless private update URLs", "CNAME target for external DNS names", "Linux cron updater", ], }, ) def _render_privacy_page(settings: DdnsSettings) -> str: base_url = settings.public_base_url.rstrip("/") description = "Privacy and legal information for KarlDNS, including stored hostnames, update links, IP history, and cleanup behavior." return _page( "Legal and Privacy", trusted(f"""
{_top_nav()}

Legal and privacy

Privacy basics.

KarlDNS stores only the data needed to keep your hostname updated.

Data processed

KarlDNS stores hostnames, protected dashboard tokens, private update links, recent IP history, timestamps, and service events.

Secrets

Dashboard links, registration URLs, and update URLs are secrets. Anyone with them may update or manage the hostname. Dashboard lookup values are not stored as readable text.

Logs and retention

KarlDNS keeps recent update events for troubleshooting. Cleanup removes unused hostnames. Server logs may also include IP addresses and request details.

Contact

For the public KarlDNS instance, contact Karl through karl.fail or karlcom.de.

"""), description=description, canonical_url=f"{base_url}/privacy", image_url=f"{base_url}/social-preview.png", image_alt="KarlDNS legal and privacy information", structured_data={ "@context": "https://schema.org", "@type": "WebPage", "name": "KarlDNS Legal and Privacy", "url": f"{base_url}/privacy", "description": description, "isPartOf": { "@type": "WebSite", "name": "KarlDNS", "url": f"{base_url}/", }, }, ) def _render_api_docs_page(settings: DdnsSettings, request_ip: str | None = None) -> str: base_url = settings.public_base_url.rstrip("/") example_ipv4, _ = _example_update_ips(request_ip) create_example = f"curl -sS -X POST {base_url}/api/v1/hostnames" register_example = f"curl -sS -X POST '{base_url}/api/v1/router/register/?myip={example_ipv4}'" update_example = f"curl -sS '{base_url}/api/v1/router/update/?myip={example_ipv4}'" status_example = f"curl -sS '{base_url}/api/v1/hostnames/?history_limit=10'" rotate_example = f"curl -sS -X POST {base_url}/api/v1/hostnames//rotate-update-url" schema_example = f"curl -sS {base_url}/openapi.json" description = "Small KarlDNS API guide for creating, activating, updating, reading, and deleting generated Dynamic DNS hostnames." return _page( "KarlDNS API", trusted(f"""
{_top_nav()}

API

Small API surface.

Create a hostname, register it, update it, and read its status.

Endpoints

  1. POST /api/v1/hostnames. Create a pending hostname and private setup values. The response includes registration_url.
  2. GET or POST /api/v1/router/register/<karl_secret>. Register the hostname after secrets are saved. Uses the request IP, or myip/myipv6, for the initial DNS record.
  3. GET or POST /api/v1/router/update/<karl_secret>. Router-friendly update endpoint. Supports myip, ipaddr, myipv6, and ip6addr.
  4. GET /api/v1/hostnames/<karl_secret>. Read hostname status and recent history.
  5. POST /api/v1/hostnames/<karl_secret>/rotate-update-url. Replace the private router update URL.
  6. DELETE /api/v1/hostnames/<karl_secret>. Delete hostname and DNS records.

Create

{_code_window(create_example, copy_label="create command", class_name="mt-3")}

Register

{_code_window(register_example, copy_label="register command", class_name="mt-3")}

Update

{_code_window(update_example, copy_label="update command", class_name="mt-3")}

Status

Use the private dashboard secret to read current DNS state and recent updates for only that hostname.

{_code_window(status_example, copy_label="status command", class_name="mt-3")}

Rotate update URL

Use the private dashboard secret to replace the router update URL. The old update URL stops working immediately.

{_code_window(rotate_example, copy_label="rotate command", class_name="mt-3")}

Schema

Machine-readable OpenAPI is available for the public hostname and router endpoints.

{_code_window(schema_example, copy_label="schema command", class_name="mt-3")}
"""), description=description, canonical_url=f"{base_url}/docs", image_url=f"{base_url}/social-preview.png", image_alt="KarlDNS API documentation", )