Skip to main content

Go-Live: DNS, Render, Vercel, Recast & United Domains

Automation for Custom Domains — without data loss (only additive DB fields and optional API steps).

Hosting paths (overview):

PathTypical forDNS target
Render (Cockpit multi-tenant)Non-MEC / previewRender LB + CNAME
Vercel (v0 shared/dedicated)v0 without RecastVercel (A / cname.vercel-dns.com)
Recast (Docker/GHCR)MEC: one GitHub repo per template, Recast pullA record → Recast server IP

Sections below on Vercel Go-Live and UD automation mainly apply to Render/Vercel. For MEC on Recast, see MEC on Recast.

Requirements (IT)

Dashboard environment (Render/Production):

VariablePurpose
RENDER_API_KEY + RENDER_FRONTEND_SERVICE_IDCockpit template on Render
VERCEL_API_TOKENoptional VERCEL_TEAM_ID
UD_RESELLING_LOGIN + UD_RESELLING_PASSWORDDNS at UD Reseller (domainreselling.de)
UD_DNS_API_KEYDNS at UD customer account (DNS API add-on, format prefix.secret)
COCKPIT_DISABLE_DNS_PROVIDER_WRITE=1Emergency: UD read-only, no DNS write

Migration: packages/database/migrations/20260531120000_add_hosting_dns_vercel_ud_SAFE.sql

Once: Golden Project + v0 Team Template + Vercel Shared Env (COCKPIT_DASHBOARD_URL, REVALIDATION_SECRET, COCKPIT_FRONTEND_CHANNEL).
Per Center: only COCKPIT_REGISTER_TOKEN + COCKPIT_CENTER_SLUG — Cockpit checks that the token and slug match.

→ Step-by-step: Set up v0 Team Template

Center ↔ Vercel Project

ModeStorage LocationWhen
Dedicated (1 Center = 1 Project)ShoppingCenter.vercelProjectIdStandard v0 per Center
Shared (Multi-Center, one layout)Organization.vercelProjectsByTemplate[websiteTemplate] → fallback vercelSharedProjectId + vercelProjectMode=sharedPart G / one Vercel project per template family

IT maintains shared projects once under Dashboard → Organizations → Hosting tab (e.g. /dashboard/organizations/mec?tab=hosting). One prj_… per MEC website template — in the UI e.g. MEC Template Rot (mec-template-a), MEC Template Hybrid (mec-template-d), MEC Grooß (mec-template-grooss), MEC 2 (mec-template-c), MEC Grün (mec-template-green). Centers in shared mode do not need their own projectId — Go-Live resolves from the center's websiteTemplate.

Resolution order for shared:

  1. Optional: ShoppingCenter.vercelProjectId (center override)
  2. Organization.vercelProjectsByTemplate[websiteTemplate]
  3. Fallback: Organization.vercelSharedProjectId

Automatically during deploy registration:

  • Vercel Env: VERCEL_PROJECT_ID, optional COCKPIT_VERCEL_PROJECT_MODE=shared
  • Route POST /api/cockpit-register → Cockpit stores vercelProjectId in Meta and at the Center

Manually: Website Management → Frontend Channels (v0) or Tab Center → Website → Activation (Block “Go-Live”).

MEC on Recast (Docker / GHCR)

Context: For MEC we run one v0 GitHub repo per website template (e.g. smg-mec-template-a, smg-mec-template-d, smg-mec-template-grooss). Recast hosts the built Docker images from GHCR — no Vercel project per center, no new repo per center.

This matches Part G (Multi-Center) in the v0 instructions: one layout per template family, many domains; content per center from the Cockpit API (by-domain).

Architecture (DNS vs. app)

