Hosting & Custom Domains

Publish static or fullstack apps, connect a custom domain, configure DNS, and verify automatic TLS

Gencow can host a frontend by itself or serve it with a Gencow backend. Every cloud app receives a managed *.gencow.app URL. Personal and Pro plans can also connect a domain that you own.

Choose a Hosting Mode

Build the frontend before publishing it. For new apps, use Vite + React unless you specifically need a server-rendered framework.

App shape Command What Gencow publishes
Static frontend gencow static dist/ Frontend files only
Fullstack app gencow deploy --static dist/ Backend first, then frontend files
Backend only gencow deploy Gencow backend without frontend files

Add --prod only when the user or operator explicitly requested the separate production app. A generic request to deploy still means the default development target:

bun run build
gencow deploy --static --prod dist/

Production deploys and custom domains are available on Personal and Pro plans. See Cloud Plan Limits for the complete matrix.

Before Connecting a Domain

Confirm all of the following:

  1. The production app exists. Static files or a running backend are not required for ownership verification.
  2. You can edit DNS records for the domain.
  3. You have chosen one canonical hostname, such as www.example.com or example.com.
  4. You are viewing or targeting the production app. New DEV-app bindings are not allowed.

For the simplest DNS setup, use a subdomain such as www.example.com. It can point directly to the app with a standard CNAME record.

Connect in the Dashboard

  1. Open the app in the Gencow Dashboard.
  2. Select Production with the app-level environment switcher.
  3. Open Hosting.
  4. In Custom Domain, confirm that the displayed environment and app name are the target you intend to publish.
  5. Enter the hostname without a scheme or path, for example www.example.com.
  6. Select Connect.
  7. Add the exact DNS record displayed by the Dashboard.
  8. Return to Hosting and select Recheck ownership until HTTP ownership and TLS are active.

The Development Hosting page is read-only for custom domains. Existing legacy DEV bindings are shown as disabled and can only be removed. They do not serve traffic, request certificates, recheck ownership, or show DNS setup guidance.

Connect with the CLI

Connect a www hostname to a production app:

gencow domain set www.example.com --prod

domain set requires --prod and stops before making a network request when it is omitted. Status and remove still accept a DEV target for legacy cleanup.

Preview the target and required DNS records without changing anything:

gencow domain set www.example.com --prod --dry-run

If the same domain is attached to another production app owned by the same account, preview the move first and then confirm it:

gencow domain set www.example.com --prod --dry-run
gencow domain set www.example.com --prod --yes

Use --app <name> only when intentionally targeting an app other than the one in the local gencow.json.

Configure DNS

Use the exact target printed by the Dashboard or CLI. Examples below use my-app-prod.gencow.app; your target will be different.

Subdomain or www

Create a CNAME record:

Type Name Value
CNAME www my-app-prod.gencow.app

Some DNS providers expect the full hostname (www.example.com) in the Name field. Others expect only the label (www). Follow the provider's convention.

A directly connected www.example.com hostname is canonical. Gencow serves it directly and does not redirect it to example.com.

Apex Domain

For example.com, use one of the apex-compatible records printed by Gencow:

Type Name Value
ALIAS / ANAME / CNAME flattening @ my-app-prod.gencow.app
A fallback @ Stable edge IP printed by Gencow

Prefer ALIAS, ANAME, or CNAME flattening when the DNS provider supports it. Otherwise, use the current stable edge IP shown by the Dashboard or CLI. Do not copy an IP address from an old guide or another project.

Create the binding operation before changing DNS. If an unregistered hostname already routes to Gencow, it is quarantined for review to prevent dangling-domain takeover. A reverse proxy such as Cloudflare may remain enabled as long as it forwards the exact host and /.well-known/gencow-domain-verification response.

If Gencow cannot establish the pre-connection routing baseline because DNS or HTTP observation is unavailable, the request returns a retryable error and does not create a binding. This prevents a temporary network failure from being mistaken for proof that the hostname was not already routed to Gencow.

Verify HTTP Ownership and TLS

DNS changes can take time to propagate. Check the selected environment:

gencow domain status --prod

For a legacy DEV binding, gencow domain status reports the binding as disabled so that it can be inspected before removal. It never reports HTTP verified or HTTPS ready.

The domain moves through these states:

State Meaning Action
pending_http The common Gencow Edge has not returned the current operation marker yet Check A/CNAME routing and retry status
pending_tls HTTP ownership is verified and certificate provisioning is in progress Wait and retry status
active HTTP ownership and TLS readiness are verified Open the HTTPS URL

An expired pending_http challenge is refreshed in place. Retrying domain set or domain status keeps the same binding operation and generation instead of deleting and recreating the claim. A verifier timeout after the binding exists leaves it in pending_http; it does not turn the timeout into success.

Gencow answers /.well-known/gencow-domain-verification at the common Edge, so the flow is identical for static, backend-only, fullstack, stopped, and not-yet- deployed production apps. You do not upload a challenge file or create a TXT record. TLS certificates are provisioned automatically after ownership is verified.

After the status becomes active, verify both the page and the intended app:

curl -I https://www.example.com

If dev and production contain visibly different builds, confirm that the custom domain serves the production build before sharing it publicly.

Same-Origin Auth and APIs

An active custom domain is a Gencow-managed app origin. Frontend pages, API requests, authentication callbacks, and realtime connections can use the same origin.

Do not add an active custom domain to frontendOrigins. Gencow adds managed app origins and active custom domains automatically. Use frontendOrigins only when the frontend is hosted outside Gencow, such as on Vercel or Netlify.

When a frontend build embeds an absolute API URL, build it for the intended public origin before publishing:

VITE_API_URL=https://www.example.com bun run build
gencow deploy --static --prod dist/

Move or Remove a Domain

Move a domain between production apps only after checking which build should receive public traffic:

gencow domain set www.example.com --prod --dry-run
gencow domain set www.example.com --prod --yes

Disconnect a production domain:

gencow domain remove --prod

Disconnect a dev domain:

gencow domain remove

Removing a domain stops Gencow from routing it to the app. Remove or update the DNS record separately at your DNS provider.

Troubleshooting

Symptom Check
Status stays pending_http Compare the public A/CNAME route with the value shown by gencow domain status; confirm port 80 and the exact well-known path reach Gencow
www redirects unexpectedly Connect www.example.com directly if it should be canonical; a non-connected www may fall back to an active apex domain
DEV page has no Connect control This is intentional; open the production app or deploy production first
TLS is not ready Confirm DNS is active first, then retry the HTTPS URL after certificate provisioning
Login or API requests use another origin Rebuild the frontend with the custom-domain base URL and use one shared base URL for auth and the Gencow client
Rebind asks for confirmation Run --dry-run, verify the source and target apps, then use --yes only for the intended move

Official Gencow domains such as gencow.app, gencow.dev, and gencow.com are not self-service custom domains.