Connect a Domain
Section titled “Connect a Domain”Point a domain you own, such as api.mycompany.com, at a container’s HTTP service with a single DNS record. The proxy issues and renews the TLS certificate for it.
Custom domains build on proxy aliases: the alias URL is what your CNAME record points at.
API Endpoints Summary
Section titled “API Endpoints Summary”A custom domain reaches a container through a DNS CNAME to a proxy alias, so the DNS side involves no API call at all. The alias itself is managed through these endpoints:
Alias management (CNAME targets):
- POST /api/v1/proxy/aliases - Create alias (used as CNAME target)
- GET /api/v1/proxy/aliases - List your aliases
- GET /api/v1/proxy/aliases/{id} - Get alias details
- PATCH /api/v1/proxy/aliases/{id} - Update alias configuration
- PATCH /api/v1/proxy/aliases/{id}/state - Enable or disable an alias
- DELETE /api/v1/proxy/aliases/{id} - Delete alias
SSL and domains:
- The proxy requests a certificate on its own once it sees a CNAME pointing at your alias
- No API call is involved in that step; you only add the DNS record
- Let’s Encrypt certificates are valid for 90 days and renewed automatically once 30 days remain
The flow in three steps
Section titled “The flow in three steps”1. Create a proxy alias → my-app.node-us.containers.hoody.com2. CNAME your domain to the alias → api.mycompany.com → my-app.node-us.containers.hoody.com3. SSL certificate automatically provisioned → https://api.mycompany.com (live)Your side of it is one DNS record. The proxy issues and renews the certificate; there is no certificate, port, or reverse-proxy step on your side.
The CNAME target pattern
Section titled “The CNAME target pattern”A custom domain points at a proxy alias, never at a container URL directly.
Step 1: Create the alias (CNAME target)
# Create alias as CNAME target for your custom domainhoody proxy create --container-id $CONTAINER_ID --alias myapp-prod --program http --port 3000const alias = await client.api.proxyAliases.create({ container_id: CONTAINER_ID, alias: 'myapp-prod', program: 'http', port: 3000});console.log(alias.data.url);// https://myapp-prod.node-us.containers.hoody.comcurl -X POST "https://api.hoody.com/api/v1/proxy/aliases" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "container_id": "'$CONTAINER_ID'", "alias": "myapp-prod", "program": "http", "port": 3000 }'One request, one link
cURL runs inside your container and can wrap any HTTP request into a single GET URL. The call stops being something you need a client for and becomes something you can paste into a browser, send in a chat, bookmark, schedule with cron, or drop into a no-code tool.
Nothing is installed on the machine that opens it. The link does carry whatever credentials the call needs, so treat it as you would treat those credentials.
Slashes, colons and braces pass through as they are. The one character you must
encode is an & inside a value, which happens when the wrapped URL
carries its own query string. Left raw it ends the value early, and the rest is
read as cURL's own parameters, so you get a 200 on a request you did
not make.
How the wrapping works Chaining calls into one link Turning a link into a shortcut
Creates the alias that becomes your CNAME target. The response’s url field is the address you point your domain’s CNAME record at.
https://PROJECT_ID-CONTAINER_ID-curl-1.SERVER.containers.hoody.com/api/v1/curl/request?url=https://api.hoody.com/api/v1/proxy/aliases&method=POST&bearer_token=TOKEN&json={"container_id":"CONTAINER_ID","alias":"myapp-prod","program":"http","port":3000}&response=transparent The link carries a credential and executes with it, so it is as sensitive as the credential itself — and it passes through the cURL service's request log on the way, not just the target's. Share it only where you would share the secret, and prefer a delegated token with minimal permissions and an expiry: see API tokens.
Gives you: https://myapp-prod.node-us.containers.hoody.com
Step 2: Add CNAME record at your DNS provider
api.mycompany.com CNAME myapp-prod.node-us.containers.hoody.comStep 3: Automatic SSL
Hoody detects the CNAME, provisions a Let’s Encrypt certificate for api.mycompany.com, and routes traffic:
User requests:https://api.mycompany.com ↓ (DNS CNAME)https://myapp-prod.node-us.containers.hoody.com ↓ (Hoody Proxy routes)Container's HTTP serviceWithin 5-10 minutes: the domain serves your container over HTTPS.
Full setup walkthrough
Section titled “Full setup walkthrough”Prerequisites
Section titled “Prerequisites”You need:
- A proxy alias (create via
POST /api/v1/proxy/aliases) - Access to your domain’s DNS settings
- Your server name (e.g.,
node-us,node-eu)
Supported subdomain setup
Section titled “Supported subdomain setup”A custom domain must be a subdomain with a genuine CNAME. Root domains are not supported.
# Create the CNAME target aliashoody proxy create --container-id $CONTAINER_ID \ --alias production-api --program http --port 3000 \ --target-path /api/v1 --allow-path-overrideconst alias = await client.api.proxyAliases.create({ container_id: CONTAINER_ID, alias: 'production-api', program: 'http', port: 3000, target_path: '/api/v1', allow_path_override: true});curl -X POST "https://api.hoody.com/api/v1/proxy/aliases" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "container_id": "'$CONTAINER_ID'", "alias": "production-api", "program": "http", "port": 3000, "target_path": "/api/v1", "allow_path_override": true }'One request, one link
cURL runs inside your container and can wrap any HTTP request into a single GET URL. The call stops being something you need a client for and becomes something you can paste into a browser, send in a chat, bookmark, schedule with cron, or drop into a no-code tool.
Nothing is installed on the machine that opens it. The link does carry whatever credentials the call needs, so treat it as you would treat those credentials.
Slashes, colons and braces pass through as they are. The one character you must
encode is an & inside a value, which happens when the wrapped URL
carries its own query string. Left raw it ends the value early, and the rest is
read as cURL's own parameters, so you get a 200 on a request you did
not make.
How the wrapping works Chaining calls into one link Turning a link into a shortcut
Creates the CNAME target alias. A bare root request lands on /api/v1; other paths are forwarded to the container unchanged.
https://PROJECT_ID-CONTAINER_ID-curl-1.SERVER.containers.hoody.com/api/v1/curl/request?url=https://api.hoody.com/api/v1/proxy/aliases&method=POST&bearer_token=TOKEN&json={"container_id":"CONTAINER_ID","alias":"production-api","program":"http","port":3000,"target_path":"/api/v1","allow_path_override":true}&response=transparent The link carries a credential and executes with it, so it is as sensitive as the credential itself — and it passes through the cURL service's request log on the way, not just the target's. Share it only where you would share the secret, and prefer a delegated token with minimal permissions and an expiry: see API tokens.
Result: production-api.node-us.containers.hoody.com
Verify it works:
curl https://production-api.node-us.containers.hoody.com# Should return your service responseAt your DNS provider (Cloudflare, Route53, Namecheap, etc.):
Type: CNAMEName: apiValue: production-api.node-us.containers.hoody.comTTL: Auto (or 3600)This creates:
api.mycompany.com → production-api.node-us.containers.hoody.comDNS propagation takes 5-60 minutes.
Check propagation:
# See if DNS has updateddig api.mycompany.com
# Should show:# api.mycompany.com. 300 IN CNAME production-api.node-us.containers.hoody.com.Or use online tools:
- https://www.whatsmydns.net
- Check from multiple locations globally
Hoody detects the CNAME and provisions the certificate without being asked.
On the first request:
- Hoody sees
Host: api.mycompany.com - Recognizes the CNAME pointing at the alias
- Requests a Let’s Encrypt certificate
- Certificate issued (30-60 seconds)
- HTTPS enabled automatically
That first request may take 30-60 seconds while the certificate is issued.
After that: HTTPS is immediate. Certificates are valid for 90 days and renewed automatically once 30 days remain.
Test:
curl https://api.mycompany.com# Should return your service with valid SSLThe domain now routes to your container over HTTPS.
Path routing
Section titled “Path routing”An alias can point your domain at a specific path inside the container, not only at the root.
Routing without a reverse proxy
Section titled “Routing without a reverse proxy”Traditional hosting:
Your domain points to server root only:api.mycompany.com → /
Problem: Your API is at /api/v1/, but domain points to /You’d need:
- Reverse proxy setup (nginx/Apache configuration)
- URL rewrite rules
- Server restarts
- Complex routing logic
- Configuration file management
With Hoody:
Then CNAME your domain:
api.mycompany.com CNAME myapp-api.node-us.containers.hoody.comResult:
User requests: https://api.mycompany.com/usersProxy routes: Container's /api/v1/users
The alias setting does the rewriting; no server config, no reverse proxy.Real-world use cases
Section titled “Real-world use cases”Use case 1: microservices on one container
# One container serves:# - Frontend at /# - API at /api/v1# - Admin panel at /admin
# Create 3 aliases, each targeting different pathPOST /api/v1/proxy/aliases{ "container_id": "CONTAINER_ID", "alias": "app-frontend", "program": "http", "port": 3000, "target_path": "/", "allow_path_override": false }
POST /api/v1/proxy/aliases{ "container_id": "CONTAINER_ID", "alias": "app-api", "program": "http", "port": 3000, "target_path": "/api/v1", "allow_path_override": false }
POST /api/v1/proxy/aliases{ "container_id": "CONTAINER_ID", "alias": "app-admin", "program": "http", "port": 3000, "target_path": "/admin", "allow_path_override": false }
# Point 3 domains to same containerwww.mycompany.com CNAME app-frontend.node-us.containers.hoody.comapi.mycompany.com CNAME app-api.node-us.containers.hoody.comadmin.mycompany.com CNAME app-admin.node-us.containers.hoody.comRouting:
www.mycompany.com/about→ Container’s/aboutapi.mycompany.com/users→ Container’s/api/v1/usersadmin.mycompany.com/dashboard→ Container’s/admin/dashboard
One container, three domains, three isolated path spaces, and no nginx config.
Use case 2: API versioning
# Container serves both v1 and v2 at different paths:# /api/v1/*# /api/v2/*
# Create version-specific aliasesPOST /api/v1/proxy/aliases{ "container_id": "CONTAINER_ID", "alias": "api-v1", "program": "http", "port": 3000, "target_path": "/api/v1", "allow_path_override": false }
POST /api/v1/proxy/aliases{ "container_id": "CONTAINER_ID", "alias": "api-v2", "program": "http", "port": 3000, "target_path": "/api/v2", "allow_path_override": false }
# Point domainsv1.api.mycompany.com CNAME api-v1.node-us.containers.hoody.comv2.api.mycompany.com CNAME api-v2.node-us.containers.hoody.comUsers call:
v1.api.mycompany.com/endpoint→/api/v1/endpointv2.api.mycompany.com/endpoint→/api/v2/endpoint
One container serves both versions, each on its own domain.
Use case 3: multi-tenant SaaS
# Container organized by tenant:# /tenant/acme/*# /tenant/globex/*# /tenant/initech/*
# Alias per customerPOST /api/v1/proxy/aliases{ "container_id": "CONTAINER_ID", "alias": "acme", "program": "http", "port": 3000, "target_path": "/tenant/acme", "allow_path_override": false }
POST /api/v1/proxy/aliases{ "container_id": "CONTAINER_ID", "alias": "globex", "program": "http", "port": 3000, "target_path": "/tenant/globex", "allow_path_override": false }
# Customer domainsacme.myapp.com CNAME acme.node-us.containers.hoody.comglobex.myapp.com CNAME globex.node-us.containers.hoody.comEach customer gets a domain that routes to their tenant path, and one container serves all of them.
Compared with an nginx config
Section titled “Compared with an nginx config”Traditional routing (nginx/Apache):
# Write config fileserver { server_name api.mycompany.com; location / { proxy_pass http://localhost:3000/api/v1; rewrite rules... header manipulation... }}
# Test confignginx -t
# Restart server (downtime risk)systemctl restart nginx
# Verify production still serves trafficHoody routing (one API call):
# Create alias with path routing; live immediately, no restarthoody proxy create --container-id $CONTAINER_ID \ --alias my-api --program http --port 3000 --target-path /api/v1// One call, live immediately, no restartawait client.api.proxyAliases.create({ container_id: CONTAINER_ID, alias: 'my-api', program: 'http', port: 3000, target_path: '/api/v1'});curl -X POST "https://api.hoody.com/api/v1/proxy/aliases" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "container_id": "'$CONTAINER_ID'", "alias": "my-api", "program": "http", "port": 3000, "target_path": "/api/v1" }'One request, one link
cURL runs inside your container and can wrap any HTTP request into a single GET URL. The call stops being something you need a client for and becomes something you can paste into a browser, send in a chat, bookmark, schedule with cron, or drop into a no-code tool.
Nothing is installed on the machine that opens it. The link does carry whatever credentials the call needs, so treat it as you would treat those credentials.
Slashes, colons and braces pass through as they are. The one character you must
encode is an & inside a value, which happens when the wrapped URL
carries its own query string. Left raw it ends the value early, and the rest is
read as cURL's own parameters, so you get a 200 on a request you did
not make.
How the wrapping works Chaining calls into one link Turning a link into a shortcut
Creates an alias routed at /api/v1, live immediately with no restart.
https://PROJECT_ID-CONTAINER_ID-curl-1.SERVER.containers.hoody.com/api/v1/curl/request?url=https://api.hoody.com/api/v1/proxy/aliases&method=POST&bearer_token=TOKEN&json={"container_id":"CONTAINER_ID","alias":"my-api","program":"http","port":3000,"target_path":"/api/v1"}&response=transparent The link carries a credential and executes with it, so it is as sensitive as the credential itself — and it passes through the cURL service's request log on the way, not just the target's. Share it only where you would share the secret, and prefer a delegated token with minimal permissions and an expiry: see API tokens.
The alias takes effect immediately, with no restart and no downtime.
Root domains (not supported)
Section titled “Root domains (not supported)”Root domains (like mycompany.com without a subdomain) cannot be connected, because CNAME records aren’t allowed at the DNS root by RFC standards and Hoody’s SSL provisioning is CNAME-only.
ALIAS and ANAME records do not work
Section titled “ALIAS and ANAME records do not work”Hoody’s automatic SSL resolves your domain by following a real CNAME record to <alias>.<serverName>.containers.hoody.com. ALIAS and ANAME records are flattened to A records by your DNS provider, so Hoody’s resolvers never see a CNAME, no certificate is issued, and the root domain never comes up over HTTPS.
Use a subdomain
Section titled “Use a subdomain”Point a subdomain at the alias instead, such as www.mycompany.com or app.mycompany.com:
Type: CNAMEName: wwwValue: production-api.node-us.containers.hoody.comThen add a redirect from root to subdomain at your DNS provider.
Multiple domains for one container
Section titled “Multiple domains for one container”Several domains can share one alias:
# 1. Create one aliasPOST /api/v1/proxy/aliases{ "container_id": "CONTAINER_ID", "alias": "prod-api", "program": "http", "port": 3000 }
# 2. CNAME multiple domains to itapi.mycompany.com CNAME prod-api.node-us.containers.hoody.comapi.mybrand.com CNAME prod-api.node-us.containers.hoody.comapi-v2.oldcompany.com CNAME prod-api.node-us.containers.hoody.comAll three domains route to the same container service, and Hoody provisions a certificate for each one automatically.
Use cases:
- Multiple brand domains pointing to the same backend
- API versioning (api-v1.com, api-v2.com)
- Regional domains (api.mycompany.eu, api.mycompany.com)
Domain migration
Section titled “Domain migration”Migration from another platform
Section titled “Migration from another platform”Move an existing domain to Hoody without taking it offline:
# Deploy your app to Hoody container# Create aliasPOST /api/v1/proxy/aliases{ "container_id": "CONTAINER_ID", "alias": "myapp-prod", "program": "http", "port": 3000 }
# Test via alias URL firstcurl https://myapp-prod.node-us.containers.hoody.com# Verify everything works# Add temporary test subdomaintest.mycompany.com CNAME myapp-prod.node-us.containers.hoody.com
# Verify SSL provisioning workscurl https://test.mycompany.com# Wait for certificate (30-60 seconds first request)# When ready, update production CNAMEapi.mycompany.com CNAME myapp-prod.node-us.containers.hoody.com
# Old:# api.mycompany.com A 203.0.113.50 (old server)
# New:# api.mycompany.com CNAME myapp-prod.node-us.containers.hoody.com# Watch DNS propagationwatch -n 5 "dig api.mycompany.com | grep CNAME"
# Monitor traffic on new container# Check logs in container's terminalDowntime: Minimal (DNS TTL period, usually 5 minutes or less)
The same domain on a new container
Section titled “The same domain on a new container”There are two ways to change which container a domain reaches.
Option A: Recreate the alias under the same name (points to different container)
The container_id of an existing alias is immutable: PATCH only updates program, port, index, target_path, allow_path_override, expires_at, enabled, and the alias name. To repoint to a different container, delete the alias and recreate it with the same alias name. The CNAME target is unchanged, so no DNS edit is required.
# Instant switch: delete, then recreate under the same alias namehoody proxy delete $ALIAS_ID --yeshoody proxy create --container-id $NEW_CONTAINER_ID \ --alias production-api --program http --port 3000// Instant switch: DNS unchanged, same alias name on the new containerawait client.api.proxyAliases.delete(ALIAS_ID);await client.api.proxyAliases.create({ container_id: NEW_CONTAINER_ID, alias: 'production-api', program: 'http', port: 3000});curl -X DELETE "https://api.hoody.com/api/v1/proxy/aliases/$ALIAS_ID" \ -H "Authorization: Bearer $TOKEN"
curl -X POST "https://api.hoody.com/api/v1/proxy/aliases" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"container_id": "'$NEW_CONTAINER_ID'", "alias": "production-api", "program": "http", "port": 3000}'One request, one link
cURL runs inside your container and can wrap any HTTP request into a single GET URL. The call stops being something you need a client for and becomes something you can paste into a browser, send in a chat, bookmark, schedule with cron, or drop into a no-code tool.
Nothing is installed on the machine that opens it. The link does carry whatever credentials the call needs, so treat it as you would treat those credentials.
Slashes, colons and braces pass through as they are. The one character you must
encode is an & inside a value, which happens when the wrapped URL
carries its own query string. Left raw it ends the value early, and the rest is
read as cURL's own parameters, so you get a 200 on a request you did
not make.
How the wrapping works Chaining calls into one link Turning a link into a shortcut
Delete removes the old alias, then Recreate reissues the same alias name on the new container. The CNAME target is unchanged, so no DNS edit is needed.
# Delete
https://PROJECT_ID-CONTAINER_ID-curl-1.SERVER.containers.hoody.com/api/v1/curl/request?url=https://api.hoody.com/api/v1/proxy/aliases/ALIAS_ID&method=DELETE&bearer_token=TOKEN&response=transparent
# Recreate
https://PROJECT_ID-CONTAINER_ID-curl-1.SERVER.containers.hoody.com/api/v1/curl/request?url=https://api.hoody.com/api/v1/proxy/aliases&method=POST&bearer_token=TOKEN&json={"container_id":"NEW_CONTAINER_ID","alias":"production-api","program":"http","port":3000}&response=transparent The link carries a credential and executes with it, so it is as sensitive as the credential itself — and it passes through the cURL service's request log on the way, not just the target's. Share it only where you would share the secret, and prefer a delegated token with minimal permissions and an expiry: see API tokens.
DNS is unchanged. Reusing the same alias name keeps the CNAME target valid, so the domain starts routing to the new container immediately.
Option B: Create new alias, update CNAME
# Create new alias for the new containerhoody proxy create --container-id $NEW_CONTAINER_ID --alias myapp-v2 --program http --port 3000await client.api.proxyAliases.create({ alias: 'myapp-v2', container_id: NEW_CONTAINER_ID, program: 'http', port: 3000});curl -X POST "https://api.hoody.com/api/v1/proxy/aliases" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"alias": "myapp-v2", "container_id": "'$NEW_CONTAINER_ID'", "program": "http", "port": 3000}'One request, one link
cURL runs inside your container and can wrap any HTTP request into a single GET URL. The call stops being something you need a client for and becomes something you can paste into a browser, send in a chat, bookmark, schedule with cron, or drop into a no-code tool.
Nothing is installed on the machine that opens it. The link does carry whatever credentials the call needs, so treat it as you would treat those credentials.
Slashes, colons and braces pass through as they are. The one character you must
encode is an & inside a value, which happens when the wrapped URL
carries its own query string. Left raw it ends the value early, and the rest is
read as cURL's own parameters, so you get a 200 on a request you did
not make.
How the wrapping works Chaining calls into one link Turning a link into a shortcut
Creates a new alias for the new container. This changes the CNAME target, so you wait out propagation again after updating DNS.
https://PROJECT_ID-CONTAINER_ID-curl-1.SERVER.containers.hoody.com/api/v1/curl/request?url=https://api.hoody.com/api/v1/proxy/aliases&method=POST&bearer_token=TOKEN&json={"alias":"myapp-v2","container_id":"NEW_CONTAINER_ID","program":"http","port":3000}&response=transparent The link carries a credential and executes with it, so it is as sensitive as the credential itself — and it passes through the cURL service's request log on the way, not just the target's. Share it only where you would share the secret, and prefer a delegated token with minimal permissions and an expiry: see API tokens.
Then update DNS:
api.mycompany.com CNAME myapp-v2.node-us.containers.hoody.comThis changes the CNAME target, so you wait out propagation again (5-60 minutes).
Recommendation: Use Option A (recreate under the same name) for instant switching.
SSL certificate management
Section titled “SSL certificate management”Automatic provisioning
Section titled “Automatic provisioning”The proxy handles issuance and renewal:
- Detection: Proxy sees request for your custom domain
- Challenge: Hoody responds to the ACME HTTP-01 challenge automatically
- Issuance: Certificate issued by Let’s Encrypt (30-60 seconds)
- Installation: Certificate installed and activated
- Renewal: Auto-renewed before expiry
Certificate details
Section titled “Certificate details”Each issued certificate:
- Certificate authority: Let’s Encrypt
- Validation method: ACME HTTP-01 challenge (automatic)
- Certificate type: Domain Validation (DV)
- Validity: 90 days (auto-renews before expiry)
- Coverage: Your exact domain (e.g.,
api.mycompany.com)
HTTPS enforcement:
- HTTP requests for platform domains and custom domains with an issued certificate → Automatic redirect to HTTPS (301); unrecognized or not-yet-issued custom domains return 400, while ACME HTTP-01 challenge requests are served over HTTP
- HSTS is not set by the proxy. Send
Strict-Transport-Securityfrom your own application if you want it
Wildcard certificates
Section titled “Wildcard certificates”For wildcard subdomains (*.api.mycompany.com):
DNS provider examples
Section titled “DNS provider examples”Cloudflare
Section titled “Cloudflare”Type: CNAMEName: apiValue: myapp-prod.node-us.containers.hoody.comProxy: OFF (DNS only, not proxied through Cloudflare)TTL: AutoImportant: Turn off Cloudflare’s proxy (the orange cloud icon) so traffic reaches Hoody directly.
AWS Route53
Section titled “AWS Route53”Type: CNAMEName: api.mycompany.comValue: myapp-prod.node-us.containers.hoody.comTTL: 300Routing Policy: SimpleGoogle Domains
Section titled “Google Domains”Type: CNAMEHost: apiData: myapp-prod.node-us.containers.hoody.comTTL: 1hNamecheap
Section titled “Namecheap”Type: CNAME RecordHost: apiValue: myapp-prod.node-us.containers.hoody.comTTL: AutomaticMulti-domain strategies
Section titled “Multi-domain strategies”API and dashboard on one container
Section titled “API and dashboard on one container”One container can serve several interfaces, each on its own domain:
# Create two aliases for different pathsPOST /api/v1/proxy/aliases{ "container_id": "CONTAINER_ID", "alias": "api-backend", "program": "http", "port": 3000, "target_path": "/api/v1", "allow_path_override": false}
POST /api/v1/proxy/aliases{ "container_id": "CONTAINER_ID", "alias": "admin-dashboard", "program": "http", "port": 3000, "target_path": "/admin", "allow_path_override": false}
# CNAME different domainsapi.mycompany.com CNAME api-backend.node-us.containers.hoody.comadmin.mycompany.com CNAME admin-dashboard.node-us.containers.hoody.comResult:
api.mycompany.com→ Container’s/api/v1/*onlyadmin.mycompany.com→ Container’s/admin/*only- Same container, different domain access, isolated paths
Frontend and backend in separate containers
Section titled “Frontend and backend in separate containers”Two containers, one domain each:
# Frontend container aliasPOST /api/v1/proxy/aliases{ "alias": "frontend", "container_id": "FRONTEND_ID", "program": "http", "port": 3000 }
# Backend container aliasPOST /api/v1/proxy/aliases{ "alias": "backend", "container_id": "BACKEND_ID", "program": "http", "port": 3000 }
# DNS configurationwww.mycompany.com CNAME frontend.node-us.containers.hoody.comapi.mycompany.com CNAME backend.node-us.containers.hoody.comEach domain routes to a different container.
Regional containers behind one domain
Section titled “Regional containers behind one domain”The same application in more than one region:
# US containerPOST /api/v1/proxy/aliases{ "alias": "app-us", "container_id": "US_CONTAINER", "program": "http", "port": 3000 }
# EU containerPOST /api/v1/proxy/aliases{ "alias": "app-eu", "container_id": "EU_CONTAINER", "program": "http", "port": 3000 }
# DNS with GeoDNS routingapi.mycompany.com → (US users) → app-us.node-us.containers.hoody.comapi.mycompany.com → (EU users) → app-eu.node-eu.containers.hoody.comUse your DNS provider’s GeoDNS feature to route users to the nearest container.
Deployment patterns
Section titled “Deployment patterns”Blue-green deployment
Section titled “Blue-green deployment”Switch versions at the DNS layer, without downtime:
# Blue (current production)POST /api/v1/proxy/aliases{ "alias": "blue", "container_id": "CURRENT_CONTAINER", "program": "http", "port": 3000 }
# Deploy to green (new version)POST /api/v1/projects/{id}/containers{ "name": "green", ... }
# Create green aliasPOST /api/v1/proxy/aliases{ "alias": "green", "container_id": "NEW_CONTAINER", "program": "http", "port": 3000 }
# Test green environmentcurl https://green.node-us.containers.hoody.com
# Switch production (update CNAME)api.mycompany.com CNAME green.node-us.containers.hoody.com# (was: blue.node-us.containers.hoody.com)
# After DNS propagation (5-10 min), all traffic on new version
# Keep blue for rollback# If issues: Revert CNAME back to blue.node-us.containers.hoody.comCanary deployment
Section titled “Canary deployment”Use DNS weighting, if your provider supports it:
api.mycompany.com CNAME stable.node-us.containers.hoody.com (Weight: 90%)api.mycompany.com CNAME canary.node-us.containers.hoody.com (Weight: 10%)That sends 10% of users to the canary version. Monitor it, then shift the weight gradually.
SSL certificate verification
Section titled “SSL certificate verification”Certificate status
Section titled “Certificate status”Once the CNAME resolves:
# Check SSL certificateopenssl s_client -showcerts -connect api.mycompany.com:443 -servername api.mycompany.com
# Should show:# issuer=C = US, O = Let's Encrypt, CN = R3# subject=CN = api.mycompany.comOr via browser:
- Visit
https://api.mycompany.com - Click padlock icon
- View certificate details
- Verify: Issued by Let’s Encrypt, Valid for your domain
Certificate renewal
Section titled “Certificate renewal”- Hoody scans certificates for expiry every 6 hours
- Renewal triggers below the configured remaining-lifetime threshold, 30 days by default (out of 90)
- New certificate issued and installed automatically
- No downtime, no intervention needed
You never create or renew a certificate yourself.
Useful questions
Section titled “Useful questions”Must I create a proxy alias first?
Section titled “Must I create a proxy alias first?”Yes. A custom domain reaches a container through a proxy alias, so create the alias first, take its URL, and CNAME your domain to that URL. You cannot CNAME directly to cryptographic container URLs.
How long does DNS propagation take?
Section titled “How long does DNS propagation take?”Typically 5-60 minutes globally, depending on your DNS provider’s TTL. A 300-second TTL means changes propagate in about 5 minutes; a 3600-second TTL means about 60. Use a tool like whatsmydns.net to check global propagation.
Is SSL automatic for custom domains?
Section titled “Is SSL automatic for custom domains?”Yes. When Hoody’s proxy detects a CNAME pointing to an alias, it automatically requests a Let’s Encrypt certificate for your custom domain. The first HTTPS request may take 30-60 seconds (certificate issuance time), then it’s instant. Certificates are valid for 90 days and renewed automatically once 30 days remain.
Can I connect a root domain?
Section titled “Can I connect a root domain?”Root domains are not supported. ALIAS/ANAME and A records both fail Hoody’s CNAME-only detection, so no certificate is ever issued. Use a subdomain (www.mycompany.com, app.mycompany.com) with a CNAME record, and redirect the root to it at your registrar.
What happens if my CNAME points to a deleted alias?
Section titled “What happens if my CNAME points to a deleted alias?”The domain will return HTTP 404 because Hoody’s proxy no longer has a matching alias for that URL. Always verify the alias exists before updating DNS, and avoid deleting aliases that have active CNAMEs pointing to them.
Can multiple custom domains point to the same container?
Section titled “Can multiple custom domains point to the same container?”Yes. Create one alias, then CNAME multiple domains to it. Hoody provisions separate SSL certificates for each domain. Common use case: www.mycompany.com and app.mycompany.com both pointing to the same HTTP service.
Does the container need any configuration?
Section titled “Does the container need any configuration?”No. Your application binds to a port (e.g., 3000) and the proxy handles routing, SSL, and domain resolution. The app itself does not know about domains; it only responds to HTTP requests.
Can I use Cloudflare’s proxy (orange cloud) with Hoody?
Section titled “Can I use Cloudflare’s proxy (orange cloud) with Hoody?”Turn it off. Cloudflare’s proxy interferes with Hoody’s SSL provisioning and IP preservation, so use DNS-only mode (gray cloud). Your traffic goes: Client → Hoody Proxy → Container, not through Cloudflare’s edge network.
How do I switch a domain from one container to another?
Section titled “How do I switch a domain from one container to another?”Option A (instant): The alias container_id is immutable, so delete the alias and recreate it with the same name on the new container (DELETE then POST /api/v1/proxy/aliases). Here “name” refers to the alias field. The CNAME target is unchanged, so no DNS edit is needed. Option B (slower): Create a new alias pointing to the new container, then update CNAME to point to the new alias (requires DNS propagation).
What’s the maximum number of custom domains I can connect?
Section titled “What’s the maximum number of custom domains I can connect?”No limit. Each alias can support unlimited CNAMEs (at your DNS provider level). One Hoody alias can have dozens of custom domains pointing to it, and each one gets automatic SSL and routes to the same container service.
Troubleshooting
Section titled “Troubleshooting”CNAME not working
Section titled “CNAME not working”1. Verify CNAME is correct
dig api.mycompany.com
# Should show CNAME record pointing to alias.node-us.containers.hoody.com# If showing A record or different CNAME: DNS not updated yet2. Check alias exists and is enabled
Verify:
- Alias exists
- enabled: true
- container is running
3. Test alias URL directly
# Bypass custom domain, test aliascurl https://myapp-prod.node-us.containers.hoody.com
# If this works but custom domain doesn't:# → DNS propagation still in progress# → Wait 15-30 more minutesSSL certificate not provisioning
Section titled “SSL certificate not provisioning”Common causes:
-
CNAME pointing to wrong target
Terminal window # Wrong: CNAME to cryptographic URLapi.mycompany.com CNAME 67e89abc...node-us.containers.hoody.com (wrong)# Correct: CNAME to aliasapi.mycompany.com CNAME myapp-prod.node-us.containers.hoody.com (correct) -
DNS not fully propagated
- Let’s Encrypt validation fails until the record resolves worldwide
- Wait for full propagation (up to 60 minutes)
-
Cloudflare proxy enabled
- Orange cloud icon in Cloudflare = Proxied through CF
- Must be gray cloud (DNS only) for Hoody SSL
-
Cert issuance blocked upstream
- The HTTP-01 challenge is answered by Hoody’s edge, not by your container, so no firewall or port 80 change on your side is needed
- If validation still fails, the cause is almost always DNS (item 2) or Cloudflare proxying (item 3)
Check Hoody status:
Contact support if the certificate keeps failing to issue.
- ACME rate limits exceeded
- Let’s Encrypt enforces per-registered-domain rate limits (for example, the duplicate-certificate limit of 5 per week for the same exact set of names)
- If you’ve been testing extensively with the same domain, you may hit one of these limits
- If you hit a limit: there is no second certificate authority to fall back to, so issuance fails outright until the weekly window resets. Use a different subdomain in the meantime
- Prevention: Use different subdomains for testing (test1.example.com, test2.example.com) instead of repeatedly recreating certificates for the same domain
Check if you hit rate limits:
# Visit Let's Encrypt rate limit checker# https://crt.sh/?q=%.mycompany.com
# Shows all certificates issued for your domain# If you see many recent certificates: likely hit the limitWorkaround while waiting:
- Use a different subdomain temporarily
- Or use the alias URL directly (already has SSL)
- Rate limit resets 7 days after first certificate in the batch
DNS propagation delays
Section titled “DNS propagation delays”Typical propagation windows by provider:
| Provider | Typical TTL | Max Wait |
|---|---|---|
| Cloudflare | 5 minutes | 10 minutes |
| Route53 | 5 minutes | 15 minutes |
| Google Domains | 1 hour | 2 hours |
| Namecheap | 30 minutes | 1 hour |
| GoDaddy | 1 hour | 2 hours |
Check propagation:
# From your machinedig api.mycompany.com @8.8.8.8
# From different DNS serverdig api.mycompany.com @1.1.1.1
# If different results: Still propagatingBest practices
Section titled “Best practices”Test through the alias URL first
Section titled “Test through the alias URL first”Exercise the alias URL before you point a domain at it:
# 1. Create aliasPOST /api/v1/proxy/aliases{ "alias": "myapp-test", ... }
# 2. Test thoroughlycurl https://myapp-test.node-us.containers.hoody.com# Run full test suite, verify responses
# 3. Add custom domain only when alias works perfectlyapi.mycompany.com CNAME myapp-test.node-us.containers.hoody.comGive aliases descriptive names
Section titled “Give aliases descriptive names”An alias name should say what it serves:
Good: production-apiGood: staging-frontendGood: blue-deploymentGood: myapp-v2
Bad: appBad: testBad: apiBad: xOnce you run 20 domains, the names are what keep them apart.
Record which domain points where
Section titled “Record which domain points where”Keep a file tracking each domain and its target:
domains: api.mycompany.com: cname_target: production-api.node-us.containers.hoody.com alias_id: 63a3e4b5c6d7e8f9a0b1c2d3 container_id: 890abcdef12345678901cdef
staging.mycompany.com: cname_target: staging-api.node-us.containers.hoody.com alias_id: 74b4f5c6d7e8f9a0b1c2d3e4 container_id: 901bcdef12345678901cdefaThat is what saves you from re-deriving which alias serves which domain months later.
Set a reminder before an alias expires
Section titled “Set a reminder before an alias expires”If you use expiring aliases:
POST /api/v1/proxy/aliases{ "alias": "beta-program", "expires_at": "2026-08-16T00:00:00.000Z" # Absolute ISO 8601 timestamp}Set a calendar reminder 7 days before expiration if users depend on this URL.
Branded URLs and platform URLs
Section titled “Branded URLs and platform URLs”The same services, under two sets of names:
Your branding:https://api.acme.comhttps://app.techstartup.iohttps://platform.saas.com
Hoody infrastructure:https://prod-acme.node-us.containers.hoody.comhttps://startup-app.node-eu.containers.hoody.comhttps://saas-platform.node-asia.containers.hoody.comVisitors see your domain; Hoody’s hostname stays behind it as the CNAME target. The CNAME record is the only thing you maintain, and you do not manage certificates, renewals, or proxy configuration.
Quick reference
Section titled “Quick reference”Setup checklist
Section titled “Setup checklist”- Create container with hoody-kit enabled
- Verify container is running (
GET /api/v1/containers/{id}) - Create proxy alias (
POST /api/v1/proxy/aliases) - Test alias URL (
curl https://alias.node-us.containers.hoody.com) - Add CNAME record at DNS provider
- Wait for DNS propagation (5-60 minutes)
- Test custom domain (
curl https://api.mycompany.com) - Verify SSL certificate (browser padlock icon)
- Configure permissions if needed
DNS record format
Section titled “DNS record format”Type: CNAMEName: [subdomain]Value: [alias].[serverName].containers.hoody.comTTL: 300-3600 (lower = faster updates, higher = better caching)Example:
Type: CNAMEName: apiValue: prod-api.node-us.containers.hoody.comTTL: 3600What’s Next
Section titled “What’s Next”Secure your domains:
- Configure Permissions → - Add authentication to custom domains
Explore related topics:
- Proxy Overview → - The overall proxy architecture
- Aliases → - Alias management in detail