Configuration Reference (epd.yml)
Complete annotated schema for epd.yml.
Full Annotated Schema
yaml
# ==============================================================================
# Global Application Settings
# ==============================================================================
name: myapp # App name (alphanumeric, dashes, underscores)
mode: docker # Runtime mode: "docker" | "process"
# ==============================================================================
# Docker Mode Settings (when mode: docker)
# ==============================================================================
image: ghcr.io/org/myapp # Docker image repository
registry: # Optional: Container registry credentials
server: ghcr.io
username: deployer
password: ${GITHUB_TOKEN} # Resolved from local environment variable
build:
dockerfile: Dockerfile # Relative path to Dockerfile (default: Dockerfile)
context: . # Build context directory (default: .)
platform: linux/amd64 # Target architecture
args: # Build arguments passed to docker build
COMMIT_SHA: ${GIT_SHA:-dev}
secrets: # BuildKit build secrets
npm_token: NPM_TOKEN
# ==============================================================================
# Process Mode Settings (when mode: process)
# ==============================================================================
process:
install: bun install # Dependency install command on server
build: bun run build # Build command on server
start: bun run start # Start command (epd automatically injects $PORT)
exclude: # Files excluded from rsync archive
- ".git"
- "node_modules"
- ".env"
- "dist"
source: rsync # Source transport: "rsync" | "git"
# ==============================================================================
# SSH Connection Details
# ==============================================================================
ssh:
user: root # SSH username (default: root)
port: 22 # SSH port (default: 22)
key: ~/.ssh/id_ed25519 # Path to explicit private key
proxy_jump: bastion.net # Optional jump host / bastion
options: # Extra OpenSSH options
- ServerAliveInterval=30
# ==============================================================================
# Server Groups & Service Definitions
# ==============================================================================
servers:
web:
hosts: # Target servers (IPs or Hetzner selectors)
- 203.0.113.10
- hetzner:prod-web-1 # Dynamic Hetzner query by server name
- hetzner:label:app=web # Dynamic Hetzner query by label selector
replicas: 2 # Number of container replicas per host
port: 3000 # Internal port the app listens on
domains: [myapp.com] # Public domains (automatic SSL)
cpus: "2.0" # Docker CPU limit
memory: "1g" # Docker RAM limit
drain: 10 # Graceful drain period (seconds) before old slot stops
stop_timeout: 15 # Grace period before SIGKILL
volumes:
- /var/lib/epd/volumes/uploads:/app/uploads
env:
clear:
APP_ENV: production
secret:
- APP_SECRET
worker: # Background worker service (no exposed routes)
hosts: [203.0.113.10]
replicas: 1
command: bun run worker.ts # Custom entrypoint command
# ==============================================================================
# Shared Reverse Proxy (Traefik)
# ==============================================================================
proxy:
enabled: true # Start & manage shared Traefik proxy (default: true)
ssl: true # Auto-provision Let's Encrypt SSL (default: true)
email: admin@myapp.com # ACME registration email
challenge: http # SSL challenge type: "http" | "dns" | "tlsalpn"
entrypoints:
web: 80
websecure: 443
cross_host: false # Route requests across all cluster nodes
private_ips: # VPC IPs for cross-host load balancing
203.0.113.10: 10.0.0.10
# ==============================================================================
# Automated DNS Synchronization (Cloudflare / Hetzner)
# ==============================================================================
dns:
provider: cloudflare # "cloudflare" | "hetzner"
api_token: ${DNS_API_TOKEN} # Provider API token
proxied: true # Cloudflare CDN orange-cloud (default: true)
ttl: 300 # DNS TTL in seconds
auto_sync: true # Sync on epd deploy and epd setup (default: true)
# ==============================================================================
# Hetzner Cloud Integration
# ==============================================================================
hetzner:
api_token: ${HETZNER_API_TOKEN}
# ==============================================================================
# Health Check Probes
# ==============================================================================
healthcheck:
path: /health # HTTP endpoint to probe (default: "/")
status: 200-399 # Acceptable HTTP status codes
timeout: 60 # Timeout in seconds before rolling back
interval: 2 # Seconds between probe attempts
delay: 1 # Initial seconds before first probe
# ==============================================================================
# Environment Variables & Secrets
# ==============================================================================
env:
clear: # Public variables (safe in git)
NODE_ENV: production
secret: # Private secrets (read from .env or shell)
- DATABASE_URL
- STRIPE_KEY
# ==============================================================================
# Persistent Accessories (Databases, Caches)
# ==============================================================================
accessories:
db:
image: postgres:17-alpine
host: 203.0.113.10
env:
clear:
POSTGRES_DB: myapp
secret:
- POSTGRES_PASSWORD
volumes:
- /var/lib/epd/volumes/myapp-db:/var/lib/postgresql/data
ports:
- "127.0.0.1:5432:5432"
redis:
image: redis:7-alpine
host: 203.0.113.10
volumes:
- /var/lib/epd/volumes/myapp-redis:/data
# ==============================================================================
# Lifecycle Hooks
# ==============================================================================
hooks:
pre_build: ./scripts/lint.sh
pre_deploy: ./scripts/db-migrate.sh
post_deploy: ./scripts/notify-slack.sh
on_failure: ./scripts/alert-ops.sh
# ==============================================================================
# General Strategy & Retention
# ==============================================================================
strategy: rolling # Rollout strategy: "rolling" | "parallel"
keep_releases: 5 # Number of past images / releases to retain
remote_root: /var/lib/epd # Root directory on remote hosts