Agent-readable docs index: /llms.txt. Full docs in one file: /llms-full.txt. Download /docs.zip to grep all markdown files locally.

Set up custom public domains

This guide configures an HTTPS controller hostname and wildcard Sandbox service URLs. For example, sandbox.example.com can reach the controller while https://review-42.tunnel.example.com reaches one published service.
Public tunnel URLs are internet-facing. Publish only an intended HTTP or WebSocket port—never a database, Docker API, debug console, or credential-bearing admin service.

Choose the ingress topology

| Topology | Origin exposure | TLS path | Use when | | --- | --- | --- | | Cloudflare Tunnel | No public origin listener | Cloudflare edge to outbound connector | The origin must stay private | | Proxied A/AAAA plus Origin CA | Origin ports remain public unless firewalled | Cloudflare edge plus Full (strict) origin TLS | A dedicated host already uses Cloudflare proxying | | Direct Caddy or Traefik | Public origin | Public CA to the origin | No Cloudflare dependency is wanted |
Orange-cloud DNS is not an access-control boundary. It hides an origin from ordinary DNS answers, but a private origin still needs Cloudflare Tunnel or restricted ingress after end-to-end verification.

Cloudflare proxied wildcard with Full (strict)

Use the fixed-domain HTTPS profile for a dedicated Cloudflare-proxied host. It is implemented by compose.cloudflare-origin.yaml.

1. Choose hostnames

Controller: sandbox.example.com Tunnel base: tunnel.example.com Tunnel wildcard: *.tunnel.example.com
Set only tunnel.example.com in Sandbox configuration. Do not include *. or a trailing dot.

2. Create proxied DNS records

Create orange-cloud records for the controller and wildcard.
sandbox.example.com A ORIGIN_IPV4 proxied *.tunnel.example.com A ORIGIN_IPV4 proxied
Use AAAA only when the origin is intentionally reachable over IPv6. Never publish worker addresses.

3. Issue the Cloudflare edge certificate

A deep wildcard needs its own certificate coverage. Cloudflare Universal SSL covers one wildcard level in a full zone: *.example.com does not cover *.tunnel.example.com. Order an Advanced certificate with the zone apex and the exact deep wildcard, choose TXT validation, publish every requested DCV record, and wait for an active certificate before continuing.

4. Issue an Origin CA certificate

The origin certificate must cover the tunnel base and wildcard. Prefer ECC; for strict private-key locality, generate the key and CSR on the server and submit only the CSR through the Origin CA API.
tunnel.example.com *.tunnel.example.com
sudo install -d -m 0700 /etc/sandbox/origin-tls sudo install -m 0644 cloudflare-origin.crt /etc/sandbox/origin-tls/tunnel.crt sudo install -m 0600 cloudflare-origin.key /etc/sandbox/origin-tls/tunnel.key sudo openssl x509 \ -in /etc/sandbox/origin-tls/tunnel.crt \ -noout -subject -issuer -dates -ext subjectAltName
The SAN list must contain *.tunnel.example.com. Never commit or transmit the private key to a client or coding agent. Origin CA certificates are only for the proxied Cloudflare-to-origin connection, so keep both DNS records proxied.

5. Configure Sandbox and Caddy

Add the non-secret runtime values, then start the matching Compose profile.
SANDBOX_DOMAIN=sandbox.example.com SANDBOX_PORT=127.0.0.1:8080 SANDBOX_TUNNEL_ENABLED=true SANDBOX_TUNNEL_DOMAIN=tunnel.example.com SANDBOX_TUNNEL_SCHEME=https SANDBOX_TUNNEL_ENTRYPOINT=web SANDBOX_TUNNEL_EDGE_TLS=false SANDBOX_ACME_EMAIL=admin@example.com CLOUDFLARE_ORIGIN_CERT_FILE=/etc/sandbox/origin-tls/tunnel.crt CLOUDFLARE_ORIGIN_KEY_FILE=/etc/sandbox/origin-tls/tunnel.key
sudo docker compose \ --env-file /etc/sandbox/runtime.env \ -f deploy/compose/compose.yaml \ -f deploy/compose/compose.caddy.yaml \ -f deploy/compose/compose.cloudflare-origin.yaml \ --profile caddy-edge \ up --build -d
Set the Cloudflare zone encryption mode to Full (strict), never Flexible. Full (strict) requires an unexpired certificate with a matching SAN and encrypts both network legs. Read Cloudflare’s Full (strict) documentation.

6. Verify before exposing workloads

An unused wildcard hostname should complete TLS and reach the tunnel edge as 404.
curl -sS -o /dev/null \ -w 'code=%{http_code} tls=%{ssl_verify_result}\n' \ https://preflight.tunnel.example.com/
Require code=404 and tls=0. A 525 or 526 means the Cloudflare-to-origin TLS path is not ready. Then run a disposable lifecycle and verify the public service before deleting both tunnel and sandbox.
sandbox create --tenant domain-smoke --image python:3.13-alpine --ttl 600 --network deny sandbox wait OPERATION_ID --timeout 120 sandbox exec SANDBOX_ID -- sh -c \ 'printf domain-ok > /tmp/index.html; cd /tmp; python -m http.server 8000 --bind 0.0.0.0 >/tmp/http.log 2>&1 &' sandbox tunnel create SANDBOX_ID --port 8000 curl --fail PUBLIC_HTTPS_URL/index.html sandbox tunnel delete SANDBOX_ID TUNNEL_ID sandbox delete SANDBOX_ID --wait
Use the IDs and URL returned by your controller. After deletion, the public URL must settle to 404 and the worker must have no route file, per-sandbox tunnel network, or runtime container for the test.

Cloudflare Tunnel with a hidden origin

Use a remotely managed Cloudflare Tunnel when direct origin ingress must stay closed. Publish these application routes:
Public hostnameInternal service
sandbox.example.comhttp://controller:8080
relay.tunnel.example.comhttp://controller:8080
*.tunnel.example.comhttp://tunnel-edge:8080
Store the connector token only in a mode-0600 file. Keep it out of Git, prompts, and agent configuration.
SANDBOX_PORT=127.0.0.1:8080 SANDBOX_TUNNEL_ENABLED=true SANDBOX_TUNNEL_DOMAIN=tunnel.example.com SANDBOX_TUNNEL_SCHEME=https SANDBOX_TUNNEL_ENTRYPOINT=web SANDBOX_TUNNEL_EDGE_TLS=false SANDBOX_LOCAL_RELAY_ENABLED=true SANDBOX_LOCAL_RELAY_REQUIRE_AUTH=true CLOUDFLARE_TUNNEL_TOKEN_FILE=/etc/sandbox/cloudflare-tunnel.token
sudo docker compose \ --env-file /etc/sandbox/runtime.env \ -f deploy/compose/compose.yaml \ -f deploy/compose/compose.cloudflare.yaml \ --profile cloudflare-edge \ up --build -d
The nested wildcard still needs an active Cloudflare edge certificate. After both routes pass end-to-end tests, close public controller, HTTP, and HTTPS ingress while preserving the management path and outbound connector traffic.
Continue with public tunnels, security, and operations. This page is maintained from the upstream custom-domain setup document.