DNS (per center domain) Recast server Cockpit
───────────────────── ───────────── ───────
center-a.de ──A──► Recast IP ──► Nginx ──► Container template-a ──► by-domain?domain=center-a.de
center-b.de ──A──► Recast IP ──► Nginx ──► Container template-a ──► Center B (same image)
center-c.de ──A──► Recast IP ──► Nginx ──► Container template-d ──► Center C (Hybrid image)
  • DNS only decides: domain → Recast server IP (not Vercel, not Render).
  • Which center loads is resolved by GET …/api/centers/by-domain?domain={host} (Host header must be forwarded by Nginx).
  • Cockpit websiteTemplate must match the template repo/container (e.g. Rot centers only on the mec-template-a stack).

Target DNS per center domain (Recast)

RecordNameValue
A@Recast root server IP
Awwwsame IP (or CNAME www → apex — per provider)

Not required: Vercel CNAME (cname.vercel-dns.com), Render CNAME, Vercel prj_… registration.

Who does what?

StepWhoAction
1IT / editorialcustomDomain (+ optional customDomains) in Cockpit — Activation tab
2Domain owner (MEC, center, UD)Set A record to Recast IP
3Recast (hosting partner)SSL: certbot --nginx -d domain.de -d www.domain.de
4Recast (if multiple template containers)Nginx: domain → correct container port (see below)
5Template repo (v0)resolveCenter() / middleware — host → by-domain

New MEC center (same template): domain + Cockpit data + DNS + SSL — no new GitHub repo, no new GHCR build. Code update for all centers in a family: one push in the template repo → GHCR → Recast pull.

Nginx on Recast

Two common variants:

Variant A — one container per template (recommended with multiple repos):

  • e.g. mec-template-a127.0.0.1:3001, mec-template-d127.0.0.1:3002
  • Per domain (or map file): Nginx routes to the matching port — based on the center's websiteTemplate in Cockpit
  • Optional in container: EXPECTED_WEBSITE_TEMPLATE=mec-template-a — wrong routing → 404 instead of wrong layout

Variant B — one multi-tenant container (Dockerfile.center-website):

  • All domains → one port (e.g. 3000), Nginx server_name _; with proxy_set_header Host $host;
  • See also SETUP-NOTES-for-hoster.md in the repo root

Deploy package for v0 repos (one repo per template): deployment-templates/v0-recast/ — details: v0 on Recast (Docker).

Env on Recast (per template container)

For multi-center per template repo (Part G):

VariableRequiredNote
NEXT_PUBLIC_DASHBOARD_URLyesAPI base for browser + server
REVALIDATION_SECRETyesmust match Cockpit dashboard
EXPECTED_WEBSITE_TEMPLATErecommendede.g. mec-template-a
COCKPIT_CENTER_SLUGno (production)preview/default only — otherwise one center “wins”
COCKPIT_REGISTER_TOKENno (production shared)register/URL per center via Cockpit/MCP, not as global container env

COCKPIT_CENTER_SLUG + COCKPIT_REGISTER_TOKEN per stack apply to dedicated Recast (one center = one compose stack) — not MEC “one repo per template, many domains”.

Cockpit Go-Live / UD automation vs. Recast

FeatureRender / VercelRecast (MEC)
Go-Live button registers domain at Vercel/Renderyesno (no Vercel prj_…)
UD automation sets CNAME/A to Vercel/Render targetyesmanual: A to Recast IP (UD zone can still be updated by hand/API — Cockpit target is currently Render/Vercel)
customDomain in Cockpit for by-domainyesyes — required
cockpit_dns_status (read current DNS)yesyes — checks reachability
Revalidate after publishyesyes — if websitePublicUrl + REVALIDATION_SECRET on Recast

In practice: save domain in Cockpit, point DNS at Recast IP, SSL on Recast, test under Frontend Channels. Optional MCP: cockpit_register_frontend_deployment with origin=https://www.center.de (AgencyOS key).

MEC template ↔ repo (reference)

Display namewebsiteTemplateTypical repo / GHCR image
MEC Template Rotmec-template-asmg-mec-template-a
MEC Template Hybridmec-template-dsmg-mec-template-d
MEC Grooßmec-template-groosssmg-mec-template-grooss
MEC 2mec-template-csmg-mec-template-c
MEC Grünmec-template-greensmg-mec-template-green

