From 70a3975ed06464b40cae6b071f029e7596831be6 Mon Sep 17 00:00:00 2001 From: Dodo Date: Sat, 13 Jun 2026 10:40:16 +0700 Subject: [PATCH] Add production deployment config (Caddy + docker compose) --- .env.prod.example | 15 +++++++++ Caddyfile | 3 ++ deploy.sh | 11 +++++++ docker-compose.prod.yml | 69 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 98 insertions(+) create mode 100644 .env.prod.example create mode 100644 Caddyfile create mode 100755 deploy.sh create mode 100644 docker-compose.prod.yml diff --git a/.env.prod.example b/.env.prod.example new file mode 100644 index 0000000..9924d09 --- /dev/null +++ b/.env.prod.example @@ -0,0 +1,15 @@ +# Copy this file to .env on the server, next to docker-compose.prod.yml, +# and fill in real values. NEVER commit the real .env file. +# +# Generate strong secrets with: +# openssl rand -hex 24 -> POSTGRES_PASSWORD +# openssl rand -hex 32 -> JWT_SECRET + +POSTGRES_DB=sig +POSTGRES_USER=sig +POSTGRES_PASSWORD= +JWT_SECRET= + +# Public hostname Caddy will request a Let's Encrypt cert for. +# No domain yet? Use .sslip.io - it resolves to the server's IP. +DOMAIN= diff --git a/Caddyfile b/Caddyfile new file mode 100644 index 0000000..d9e9356 --- /dev/null +++ b/Caddyfile @@ -0,0 +1,3 @@ +{$DOMAIN} { + reverse_proxy frontend:3000 +} diff --git a/deploy.sh b/deploy.sh new file mode 100755 index 0000000..5bf0d7e --- /dev/null +++ b/deploy.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Deploys the current main branch to production over SSH + Docker Compose. +# Usage: ./deploy.sh + +SERVER="root@159.223.38.184" +SSH_KEY="$HOME/.ssh/id_ed25519" +APP_DIR="/root/pba-new" + +ssh -i "$SSH_KEY" "$SERVER" "cd $APP_DIR && git pull --ff-only && docker compose -f docker-compose.prod.yml --env-file .env up -d --build && docker compose -f docker-compose.prod.yml ps" diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml new file mode 100644 index 0000000..ff5cd5b --- /dev/null +++ b/docker-compose.prod.yml @@ -0,0 +1,69 @@ +services: + postgres: + image: postgres:16-alpine + environment: + POSTGRES_DB: ${POSTGRES_DB:-sig} + POSTGRES_USER: ${POSTGRES_USER:-sig} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + volumes: + - postgres_data:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-sig} -d ${POSTGRES_DB:-sig}"] + interval: 5s + timeout: 5s + retries: 10 + restart: unless-stopped + + fuzzy-service: + build: + context: ./fuzzy-service + dockerfile: Dockerfile + restart: unless-stopped + + backend: + build: + context: ./backend + dockerfile: Dockerfile + environment: + PORT: 4000 + JWT_SECRET: ${JWT_SECRET} + FRONTEND_URL: https://${DOMAIN} + DATABASE_URL: postgres://${POSTGRES_USER:-sig}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-sig} + FUZZY_SERVICE_URL: http://fuzzy-service:5001 + depends_on: + postgres: + condition: service_healthy + restart: unless-stopped + + frontend: + build: + context: ./frontend + dockerfile: Dockerfile.frontend + args: + NEXT_PUBLIC_BACKEND_URL: https://${DOMAIN} + BACKEND_URL: http://backend:4000 + environment: + NODE_ENV: production + depends_on: + - backend + restart: unless-stopped + + caddy: + image: caddy:2-alpine + environment: + DOMAIN: ${DOMAIN} + ports: + - "80:80" + - "443:443" + volumes: + - ./Caddyfile:/etc/caddy/Caddyfile:ro + - caddy_data:/data + - caddy_config:/config + depends_on: + - frontend + restart: unless-stopped + +volumes: + postgres_data: + caddy_data: + caddy_config: