Docker Deployment
Deploy Deckyard using Docker and Docker Compose for easy setup and management.
Prerequisites
Section titled “Prerequisites”- Docker - Version 20.10 or later
- Docker Compose - Version 2.0 or later
- Domain name - For HTTPS (production)
- DNS configured - Pointing to your server
Quick Start
Section titled “Quick Start”1. Clone the Repository
Section titled “1. Clone the Repository”git clone https://github.com/your-org/deckyard.gitcd deckyard2. Create Environment File
Section titled “2. Create Environment File”Copy the example environment file:
cp .env.example .envEdit .env with your configuration:
# RequiredAUTH_SECRET=your-random-secret-key-here
# Domain (for Caddy HTTPS)DOMAIN=slides.yourdomain.comLETSENCRYPT_EMAIL=admin@yourdomain.com
# Optional: Database (defaults to SQLite/JSON)DATABASE_URL=postgresql://user:pass@host:5432/deckyard
# Optional: EmailBREVO_API_KEY=your-brevo-api-keyEMAIL_SENDER_ADDRESS=slides@yourdomain.comEMAIL_SENDER_NAME=Deckyard
# Optional: AI featuresOPENAI_API_KEY=sk-...
# Optional: Media storageIMAGEKIT_PUBLIC_KEY=...IMAGEKIT_PRIVATE_KEY=...IMAGEKIT_URL_ENDPOINT=...3. Start the Stack
Section titled “3. Start the Stack”docker compose up -dThis starts:
- app - The Deckyard application on port 4177
- caddy - Reverse proxy with automatic HTTPS
4. Access Your Instance
Section titled “4. Access Your Instance”Open https://your-domain.com in your browser.
Docker Compose Configuration
Section titled “Docker Compose Configuration”Default Configuration
Section titled “Default Configuration”services: app: build: . container_name: deckyard-app restart: unless-stopped extra_hosts: - "host.docker.internal:host-gateway" env_file: - path: .env required: false environment: PORT: "4177" HOST: "0.0.0.0" volumes: - ./server/data:/app/server/data - ./server/uploads:/app/server/uploads expose: - "4177"
caddy: image: caddy:2-alpine container_name: deckyard-caddy restart: unless-stopped depends_on: - app ports: - "80:80" - "443:443" env_file: - path: .env required: false volumes: - ./Caddyfile:/etc/caddy/Caddyfile:ro - caddy_data:/data - caddy_config:/config
volumes: caddy_data: caddy_config:Volumes
Section titled “Volumes”| Volume | Purpose |
|---|---|
./server/data | Presentation data, settings, sessions |
./server/uploads | Uploaded images and files |
caddy_data | SSL certificates and Caddy state |
caddy_config | Caddy configuration cache |
Reverse Proxy (Caddy)
Section titled “Reverse Proxy (Caddy)”Default Caddyfile
Section titled “Default Caddyfile”{ email {$LETSENCRYPT_EMAIL}}
{$DOMAIN} { encode gzip reverse_proxy app:4177}Caddy automatically:
- Obtains SSL certificates from Let’s Encrypt
- Renews certificates before expiry
- Redirects HTTP to HTTPS
- Enables gzip compression
Environment Variables
Section titled “Environment Variables”Set these in your .env file:
DOMAIN=slides.yourdomain.comLETSENCRYPT_EMAIL=admin@yourdomain.comMultiple Domains
Section titled “Multiple Domains”To serve multiple domains:
{ email {$LETSENCRYPT_EMAIL}}
slides.example.com, presentations.example.com { encode gzip reverse_proxy app:4177}Dockerfile
Section titled “Dockerfile”The included Dockerfile:
FROM node:20-alpine
WORKDIR /app
# Install Chromium for PNG exportRUN apk add --no-cache \ chromium \ nss \ freetype \ harfbuzz \ ca-certificates \ ttf-freefont
# Install dependenciesCOPY package.json package-lock.json* ./COPY scripts/vendor-phosphor.js ./scripts/vendor-phosphor.jsCOPY shared/phosphor-icons.js ./shared/phosphor-icons.jsRUN npm install --omit=dev || npm install
# Copy applicationCOPY . .
ENV NODE_ENV=productionENV PORT=4177ENV HOST=0.0.0.0ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser
EXPOSE 4177
CMD ["node", "server/server.js"]Key features:
- Alpine base - Small image size
- Chromium - For PDF/PNG exports
- Production mode - Optimized for deployment
Production Configuration
Section titled “Production Configuration”Resource Limits
Section titled “Resource Limits”Add resource limits in docker-compose.yml:
services: app: # ... other config deploy: resources: limits: cpus: '2' memory: 2G reservations: cpus: '0.5' memory: 512MHealth Checks
Section titled “Health Checks”Add health checks for reliability:
services: app: # ... other config healthcheck: test: ["CMD", "wget", "-q", "--spider", "http://localhost:4177/health"] interval: 30s timeout: 10s retries: 3 start_period: 40sLogging
Section titled “Logging”Configure log rotation:
services: app: # ... other config logging: driver: "json-file" options: max-size: "10m" max-file: "3"External Database
Section titled “External Database”PostgreSQL with Docker Compose
Section titled “PostgreSQL with Docker Compose”Add PostgreSQL to your stack:
services: db: image: postgres:15-alpine container_name: deckyard-db restart: unless-stopped environment: POSTGRES_USER: deckyard POSTGRES_PASSWORD: your-secure-password POSTGRES_DB: deckyard volumes: - postgres_data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U deckyard"] interval: 10s timeout: 5s retries: 5
app: # ... existing config depends_on: db: condition: service_healthy environment: DATABASE_URL: postgresql://deckyard:your-secure-password@db:5432/deckyard
volumes: postgres_data:External PostgreSQL
Section titled “External PostgreSQL”Connect to an existing database:
DATABASE_URL=postgresql://user:pass@your-db-host:5432/deckyardUpdating
Section titled “Updating”Pull Latest Changes
Section titled “Pull Latest Changes”git pull origin maindocker compose builddocker compose up -dZero-Downtime Updates
Section titled “Zero-Downtime Updates”For production, use rolling updates:
docker compose up -d --no-deps --build appBackup
Section titled “Backup”Data Backup
Section titled “Data Backup”Back up the data volume:
# Stop the app (optional, for consistency)docker compose stop app
# Create backuptar -czvf backup-$(date +%Y%m%d).tar.gz \ ./server/data \ ./server/uploads
# Restartdocker compose start appDatabase Backup
Section titled “Database Backup”For PostgreSQL:
docker compose exec db pg_dump -U deckyard deckyard > backup.sqlTroubleshooting
Section titled “Troubleshooting”View Logs
Section titled “View Logs”# All servicesdocker compose logs -f
# Specific servicedocker compose logs -f appdocker compose logs -f caddyContainer Status
Section titled “Container Status”docker compose psShell Access
Section titled “Shell Access”docker compose exec app shSSL Certificate Issues
Section titled “SSL Certificate Issues”If Caddy fails to get certificates:
- Check domain DNS is pointing to your server
- Verify ports 80 and 443 are open
- Check Caddy logs:
docker compose logs caddy
Memory Issues
Section titled “Memory Issues”If the app crashes due to memory:
- Increase memory limits in docker-compose.yml
- Disable PNG export if not needed
- Use external media storage
Development Mode
Section titled “Development Mode”For local development with Docker:
# Use development compose filedocker compose -f docker-compose.dev.yml upOr run without Docker for faster iteration.