From ff41dcaae084f492b980fcf259935f0015fd7e4a Mon Sep 17 00:00:00 2001 From: Johannes Millan Date: Wed, 10 Dec 2025 13:21:30 +0100 Subject: [PATCH] build(superSync): add docker config --- packages/super-sync-server/Caddyfile | 20 ++++ packages/super-sync-server/Dockerfile | 81 +++++++++++++ packages/super-sync-server/docker-compose.yml | 112 ++++++++++++++++++ packages/super-sync-server/env.example | 64 ++++++++++ 4 files changed, 277 insertions(+) create mode 100644 packages/super-sync-server/Caddyfile create mode 100644 packages/super-sync-server/Dockerfile create mode 100644 packages/super-sync-server/docker-compose.yml create mode 100644 packages/super-sync-server/env.example diff --git a/packages/super-sync-server/Caddyfile b/packages/super-sync-server/Caddyfile new file mode 100644 index 0000000000..21cccb6754 --- /dev/null +++ b/packages/super-sync-server/Caddyfile @@ -0,0 +1,20 @@ +{$DOMAIN} { + reverse_proxy supersync:1900 + + # Security headers + header { + X-Content-Type-Options nosniff + X-Frame-Options DENY + Referrer-Policy strict-origin-when-cross-origin + -Server + } + + # Enable compression + encode gzip zstd + + # Logging + log { + output stdout + format console + } +} diff --git a/packages/super-sync-server/Dockerfile b/packages/super-sync-server/Dockerfile new file mode 100644 index 0000000000..035d125cd3 --- /dev/null +++ b/packages/super-sync-server/Dockerfile @@ -0,0 +1,81 @@ +# Production Dockerfile for super-sync-server +# +# Build from repo root (to include workspace deps): +# docker build -f packages/super-sync-server/Dockerfile -t supersync . +# +# Or use docker-compose: +# docker-compose -f packages/super-sync-server/docker-compose.yml up -d + +FROM node:22-alpine AS builder + +WORKDIR /app + +# Install required system dependencies for Prisma +RUN apk add --no-cache openssl libc6-compat + +# Copy package files for workspace setup +COPY package.json package-lock.json ./ +COPY packages/shared-schema/package.json ./packages/shared-schema/ +COPY packages/super-sync-server/package.json ./packages/super-sync-server/ + +# Install dependencies (ignore scripts to skip husky/prepare from root) +RUN npm ci --workspace=packages/shared-schema --workspace=packages/super-sync-server --ignore-scripts + +# Copy source files +COPY packages/shared-schema/ ./packages/shared-schema/ +COPY packages/super-sync-server/ ./packages/super-sync-server/ + +# Build shared-schema first (it's a dependency) +WORKDIR /app/packages/shared-schema +RUN npm run build + +# Build super-sync-server +WORKDIR /app/packages/super-sync-server +RUN npx prisma generate +RUN rm -rf dist && npm run build + +# Copy public files to dist +RUN cp -r public dist/ + +# --- Production image --- +FROM node:22-alpine AS production + +WORKDIR /app + +# Install runtime dependencies only +RUN apk add --no-cache openssl libc6-compat + +# Create non-root user for security +RUN addgroup -g 1001 -S nodejs && \ + adduser -S supersync -u 1001 -G nodejs + +# Copy built artifacts from builder +COPY --from=builder /app/packages/super-sync-server/dist ./dist +COPY --from=builder /app/packages/super-sync-server/node_modules ./node_modules +COPY --from=builder /app/packages/super-sync-server/package.json ./ +COPY --from=builder /app/packages/super-sync-server/prisma ./prisma + +# Copy shared-schema (required dependency) +COPY --from=builder /app/packages/shared-schema/dist /app/node_modules/@sp/shared-schema/dist +COPY --from=builder /app/packages/shared-schema/package.json /app/node_modules/@sp/shared-schema/ + +# Create data directory +RUN mkdir -p /app/data && chown -R supersync:nodejs /app/data + +# Switch to non-root user +USER supersync + +# Expose default port +EXPOSE 1900 + +# Environment defaults (override in docker-compose or .env) +ENV NODE_ENV=production +ENV PORT=1900 +ENV DATA_DIR=/app/data + +# Health check +HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \ + CMD wget --no-verbose --tries=1 --spider http://localhost:${PORT}/health || exit 1 + +# Start server (run migrations first) +CMD ["sh", "-c", "npx prisma db push --skip-generate && node dist/index.js"] diff --git a/packages/super-sync-server/docker-compose.yml b/packages/super-sync-server/docker-compose.yml new file mode 100644 index 0000000000..3b4520a1ea --- /dev/null +++ b/packages/super-sync-server/docker-compose.yml @@ -0,0 +1,112 @@ +# Production docker-compose for super-sync-server +# +# Usage: +# 1. Copy env.example to .env and configure your settings +# 2. Run: docker-compose up -d +# 3. View logs: docker-compose logs -f +# +# Build from repo root: +# docker-compose -f packages/super-sync-server/docker-compose.yml up -d --build + +x-logging: &default-logging + driver: 'json-file' + options: + max-size: '10m' + max-file: '3' + +services: + supersync: + build: + context: ../.. + dockerfile: packages/super-sync-server/Dockerfile + image: supersync:latest + container_name: supersync-server + restart: always + environment: + - NODE_ENV=production + - PORT=1900 + - DATABASE_URL=postgresql://${POSTGRES_USER:-supersync}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-supersync} + - JWT_SECRET=${JWT_SECRET} + - PUBLIC_URL=https://${DOMAIN} + - CORS_ORIGINS=${CORS_ORIGINS:-https://app.super-productivity.com} + - SMTP_HOST=${SMTP_HOST:-} + - SMTP_PORT=${SMTP_PORT:-587} + - SMTP_SECURE=${SMTP_SECURE:-false} + - SMTP_USER=${SMTP_USER:-} + - SMTP_PASS=${SMTP_PASS:-} + - SMTP_FROM=${SMTP_FROM:-} + volumes: + - supersync-data:/app/data + depends_on: + postgres: + condition: service_healthy + healthcheck: + test: + [ + 'CMD', + 'wget', + '--no-verbose', + '--tries=1', + '--spider', + 'http://localhost:1900/health', + ] + interval: 30s + timeout: 5s + retries: 3 + start_period: 10s + networks: + - internal + logging: *default-logging + + postgres: + image: postgres:16-alpine + container_name: supersync-postgres + restart: always + environment: + - POSTGRES_USER=${POSTGRES_USER:-supersync} + - POSTGRES_PASSWORD=${POSTGRES_PASSWORD} + - POSTGRES_DB=${POSTGRES_DB:-supersync} + volumes: + - postgres-data:/var/lib/postgresql/data + healthcheck: + test: + [ + 'CMD-SHELL', + 'pg_isready -U ${POSTGRES_USER:-supersync} -d ${POSTGRES_DB:-supersync}', + ] + interval: 10s + timeout: 5s + retries: 5 + start_period: 10s + networks: + - internal + logging: *default-logging + + caddy: + image: caddy:2-alpine + container_name: supersync-caddy + restart: always + ports: + - '80:80' + - '443:443' + volumes: + - ./Caddyfile:/etc/caddy/Caddyfile:ro + - caddy-data:/data + - caddy-config:/config + environment: + - DOMAIN=${DOMAIN} + networks: + - internal + depends_on: + - supersync + logging: *default-logging + +volumes: + supersync-data: + postgres-data: + caddy-data: + caddy-config: + +networks: + internal: + driver: bridge diff --git a/packages/super-sync-server/env.example b/packages/super-sync-server/env.example new file mode 100644 index 0000000000..f9a37a550d --- /dev/null +++ b/packages/super-sync-server/env.example @@ -0,0 +1,64 @@ +# Super Sync Server - Production Environment Configuration +# Copy this file to .env and configure all required values + +# ============================================================================= +# REQUIRED SETTINGS +# ============================================================================= + +# Your domain (without https://) +# Caddy will automatically obtain SSL certificates for this domain +DOMAIN=sync.your-domain.com + +# JWT secret for authentication tokens (minimum 32 characters) +# Generate with: openssl rand -base64 32 +JWT_SECRET=your-secure-jwt-secret-minimum-32-characters + +# PostgreSQL password for the database +# Generate with: openssl rand -base64 24 +POSTGRES_PASSWORD=your-secure-postgres-password + +# ============================================================================= +# DATABASE SETTINGS (optional - defaults provided) +# ============================================================================= + +# PostgreSQL user (default: supersync) +# POSTGRES_USER=supersync + +# PostgreSQL database name (default: supersync) +# POSTGRES_DB=supersync + +# ============================================================================= +# CORS SETTINGS +# ============================================================================= + +# CORS allowed origins (comma-separated) +# Default: https://app.super-productivity.com +# Add your self-hosted frontend URL if applicable +CORS_ORIGINS=https://app.super-productivity.com + +# ============================================================================= +# SMTP CONFIGURATION (Required for email verification) +# ============================================================================= + +# SMTP server hostname +SMTP_HOST=smtp.your-email-provider.com + +# SMTP port (default: 587 for TLS, 465 for SSL) +SMTP_PORT=587 + +# Use SSL/TLS (true for port 465, false for STARTTLS on 587) +SMTP_SECURE=false + +# SMTP authentication credentials +SMTP_USER=your-smtp-username +SMTP_PASS=your-smtp-password + +# From address for emails +SMTP_FROM="Super Productivity Sync" + +# ============================================================================= +# ADVANCED SETTINGS (usually no changes needed) +# ============================================================================= + +# Log level (info, debug, warn, error) +# LOG_LEVEL=info