
Zero Trust HTTPS: How to Setup Custom Domains on Phala Cloud
2025-04-21
Overview
Running a CVM on Phala Cloud gives you hardware‑enforced confidentiality out of the box, but the default service URL (<app‑id>.prod5-dstack.phala.network
) isn’t exactly brandable. Luckily, Phala’s dstack‑ingress setup lets you attach your own domain, provision a trusted TLS certificate through Let’s Encrypt, and even produce cryptographic evidence that the certificate lives inside an Intel TDX-protected enclave — all in just a few minutes. Check the Phala Docs for more details.
Below we’ll cover prerequisites, show a production‑ready docker‑compose.yml
, walk through deploying on Phala Cloud, and explain the attestation files that prove your endpoint is running inside a genuine TEE.
1. How the dstack‑ingress pattern works
- DNS automation – A tiny side‑car container talks to Cloudflare’s API, creating the CNAME, TXT (routing hint), and optional CAA records needed for DNS‑01 validation.
- Let’s Encrypt via DNS‑01 – With those records in place, Certbot requests a certificate without ever exposing ports 80/443 on the raw CVM
- Nginx reverse proxy – The same container terminates TLS and forwards plain HTTP to your app on
TARGET_ENDPOINT
.
- Evidence generation – Each time a cert is issued or renewed the container writes
cert.pem
,acme‑account.json
, asha256sum.txt
, and an Intel TDX quote (quote.json
) that ties the SHA‑256 digest into the quote’sreport_data
field.
- Certificate Transparency – All issued certs are logged in public CT logs, so anyone can audit issuance via tools like
crt.sh
.
2. Prerequisites
What | Why |
A registered domain managed by Cloudflare | dstack‑ingress currently automates only Cloudflare DNS |
Cloudflare API Token with Edit zone DNS scope | Allows the container to add CNAME/TXT/CAA records safely, limiting blast radius compared to the legacy Global API Key |
Phala Cloud account with credits | To launch the CVM |
Email for Let’s Encrypt | Used by Certbot for renewal notices |
3. Create the Cloudflare API token
- Dashboard → My Profile → API Tokens → Create Token.

- Pick the “Edit zone DNS” template, restrict it to just your zone, and finish.
- Copy the token and save it as
CLOUDFLARE_API_TOKEN
.
(Rolling a token later is as simple as ⋮ → Roll in the same UI.)
4. Drop‑in docker‑compose.yml
services:
dstack-ingress:
image: kvin/dstack-ingress@sha256:8dfc3536d1bd0be0cb938140aeff77532d35514ae580d8bec87d3d5a26a21470 # pre‑built
ports:
- "443:443"
environment:
- CLOUDFLARE_API_TOKEN=${CLOUDFLARE_API_TOKEN}
- DOMAIN=${DOMAIN} # e.g. api.example.com
- GATEWAY_DOMAIN=_.dstack-prod5.phala.network
- CERTBOT_EMAIL=${CERTBOT_EMAIL}
- TARGET_ENDPOINT=http://app:80
- SET_CAA=true
volumes:
- cert-data:/etc/letsencrypt
- /var/run/tappd.sock:/var/run/tappd.sock
restart: unless-stopped
app:
image: nginx # swap in your own image
restart: unless-stopped
volumes:
cert-data:
Phala’s Advanced tab accepts this verbatim when you choose docker‑compose.yml during CVM creation.

5. Deploy on Phala Cloud
- New CVM → Compose file → Advanced, paste the YAML, and select a
prodX
region.

- Fill in the environment variables (
DOMAIN
,CLOUDFLARE_API_TOKEN
, etc.).

- Click Create and watch logs: within ~2 minutes Certbot shows
Congratulations! Your certificate and chain have been saved
. Here is an example of a custom domain deployed to phala.incipient.ltd.

Behind the scenes, dstack‑ingress:
- Adds a CNAME from
api.example.com
→.dstack-prod5.phala.network
so traffic routes through Phala’s secure gateway
- Publishes a TXT record that the gateway reads to identify your CVM instance.
- (Optional) Publishes CAA records limiting issuance to
letsencrypt.org
, reducing the risk of rogue CAs.
6. Verifying attestation evidence
Visit https://api.example.com/evidences/
and download:
File | Purpose |
cert.pem | Current leaf certificate |
acme-account.json | ACME account key used to request cert |
sha256sum.txt | Hashes of cert.pem & acme-account.json |
quote.json | Intel TDX quote embedding SHA‑256 of sha256sum.txt in report_data |
Because the quote is signed by Intel’s TDX Attestation Key and bound to the hash chain above, anyone can cryptographically prove the certificate was generated inside this very enclave. You can check the example of the deployment at phala.incipient.ltd/evidences/.

7. Inspect CAA & CT logs (optional)
dig +short CAA api.example.com # should list only letsencrypt.org
If you see an entry like 0 issue "letsencrypt.org"
, you’re good.
To monitor certificate issuance, plug your domain into crt.sh or any CT monitor. Every renewal will show up within minutes, giving you an extra audit trail.
8. Automatic renewals & housekeeping
- Certbot runs twice daily and reloads Nginx when certs hit the 30‑day renewal window.
- Because everything is stored in the
cert-data
volume, redeploying or resizing the CVM preserves certificates and evidence.
- If you ever migrate to a different prod region, just update
GATEWAY_DOMAIN
, redeploy, and the script will re‑issue the cert for the new CNAME.
9. Troubleshooting tips
Symptom | Likely cause |
SERVFAIL on _acme‑challenge TXT lookup | Token lacks Edit zone DNS or record hasn’t propagated yet (Cloudflare global TTL ≈ 60 s) |
Certbot errors about “unauthorized” | CAA forbids Let’s Encrypt or TXT record not visible from Let’s Encrypt resolver |
Custom domain loads but shows Cloudflare SSL, not Let’s Encrypt | Cloudflare “Flexible” SSL overrides upstream ‑ switch to **Full (strict)** |
10. Where to go next
- Phala Cloud CLI – script the entire flow with
phala cvms create --compose docker-compose.yml --env ...
.
- Nginx hardening – enforce modern ciphers and HSTS once your cert is live.
- Intel Trust Authority – verify TDX quotes remotely for continuous compliance.
Your application now runs behind a vanity URL, serves modern HTTPS, and ships its own enclave‑backed audit trail—perfect for security‑minded customers and enterprise procurement checklists alike.