Org Hosting tab (vercelProjectsByTemplate) is for Vercel shared — irrelevant for Recast; GHCR image mapping on the server matters instead.

See also: v0 Recast Deploy, v0 Instructions Part G, SETUP-NOTES-for-hoster.md.

Preview vs. Live (Website URLs)

FieldPurposeUD / Go-Live
websitePublicUrlStagingPreview / Staging (e.g. *.vercel.app, staging.…)No — only revalidate & connection test
websitePublicUrlProductionLive origin (Custom Domain on Vercel)Yes — often set automatically after Go Live
websitePublicUrlLegacy (Production → Staging)Backward compatible

Deploy register: Body environment: preview | production (Vercel: VERCEL_ENV is sent).
Without environment, the origin counts as staging when the hostname is e.g. *.vercel.app, staging.…, preview.…, or v0.… — otherwise use the Preview / Staging field in the dashboard when setting URLs manually.
Migration: 20260601120000_add_website_url_staging_production_SAFE.sql (existing websitePublicUrl is split, not deleted).

Center Detail (Tab “Website Technology”), Preview and SEO Tabs: Links to the live website use the same logic — Production URL from Cockpit (websitePublicUrlProduction, Custom Domain, or Legacy websitePublicUrl). Without an entry: https://{center-slug}.cockpit-os.de (no longer mallos-center-website.onrender.com/{slug}).

Go-Live Procedure

  1. Enter and save Custom Domain(s) in the Activation tab.
  2. Choose Hosting: Cockpit Template (Render) or v0/Vercel; set Project ID / Mode in Vercel.
  3. DNS Preview (Dry-Run) — shows planned steps without changes.
  4. Execute Go Live — registers Domain at Render/Vercel, replaces conflicting A/AAAA/CNAME at UD (delrr + addrr), checks status.

UD: automatic DNS migration

Go-Live supports two United Domains APIs (auto-detected per domain):

APIEnvWhen
ResellerUD_RESELLING_*Domain/DNS zone in reseller portal (domainreselling.de)
Customer DNS APIUD_DNS_API_KEYDomain in normal UD portfolio with DNS API product

Priority: check reseller zone first, then retail portfolio. Go-Live reads the current zone and compares it to the target (Render or Vercel):

ActionWhen
Delete (delrr)Old A, AAAA, or CNAME on @ / www that does not match the Cockpit target
Add (addrr)Missing target records (Render: A @216.24.57.1, CNAME wwwmallos-center-website.onrender.com)
UntouchedMX, TXT, NS, SOA — mail and verification records stay

Dry-run lists exactly which records would be removed and added.
GET …/dns-status exposes pendingSync for what Go-Live would change.

Domains not at UD (other nameserver): manual steps in the Activation tab — UD automation does not apply.

API (Session):

  • GET /api/centers/{centerId}/dns-status
  • POST /api/centers/{centerId}/go-live-domain — Body: { "dryRun": false, "applyUdDns": true, "domains": ["example.com"] } (optional domains for preview before save; otherwise only persisted DB domains)

Expected client errors (not HTTP 500):

HTTPCodeMeaning
400NO_CUSTOM_DOMAINSNo domain saved — fill Activation tab and save website config
400VERCEL_PROJECT_MISSINGVercel mode without projectId
404CENTER_NOT_FOUNDUnknown center ID
503VERCEL_NOT_CONFIGUREDVERCEL_API_TOKEN missing in dashboard env

Troubleshooting (Go-Live steps)

StepMessageCause / fix
render:…401 UnauthorizedInvalid or expired RENDER_API_KEY on the dashboard service
render:…service not foundWrong RENDER_FRONTEND_SERVICE_ID (placeholder) — copy real ID from mallos-center-website → Settings (srv_…)
render:…Key missingSet RENDER_API_KEY and RENDER_FRONTEND_SERVICE_ID, or add domain manually in Render
ud:…Zone not foundDomain not in UD reseller or customer DNS API portfolio
ud:…fetch failedUD API unreachable from dashboard server
ud:…CNAME is not allowed for a zonenameApex needs A @ → 216.24.57.1, not CNAME @ — re-run Go-Live after dashboard deploy
verifyDNS/HTTPS activeDomain works — Render/UD errors affect automation only, not necessarily the live site

