Files
FlowReader/docker-compose.yaml
T
Claude f3816f4d78 feat: rewrite the backend in Rust
Replaces the Go server with a Rust one (axum, tokio, sqlx, feed-rs,
ammonia, reqwest) serving the same REST/WebSocket API, so the React
frontend is unchanged.

- Same database: migrations keep the schema_migrations table and file
  names, Argon2id hashes and hashed session tokens created by the Go
  server keep working (users stay logged in), and feed item GUIDs are
  computed the same way, so existing articles are not re-ingested.
- Same security model: SSRF-safe fetching (public addresses only,
  checked at resolution time and on every redirect), HTML sanitization,
  CSP and security headers, same-origin guard, WebSocket origin check,
  per-IP / per-user rate limits, trusted-proxy aware client IPs.
- Fix: articles whose publication date lies in the future (ingested
  before the clamp existed) pinned the top of the list. The maintenance
  job now pulls such dates back at startup and daily.
- Relative links and images in feed content are resolved against the
  article URL instead of being dropped.
- Deploy: static musl binary in an Alpine image; the Unraid compose file
  uses pull_policy: always so the new image is applied on the next
  `docker compose up -d`. CI runs fmt, clippy and tests (including a
  PostgreSQL integration test) before building the image.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fc1UFpB4V1MGWLxHAu3BMK
2026-10-13 10:56:18 +00:00

65 lines
2.1 KiB
YAML

services:
app:
build:
context: .
dockerfile: Dockerfile
ports:
- "8080:8080"
environment:
- PORT=8080
# Set a strong password in a .env file next to this compose file.
# Note: POSTGRES_PASSWORD only applies when the volume is first created.
- DATABASE_URL=postgres://flowreader:${POSTGRES_PASSWORD:-flowreader}@db:5432/flowreader?sslmode=disable
# Close public sign-ups once your account exists (the first account is admin).
- REGISTRATION_ENABLED=${REGISTRATION_ENABLED:-true}
# Behind a reverse proxy (Traefik, NPM, Caddy…): its IP/CIDR, so rate
# limiting sees real client IPs. Leave empty when exposed directly.
- TRUSTED_PROXIES=${TRUSTED_PROXIES:-}
# Force Secure cookies when served over HTTPS behind a proxy.
- COOKIE_SECURE=${COOKIE_SECURE:-}
# Optional: AI summaries (OpenRouter). Leave empty to disable.
- OPENROUTER_API_KEY=${OPENROUTER_API_KEY:-}
depends_on:
db:
condition: service_healthy
restart: unless-stopped
healthcheck:
test: [ "CMD", "wget", "-q", "--spider", "http://localhost:8080/health" ]
interval: 10s
timeout: 5s
retries: 3
start_period: 10s
deploy:
resources:
limits:
memory: 64M
db:
image: postgres:16-alpine
environment:
- POSTGRES_USER=flowreader
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-flowreader}
- POSTGRES_DB=flowreader
volumes:
- postgres_data:/var/lib/postgresql/data
# Not published on the host: only the app container needs the database.
# Uncomment for local debugging only (and bind to 127.0.0.1).
# ports:
# - "127.0.0.1:5432:5432"
restart: unless-stopped
healthcheck:
test: [ "CMD-SHELL", "pg_isready -U flowreader -d flowreader" ]
interval: 5s
timeout: 5s
retries: 5
# RAM Optimization (from Architecture NFR1)
command: >
postgres -c shared_buffers=24MB -c max_connections=20 -c work_mem=2MB
deploy:
resources:
limits:
memory: 80M
volumes:
postgres_data: