Files
plunk/docker-compose.yml
T

251 lines
7.3 KiB
YAML

version: '3.8'
# Plunk Self-Hosting Docker Compose
# This setup runs all Plunk services in a single container with nginx reverse proxy
#
# Uses subdomain-based routing:
# - api.example.com -> API Server
# - app.example.com -> Web Dashboard
# - www.example.com -> Landing Page
# - docs.example.com -> Documentation
# - smtp.example.com -> SMTP Relay Server (ports 465, 587)
#
# Usage:
# 1. Copy .env.self-host.example to .env and configure
# 2. Set your domain names (API_DOMAIN, DASHBOARD_DOMAIN, SMTP_DOMAIN, etc.)
# 3. Run: docker compose up -d
# 4. Access your instance at the configured domains
#
# SMTP Server:
# - Supports TLS certificates via:
# 1. Traefik acme.json (mount to /certs/acme.json, requires SMTP_DOMAIN)
# 2. PEM files (mount privkey.pem and fullchain.pem to /certs/)
# - Runs without TLS if no certificates are mounted
services:
# ============================================
# Infrastructure Services
# ============================================
postgres:
image: postgres:16-alpine
container_name: plunk-postgres
restart: unless-stopped
environment:
POSTGRES_DB: plunk
POSTGRES_USER: plunk
POSTGRES_PASSWORD: ${DB_PASSWORD:-changeme123}
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: [ "CMD-SHELL", "pg_isready -U plunk" ]
interval: 10s
timeout: 5s
retries: 5
networks:
- plunk
redis:
image: redis:7-alpine
container_name: plunk-redis
restart: unless-stopped
command: redis-server --appendonly yes
volumes:
- redis_data:/data
healthcheck:
test: [ "CMD", "redis-cli", "ping" ]
interval: 10s
timeout: 5s
retries: 5
networks:
- plunk
minio:
image: minio/minio:latest
container_name: plunk-minio
restart: unless-stopped
command: server /data --console-address ":9001"
environment:
MINIO_ROOT_USER: ${MINIO_ROOT_USER:-plunk}
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:-plunkminiopass}
volumes:
- minio_data:/data
ports:
# Expose Minio API (for S3 operations) and Console (for web UI)
- "${MINIO_API_PORT:-9000}:9000"
- "${MINIO_CONSOLE_PORT:-9001}:9001"
healthcheck:
test: [ "CMD", "curl", "-f", "http://localhost:9000/minio/health/live" ]
interval: 30s
timeout: 20s
retries: 3
networks:
- plunk
ntfy:
image: binwiederhier/ntfy:latest
container_name: plunk-ntfy
restart: unless-stopped
command: serve
environment:
- TZ=UTC
volumes:
- ntfy_cache:/var/cache/ntfy
- ntfy_etc:/etc/ntfy
ports:
# Expose ntfy web UI and API
- "${NTFY_PORT:-8080}:80"
healthcheck:
test: [ "CMD-SHELL", "wget -q --tries=1 http://localhost:80/v1/health -O - | grep -Eo '\"healthy\"\\s*:\\s*true' || exit 1" ]
interval: 30s
timeout: 10s
retries: 3
start_period: 10s
networks:
- plunk
# ============================================
# Plunk Application
# ============================================
plunk:
image: ghcr.io/useplunk/plunk:latest
container_name: plunk
restart: unless-stopped
environment:
# Service mode
SERVICE: all
NODE_ENV: production
# Database
DATABASE_URL: postgresql://plunk:${DB_PASSWORD:-changeme123}@postgres:5432/plunk
DIRECT_DATABASE_URL: postgresql://plunk:${DB_PASSWORD:-changeme123}@postgres:5432/plunk
# Redis
REDIS_URL: redis://redis:6379
# Security
JWT_SECRET: ${JWT_SECRET}
# Nginx configuration
NGINX_PORT: ${NGINX_PORT:-80}
# Domain configuration (subdomain-based routing)
# Each service gets its own subdomain
API_DOMAIN: ${API_DOMAIN:-api.localhost}
DASHBOARD_DOMAIN: ${DASHBOARD_DOMAIN:-app.localhost}
LANDING_DOMAIN: ${LANDING_DOMAIN:-www.localhost}
WIKI_DOMAIN: ${WIKI_DOMAIN:-docs.localhost}
# Protocol configuration (set to true for HTTPS in production)
USE_HTTPS: ${USE_HTTPS:-false}
# Application URLs (auto-configured by setup-nginx.sh from domains above)
# You can override these if needed
API_URI: ${API_URI:-}
DASHBOARD_URI: ${DASHBOARD_URI:-}
LANDING_URI: ${LANDING_URI:-}
WIKI_URI: ${WIKI_URI:-}
# AWS SES (for sending emails)
AWS_SES_REGION: ${AWS_SES_REGION}
AWS_SES_ACCESS_KEY_ID: ${AWS_SES_ACCESS_KEY_ID}
AWS_SES_SECRET_ACCESS_KEY: ${AWS_SES_SECRET_ACCESS_KEY}
SES_CONFIGURATION_SET: ${SES_CONFIGURATION_SET}
SES_CONFIGURATION_SET_NO_TRACKING: ${SES_CONFIGURATION_SET_NO_TRACKING:-}
# Optional: OAuth
GITHUB_OAUTH_CLIENT: ${GITHUB_OAUTH_CLIENT:-}
GITHUB_OAUTH_SECRET: ${GITHUB_OAUTH_SECRET:-}
GOOGLE_OAUTH_CLIENT: ${GOOGLE_OAUTH_CLIENT:-}
GOOGLE_OAUTH_SECRET: ${GOOGLE_OAUTH_SECRET:-}
# Optional: Stripe
STRIPE_SK: ${STRIPE_SK:-}
STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET:-}
STRIPE_PRICE_ONBOARDING: ${STRIPE_PRICE_ONBOARDING:-}
STRIPE_PRICE_EMAIL_USAGE: ${STRIPE_PRICE_EMAIL_USAGE:-}
STRIPE_METER_EVENT_NAME: ${STRIPE_METER_EVENT_NAME:-emails}
# S3-compatible storage (Minio)
S3_ENDPOINT: ${S3_ENDPOINT:-http://minio:9000}
S3_ACCESS_KEY_ID: ${S3_ACCESS_KEY_ID:-plunk}
S3_ACCESS_KEY_SECRET: ${S3_ACCESS_KEY_SECRET:-plunkminiopass}
S3_BUCKET: ${S3_BUCKET:-uploads}
S3_PUBLIC_URL: ${S3_PUBLIC_URL:-http://localhost:9000/uploads}
S3_FORCE_PATH_STYLE: ${S3_FORCE_PATH_STYLE:-true}
# Notifications (ntfy.sh)
NTFY_URL: ${NTFY_URL:-http://ntfy/plunk-notifications}
# SMTP Server (for sending emails via SMTP)
# SMTP_DOMAIN is required to select the correct certificate from Traefik acme.json
# If using PEM files, SMTP_DOMAIN is optional
SMTP_DOMAIN: ${SMTP_DOMAIN:-}
# Platform emails
PLUNK_API_KEY: ${PLUNK_API_KEY:-}
PLUNK_FROM_ADDRESS: ${PLUNK_FROM_ADDRESS:-}
# Security
AUTO_PROJECT_DISABLE: ${AUTO_PROJECT_DISABLE:-false}
volumes:
# Persistent storage for application data
- plunk_data:/app/data
# Optional: Mount certificates for SMTP TLS
# For Traefik acme.json:
# - /path/to/acme.json:/certs/acme.json:ro
# For PEM files:
# - /path/to/privkey.pem:/certs/privkey.pem:ro
# - /path/to/fullchain.pem:/certs/fullchain.pem:ro
ports:
# SMTP ports (for email relay)
- "465:465" # SMTPS (implicit TLS)
- "587:587" # SMTP Submission (STARTTLS)
# Optional: Expose individual service ports for debugging
# - "8080:8080" # API
# - "3000:3000" # Web
# - "4000:4000" # Landing
# - "1000:1000" # Wiki
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
minio:
condition: service_healthy
ntfy:
condition: service_healthy
healthcheck:
# Check nginx is running and responding
test: [ "CMD", "curl", "-f", "http://localhost:80/" ]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
networks:
- plunk
volumes:
postgres_data:
driver: local
redis_data:
driver: local
minio_data:
driver: local
plunk_data:
driver: local
ntfy_cache:
driver: local
ntfy_etc:
driver: local
networks:
plunk:
driver: bridge