Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions custom-domain/dstack-ingress/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/.claude/
/CLAUDE.md
/test/
__pycache__
114 changes: 114 additions & 0 deletions custom-domain/dstack-ingress/DNS_PROVIDERS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# DNS Provider Configuration Guide

This guide explains how to configure dstack-ingress to work with different DNS providers for managing custom domains and SSL certificates.

## Supported DNS Providers

- **Cloudflare** - The original and default provider
- **Linode DNS** - For Linode-hosted domains

## Environment Variables

### Common Variables (Required for all providers)

- `DOMAIN` - Your custom domain (e.g., `app.example.com`)
- `GATEWAY_DOMAIN` - dstack gateway domain (e.g., `_.dstack-prod5.phala.network`)
- `CERTBOT_EMAIL` - Email for Let's Encrypt registration
- `TARGET_ENDPOINT` - Backend application endpoint to proxy to
- `DNS_PROVIDER` - DNS provider to use (`cloudflare`, `linode`)

### Optional Variables

- `SET_CAA` - Enable CAA record setup (default: false)
- `PORT` - HTTPS port (default: 443)
- `TXT_PREFIX` - Prefix for TXT records (default: "_tapp-address")

## Provider-Specific Configuration

### Cloudflare

```bash
DNS_PROVIDER=cloudflare
CLOUDFLARE_API_TOKEN=your-api-token
```

**Required Permissions:**
- Zone:Read
- DNS:Edit

### Linode DNS

```bash
DNS_PROVIDER=linode
LINODE_API_TOKEN=your-api-token
```

**Required Permissions:**
- Domains: Read/Write access

