From b0bd8277a83af35f241754ed7d83e49d7f4d1d09 Mon Sep 17 00:00:00 2001 From: Justin Reiners Date: Thu, 26 Mar 2026 12:49:42 -0500 Subject: [PATCH] feat: add Docker deployment (Dockerfile, compose, Caddyfile) Multi-stage Dockerfile builds SvelteKit then runs a lean production image. docker-compose.yml wires up MariaDB with health checks, the app, and Caddy for TLS termination. Caddyfile uses SITE_DOMAIN env var with localhost fallback. Co-Authored-By: Claude Sonnet 4.6 --- Caddyfile | 3 +++ Dockerfile | 18 ++++++++++++++++ docker-compose.yml | 52 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+) create mode 100644 Caddyfile create mode 100644 Dockerfile create mode 100644 docker-compose.yml diff --git a/Caddyfile b/Caddyfile new file mode 100644 index 0000000..4679d77 --- /dev/null +++ b/Caddyfile @@ -0,0 +1,3 @@ +{$SITE_DOMAIN:localhost} { + reverse_proxy app:3000 +} diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..6d727b7 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,18 @@ +FROM node:22-alpine AS builder +WORKDIR /app +COPY package*.json ./ +RUN npm ci +COPY . . +RUN npm run build + +FROM node:22-alpine +WORKDIR /app +COPY --from=builder /app/build ./build +COPY --from=builder /app/node_modules ./node_modules +COPY --from=builder /app/package.json ./ +COPY --from=builder /app/drizzle ./drizzle +COPY --from=builder /app/scripts ./scripts + +ENV NODE_ENV=production +EXPOSE 3000 +CMD ["node", "build"] diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..5175749 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,52 @@ +services: + db: + image: mariadb:11 + restart: unless-stopped + environment: + MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD:-fosterflow} + MYSQL_DATABASE: fosterflow + MYSQL_USER: fosterflow + MYSQL_PASSWORD: ${DB_PASSWORD:-fosterflow} + volumes: + - db_data:/var/lib/mysql + healthcheck: + test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"] + interval: 10s + timeout: 5s + retries: 5 + + app: + build: . + restart: unless-stopped + depends_on: + db: + condition: service_healthy + environment: + DATABASE_URL: mysql://fosterflow:${DB_PASSWORD:-fosterflow}@db:3306/fosterflow + SESSION_SECRET: ${SESSION_SECRET:-change-me-in-production} + PUBLIC_SITE_URL: ${PUBLIC_SITE_URL:-http://localhost:3000} + UPLOAD_DIR: /app/uploads + PORT: 3000 + env_file: + - .env + ports: + - "3000:3000" + volumes: + - uploads:/app/uploads + + caddy: + image: caddy:2-alpine + restart: unless-stopped + ports: + - "80:80" + - "443:443" + volumes: + - ./Caddyfile:/etc/caddy/Caddyfile + - caddy_data:/data + - caddy_config:/config + +volumes: + db_data: + uploads: + caddy_data: + caddy_config: