Custom domains, subdomains, wildcards, multi-tenant routing, and DNS setup.
# Set your domain, request TLS, deploy
nself init --domain yourdomain.com --env prod
nself ssl request --domain yourdomain.com
nself deploy prodSet BASE_DOMAIN in your environment's .env file. ɳSelf automatically creates subdomains for all services.
# .environments/dev/.env
BASE_DOMAIN=local.nself.org
# .environments/staging/.env
BASE_DOMAIN=staging.yourdomain.com
# .environments/prod/.env
BASE_DOMAIN=yourdomain.com| Subdomain | Service | Example |
|---|---|---|
api. | Hasura GraphQL | api.yourdomain.com |
auth. | Authentication | auth.yourdomain.com |
storage. | MinIO / S3 | storage.yourdomain.com |
search. | MeiliSearch | search.yourdomain.com |
admin. | Admin UI (dev only) | admin.local.nself.org |
# Replace 5.75.235.42 with your VPS IP
# Root domain
yourdomain.com A 5.75.235.42
# Backend subdomains (explicit records)
api.yourdomain.com A 5.75.235.42
auth.yourdomain.com A 5.75.235.42
storage.yourdomain.com A 5.75.235.42
# Optional: wildcard (covers all subdomains)
*.yourdomain.com A 5.75.235.42# Cloudflare dashboard or via wrangler:
# Root — proxied for CDN + DDoS protection
yourdomain.com A 5.75.235.42 [Proxied ✓]
# Backend APIs — NOT proxied (WebSocket + real IP needed)
api.yourdomain.com A 5.75.235.42 [DNS only]
auth.yourdomain.com A 5.75.235.42 [DNS only]
# Frontend apps — proxied
app.yourdomain.com A 5.75.235.42 [Proxied ✓]Hasura WebSocket subscriptions require a direct connection. Set api.yourdomain.com to DNS-only (grey cloud) in Cloudflare, not proxied (orange cloud). Proxied mode breaks GraphQL subscriptions.
nself prod check --item dns --domain yourdomain.com
# Manual check
dig A yourdomain.com +short # should return VPS IP
dig A api.yourdomain.com +short # should return VPS IP
# Check from multiple locations
curl https://dnschecker.org/api/dns/yourdomain.comRoute external frontend apps (Next.js, React, etc.) through your nself domain:
# In .environments/prod/.env:
# Frontend app routing — point subdomains to external services
FRONTEND_APP_1=app.yourdomain.com -> https://your-app.vercel.app
FRONTEND_APP_2=docs.yourdomain.com -> https://your-docs.vercel.app
# Or to a local port (app running on same server)
FRONTEND_APP_3=dashboard.yourdomain.com -> localhost:3000Route custom backend services (your own Docker containers) through nself's Nginx:
# In .environments/prod/.env:
# Custom service routing (CS_1..CS_10)
CS_1_NAME=myapi
CS_1_ROUTE=myapi.yourdomain.com
CS_1_PORT=8001
CS_1_IMAGE=myorg/myapi:latest
# Rebuild to apply custom service config
nself build
nself startFor SaaS deployments where each customer gets their own subdomain:
# In .environments/prod/.env:
MULTI_TENANT=true
TENANT_SUBDOMAIN_PATTERN=*.yourdomain.com
# DNS: add a wildcard A record
*.yourdomain.com A 5.75.235.42
# Tenant isolation is enforced at the Hasura layer via tenant_id.
# See: /architecture for the multi-tenant conventions.
# SSL: wildcard cert required
nself ssl request --domain "*.yourdomain.com" --challenge dns --dns-provider cloudflareBy default, local dev uses *.local.nself.org, which resolves to 127.0.0.1 via a public Cloudflare DNS record. No hosts file editing needed.
# Verify the resolution
dig A api.local.nself.org +short
# Expected: 127.0.0.1
# Use a custom local domain instead
BASE_DOMAIN=local.mycompany.com
# Add to /etc/hosts (or use a local DNS resolver like dnsmasq):
127.0.0.1 local.mycompany.com
127.0.0.1 api.local.mycompany.com
127.0.0.1 auth.local.mycompany.com# 1. Update BASE_DOMAIN in .env
nself env set BASE_DOMAIN newdomain.com
# 2. Request TLS certificate for new domain
nself ssl request --domain newdomain.com
# 3. Rebuild Nginx config
nself build
# 4. Deploy
nself deploy prod
# 5. Update DNS to point to your VPS IP
# (propagation: up to 48h, usually < 5 min)# Check all domain routing
nself prod check --item dns
# Test a specific subdomain
curl -I https://api.yourdomain.com/v1/version
# View Nginx routing table
nself service exec nginx nginx -T | grep server_name
# Check which cert is being served
openssl s_client -connect yourdomain.com:443 -servername yourdomain.com 2>/dev/null | openssl x509 -noout -subject -dates