From 3fe862109d42bb0830a2bca52a1b594bc54e01c8 Mon Sep 17 00:00:00 2001 From: Ryan Malloy Date: Tue, 24 Feb 2026 09:36:43 -0700 Subject: [PATCH] add docs site deployment infrastructure (Docker + Caddy) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Multi-stage Dockerfile: Node builder → Caddy static prod, Node HMR dev - docker-compose with dev/prod profiles on external caddy network - Caddyfile with immutable hashed asset caching - Makefile: prod, dev, down, logs, rebuild targets - Site URL configurable via SITE_URL env var --- docs/.dockerignore | 5 +++++ docs/.env.example | 3 +++ docs/Caddyfile | 15 ++++++++++++++ docs/Dockerfile | 37 ++++++++++++++++++++++++++++++++++ docs/Makefile | 16 +++++++++++++++ docs/astro.config.mjs | 2 +- docs/docker-compose.yml | 44 +++++++++++++++++++++++++++++++++++++++++ 7 files changed, 121 insertions(+), 1 deletion(-) create mode 100644 docs/.dockerignore create mode 100644 docs/.env.example create mode 100644 docs/Caddyfile create mode 100644 docs/Dockerfile create mode 100644 docs/Makefile create mode 100644 docs/docker-compose.yml diff --git a/docs/.dockerignore b/docs/.dockerignore new file mode 100644 index 0000000..c458afe --- /dev/null +++ b/docs/.dockerignore @@ -0,0 +1,5 @@ +node_modules/ +dist/ +.astro/ +.env +agent-threads/ diff --git a/docs/.env.example b/docs/.env.example new file mode 100644 index 0000000..a1271e9 --- /dev/null +++ b/docs/.env.example @@ -0,0 +1,3 @@ +COMPOSE_PROJECT=gr-mcp-docs +DOMAIN=gr-mcp.warehack.ing +MODE=prod diff --git a/docs/Caddyfile b/docs/Caddyfile new file mode 100644 index 0000000..b8fe7ef --- /dev/null +++ b/docs/Caddyfile @@ -0,0 +1,15 @@ +:80 { + root * /srv + file_server + + # Hashed assets are immutable + @hashed path /_astro/* + header @hashed Cache-Control "public, max-age=31536000, immutable" + + # Everything else: short cache, revalidate + @unhashed not path /_astro/* + header @unhashed Cache-Control "public, max-age=3600, must-revalidate" + + # SPA fallback for clean URLs + try_files {path} {path}/ /404.html +} diff --git a/docs/Dockerfile b/docs/Dockerfile new file mode 100644 index 0000000..2d28fc2 --- /dev/null +++ b/docs/Dockerfile @@ -0,0 +1,37 @@ +# ── Stage 1: Build ───────────────────────────────────────────────── +FROM node:22-slim AS builder + +WORKDIR /app + +COPY package.json package-lock.json ./ +RUN npm ci + +COPY . . + +ARG SITE_URL=https://gr-mcp.warehack.ing +ENV ASTRO_TELEMETRY_DISABLED=1 + +RUN npm run build + +# ── Stage 2: Production (Caddy static server) ───────────────────── +FROM caddy:2-alpine AS prod + +COPY --from=builder /app/dist /srv +COPY Caddyfile /etc/caddy/Caddyfile + +EXPOSE 80 + +# ── Stage 3: Development (Node with HMR) ────────────────────────── +FROM node:22-slim AS dev + +WORKDIR /app + +COPY package.json package-lock.json ./ +RUN npm ci + +ENV ASTRO_TELEMETRY_DISABLED=1 +ENV HOST=0.0.0.0 + +EXPOSE 4321 + +CMD ["npm", "run", "dev", "--", "--host", "0.0.0.0"] diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..389193c --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,16 @@ +prod: + docker compose up -d --build + +dev: + docker compose --profile dev up --build + +down: + docker compose down + docker compose --profile dev down + +logs: + docker compose logs -f + +rebuild: + docker compose build --no-cache + docker compose up -d diff --git a/docs/astro.config.mjs b/docs/astro.config.mjs index 352738e..f22eadf 100644 --- a/docs/astro.config.mjs +++ b/docs/astro.config.mjs @@ -2,7 +2,7 @@ import { defineConfig } from 'astro/config'; import starlight from '@astrojs/starlight'; export default defineConfig({ - site: 'https://gr-mcp.supported.systems', + site: process.env.SITE_URL || 'https://gr-mcp.warehack.ing', integrations: [ starlight({ title: 'GR-MCP', diff --git a/docs/docker-compose.yml b/docs/docker-compose.yml new file mode 100644 index 0000000..45b73f4 --- /dev/null +++ b/docs/docker-compose.yml @@ -0,0 +1,44 @@ +services: + # ── Production: Caddy serves static build ────────────────────── + docs: + build: + context: . + target: prod + args: + SITE_URL: https://${DOMAIN} + restart: unless-stopped + networks: + - caddy + labels: + caddy: ${DOMAIN} + caddy.reverse_proxy: "{{upstreams 80}}" + + # ── Development: Node with HMR ──────────────────────────────── + docs-dev: + build: + context: . + target: dev + profiles: [dev] + volumes: + - ./src:/app/src + - ./astro.config.mjs:/app/astro.config.mjs + - ./package.json:/app/package.json + environment: + - VITE_HMR_HOST=${DOMAIN} + networks: + - caddy + labels: + caddy: ${DOMAIN} + caddy.reverse_proxy: "{{upstreams 4321}}" + caddy.reverse_proxy.flush_interval: "-1" + caddy.reverse_proxy.transport: http + caddy.reverse_proxy.transport.read_timeout: "0" + caddy.reverse_proxy.transport.write_timeout: "0" + caddy.reverse_proxy.transport.keepalive: 5m + caddy.reverse_proxy.transport.keepalive_idle_conns: "10" + caddy.reverse_proxy.stream_timeout: 24h + caddy.reverse_proxy.stream_close_delay: 5s + +networks: + caddy: + external: true