**Important Note for Linode:**
- Linode has a limitation where CAA and CNAME records cannot coexist on the same subdomain
- To work around this, the system will attempt to use A records instead of CNAME records
- If the gateway domain can be resolved to an IP, an A record will be created
- If resolution fails, it falls back to CNAME (but CAA records won't work on that subdomain)
- This is a Linode-specific limitation not present in other providers

## Docker Compose Example

```yaml
version: '3.8'

services:
ingress:
image: dstack-ingress:latest
ports:
- "443:443"
environment:
# Common configuration
- DNS_PROVIDER=linode
- DOMAIN=app.example.com
- GATEWAY_DOMAIN=_.dstack-prod5.phala.network
- [email protected]
- TARGET_ENDPOINT=http://backend:8080

# Linode specific
- LINODE_API_TOKEN=your-api-token
volumes:
- ./letsencrypt:/etc/letsencrypt
- ./evidences:/evidences
```

## Migration from Cloudflare-only Setup

If you're currently using the Cloudflare-only version:

1. **No changes needed for Cloudflare users** - The default behavior remains Cloudflare
2. **For other providers** - Add the `DNS_PROVIDER` environment variable and provider-specific credentials

## Troubleshooting

### DNS Provider Detection

If you see "Could not detect DNS provider type", ensure you have either:
- Set `DNS_PROVIDER` environment variable explicitly, OR
- Set provider-specific credential environment variables (e.g., `CLOUDFLARE_API_TOKEN`)

### Certificate Generation Issues

Different providers may have different propagation times. The default is 120 seconds, but you may need to adjust based on your provider's behavior.

### Permission Errors

Ensure your API tokens/credentials have the necessary permissions listed above for your provider.

## API Token Generation

### Cloudflare
1. Go to https://dash.cloudflare.com/profile/api-tokens
2. Create token with Zone:Read and DNS:Edit permissions
3. Scope to specific zones if desired

### Linode
1. Go to https://cloud.linode.com/profile/tokens
2. Create a Personal Access Token
3. Grant "Domains" Read/Write access
5 changes: 3 additions & 2 deletions custom-domain/dstack-ingress/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,10 @@ RUN set -e; \

RUN mkdir -p /etc/letsencrypt /var/www/certbot /usr/share/nginx/html

COPY ./scripts/* /scripts/
RUN chmod +x /scripts/*
COPY ./scripts /scripts/
RUN chmod +x /scripts/*.sh /scripts/*.py
ENV PATH="/scripts:$PATH"
ENV PYTHONPATH="/scripts"
COPY .GIT_REV /etc/

ENTRYPOINT ["/scripts/entrypoint.sh"]
Expand Down
42 changes: 30 additions & 12 deletions custom-domain/dstack-ingress/README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
# Custom Domain Setup for dstack Applications

This repository provides a solution for setting up custom domains with automatic SSL certificate management for dstack applications using Cloudflare DNS and Let's Encrypt.
This repository provides a solution for setting up custom domains with automatic SSL certificate management for dstack applications using various DNS providers and Let's Encrypt.

## Overview

This project enables you to run dstack applications with your own custom domain, complete with:

- Automatic SSL certificate provisioning and renewal via Let's Encrypt
- Cloudflare DNS configuration for CNAME, TXT, and CAA records
- Multi-provider DNS support (Cloudflare, Linode DNS, more to come)
- Automatic DNS configuration for CNAME, TXT, and CAA records
- Nginx reverse proxy to route traffic to your application
- Certificate evidence generation for verification
- Strong SSL/TLS configuration with modern cipher suites (AES-GCM and ChaCha20-Poly1305)
Expand All @@ -17,16 +18,20 @@ This project enables you to run dstack applications with your own custom domain,
The dstack-ingress system provides a seamless way to set up custom domains for dstack applications with automatic SSL certificate management. Here's how it works:

1. **Initial Setup**:

- When first deployed, the container automatically obtains SSL certificates from Let's Encrypt using DNS validation
- It configures Cloudflare DNS by creating necessary CNAME, TXT, and optional CAA records
- It configures your DNS provider by creating necessary CNAME, TXT, and optional CAA records
- Nginx is configured to use the obtained certificates and proxy requests to your application

2. **DNS Configuration**:

- A CNAME record is created to point your custom domain to the dstack gateway domain
- A TXT record is added with application identification information to help dstack-gateway to route traffic to your application
- If enabled, CAA records are set to restrict which Certificate Authorities can issue certificates for your domain
- The system automatically detects your DNS provider based on environment variables

3. **Certificate Management**:

- SSL certificates are automatically obtained during initial setup
- A scheduled task runs twice daily to check for certificate renewal
- When certificates are renewed, Nginx is automatically reloaded to use the new certificates
Expand All @@ -40,7 +45,8 @@ The dstack-ingress system provides a seamless way to set up custom domains for d

### Prerequisites

- Host your domain on Cloudflare and have access to the Cloudflare account with API token
- Host your domain on one of the supported DNS providers
- Have appropriate API credentials for your DNS provider (see [DNS Provider Configuration](DNS_PROVIDERS.md) for details)

### Deployment

Expand All @@ -57,7 +63,13 @@ services:
ports:
- "443:443"
environment:
# DNS Provider
- DNS_PROVIDER=cloudflare

# Cloudflare example
- CLOUDFLARE_API_TOKEN=${CLOUDFLARE_API_TOKEN}

# Common configuration
- DOMAIN=${DOMAIN}
- GATEWAY_DOMAIN=${GATEWAY_DOMAIN}
- CERTBOT_EMAIL=${CERTBOT_EMAIL}
Expand All @@ -68,21 +80,23 @@ services:
- cert-data:/etc/letsencrypt
restart: unless-stopped
app:
image: nginx # Replace with your application image
image: nginx # Replace with your application image
restart: unless-stopped
volumes:
cert-data: # Persistent volume for certificates
cert-data: # Persistent volume for certificates
```

Explanation of environment variables:
**Core Environment Variables:**

- `CLOUDFLARE_API_TOKEN`: Your Cloudflare API token
- `DNS_PROVIDER`: DNS provider to use (cloudflare, linode)
- `DOMAIN`: Your custom domain
- `GATEWAY_DOMAIN`: The dstack gateway domain. (e.g. `_.dstack-prod5.phala.network` for Phala Cloud)
- `GATEWAY_DOMAIN`: The dstack gateway domain (e.g. `_.dstack-prod5.phala.network` for Phala Cloud)
- `CERTBOT_EMAIL`: Your email address used in Let's Encrypt certificate requests
- `TARGET_ENDPOINT`: The plain HTTP endpoint of your dstack application
- `SET_CAA`: Set to `true` to enable CAA record setup

For provider-specific configuration details, see [DNS Provider Configuration](DNS_PROVIDERS.md).

#### Option 2: Build Your Own Image

If you prefer to build the image yourself:
Expand All @@ -95,6 +109,7 @@ If you prefer to build the image yourself:
```

**Important**: You must use the `build-image.sh` script to build the image. This script ensures reproducible builds with:

- Specific buildkit version (v0.20.2)
- Deterministic timestamps (`SOURCE_DATE_EPOCH=0`)
- Package pinning for consistency
Expand Down Expand Up @@ -150,10 +165,12 @@ The dstack-ingress system provides mechanisms to verify and attest that your cus
When certificates are issued or renewed, the system automatically generates a set of cryptographically linked evidence files:

1. **Access Evidence Files**:

- Evidence files are accessible at `https://your-domain.com/evidences/`
- Key files include `acme-account.json`, `cert.pem`, `sha256sum.txt`, and `quote.json`

2. **Verification Chain**:

- `quote.json` contains a TDX quote with the SHA-256 digest of `sha256sum.txt` embedded in the report_data field
- `sha256sum.txt` contains cryptographic checksums of both `acme-account.json` and `cert.pem`
- When the TDX quote is verified, it cryptographically proves the integrity of the entire evidence chain
Expand All @@ -178,9 +195,10 @@ The output will display CAA records that restrict certificate issuance exclusive
All Let's Encrypt certificates are logged in public Certificate Transparency (CT) logs, enabling independent verification:

**CT Log Verification**:
- Visit [crt.sh](https://crt.sh/) and search for your domain
- Confirm that the certificates match those issued by the dstack-ingress system
- This public logging ensures that all certificates are visible and can be monitored for unauthorized issuance

- Visit [crt.sh](https://crt.sh/) and search for your domain
- Confirm that the certificates match those issued by the dstack-ingress system
- This public logging ensures that all certificates are visible and can be monitored for unauthorized issuance

## License

Expand Down
1 change: 0 additions & 1 deletion custom-domain/dstack-ingress/docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,4 @@
restart: unless-stopped

volumes:
cert-data:

Check failure on line 23 in custom-domain/dstack-ingress/docker-compose.yaml

View workflow job for this annotation

GitHub Actions / Basic Checks (dev.sh)

23:13 [empty-values] empty value in block mapping

Check failure on line 23 in custom-domain/dstack-ingress/docker-compose.yaml

View workflow job for this annotation

GitHub Actions / check-all

23:13 [empty-values] empty value in block mapping

Loading
Loading