Skip to content

Commit 4378932

Browse files
authored
Merge pull request #28 from Dstack-TEE/ingress
Better custom domain example
2 parents e26aca0 + 93db59a commit 4378932

11 files changed

Lines changed: 712 additions & 161 deletions

File tree

custom-domain/README.md

Lines changed: 0 additions & 36 deletions
This file was deleted.

custom-domain/docker-compose.yaml

Lines changed: 0 additions & 125 deletions
This file was deleted.
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
FROM nginx@sha256:b6653fca400812e81569f9be762ae315db685bc30b12ddcdc8616c63a227d3ca
2+
3+
# Use a specific Debian snapshot for reproducible builds
4+
RUN set -e; \
5+
# Create a sources.list file pointing to a specific snapshot
6+
echo 'deb [check-valid-until=no] https://snapshot.debian.org/archive/debian/20250411T024939Z bookworm main' > /etc/apt/sources.list && \
7+
echo 'deb [check-valid-until=no] https://snapshot.debian.org/archive/debian-security/20250411T024939Z bookworm-security main' >> /etc/apt/sources.list && \
8+
echo 'Acquire::Check-Valid-Until "false";' > /etc/apt/apt.conf.d/10no-check-valid-until && \
9+
# Install packages with exact versions for reproducibility
10+
apt-get -o Acquire::Check-Valid-Until=false update && \
11+
apt-get install -y --no-install-recommends \
12+
certbot=2.1.0-4 \
13+
openssl=3.0.15-1~deb12u1 \
14+
bash=5.2.15-2+b7 \
15+
python3=3.11.2-1+b1 \
16+
python3-pip=23.0.1+dfsg-1 \
17+
python3-requests=2.28.1+dfsg-1 \
18+
python3.11-venv=3.11.2-6+deb12u5 \
19+
curl=7.88.1-10+deb12u12 \
20+
jq=1.6-2.1 \
21+
coreutils=9.1-1 && \
22+
rm -rf /var/lib/apt/lists/* /var/log/* /var/cache/ldconfig/aux-cache
23+
24+
25+
RUN mkdir -p /etc/letsencrypt /var/www/certbot /usr/share/nginx/html
26+
27+
COPY ./scripts/* /scripts/
28+
RUN chmod +x /scripts/*
29+
ENV PATH="/scripts:$PATH"
30+
31+
ENTRYPOINT ["/scripts/entrypoint.sh"]
32+
CMD ["nginx", "-g", "daemon off;"]
33+
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
# Custom Domain Setup for dstack Applications
2+
3+
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.
4+
5+
## Overview
6+
7+
This project enables you to run dstack applications with your own custom domain, complete with:
8+
9+
- Automatic SSL certificate provisioning and renewal via Let's Encrypt
10+
- Cloudflare DNS configuration for CNAME, TXT, and CAA records
11+
- Nginx reverse proxy to route traffic to your application
12+
- Certificate evidence generation for verification
13+
14+
## How It Works
15+
16+
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:
17+
18+
1. **Initial Setup**:
19+
- When first deployed, the container automatically obtains SSL certificates from Let's Encrypt using DNS validation
20+
- It configures Cloudflare DNS by creating necessary CNAME, TXT, and optional CAA records
21+
- Nginx is configured to use the obtained certificates and proxy requests to your application
22+
23+
2. **DNS Configuration**:
24+
- A CNAME record is created to point your custom domain to the dstack gateway domain
25+
- A TXT record is added with application identification information to help dstack-gateway to route traffic to your application
26+
- If enabled, CAA records are set to restrict which Certificate Authorities can issue certificates for your domain
27+
28+
3. **Certificate Management**:
29+
- SSL certificates are automatically obtained during initial setup
30+
- A scheduled task runs twice daily to check for certificate renewal
31+
- When certificates are renewed, Nginx is automatically reloaded to use the new certificates
32+
33+
4. **Evidence Generation**:
34+
- The system generates evidence files for verification purposes
35+
- These include the ACME account information and certificate data
36+
- Evidence files are accessible through a dedicated endpoint
37+
38+
## Usage
39+
40+
### Prerequisites
41+
42+
- Host your domain on Cloudflare and have access to the Cloudflare account with API token
43+
44+
### Deployment
45+
46+
You can either build the ingress container and push it to docker hub, or use the prebuilt image at `kvin/dstack-ingress`.
47+
48+
#### Option 1: Use the Pre-built Image
49+
50+
The fastest way to get started is to use our pre-built image. Simply use the following docker-compose configuration:
51+
52+
```yaml
53+
services:
54+
dstack-ingress:
55+
image: kvin/dstack-ingress@sha256:8dfc3536d1bd0be0cb938140aeff77532d35514ae580d8bec87d3d5a26a21470
56+
ports:
57+
- "443:443"
58+
environment:
59+
- CLOUDFLARE_API_TOKEN=${CLOUDFLARE_API_TOKEN}
60+
- DOMAIN=${DOMAIN}
61+
- GATEWAY_DOMAIN=${GATEWAY_DOMAIN}
62+
- CERTBOT_EMAIL=${CERTBOT_EMAIL}
63+
- SET_CAA=true
64+
- TARGET_ENDPOINT=http://app:80
65+
volumes:
66+
- /var/run/tappd.sock:/var/run/tappd.sock
67+
- cert-data:/etc/letsencrypt
68+
restart: unless-stopped
69+
app:
70+
image: nginx # Replace with your application image
71+
restart: unless-stopped
72+
volumes:
73+
cert-data: # Persistent volume for certificates
74+
```
75+
76+
Explanation of environment variables:
77+
78+
- `CLOUDFLARE_API_TOKEN`: Your Cloudflare API token
79+
- `DOMAIN`: Your custom domain
80+
- `GATEWAY_DOMAIN`: The dstack gateway domain. (e.g. `_.dstack-prod5.phala.network` for Phala Cloud)
81+
- `CERTBOT_EMAIL`: Your email address used in Let's Encrypt certificate requests
82+
- `TARGET_ENDPOINT`: The plain HTTP endpoint of your dstack application
83+
- `SET_CAA`: Set to `true` to enable CAA record setup
84+
85+
#### Option 2: Build Your Own Image
86+
87+
If you prefer to build the image yourself:
88+
89+
1. Clone this repository
90+
2. Build the Docker image:
91+
92+
```bash
93+
docker build -t yourusername/dstack-ingress .
94+
```
95+
96+
3. Push to your registry (optional):
97+
98+
```bash
99+
docker push yourusername/dstack-ingress
100+
```
101+
102+
4. Update the docker-compose.yaml file with your image name and deploy
103+
104+
## Domain Attestation and Verification
105+
106+
The dstack-ingress system provides mechanisms to verify and attest that your custom domain endpoint is secure and properly configured. This comprehensive verification approach ensures the integrity and authenticity of your application.
107+
108+
### Evidence Collection
109+
110+
When certificates are issued or renewed, the system automatically generates a set of cryptographically linked evidence files:
111+
112+
1. **Access Evidence Files**:
113+
- Evidence files are accessible at `https://your-domain.com/evidences/`
114+
- Key files include `acme-account.json`, `cert.pem`, `sha256sum.txt`, and `quote.json`
115+
116+
2. **Verification Chain**:
117+
- `quote.json` contains a TDX quote with the SHA-256 digest of `sha256sum.txt` embedded in the report_data field
118+
- `sha256sum.txt` contains cryptographic checksums of both `acme-account.json` and `cert.pem`
119+
- When the TDX quote is verified, it cryptographically proves the integrity of the entire evidence chain
120+
121+
3. **Certificate Authentication**:
122+
- `acme-account.json` contains the ACME account credentials used to request certificates
123+
- When combined with the CAA DNS record, this provides evidence that certificates can only be requested from within this specific TEE application
124+
- `cert.pem` is the Let's Encrypt certificate currently serving your custom domain
125+
126+
### CAA Record Verification
127+
128+
If you've enabled CAA records (`SET_CAA=true`), you can verify that only authorized Certificate Authorities can issue certificates for your domain:
129+
130+
```bash
131+
dig CAA your-domain.com
132+
```
133+
134+
The output will display CAA records that restrict certificate issuance exclusively to Let's Encrypt with your specific account URI, providing an additional layer of security.
135+
136+
### TLS Certificate Transparency
137+
138+
All Let's Encrypt certificates are logged in public Certificate Transparency (CT) logs, enabling independent verification:
139+
140+
**CT Log Verification**:
141+
- Visit [crt.sh](https://crt.sh/) and search for your domain
142+
- Confirm that the certificates match those issued by the dstack-ingress system
143+
- This public logging ensures that all certificates are visible and can be monitored for unauthorized issuance
144+
145+
## License
146+
147+
MIT License
148+
149+
Copyright (c) 2025
150+
151+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
152+
153+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
154+
155+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#!/bin/bash
2+
NAME=$1
3+
if [ -z "$NAME" ]; then
4+
echo "Usage: $0 <name>[:<tag>]"
5+
exit 1
6+
fi
7+
# Check if buildkit_20 already exists before creating it
8+
if ! docker buildx inspect buildkit_20 &>/dev/null; then
9+
docker buildx create --use --driver-opt image=moby/buildkit:v0.20.2 --name buildkit_20
10+
fi
11+
docker buildx build --builder buildkit_20 --no-cache --build-arg SOURCE_DATE_EPOCH="0" --output type=docker,name=$NAME,rewrite-timestamp=true .
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
services:
2+
dstack-ingress:
3+
image: kvin/dstack-ingress@sha256:5cbf6eff9983fad4018de90ed11b0593c84f2022ddfc64b9eb513d1ba79970c7
4+
ports:
5+
- "443:443"
6+
environment:
7+
- CLOUDFLARE_API_TOKEN=${CLOUDFLARE_API_TOKEN}
8+
- DOMAIN=${DOMAIN}
9+
- GATEWAY_DOMAIN=${GATEWAY_DOMAIN}
10+
- CERTBOT_EMAIL=${CERTBOT_EMAIL}
11+
- SET_CAA=true
12+
- TARGET_ENDPOINT=http://app:80
13+
volumes:
14+
- /var/run/tappd.sock:/var/run/tappd.sock
15+
- cert-data:/etc/letsencrypt
16+
restart: unless-stopped
17+
18+
app:
19+
image: nginx
20+
restart: unless-stopped
21+
22+
volumes:
23+
cert-data:
24+

0 commit comments

Comments
 (0)