This guide is for self-hosted deployments on your own TDX hardware. For cloud deployments, see Quickstart.
To set up dstack-gateway for production, you need a wildcard domain and SSL certificate.
Set up a second-level wildcard domain using Cloudflare; make sure to disable proxy mode and use DNS Only.
You need to get a Cloudflare API Key and ensure the API can manage this domain.
Open your certbot.toml, and update these fields:
acme_url: change tohttps://acme-v02.api.letsencrypt.org/directorycf_api_token: Obtain from Cloudflare
./certbot set-caa
./certbot renewFocus on these five fields in the core.proxy section:
cert_chain&cert_key: Point to the certificate paths from the previous stepbase_domain: The wildcard domain for proxylisten_addr&listen_port: Listen to0.0.0.0and preferably443in production. If using another port, specify it in the URL
For example, if your base domain is gateway.example.com, app ID is <app_id>, listening on 80, and dstack-gateway is on port 7777, the URL would be https://<app_id>-80.gateway.example.com:7777
The gateway supports the following URL format:
<app_id>[-<port>][<suffix>].<base_domain>
Where:
<app_id>: The application identifier<port>: Optional port number (defaults to 80 for HTTP, 443 for HTTPS)<suffix>: Optional suffix flags:s: Enable TLS passthrough (proxy passes encrypted traffic directly to backend)g: Enable HTTP/2 (gRPC) support (proxy advertises h2 via ALPN)
Examples:
<app_id>.gateway.example.com- Default HTTP on port 80<app_id>-8080.gateway.example.com- HTTP on port 8080<app_id>-s.gateway.example.com- TLS passthrough on port 443<app_id>-443s.gateway.example.com- TLS passthrough on port 443<app_id>-50051g.gateway.example.com- HTTP/2/gRPC on port 50051
Note: The s and g suffixes cannot be used together
Open vmm.toml and adjust dstack-gateway configuration in the gateway section:
base_domain: Same asbase_domainfromgateway.toml'score.proxysectionport: Same aslisten_portfromgateway.toml'score.proxysection
The gateway exposes a separate admin API (used for sync, WireGuard peer management, and other operator RPCs). Configure it in the core.admin section of gateway.toml:
[core.admin]
enabled = true
address = "0.0.0.0:9016"
# generate with: openssl rand -hex 32
admin_token = "<paste output of: openssl rand -hex 32>"
# alternatively, an Apache bcrypt htpasswd file (htpasswd -B -c admin.htpasswd admin)
# htpasswd_file = "/etc/dstack/gateway-admin.htpasswd"
insecure_no_auth = falseenabled: enable the admin API server.address: bind address/port for the admin API.admin_token: shared admin token. It can also be supplied via the environment variablesDSTACK_GATEWAY_ADMIN_TOKENorADMIN_API_TOKENinstead of the config file.htpasswd_file: path to an Apache bcrypt htpasswd file (create withhtpasswd -B -c admin.htpasswd admin); only bcrypt entries are accepted. Can be used instead of, or alongside,admin_token.insecure_no_auth: development-only escape hatch that disables admin authentication. Never enable it on a network-reachable admin interface.
The admin server is fail-closed: if it is enabled with no admin_token and no htpasswd_file, and insecure_no_auth is false, it refuses to start rather than exposing an unauthenticated admin API.
Clients authenticate by sending Authorization: Bearer <token> or the X-Admin-Token: <token> header.
