This guide shows you how to use your own domain (like api.mycompany.com) instead of the default Phala Cloud domain.
Prerequisites
- A domain with DNS hosted on Cloudflare (Linode and Namecheap also supported)
- Access to your DNS provider’s API token
- A deployed CVM application
Step 1: Create DNS API Token
Cloudflare
Linode
Namecheap
- Go to your Cloudflare Dashboard
- Select your domain
- Go to Get Your API Token
- Click Create Token
- Use the Edit zone DNS template
- Select your domain in Zone Resources
- Click Continue to summary and create the token
- Copy the token for later use
- Go to Linode Cloud Manager
- Click on your profile → API Tokens
- Create a Personal Access Token with Read/Write access to Domains
- Copy the token for later use
- Enable API access in your Namecheap account
- Go to Profile → Tools → API Access
- Note your username and API key
Step 2: Add dstack-ingress to Your Deployment
Update your docker-compose.yml to include the dstack-ingress container:
Set DOMAIN to your custom domain and TARGET_ENDPOINT to your app’s internal endpoint. TARGET_ENDPOINT tells dstack-ingress where to forward incoming traffic:
app:80 - Forward to service named “app” on port 80
api:3000 - Forward to service named “api” on port 3000
http://app:80 and grpc://app:50051 are also accepted, but the protocol prefix is stripped before proxying
- Use the service name from docker-compose, not localhost
dstack-ingress is a HAProxy-based L4/TCP proxy. It terminates TLS and forwards the TCP stream to TARGET_ENDPOINT; it does not apply Nginx-style HTTP redirects, header rules, body limits, or buffering settings. Put HTTP-specific behavior in your application or in a separate HTTP proxy behind TARGET_ENDPOINT if needed.
In the Phala Cloud dashboard, add these encrypted secrets:
Cloudflare
Linode
Namecheap
CLOUDFLARE_API_TOKEN: Your API token from Step 1
CERTBOT_EMAIL: Your email for Let’s Encrypt notifications
LINODE_API_TOKEN: Your API token from Step 1
CERTBOT_EMAIL: Your email for Let’s Encrypt notifications
NAMECHEAP_USERNAME: Your Namecheap username
NAMECHEAP_API_KEY: Your API key from Step 1
NAMECHEAP_CLIENT_IP: Your whitelisted IP address
CERTBOT_EMAIL: Your email for Let’s Encrypt notifications
Step 4: Deploy
Deploy your updated docker-compose.yml through the dashboard. The first deployment typically takes 3–5 minutes as it:
- Configures DNS records
- Requests SSL certificate from Let’s Encrypt
- Starts the HAProxy TCP proxy
Step 5: Verify
After deployment, you can:
- Access your domain: Visit
https://api.mycompany.com
- Check certificate: Your browser should show a valid Let’s Encrypt certificate
- Verify evidence: Visit
https://api.mycompany.com/evidences/ to see attestation data
Multiple Custom Domains
You can route multiple custom domains from one ingress container by using DOMAINS and ROUTING_MAP:
Why We Pin Infrastructure Images
The dstack-ingress image uses a SHA256 hash instead of a tag to ensure:
- Auditability: Anyone can verify the exact infrastructure code handling domains
- Immutability: The ingress behavior never changes unexpectedly
- Security: Prevents infrastructure image substitution
- Reproducibility: Domain handling is consistent across all deployments
Security Features
When SET_CAA=true is enabled:
- CAA records restrict certificate issuance to the TEE managed Let’s Encrypt account
- Only certificates requested from within your TEE can be issued
- Certificate transparency logs can be monitored for unauthorized certificates
Cloudflare Users: Cloudflare automatically overrides CAA records at the apex domain (e.g., example.com). This prevents domain attestation from working correctly.Solution options:
- Use a subdomain (recommended): Deploy to
app.example.com instead of example.com
- Disable Cloudflare’s CAA management: See Cloudflare CAA documentation
To verify your CAA record is working:Should return the Let’s Encrypt account URI with validationmethods=dns-01;accounturi=...
Troubleshooting
Check Logs
Look for dstack-ingress container logs in the dashboard:
Certbot Error: “too many certificates (5) already issued for this exact set of identifiers”
You may have forgotten to attach the data volume.
Other Common Issues
DNS not propagating: Wait 2-5 minutes for DNS changes to propagate globally.
Certificate request failed: Verify your API token has permission to edit DNS records.
Connection refused: Ensure TARGET_ENDPOINT points to the correct service:port.
CAA record conflicts: Some providers (like Linode) don’t allow CAA and CNAME on the same subdomain. The system will automatically use A records instead.
Next Steps