Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
8682c03
feat: init
ogzhanolguncu Oct 7, 2025
9e856a9
feat: add depot_id mapping
ogzhanolguncu Oct 7, 2025
47c3fb9
chore: cleanup comments
ogzhanolguncu Oct 7, 2025
9d655bf
Merge branch 'main' of github.com:unkeyed/unkey into depot-poc
ogzhanolguncu Oct 8, 2025
e16c437
feat: add s3 support
ogzhanolguncu Oct 8, 2025
730bc00
feat: pass build to restate
ogzhanolguncu Oct 9, 2025
16a3901
feat: add proper flow for local
ogzhanolguncu Oct 9, 2025
cb83eba
feat: get rid of build backed from krane
ogzhanolguncu Oct 10, 2025
7be3589
chore: cleanup vault/storage and move s3 to build service
ogzhanolguncu Oct 13, 2025
82a0f05
feat: upload directly to depot from blob storage
ogzhanolguncu Oct 13, 2025
af949e5
refactor: allow script to generate blob storage creds
ogzhanolguncu Oct 13, 2025
412354c
refactor: local docker build
ogzhanolguncu Oct 14, 2025
371a17b
refactor: update protos and logs
ogzhanolguncu Oct 14, 2025
297e3d9
fix: dockerpath location
ogzhanolguncu Oct 14, 2025
ca3966d
chore: update quickstart
ogzhanolguncu Oct 14, 2025
0c2ae0c
revert: changes
ogzhanolguncu Oct 14, 2025
9058cc6
revert: s3 changes
ogzhanolguncu Oct 14, 2025
0613ce1
chore: update protos
ogzhanolguncu Oct 14, 2025
9295aad
Merge branch 'main' of github.com:unkeyed/unkey into depot-poc
ogzhanolguncu Oct 14, 2025
7b456c7
fix: build issue
ogzhanolguncu Oct 14, 2025
e27e84e
fix: comments
ogzhanolguncu Oct 15, 2025
7f61242
fix: proto definitions
ogzhanolguncu Oct 15, 2025
fa1177a
[autofix.ci] apply automated fixes
autofix-ci[bot] Oct 15, 2025
ae034a8
fix: proto definition
ogzhanolguncu Oct 16, 2025
dd6b3c6
[autofix.ci] apply automated fixes
autofix-ci[bot] Oct 16, 2025
caa937f
refactor: get rid of etc/host and allow s3 to talk to outside for loc…
ogzhanolguncu Oct 16, 2025
0af2f14
feat: allow k8s to use depot
ogzhanolguncu Oct 17, 2025
284ca7f
fix: s3 external access
ogzhanolguncu Oct 17, 2025
63d462e
refactor: move image pulling to krane for local dev
ogzhanolguncu Oct 17, 2025
1a17fb8
chore: replace busybox with alpine and add ca-certs
ogzhanolguncu Oct 17, 2025
b920b57
fix: add missing close
ogzhanolguncu Oct 17, 2025
a2e39b3
fix: comments
ogzhanolguncu Oct 21, 2025
68191a0
refactor: build backend script
ogzhanolguncu Oct 21, 2025
a1b5be8
Merge branch 'main' of github.com:unkeyed/unkey into depot-poc
ogzhanolguncu Oct 23, 2025
98149da
chore: rename contextKey to contextBuildPath
ogzhanolguncu Oct 23, 2025
2d1d163
[autofix.ci] apply automated fixes
autofix-ci[bot] Oct 23, 2025
ff12361
Merge branch 'main' into depot-poc
Flo4604 Oct 23, 2025
71bbc71
fix: comments
ogzhanolguncu Oct 27, 2025
88ff163
fix: flags and envs
ogzhanolguncu Oct 27, 2025
3105062
chore: update readme
ogzhanolguncu Oct 27, 2025
863e684
fix: k8s manifest
ogzhanolguncu Oct 27, 2025
3bec7a7
refactor: change names of s3. make them more obvious
ogzhanolguncu Oct 27, 2025
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,6 @@ dist
.secrets.json
certs/
deployment/data/*
deployment/config/depot.json
metald.db
bin/
209 changes: 171 additions & 38 deletions QUICKSTART-DEPLOY.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,105 @@ This guide will help you get the Unkey deployment platform up and running locall
- A terminal/command line
- dnsmasq (for wildcard DNS setup)

## Step 1: Start the Platform
## Step 1: Configure Build Backend

1. Set up the API key for ctrl service authentication by adding it to `go/apps/ctrl/.env`:
**You must configure the build backend before starting Docker Compose.** This script generates the `.env` file that Docker Compose requires.

### Why This Matters

The platform builds **unknown user code** in isolation for security. When users deploy their applications, the system:

1. **Isolates each build** - User code runs in separate containers/VMs to prevent interference
2. **Caches layers** - Speeds up rebuilds by reusing unchanged Docker layers
3. **Stores artifacts** - Uses S3-compatible storage for built images and artifacts

You have two options:

- **Docker**: Fully local setup, slower builds, good for development
- **Depot**: Fast remote builds with persistent layer caching

Navigate to the deployment directory:

```bash
cd deployment
```

### Option A: Local Docker

Fully local setup using Docker with MinIO for S3 storage:

```bash
./setup-build-backend.sh docker
```

This configures:

- Local Docker builds (no external services)
- MinIO S3 storage running in Docker

### Option B: Depot

Remote builds with persistent caching for faster iteration. Create `deployment/config/depot.json`:

```json
{
"token": "depot_org_YOUR_TOKEN_HERE",
"s3_url": "https://your-s3-endpoint.com",
"s3_access_key_id": "your_access_key",
"s3_access_key_secret": "your_secret_key"
}
```

Then run:

```bash
./setup-build-backend.sh depot
```

This configures:

- Remote Depot infrastructure for builds
- Persistent layer caching across builds
- Your S3-compatible storage for artifacts

**Note:** The token must start with `depot_org_` or the script will fail validation.

### Kubernetes: Additional Setup for Depot and S3

If you're deploying to Kubernetes, you must create secrets for Depot and S3 credentials:

**1. Create Depot credentials secret:**

```bash
kubectl create secret generic depot-credentials \
--from-literal=token=depot_org_YOUR_TOKEN_HERE \
--from-literal=s3-url=https://your-s3-endpoint.com \
--from-literal=s3-access-key-id=your_access_key \
--from-literal=s3-access-key-secret=your_secret_key \
--namespace=unkey
```

**2. Create Depot registry credentials secret:**

```bash
kubectl create secret docker-registry depot-registry \
--docker-server=registry.depot.dev \
--docker-username=x-token \
--docker-password=depot_org_YOUR_TOKEN_HERE \
--namespace=unkey
```

**Critical:** These secrets must exist before deploying the `ctrl` service to Kubernetes. The `ctrl` deployment references these secrets for:

- Building user code via Depot
- Storing build contexts in S3
- Pulling built images from Depot's registry

Without these secrets, deployments will fail with authentication errors.

## Step 2: Configure API Keys
Comment on lines +75 to +108
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Call out build S3 external URL as mandatory for Depot.

Add a note that when using Depot, the presigned URLs must be reachable from Depot/CLI and UNKEY_BUILD_S3_EXTERNAL_URL must point to a public/host-reachable endpoint (e.g., http://127.0.0.1:3902 for MinIO in local).

🧰 Tools
🪛 Gitleaks (8.28.0)

[high] 89-89: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

🤖 Prompt for AI Agents
In QUICKSTART-DEPLOY.md around lines 75 to 108, add a mandatory note that when
using Depot the S3 presigned URLs must be reachable by Depot/CLI and therefore
UNKEY_BUILD_S3_EXTERNAL_URL must point to an externally reachable endpoint (not
just localhost inside a pod); instruct users to set UNKEY_BUILD_S3_EXTERNAL_URL
to a public or host-reachable URL (eg. http://127.0.0.1:3902 for local MinIO
with proper host network/port-forwarding or a public MinIO endpoint) and ensure
any ingress/firewall and S3 endpoint configuration allows Depot to fetch
presigned URLs so builds and image pulls succeed.


1. Set up the API key for ctrl service authentication in `go/apps/ctrl/.env`:

```bash
UNKEY_API_KEY="your-local-dev-key"
Expand All @@ -24,76 +120,87 @@ CTRL_URL="http://127.0.0.1:7091"
CTRL_API_KEY="your-local-dev-key"
```

Note: Use the same API key value in both files for authentication to work properly.
**Critical:** Use the same API key value in both files for authentication to work.

## Step 3: Start the Platform

3. Start all necessary services using Docker Compose:
From the project root directory, start all services:

```bash
docker compose -f ./deployment/docker-compose.yaml up mysql planetscale clickhouse redis s3 dashboard gw metald ctrl -d --build
docker compose -f ./deployment/docker-compose.yaml up mysql planetscale clickhouse redis s3 dashboard gw krane ctrl -d --build
```

This will start:
- **mysql**: Database for storing workspace, project, and deployment data
This starts:

- **mysql**: Database for workspace, project, and deployment data
- **planetscale**: PlanetScale HTTP simulator for database access
- **clickhouse**: Analytics database for metrics and logs
- **redis**: Caching layer for session and temporary data
- **s3**: MinIO S3-compatible storage for assets and vault data
- **s3**: MinIO S3-compatible storage for assets and vault data (when using docker backend)
- **dashboard**: Web UI for managing deployments (port 3000)
- **gw**: Gateway service for routing traffic (ports 80/443)
- **metald**: VM/container management service (port 8090)
- **krane**: VM/container management service (port 8090)
- **ctrl**: Control plane service for managing deployments (port 7091)

4. Set up wildcard DNS for `unkey.local`:
## Step 4: Set Up DNS and Certificates

1. Set up wildcard DNS for `unkey.local`:

```bash
./deployment/setup-wildcard-dns.sh
```

5. **OPTIONAL**: Install self-signed certificate for HTTPS (to avoid SSL errors):
2. **OPTIONAL**: Install self-signed certificate for HTTPS (to avoid SSL errors):

```bash
# For macOS
sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain ./deployment/certs/unkey.local.crt
```

Note: Certificates should be mounted to `deployment/certs`. You can skip this if you're fine with SSL errors in your browser.
Note: Certificates are in `deployment/certs`. You can skip this if you're fine with SSL warnings in your browser.

## Step 2: Set Up Your Workspace
## Step 5: Set Up Your Workspace

1. Open your browser and navigate to the dashboard:

```
http://localhost:3000
```

2. Create a workspace and copy its id
2. Create a workspace and copy its ID

3. Create a new project by filling out the form:
3. Create a new project by going to:

Go to http://localhost:3000/projects
```
http://localhost:3000/projects
```

Fill out the form:

- **Name**: Choose any name (e.g., "My Test App")
- **Slug**: This will auto-generate based on the name
- **Git URL**: Optional, leave blank for testing

4. After creating the project, **copy the Project ID** from the project details. It will look like:
4. After creating the project, **copy the Project ID** from the project details

## Step 3: Deploy a Version
## Step 6: Deploy a Version

1. Navigate to the go directory:

```bash
cd go
```

2. Set up API key authentication for the CLI (choose one option):
2. Set up API key authentication for the CLI:

**Option A: Environment variable (recommended)**

```bash
export API_KEY="your-local-dev-key"
```

**Option B: CLI flag**

Use `--api-key="your-local-dev-key"` in the command below.

3. Deploy using the CLI with your copied IDs:
Expand All @@ -105,50 +212,52 @@ go run . deploy \
--project-id="REPLACE_ME" \
--control-plane-url="http://127.0.0.1:7091" \
--api-key="your-local-dev-key" \
--keyspace-id="REPLACE_ME" # This is optional if you want key verifications
--keyspace-id="REPLACE_ME" # Optional, only needed for key verifications
```

Replace the placeholder values:
- `REPLACE_ME` with your actual workspace ID, project ID, and keyspace ID
- `your-local-dev-key` with the same API key value you set in steps 1 and 2

- `REPLACE_ME` with your actual workspace ID, project ID, and keyspace ID (if needed)
- `your-local-dev-key` with the same API key value you set in Step 2
- Keep `--context=./demo_api` as shown (there's a demo API in that folder)

**Note**: If using Option A (environment variable), you can omit the `--api-key` flag from the command.

3. The CLI will:
- Build a Docker image from the demo_api code
4. The CLI will:
- Build a Docker image from the demo_api code (using your configured build backend)
- Create a deployment on the Unkey platform
- Show real-time progress through deployment stages
- Deploy using metald's VM/container backend
- Deploy using Krane's VM/container backend

## Step 4: Test Your Deployment
## Step 7: Test Your Deployment

1. Once deployment completes, test the API in the unkey root directory:
1. Once deployment completes, test the API from the project root directory:

```bash
curl --cacert ./deployment/certs/unkey.local.crt https://REPLACE_ME/v1/liveness
```

Replace:
- `REPLACE_ME` (URL) with your deployment domain
Replace `REPLACE_ME` with your deployment domain.

**Note:** The liveness endpoint is public and doesn't require authentication. For protected endpoints, include an Authorization header:

```bash
curl --cacert ./deployment/certs/unkey.local.crt -H "Authorization: Bearer YOUR_API_KEY" https://YOUR_DOMAIN/protected/endpoint
curl --cacert ./deployment/certs/unkey.local.crt \
-H "Authorization: Bearer YOUR_API_KEY" \
https://YOUR_DOMAIN/protected/endpoint
```

2. Return to the dashboard to monitor your deployment:
2. Monitor your deployment in the dashboard:

```
http://localhost:3000/deployments
```

### Important: Your Application Must Listen on the PORT Environment Variable
## Important: Application Port Configuration

**Your deployed application MUST read the `PORT` environment variable and listen on that port.** The platform sets `PORT=8080` in the container, and your code needs to use this value.
**Your deployed application MUST read the `PORT` environment variable and listen on that port.** The platform sets `PORT=8080` in the container.

**Example for different languages:**
**Examples for different languages:**

```javascript
// Node.js
Expand Down Expand Up @@ -178,7 +287,31 @@ The demo_api already follows this pattern and listens on the PORT environment va

## Troubleshooting

- If you see "port is already allocated" errors, the system will automatically retry with a new random port
- Check container logs: `docker logs <container-name>`
- Verify the demo_api is listening on the PORT environment variable (should be 8080)
- Make sure your Dockerfile exposes the correct port (8080 in the demo_api example)
### Build Issues

- **"depot login failed"**: Check your depot token in `deployment/config/depot.json` - it must start with `depot_org_`
- **"S3 connection failed"**: Verify S3 credentials in your depot.json or ensure MinIO is running (for docker backend)
- **Slow builds**: Switch to depot backend for faster builds with layer caching
- **Stuck builds**: If you are stuck with a deployment go to `http://localhost:9070/ui/invocations` and kill the ongoing invocation.

### Kubernetes Issues

- **"secret not found"**: Ensure you created both `depot-credentials` and `depot-registry` secrets before deploying ctrl
- **"imagePullBackOff"**: Verify depot-registry secret credentials are correct and token is valid
- **"build context upload failed"**: Check depot-credentials secret has valid S3 credentials

### Deployment Issues

- **"port is already allocated"**: The system will automatically retry with a new random port
- **Application not responding**: Verify your app listens on the PORT environment variable (should be 8080)
- **Dockerfile issues**: Ensure your Dockerfile exposes the correct port (8080 in the demo_api example)

### Service Logs

Check container logs for any service:

```bash
docker logs <container-name>
```

Service names: `mysql`, `planetscale`, `clickhouse`, `redis`, `s3`, `dashboard`, `gw`, `krane`, `ctrl`
25 changes: 24 additions & 1 deletion deployment/docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ services:
image: bitnamilegacy/minio:2025.7.23-debian-12-r5
ports:
- 3902:3902
- 2903:2903
- 3903:3903
environment:
MINIO_ROOT_USER: minio_root_user
MINIO_ROOT_PASSWORD: minio_root_password
Expand Down Expand Up @@ -286,6 +286,10 @@ services:
UNKEY_DOCKER_SOCKET: "/var/run/docker.sock"
UNKEY_DEPLOYMENT_EVICTION_TTL: "10m"

UNKEY_REGISTRY_URL: "${UNKEY_REGISTRY_URL:-}"
UNKEY_REGISTRY_USERNAME: "${UNKEY_REGISTRY_USERNAME:-}"
UNKEY_REGISTRY_PASSWORD: "${UNKEY_REGISTRY_PASSWORD:-}"

restate:
networks:
- default
Expand Down Expand Up @@ -355,8 +359,27 @@ services:
UNKEY_VAULT_S3_ACCESS_KEY_SECRET: "minio_root_password"
UNKEY_VAULT_MASTER_KEYS: "Ch9rZWtfMmdqMFBJdVhac1NSa0ZhNE5mOWlLSnBHenFPENTt7an5MRogENt9Si6wms4pQ2XIvqNSIgNpaBenJmXgcInhu6Nfv2U="

# Build configuration
UNKEY_BUILD_S3_URL: "${UNKEY_BUILD_S3_URL:-http://s3:3902}"
UNKEY_BUILD_S3_EXTERNAL_URL: "${UNKEY_BUILD_S3_EXTERNAL_URL:-}" # For CLI/external access
UNKEY_BUILD_S3_BUCKET: "build-contexts"
UNKEY_BUILD_S3_ACCESS_KEY_ID: "${UNKEY_BUILD_S3_ACCESS_KEY_ID:-minio_root_user}"
UNKEY_BUILD_S3_ACCESS_KEY_SECRET: "${UNKEY_BUILD_S3_ACCESS_KEY_SECRET:-minio_root_password}"

Comment on lines +362 to +368
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Depot builds need an externally reachable S3 URL.

When UNKEY_BUILD_BACKEND=depot, UNKEY_BUILD_S3_EXTERNAL_URL must be set so Depot/CLI can fetch the presigned URLs. Otherwise builds will fail at runtime. Suggest enforcing this in config.Validate() and documenting it here.

🤖 Prompt for AI Agents
In deployment/docker-compose.yaml around lines 362 to 368, the compose config
allows UNKEY_BUILD_BACKEND=depot without requiring an externally reachable
UNKEY_BUILD_S3_EXTERNAL_URL which causes Depot/CLI fetches to fail at runtime;
update the application config validation to assert that when UNKEY_BUILD_BACKEND
equals "depot" the UNKEY_BUILD_S3_EXTERNAL_URL env var is non-empty and return a
clear validation error if missing, and add a short comment in this
docker-compose section documenting that UNKEY_BUILD_S3_EXTERNAL_URL must be set
for depot builds with an example value.

# API key for simple authentication (temporary, will be replaced with JWT)
UNKEY_API_KEY: "your-local-dev-key"
# Build backend configuration
UNKEY_BUILD_BACKEND: "${UNKEY_BUILD_BACKEND:-docker}"
UNKEY_BUILD_PLATFORM: "linux/amd64"
UNKEY_DOCKER_SOCKET: "/var/run/docker.sock"
UNKEY_DEPLOYMENT_EVICTION_TTL: "10m"
# Registry configuration (used by both Docker and Depot backends)
UNKEY_REGISTRY_URL: "${UNKEY_REGISTRY_URL:-registry.depot.dev}"
UNKEY_REGISTRY_USERNAME: "${UNKEY_REGISTRY_USERNAME:-x-token}"
UNKEY_REGISTRY_PASSWORD: "${UNKEY_REGISTRY_PASSWORD:-${DEPOT_TOKEN:-}}"
# Depot-specific configuration (only needed when UNKEY_BUILD_BACKEND=depot)
UNKEY_DEPOT_API_URL: "https://api.depot.dev"
UNKEY_DEPOT_PROJECT_REGION: "us-east-1"

otel:
networks:
Expand Down
Loading
Loading