name: usesend-prod services: postgres: image: postgres:16 container_name: usesend-db-prod restart: always environment: - POSTGRES_USER=${POSTGRES_USER:?err} - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:?err} - POSTGRES_DB=${POSTGRES_DB:?err} healthcheck: test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER}"] interval: 10s timeout: 5s retries: 5 # ports: # - "5432:5432" volumes: - database:/var/lib/postgresql/data redis: image: redis:7 container_name: usesend-redis-prod restart: always # ports: # - "6379:6379" volumes: - cache:/data command: ["redis-server", "--maxmemory-policy", "noeviction"] # S3-compatible storage for images uploaded in the email editor. Uploads go # straight from the browser to S3_COMPATIBLE_API_URL, and emails link to # S3_COMPATIBLE_PUBLIC_URL, so both must be public URLs (for example a # reverse proxy in front of port 9002). Leave them unset to disable uploads. rustfs: image: rustfs/rustfs:1.0.4 container_name: usesend-rustfs-prod restart: always security_opt: - no-new-privileges:true ports: - 127.0.0.1:${RUSTFS_API_PORT:-9002}:9000 - 127.0.0.1:${RUSTFS_CONSOLE_PORT:-9001}:9001 environment: # Falls back to the MinIO credentials older setups already have. RUSTFS_ACCESS_KEY: ${RUSTFS_ACCESS_KEY:-${MINIO_ROOT_USER:?set RUSTFS_ACCESS_KEY}} RUSTFS_SECRET_KEY: ${RUSTFS_SECRET_KEY:-${MINIO_ROOT_PASSWORD:?set RUSTFS_SECRET_KEY}} RUSTFS_ADDRESS: 0.0.0.0:9000 RUSTFS_CONSOLE_ADDRESS: 0.0.0.0:9001 RUSTFS_CONSOLE_ENABLE: "true" RUSTFS_OBS_LOGGER_LEVEL: error volumes: - rustfs:/data command: ["/data"] healthcheck: test: ["CMD", "curl", "-fsS", "http://127.0.0.1:9000/health"] interval: 20s timeout: 10s retries: 5 start_period: 40s # Creates the bucket, lets the dashboard upload to it (CORS) and makes # objects publicly readable so images load in sent emails. Safe to rerun. rustfs-init: image: amazon/aws-cli:2.34.30 restart: "no" entrypoint: ["/bin/sh", "-ec"] environment: AWS_ACCESS_KEY_ID: ${RUSTFS_ACCESS_KEY:-${MINIO_ROOT_USER:?set RUSTFS_ACCESS_KEY}} AWS_SECRET_ACCESS_KEY: ${RUSTFS_SECRET_KEY:-${MINIO_ROOT_PASSWORD:?set RUSTFS_SECRET_KEY}} AWS_DEFAULT_REGION: us-east-1 AWS_EC2_METADATA_DISABLED: "true" BUCKET: ${S3_COMPATIBLE_BUCKET:-unsend} APP_ORIGIN: ${NEXTAUTH_URL:?err} depends_on: rustfs: condition: service_healthy command: - | s3="aws --endpoint-url http://rustfs:9000 s3api" $$s3 head-bucket --bucket "$$BUCKET" >/dev/null 2>&1 || $$s3 create-bucket --bucket "$$BUCKET" $$s3 put-bucket-cors --bucket "$$BUCKET" --cors-configuration \ '{"CORSRules":[{"AllowedOrigins":["'"$$APP_ORIGIN"'"],"AllowedMethods":["GET","HEAD","PUT"],"AllowedHeaders":["*"],"ExposeHeaders":["ETag"],"MaxAgeSeconds":3600}]}' $$s3 put-bucket-policy --bucket "$$BUCKET" --policy \ '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":"*","Action":["s3:GetObject"],"Resource":["arn:aws:s3:::'"$$BUCKET"'/*"]}]}' usesend: image: usesend/usesend:latest container_name: usesend restart: always ports: - ${PORT:-3000}:${PORT:-3000} environment: - HOSTNAME=${HOSTNAME:-0.0.0.0} - PORT=${PORT:-3000} - DATABASE_URL=${DATABASE_URL:?err} - NEXTAUTH_URL=${NEXTAUTH_URL:?err} - NEXTAUTH_SECRET=${NEXTAUTH_SECRET:?err} - AWS_ACCESS_KEY=${AWS_ACCESS_KEY:-} - AWS_SECRET_KEY=${AWS_SECRET_KEY:-} - AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID:-} - AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY:-} - AWS_DEFAULT_REGION=${AWS_DEFAULT_REGION:?err} - SNS_SIGNATURE_VERIFICATION=${SNS_SIGNATURE_VERIFICATION:-enforce} - GITHUB_ID=${GITHUB_ID:?err} - GITHUB_SECRET=${GITHUB_SECRET:?err} - REDIS_URL=${REDIS_URL:?err} - REDIS_KEY_PREFIX=${REDIS_KEY_PREFIX:-} - NEXT_PUBLIC_IS_CLOUD=${NEXT_PUBLIC_IS_CLOUD:-false} - API_RATE_LIMIT=${API_RATE_LIMIT:-1} - SMTP_HOST=${SMTP_HOST:-smtp.usesend.com} - SMTP_USER=${SMTP_USER:-usesend} - S3_COMPATIBLE_ACCESS_KEY=${RUSTFS_ACCESS_KEY:-${MINIO_ROOT_USER:?set RUSTFS_ACCESS_KEY}} - S3_COMPATIBLE_SECRET_KEY=${RUSTFS_SECRET_KEY:-${MINIO_ROOT_PASSWORD:?set RUSTFS_SECRET_KEY}} - S3_COMPATIBLE_API_URL=${S3_COMPATIBLE_API_URL:-} - S3_COMPATIBLE_PUBLIC_URL=${S3_COMPATIBLE_PUBLIC_URL:-} - S3_COMPATIBLE_BUCKET=${S3_COMPATIBLE_BUCKET:-unsend} depends_on: postgres: condition: service_healthy redis: condition: service_started rustfs-init: condition: service_completed_successfully volumes: database: cache: rustfs: