Docs/ Infrastructure/ Custom Domains

Custom Domains

Connect your own domain names to sh0 apps with automatic SSL certificates and zero-downtime configuration.

Adding a Domain

Every app deployed on sh0 gets a default subdomain under *.sh0.app. To use your own domain, navigate to your app's settings and add it through the Domains panel.

  1. Open the Dashboard and select your app.
  2. Navigate to Settings → Domains.
  3. Click Add Domain and enter your domain name (e.g., example.com).
  4. sh0 will display the required DNS records to configure at your registrar.
Adding a custom domain in the sh0 dashboard
Tip
You can add both root domains (example.com) and subdomains (app.example.com). sh0 handles both seamlessly.

DNS Configuration

After adding a domain in the dashboard, you need to configure DNS records at your domain registrar (Cloudflare, Namecheap, GoDaddy, etc.). sh0 supports both A records and CNAME records.

A Record Setup

Use an A record for root domains. Point it to your sh0 server's IP address:

DNS A Record
Type: A
Name: @
Value: YOUR_SERVER_IP
TTL: 3600 (or Auto)

CNAME Setup

Use a CNAME record for subdomains. Point it to your sh0 server's hostname:

DNS CNAME Record
Type: CNAME
Name: app
Value: your-server.example.com
TTL: 3600 (or Auto)
DNS configuration panel showing required records
Note
DNS propagation can take up to 48 hours, but typically completes within a few minutes. sh0 will automatically detect when your DNS records are configured correctly.

Domain Verification

sh0 automatically verifies domain ownership by checking DNS records. The verification process works as follows:

  1. sh0 generates a unique verification token for your domain.
  2. You add the DNS record as displayed in the dashboard.
  3. sh0 periodically checks for the record (every 30 seconds).
  4. Once verified, sh0 provisions an SSL certificate and routes traffic to your app.

You can also trigger a manual check via the API:

Terminal
curl -X POST https://your-server:9000/api/domains/verify \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '[object Object]'
Domain verification status in the dashboard

Automatic SSL via Let's Encrypt

sh0 uses Caddy as its reverse proxy, which automatically obtains and renews SSL certificates from Let's Encrypt. There is nothing to configure -- once your domain is verified:

  • An HTTPS certificate is provisioned within seconds.
  • HTTP traffic is automatically redirected to HTTPS.
  • Certificates are renewed automatically before expiry (every 60 days).
  • Both RSA and ECDSA certificates are supported.
SSL certificate details for a custom domain
Tip
If you use Cloudflare as your DNS provider, set the proxy mode to DNS only (gray cloud) to let sh0 manage SSL directly. If you prefer Cloudflare's proxy (orange cloud), set the SSL mode to Full (Strict) in Cloudflare.

Wildcard Domains

Wildcard domains let you route all subdomains of a domain to a single app. This is useful for multi-tenant applications where each customer gets their own subdomain.

DNS Wildcard Record
Type: A
Name: *
Value: YOUR_SERVER_IP
TTL: 3600

In the sh0 dashboard, add the wildcard domain as *.example.com. Your application will receive the full hostname in the request headers and can route accordingly.

Warning
Wildcard SSL certificates require DNS-01 challenge validation. sh0 supports this automatically for supported DNS providers (Cloudflare, Route53, DigitalOcean). For other providers, you may need to configure the DNS challenge manually.

Domain Status Indicators

The dashboard shows a status badge for each domain. Here is what each status means:

StatusDescription
PendingDNS records have not been detected yet.
VerifyingDNS records detected, SSL certificate being provisioned.
ActiveDomain is verified, SSL is active, traffic is being routed.
ErrorSSL provisioning failed or DNS records are misconfigured.
Domain list with status indicators

Troubleshooting DNS

If your domain is stuck in Pending or Error status, try these steps:

Check your DNS records locally:

Terminal
dig example.com +short
dig CNAME app.example.com +short

Verify your server is reachable on ports 80 and 443:

Terminal
curl -I http://YOUR_SERVER_IP
curl -I https://YOUR_SERVER_IP

Common issues and solutions:

  • DNS not propagated: Wait up to 48 hours, or use a lower TTL value.
  • Firewall blocking ports 80/443: Ensure your server firewall allows inbound HTTP and HTTPS traffic.
  • Cloudflare proxy interference: Switch to DNS-only mode (gray cloud) or configure Full (Strict) SSL in Cloudflare.
  • Wrong IP address: Double-check your server's public IP with curl ifconfig.me.
  • Rate limit: Let's Encrypt has rate limits (50 certificates per domain per week). If you hit them, wait or use a staging certificate.
Danger
Never point a domain to your server before adding it in the sh0 dashboard. sh0 needs to know about the domain before it can provision an SSL certificate. Adding the DNS record first may cause certificate provisioning to fail due to missing Caddy configuration.