curltastic/docker/README.md
2026-09-08 02:16:58 +00:00

71 lines
3.7 KiB
Markdown

# Production images
Build from the repository root (no source mounts or runtime package installs):
```sh
docker build --target frontend -t curltastic-frontend .
docker build --target backend -t curltastic-backend .
```
| Target | Listener | Runtime user | Healthcheck |
| --- | --- | --- | --- |
| `frontend` (default final target) | HTTP `8080` | `101:101` | `GET /healthz` |
| `backend` | HTTP/WebSocket `3000` | `10001:10001` | `GET /` |
The frontend build argument `VITE_BASE_PATH` defaults to `/curltastic/` and is
passed to `vite build --base`. There are no required runtime environment
variables, credentials, writable application directories, or persistent volumes.
The Rust server keeps rooms in memory; rebuilding/restarting it loses games.
## Compose integration contract
- Publish/route only frontend port **8080**. Explicitly set Traefik's load-balancer
port to 8080; do not infer it from the upstream nginx image metadata.
- Traefik routes `/curltastic/` and strips `/curltastic` before forwarding.
- Attach frontend to Traefik's external `web` network and a private application
network. Put backend only on that private network, with the service/DNS name
**`curltastic-backend`**. Do not publish backend port 3000 or enable Traefik on it.
- The browser requests public `/curltastic/ws` using its existing host, port and
TLS scheme. nginx receives `/ws` and proxies the upgrade and query string to
`curltastic-backend:3000/ws`. It also proxies `POST /room`, exposed publicly as
`/curltastic/room`. The current frontend creates room IDs locally and does not
make HTTP room requests; there is no separate frontend HTTP API URL to set.
- Docker DNS is re-resolved every five seconds so backend replacement during
Compose watch does not leave nginx using a stale container address.
- Recommended runtime settings: `read_only: true`, `cap_drop: [ALL]`,
`security_opt: [no-new-privileges:true]`. Give frontend a writable `/tmp` tmpfs
(mode 1777) for nginx PID/temp files. Backend needs no writable mount.
- Never mount source code, a Docker socket, or host credentials. The build context
is allowlisted by `.dockerignore`; host dependencies and `.env*` are excluded.
- Use Compose watch `action: rebuild`: frontend changes rebuild the `frontend`
target, backend changes rebuild the `backend` target. Ignore node_modules,
dist, target, .git and other generated files. Watch Dockerfile for both services
and `docker/nginx.conf` for frontend.
The nginx listener expects already-stripped paths; a raw host-port request to
`/curltastic/` does not simulate Traefik. Test the public route through a
prefix-stripping test proxy, or request `/`, `/assets/...`, `/ws`, `/room` directly
when testing nginx alone.
## Development and verification
Local `npm run dev` still defaults to `/` and connects to the page hostname on
backend port 3000. Existing `VITE_WS_URL` overrides are preserved for custom local
setups; Vite variables are build-time settings, not runtime container settings.
Room navigation and share links retain the page path.
```sh
(cd frontend && npm ci && npm test -- --pool=forks --poolOptions.forks.singleFork)
(cd frontend && npm run build -- --base=/curltastic/)
(cd backend && cargo test --locked)
```
The frontend Docker build runs its tests and TypeScript checking before producing
static assets. The backend build uses the committed Cargo lockfile.
Verification at implementation: frontend 26 tests passed, Rust 22 tests passed,
and the production subpath frontend build passed. Both Docker build attempts were
denied by the execution approval layer; image builds, nginx syntax, and live
HTTP/WebSocket proxy behavior therefore remain unverified. No servers were
started and no deployment was performed.