add docs site deployment infrastructure (Docker + Caddy)

- 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
This commit is contained in:
Ryan Malloy 2026-02-24 09:36:43 -07:00
parent 8800d35fd4
commit 3fe862109d
7 changed files with 121 additions and 1 deletions

5
docs/.dockerignore Normal file
View File

@ -0,0 +1,5 @@
node_modules/
dist/
.astro/
.env
agent-threads/

3
docs/.env.example Normal file
View File

@ -0,0 +1,3 @@
COMPOSE_PROJECT=gr-mcp-docs
DOMAIN=gr-mcp.warehack.ing
MODE=prod

15
docs/Caddyfile Normal file
View File

@ -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
}

37
docs/Dockerfile Normal file
View File

@ -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"]

16
docs/Makefile Normal file
View File

@ -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

View File

@ -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',

44
docs/docker-compose.yml Normal file
View File

@ -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