AgencyOS / MCP:

  • cockpit_dns_status
  • cockpit_go_live_domain
  • cockpit_register_frontend_deployment (with vercelProjectId, vercelProjectMode)

Org Shared Project (Super Admin):

  • UI: Organization → Hosting tab (e.g. /dashboard/organizations/mec?tab=hosting)
  • GET/PATCH /api/organizations/{slug}/hosting — body e.g.:
    {
    "vercelProjectsByTemplate": {
    "mec-template-green": "prj_…",
    "mec-template-grooss": "prj_…"
    },
    "vercelSharedProjectId": "prj_…"
    }
    (vercelSharedProjectId optional as fallback; slug or Org UUID)

Editorial: Website Live (v0 + MCP)

  1. Enter the Domain in Cockpit under Center → Website → Activationor via MCP: cockpit_update_center_website_config with top-level customDomain: "example.de" (not contentConfig). For go-live, you can also pass customDomain directly to cockpit_publish_website_live.

  2. Build in v0; when finished, in the chat (with Cockpit MCP):

    “The website is ready and should go live. Domain: example.de — please check UD and make it live.”

  3. Assistant calls cockpit_publish_website_live (dryRun: true, then false).

In the Dashboard under Frontend Channels (v0), there is the copyable chat text and a compact status (UD/DNS).

Connection Overview (Dashboard)

In the Tab Center → Website → Activation and under Website Management → Frontend Channels (v0), the Connection Overview displays at a glance:

  • Cockpit website active, layout template, Cockpit preview
  • Custom Domain / DNS / SSL (Live)
  • Hosting Render vs. Vercel, Preview URL, Live URL
  • Auto-Update (Revalidate) after Publish

Button Test checks reachability and revalidate — without database changes.

Section “DNS: where does the domain point?” (read-only, GET …/dns-status):

SourceWhat is read
PublicDNS Lookup + HTTPS — shows, e.g., on Render or Vercel
Vercel APIDomain in the project? verified?
UD ResellingQueryDNSZoneRRList — Actual records vs. Desired (Render/Vercel)

IT requirement: VERCEL_API_TOKEN, UD_RESELLING_* and/or UD_DNS_API_KEY on the Dashboard (Render).

Revalidate: Render (Multi-Center) vs. Dedicated v0 Live Domain

The Dashboard invalidates in parallel all configured targets (CENTER_WEBSITE_URL + Staging/Production URL of the Center).

TargetPath ModeExample
Cockpit Center Website on Render (mallos-center-website…)/{centerSlug}/…/allen-center-trier/shops
Own v0/Vercel Live Domain (only one Center, Root Routing)/shops, /news, .../shops on alleencenter.com
Recast / v0 template repo (MEC multi-center)/shops, /news, … (root)/shops on center-a.de — center via by-domain

If the Live Domain does not have a route POST /api/revalidate with the same REVALIDATION_SECRET, this target is logged as skipped — the Render instance will still be updated. For auto-update on the real domain: Implement the Cockpit revalidate route from the Monorepo (apps/center-website/app/api/revalidate/route.ts) into the v0 project and set Secret on Vercel.

Notes

  • UD API only updates zones hosted at UD (domain nameservers at United Domains). Conflicting A/AAAA/CNAME on @/www are replaced on Go-Live; MX/TXT are kept.
  • Domains at other providers: continue manual guidance in the Activation tab.
  • Apex Domains (.de): often A-Record instead of CNAME `@ — adopt Vercel/Render guidelines from API.

Nutzungsstatistik: Seitenaufrufe werden anonymisiert erfasst. Im Umami-Dashboard nach diesem Pfad filtern: /en/dashboard/go-live-dns-vercel-ud