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