Files
homelab-optimized/docs/guides/add-new-subdomain.md
Gitea Mirror Bot 1ab33b1e66
Some checks failed
Documentation / Deploy to GitHub Pages (push) Has been cancelled
Documentation / Build Docusaurus (push) Has been cancelled
Sanitized mirror from private repository - 2026-04-19 09:48:50 UTC
2026-04-19 09:48:50 +00:00

4.2 KiB

Adding a New Subdomain

Every new subdomain needs to be registered in three places. Miss one and either the DNS won't auto-update when your WAN IP changes, or the service won't be reachable.


The Three Places

# Where What it does
1 Cloudflare DNS Creates the A record
2 DDNS compose file Keeps the A record pointed at your current WAN IP
3 NPM proxy host Routes HTTPS traffic to the right container

Step 1 — Cloudflare DNS

Create the A record via the Cloudflare dashboard or API.

Proxied (orange cloud) — use for all standard HTTP/HTTPS services:

curl -s -X POST "https://api.cloudflare.com/client/v4/zones/ZONE_ID/dns_records" \
  -H "Authorization: Bearer $CF_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"type":"A","name":"myservice.vish.gg","content":"1.2.3.4","proxied":true}'

Direct (grey cloud) — use only for non-HTTP protocols (TURN, SSH, game servers, WebRTC):

# same but "proxied":false

Zone IDs:

Domain Zone ID
vish.gg 4dbd15d096d71101b7c0c6362b307a66
thevish.io 11681f1c93ca32f56a0c41973e02b6f9
crista.love (check Cloudflare dashboard)

The content IP doesn't matter much if it's proxied — the DDNS updater will overwrite it. Use a placeholder like 1.2.3.4 for now.


Step 2 — DDNS Compose File

Add the domain to the correct host's DDNS DOMAINS= list. Pick the host whose WAN IP the service is behind:

Host File Use when
Atlantis / Calypso (home) hosts/synology/atlantis/dynamicdnsupdater.yaml Service is behind home WAN IP
concord-nuc hosts/physical/concord-nuc/dyndns_updater.yaml API/direct-access on concord-nuc
Seattle VPS hosts/vms/seattle/ddns-updater.yaml Service is on the Seattle VPS
Guava (crista.love) hosts/physical/guava/portainer_yaml/dynamic_dns.yaml crista.love subdomains

For a standard proxied service on Atlantis/Calypso, edit dynamicdnsupdater.yaml and append your domain to the ddns-vish-proxied service:

- DOMAINS=...,myservice.vish.gg   # add here, keep comma-separated
- PROXIED=true

For an unproxied (direct) domain, use the ddns-thevish-unproxied service or create a new service block with PROXIED=false.

Then redeploy the stack via Portainer (Atlantis, stack dyndns-updater-stack, ID 613):

# Portainer API — or just use the UI: Stacks → dyndns-updater-stack → Editor → Update

Step 3 — NPM Proxy Host

Add a proxy host at http://npm.vish.gg:81 (or http://192.168.0.250:81):

  1. Hosts → Proxy Hosts → Add Proxy Host
  2. Domain names: myservice.vish.gg
  3. Forward hostname/IP: container name or LAN IP of the service
  4. Forward port: the service's internal port
  5. SSL tab: Request a new Let's Encrypt cert, enable Force SSL
  6. (Optional) Advanced tab: add Authentik forward-auth snippet if SSO is needed

Exceptions — services that skip Step 3

If your subdomain doesn't need an NPM proxy rule (direct-access APIs, WebRTC, services with their own proxy), add it to DDNS_ONLY_EXCEPTIONS in .gitea/scripts/dns-audit.py so the daily audit doesn't flag it:

DDNS_ONLY_EXCEPTIONS = {
    ...
    "myservice.vish.gg",  # reason: direct access / own proxy
}

Step 4 — Verify

Run the DNS audit to confirm everything is wired up:

cd /home/homelab/organized/repos/homelab
CF_TOKEN=<your-cf-token> \
NPM_EMAIL=<npm-admin-email> \
NPM_PASSWORD="REDACTED_PASSWORD" \
python3 .gitea/scripts/dns-audit.py

The CF token is stored in Portainer as CLOUDFLARE_API_TOKEN on the DDNS stacks. NPM credentials are stored as NPM_EMAIL / NPM_PASSWORD Gitea Actions secrets. The audit also runs automatically every day at 08:00 UTC — check the Gitea Actions tab.

Expected output:

✅ All N DDNS domains OK, CF and DDNS are in sync

Commit the changes

git add hosts/synology/atlantis/dynamicdnsupdater.yaml   # (whichever file you edited)
git commit -m "Add myservice.vish.gg subdomain"
git push

Portainer will pick up the DDNS change on the next git redeploy, or trigger it manually.