fabro/docker-compose.split-web.yaml
Bryan Helmkamp 31a990c4dc
Add split web Docker Compose PoC (#445)
## Summary

Adds a standalone Docker Compose proof that runs the Fabro Rust API, a
Caddy static SPA server, and a Caddy edge proxy as separate services.
This demonstrates split web asset serving while keeping `/api/*`,
`/auth/*`, and `/health` same-origin with the API server.

## Changes

- Adds `docker-compose.split-web.yaml` with private `fabro-api` and
`fabro-web` services behind an exposed `edge` proxy on port 8080.
- Adds Caddy edge routing that sends `/api/*`, `/auth/*`, and `/health`
to Rust, while everything else goes to the static web service.
- Adds a static Caddy config for `apps/fabro-web/dist` with SPA
fallback, source-map blocking, security headers, immutable asset
caching, and `X-Fabro-PoC-Upstream` route-proof headers.
- Adds PoC server settings and a README with build, run, and validation
commands.

## Verification

- `cargo dev docker-build --tag fabro-sh/fabro:split-web-poc`
- `docker compose -f docker-compose.split-web.yaml up -d`
- `docker compose -f docker-compose.split-web.yaml ps`
- `curl` checks for `/runs`, `/assets/app.css`, `/assets/app.css.map`,
`/api/v1/health`, `/api/v1/auth/config`, `/auth/login/dev-token`,
`/api/v1/auth/me`, and `/api/v1/attach`
- Browser login flow via `browser-use`: loaded `/login`, submitted the
dev token, and landed on the authenticated Runs screen
- `docker compose -f docker-compose.split-web.yaml config`
- `caddy validate` for both Caddyfiles
- `git diff --check`

---

[![Compound
Engineering](https://img.shields.io/badge/Compound_Engineering-6366f1)](https://github.com/EveryInc/compound-engineering-plugin)
🤖 Generated with GPT-5 via [Codex](https://openai.com/codex)
2026-05-28 00:03:00 -04:00

52 lines
1.3 KiB
YAML

services:
fabro-api:
image: ${FABRO_IMAGE:-fabro-sh/fabro:split-web-poc}
restart: unless-stopped
expose:
- "32276"
command:
- sh
- -c
- >-
exec fabro server start --foreground
--bind 0.0.0.0:32276
--config /config/settings.toml
volumes:
- fabro-storage:/storage
- /var/run/docker.sock:/var/run/docker.sock
- ./docker/split-web/settings.toml:/config/settings.toml:ro
environment:
FABRO_WEB_URL: http://localhost:${SPLIT_WEB_PORT:-8080}
SESSION_SECRET: ${SESSION_SECRET:-}
FABRO_DEV_TOKEN: ${FABRO_DEV_TOKEN:-}
healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1:32276/health"]
interval: 10s
timeout: 5s
retries: 12
start_period: 20s
fabro-web:
image: caddy:2-alpine
restart: unless-stopped
expose:
- "80"
volumes:
- ./apps/fabro-web:/srv/web:ro
- ./docker/split-web/Caddyfile.static:/etc/caddy/Caddyfile:ro
edge:
image: caddy:2-alpine
restart: unless-stopped
ports:
- "${SPLIT_WEB_PORT:-8080}:80"
volumes:
- ./docker/split-web/Caddyfile.edge:/etc/caddy/Caddyfile:ro
depends_on:
fabro-api:
condition: service_healthy
fabro-web:
condition: service_started
volumes:
fabro-storage: