IC Custom Domain Setup Runbook
Overview
This runbook documents how to configure custom domains for Internet Computer canisters. IC uses DNS TXT records to map custom domains to canister IDs.
Prerequisites
- Access to DNS management (GoDaddy for helloworlddao.com)
- Canister deployed to IC mainnet
- Canister ID (get via
dfx canister --network ic id <canister-name>)
How IC Custom Domains Work
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ User Browser │────▶│ IC Boundary │────▶│ Canister │
│ │ │ Nodes │ │ │
└─────────────────┘ └──────────────────┘ └─────────────────┘
│ │
│ 1. Request to │ 2. Lookup TXT record
│ custom domain │ _canister-id.domain
│ │
│ │ 3. Route to canister
│ │ + generate SSL certIC boundary nodes:
- Receive requests for custom domains
- Query DNS for
_canister-id.<domain>TXT record - Route traffic to the specified canister
- Automatically provision Let's Encrypt SSL certificates
Current Domain Configuration
Active Suite Domains
| Domain | Canister | Canister ID | Status |
|---|---|---|---|
| staging-think-tank.helloworlddao.com | think-tank-suite | wnfjk-biaaa-aaaao-a6dhq-cai | ✅ Working |
| staging-governance.helloworlddao.com | governance-suite | wkep6-mqaaa-aaaao-a6dha-cai | ✅ Working |
| staging-ottercamp.helloworlddao.com | otter-camp-suite | dzt3i-sqaaa-aaaao-a6uaa-cai | ✅ Working |
| staging-portal.helloworlddao.com | dao-suite | d6s54-7iaaa-aaaao-a6uaq-cai | ✅ Working |
| staging-admin.helloworlddao.com | dao-admin-suite | dxrwa-jaaaa-aaaao-a6uba-cai | ✅ Working |
| www.helloworlddao.com | marketing-suite | d5fe6-hqaaa-aaaao-a6t5q-cai | ✅ Working |
| staging-docs.helloworlddao.com | docs_site | 4t67s-qaaaa-aaaao-a62ga-cai | ✅ Working |
Legacy Monolith Domains (Archived)
| Domain | Canister | Canister ID | Status |
|---|---|---|---|
| staging.helloworlddao.com | www (frontend) | vlmti-wqaaa-aaaad-acoiq-cai | ⚠️ Archived |
Step 1: Get Canister ID
# Set environment to suppress warnings
export DFX_WARNING=-mainnet_plaintext_identity
# Get canister ID
cd /home/coby/git/frontend
dfx canister --network ic id admin
# Output: ehbll-kiaaa-aaaac-qc2aa-cai
dfx canister --network ic id www
# Output: vlmti-wqaaa-aaaad-acoiq-caiStep 2: Configure DNS Records
Required Records
For each custom domain, add these DNS records in GoDaddy:
A Record (Points domain to IC)
Type: A
Name: <subdomain> (e.g., "staging-admin" or "staging")
Value: 23.142.184.129
TTL: 600Note: IC boundary nodes are at multiple IPs. Using icp0.io as CNAME is preferred:
Type: CNAME
Name: <subdomain>
Value: icp0.io
TTL: 600TXT Record (Links domain to canister)
Type: TXT
Name: _canister-id.<subdomain>
Value: <canister-id>
TTL: 600Example: staging-admin.helloworlddao.com
# Option 1: CNAME (preferred)
Type: CNAME
Name: staging-admin
Value: icp0.io
TTL: 600
# Required: Canister ID TXT record
Type: TXT
Name: _canister-id.staging-admin
Value: ehbll-kiaaa-aaaac-qc2aa-cai
TTL: 600Example: www.helloworlddao.com (Production)
# Option 1: CNAME
Type: CNAME
Name: www
Value: icp0.io
TTL: 600
# Required: Canister ID TXT record
Type: TXT
Name: _canister-id.www
Value: vlmti-wqaaa-aaaad-acoiq-cai
TTL: 600Step 3: Verify DNS Propagation
Wait for DNS propagation (typically 1-2 hours, maximum 24 hours), then verify:
# Check A/CNAME record
dig staging-admin.helloworlddao.com +short
# Should return: icp0.io or 23.142.184.129
# Check TXT record (critical!)
dig _canister-id.staging-admin.helloworlddao.com TXT +short
# Should return: "ehbll-kiaaa-aaaac-qc2aa-cai"Step 4: Register Domain with IC API
CRITICAL: DNS records alone are not enough. You must explicitly register the domain with IC's custom domain API.
New Domain Registration
For a new domain (first time setup):
# Validate configuration first
curl -s "https://icp0.io/custom-domains/v1/staging-admin.helloworlddao.com/validate" | jq .
# Register the domain (POST for new domains)
curl -s -X POST "https://icp0.io/custom-domains/v1/staging-admin.helloworlddao.com" | jq .
# Check registration status
curl -s "https://icp0.io/custom-domains/v1/staging-admin.helloworlddao.com" | jq .Domain Transfer (Moving Between Canisters)
If you need to transfer a domain from one canister to another:
# Update DNS records first (change _canister-id TXT record to new canister ID)
# Wait for DNS propagation (1-2 hours typically, max 24 hours)
# Transfer the domain (PATCH for existing domains)
curl -s -X PATCH "https://icp0.io/custom-domains/v1/YOUR_DOMAIN" | jq .
# IMPORTANT: Also remove domain from old canister's .well-known/ic-domains file
# The domain must be removed from the old canister to complete the transferNote: IC boundary nodes now auto-discover domains from DNS records, but explicit registration via the API is still best practice to ensure proper SSL certificate provisioning.
Expected Registration Flow
validation_status: "valid"- DNS is correctly configuredregistration_status: "registering"- Processing requestregistration_status: "registered"- Complete, SSL will be provisioned
Step 5: Verify SSL Certificate
After registration completes, IC will provision SSL. Verify:
# Check SSL certificate
echo | openssl s_client -connect staging-admin.helloworlddao.com:443 \
-servername staging-admin.helloworlddao.com 2>&1 | grep "subject="
# Should return: subject=CN = staging-admin.helloworlddao.comIf SSL shows wrong domain (e.g., ai.icpex.org):
- TXT record is missing or incorrect
- DNS hasn't propagated yet
- Wait 10-15 minutes and retry
Step 6: Test the Domain
# Test HTTPS
curl -s -o /dev/null -w "%{http_code}\n" https://staging-admin.helloworlddao.com
# Should return: 200Troubleshooting
Problem: SSL Certificate Mismatch (Wrong Domain)
Symptom: Browser shows SSL error, certificate for wrong domain (e.g., ai.icpex.org)
Cause: Domain was never registered with IC's custom domain API, or domain transfer incomplete
Solution:
- Check registration status:bash
curl -s "https://icp0.io/custom-domains/v1/YOUR_DOMAIN" | jq . - If
not_found, register the domain:bashcurl -s -X POST "https://icp0.io/custom-domains/v1/YOUR_DOMAIN" | jq . - If transferring from another canister:bash
# Use PATCH instead of POST for existing domains curl -s -X PATCH "https://icp0.io/custom-domains/v1/YOUR_DOMAIN" | jq . # Also remove domain from old canister's .well-known/ic-domains file - Wait for
registration_status: "registered" - Certificate will be provisioned automatically
Problem: _canister-id TXT Record Missing
Symptom: Validation fails, can't register domain
Cause: _canister-id TXT record missing or incorrect
Solution:
- Verify TXT record:
dig _canister-id.<domain> TXT +short - If missing, add the TXT record in DNS
- Wait 10-15 minutes for propagation
- Re-run validation and registration
Problem: DNS Not Resolving
Symptom: dig <domain> +short returns nothing
Cause: A/CNAME record missing
Solution:
- Add A record pointing to
23.142.184.129or CNAME toicp0.io - Wait 5-10 minutes for propagation
Problem: HTTP 308 Redirect Loop
Symptom: Constant redirects, never loads
Cause: Usually a caching issue
Solution:
- Clear browser cache
- Try incognito/private window
- Try
curl -Lto follow redirects
Problem: Canister Returns 404
Symptom: Domain works but shows 404
Cause: Canister assets not deployed or wrong path
Solution:
- Verify canister has assets:
dfx canister --network ic info <name> - Redeploy if needed:
dfx deploy --network ic <name>
Fallback: Raw IC URL
If custom domain isn't working, use the raw IC URL:
| Canister | Raw URL |
|---|---|
| Foundery OS Suite | https://wnfjk-biaaa-aaaao-a6dhq-cai.icp0.io/ |
| Governance Suite | https://wkep6-mqaaa-aaaao-a6dha-cai.icp0.io/ |
| Marketing Suite | https://d5fe6-hqaaa-aaaao-a6t5q-cai.icp0.io/ |
| Otter Camp Suite | https://dzt3i-sqaaa-aaaao-a6uaa-cai.icp0.io/ |
| DAO Suite | https://d6s54-7iaaa-aaaao-a6uaq-cai.icp0.io/ |
| DAO Admin Suite | https://dxrwa-jaaaa-aaaao-a6uba-cai.icp0.io/ |
| Docs Site | https://4t67s-qaaaa-aaaao-a62ga-cai.icp0.io/ |
DNS Records Checklist
Staging Environment
| Record Type | Name | Value | Status |
|---|---|---|---|
| CNAME | staging-think-tank | icp0.io | ✅ |
| TXT | _canister-id.staging-think-tank | wnfjk-biaaa-aaaao-a6dhq-cai | ✅ |
| CNAME | staging-governance | icp0.io | ✅ |
| TXT | _canister-id.staging-governance | wkep6-mqaaa-aaaao-a6dha-cai | ✅ |
| CNAME | staging-ottercamp | icp0.io | ✅ |
| TXT | _canister-id.staging-ottercamp | dzt3i-sqaaa-aaaao-a6uaa-cai | ✅ |
| CNAME | staging-portal | icp0.io | ✅ |
| TXT | _canister-id.staging-portal | d6s54-7iaaa-aaaao-a6uaq-cai | ✅ |
| CNAME | staging-admin | icp0.io | ✅ |
| TXT | _canister-id.staging-admin | dxrwa-jaaaa-aaaao-a6uba-cai | ✅ |
| CNAME | staging-docs | icp0.io | ✅ |
| TXT | _canister-id.staging-docs | 4t67s-qaaaa-aaaao-a62ga-cai | ✅ |
Production Environment
| Record Type | Name | Value | Status |
|---|---|---|---|
| CNAME | www | icp0.io | ✅ |
| TXT | _canister-id.www | d5fe6-hqaaa-aaaao-a6t5q-cai | ✅ |
| CNAME | foundery | icp0.io | ⚠️ Configure when ready |
| TXT | _canister-id.foundery | wnfjk-biaaa-aaaao-a6dhq-cai | ⚠️ Configure when ready |
| CNAME | governance | icp0.io | ⚠️ Configure when ready |
| TXT | _canister-id.governance | wkep6-mqaaa-aaaao-a6dha-cai | ⚠️ Configure when ready |
| CNAME | ottercamp | icp0.io | ⚠️ Configure when ready |
| TXT | _canister-id.ottercamp | dzt3i-sqaaa-aaaao-a6uaa-cai | ⚠️ Configure when ready |
| CNAME | portal | icp0.io | ⚠️ Configure when ready |
| TXT | _canister-id.portal | d6s54-7iaaa-aaaao-a6uaq-cai | ⚠️ Configure when ready |
| CNAME | admin | icp0.io | ⚠️ Configure when ready |
| TXT | _canister-id.admin | dxrwa-jaaaa-aaaao-a6uba-cai | ⚠️ Configure when ready |
| CNAME | docs | icp0.io | ⚠️ Configure when ready |
| TXT | _canister-id.docs | 4t67s-qaaaa-aaaao-a62ga-cai | ⚠️ Configure when ready |
Related Documentation
Estimated Time
- DNS record addition: 5 minutes
- DNS propagation: 1-2 hours typically (max 24 hours)
- API registration: 1-2 minutes
- SSL certificate provisioning: 5-10 minutes
- Total: ~2-3 hours (wait for DNS), then 5-10 minutes for SSL