From 818ead1755087df7924a2c908ff2c705f06cc87f Mon Sep 17 00:00:00 2001 From: Adam Reif Date: Mon, 23 Mar 2026 15:24:07 -0400 Subject: [PATCH 1/2] feat: add ALIAS_DOMAIN / SAN support for all DNS providers When ALIAS_DOMAIN is set: - certbot issues a SAN cert covering both DOMAIN and ALIAS_DOMAIN - nginx server_name includes ALIAS_DOMAIN - Works with all DNS providers (Cloudflare, Linode, Namecheap, Route53) Co-Authored-By: Claude Opus 4.6 (1M context) --- custom-domain/dstack-ingress/DNS_PROVIDERS.md | 1 + custom-domain/dstack-ingress/README.md | 1 + custom-domain/dstack-ingress/scripts/certman.py | 5 ++++- custom-domain/dstack-ingress/scripts/entrypoint.sh | 10 +++++++++- 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/custom-domain/dstack-ingress/DNS_PROVIDERS.md b/custom-domain/dstack-ingress/DNS_PROVIDERS.md index 845d288..40c0ffb 100644 --- a/custom-domain/dstack-ingress/DNS_PROVIDERS.md +++ b/custom-domain/dstack-ingress/DNS_PROVIDERS.md @@ -24,6 +24,7 @@ This guide explains how to configure dstack-ingress to work with different DNS p - `SET_CAA` - Enable CAA record setup (default: false) - `PORT` - HTTPS port (default: 443) - `TXT_PREFIX` - Prefix for TXT records (default: "_tapp-address") +- `ALIAS_DOMAIN` - An additional domain to include as a Subject Alternative Name (SAN) on the TLS certificate and in nginx `server_name`. When set, the node's certificate covers both `DOMAIN` and `ALIAS_DOMAIN`, and nginx will accept requests for either hostname. ## Provider-Specific Configuration diff --git a/custom-domain/dstack-ingress/README.md b/custom-domain/dstack-ingress/README.md index d166cd2..fd4bc05 100644 --- a/custom-domain/dstack-ingress/README.md +++ b/custom-domain/dstack-ingress/README.md @@ -217,6 +217,7 @@ configs: - `PROXY_BUFFERS`: Optional value for nginx `proxy_buffers` (format: `number size`, e.g. `4 256k`) in single-domain mode - `PROXY_BUSY_BUFFERS_SIZE`: Optional value for nginx `proxy_busy_buffers_size` (numeric with optional `k|m` suffix, e.g. `256k`) in single-domain mode - `CERTBOT_STAGING`: Optional; set this value to the string `true` to set the `--staging` server option on the [`certbot` cli](https://eff-certbot.readthedocs.io/en/stable/using.html#certbot-command-line-options) +- `ALIAS_DOMAIN`: Optional; an additional domain to include as a Subject Alternative Name (SAN) on the TLS certificate and in nginx `server_name`. When set, the node's certificate covers both `DOMAIN` and `ALIAS_DOMAIN`, and nginx will accept requests for either hostname. **Backward Compatibility:** diff --git a/custom-domain/dstack-ingress/scripts/certman.py b/custom-domain/dstack-ingress/scripts/certman.py index 52126d2..b767254 100644 --- a/custom-domain/dstack-ingress/scripts/certman.py +++ b/custom-domain/dstack-ingress/scripts/certman.py @@ -287,7 +287,10 @@ def _build_certbot_command(self, action: str, domain: str, email: str) -> List[s if action == "certonly": base_cmd.extend(["--agree-tos", "--no-eff-email", - "--email", email, "-d", domain]) + "--email", email, "--cert-name", domain, "-d", domain]) + alias_domain = os.environ.get("ALIAS_DOMAIN", "").strip() + if alias_domain: + base_cmd.extend(["--expand", "-d", alias_domain]) if os.environ.get("CERTBOT_STAGING", "false") == "true": base_cmd.extend(["--staging"]) diff --git a/custom-domain/dstack-ingress/scripts/entrypoint.sh b/custom-domain/dstack-ingress/scripts/entrypoint.sh index d1994a3..5777f6e 100644 --- a/custom-domain/dstack-ingress/scripts/entrypoint.sh +++ b/custom-domain/dstack-ingress/scripts/entrypoint.sh @@ -40,6 +40,9 @@ fi if ! TXT_PREFIX=$(sanitize_dns_label "$TXT_PREFIX"); then exit 1 fi +if ! ALIAS_DOMAIN=$(sanitize_domain "$ALIAS_DOMAIN"); then + exit 1 +fi PROXY_CMD="proxy" if [[ "${TARGET_ENDPOINT}" == grpc://* ]]; then @@ -144,11 +147,16 @@ setup_nginx_conf() { proxy_busy_buffers_size_conf=" proxy_busy_buffers_size ${PROXY_BUSY_BUFFERS_SIZE};" fi + local server_name_value="${DOMAIN}" + if [ -n "$ALIAS_DOMAIN" ]; then + server_name_value="${DOMAIN} ${ALIAS_DOMAIN}" + fi + cat </etc/nginx/conf.d/default.conf server { listen ${PORT} ssl; http2 on; - server_name ${DOMAIN}; + server_name ${server_name_value}; # SSL certificate configuration ssl_certificate /etc/letsencrypt/live/${cert_name}/fullchain.pem; From d1eb9c3a9355d558bb8d8e01a9b8e7395c00bf34 Mon Sep 17 00:00:00 2001 From: Adam Reif Date: Mon, 23 Mar 2026 16:09:46 -0400 Subject: [PATCH 2/2] fix: only add --cert-name when ALIAS_DOMAIN requires it --cert-name is only needed when --expand adds a SAN, to prevent certbot from creating a suffixed cert directory. Without ALIAS_DOMAIN certbot already names the cert after the -d domain by default. Co-Authored-By: Claude Opus 4.6 (1M context) --- custom-domain/dstack-ingress/scripts/certman.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/custom-domain/dstack-ingress/scripts/certman.py b/custom-domain/dstack-ingress/scripts/certman.py index b767254..5c81a16 100644 --- a/custom-domain/dstack-ingress/scripts/certman.py +++ b/custom-domain/dstack-ingress/scripts/certman.py @@ -287,10 +287,10 @@ def _build_certbot_command(self, action: str, domain: str, email: str) -> List[s if action == "certonly": base_cmd.extend(["--agree-tos", "--no-eff-email", - "--email", email, "--cert-name", domain, "-d", domain]) + "--email", email, "-d", domain]) alias_domain = os.environ.get("ALIAS_DOMAIN", "").strip() if alias_domain: - base_cmd.extend(["--expand", "-d", alias_domain]) + base_cmd.extend(["--cert-name", domain, "--expand", "-d", alias_domain]) if os.environ.get("CERTBOT_STAGING", "false") == "true": base_cmd.extend(["--staging"])