Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions backend/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,23 @@ FROM python:3.12-slim

WORKDIR /app

RUN useradd --create-home --shell /usr/sbin/nologin routeforge
RUN apt-get update \
&& apt-get install -y --no-install-recommends gosu \
&& rm -rf /var/lib/apt/lists/* \
&& useradd --create-home --shell /usr/sbin/nologin routeforge

COPY pyproject.toml ./
COPY app ./app
COPY alembic ./alembic
COPY alembic.ini ./alembic.ini
COPY docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh

RUN pip install --no-cache-dir . \
&& mkdir -p /app/data \
&& chown -R routeforge:routeforge /app
&& chown -R routeforge:routeforge /app \
&& chmod +x /usr/local/bin/docker-entrypoint.sh

USER routeforge
ENTRYPOINT ["docker-entrypoint.sh"]

EXPOSE 8000

Expand Down
7 changes: 7 additions & 0 deletions backend/docker-entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/bin/sh
set -e

mkdir -p /app/data
chown -R routeforge:routeforge /app/data

exec gosu routeforge "$@"
1 change: 1 addition & 0 deletions docs/operations/logging.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@ docker compose -f docker-compose.prod.yml logs -f postgres
- Check Postgres health and credentials (`DATABASE_URL`).
- Validate `CORS_ORIGINS` and `VITE_API_URL` alignment.
- Inspect retry/fallback diagnostics for upstream RIPEstat outages.
- If you see `sqlite3.OperationalError: attempt to write a readonly database` in dev/compose mode, check volume ownership on `/app/data` and rebuild/restart with the fixed backend image that normalizes volume permissions at startup.
8 changes: 8 additions & 0 deletions docs/operations/security.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,19 @@ Frontend nginx sets baseline headers:

## Container hardening

- Backend container starts through an entrypoint as root only long enough to normalize `/app/data` ownership, then drops privileges to non-root user `routeforge` for runtime.

- Backend container runs as non-root user `routeforge`.
- Backend image keeps only runtime-relevant files.
- Frontend image is multi-stage (build + runtime).
- Nginx container still runs with default upstream behavior; strict non-root nginx runtime can be added later as a dedicated hardening step.

## SQLite volume permissions (Docker Compose)

In the standard `docker-compose.yml` setup with SQLite, the database file is stored at `/app/data/routeforge.db` via the named volume mount `routeforge_data:/app/data`.

The backend entrypoint ensures `/app/data` is writable for the non-root runtime user `routeforge` on container start. This prevents SQLite write failures such as `sqlite3.OperationalError: attempt to write a readonly database` when a mounted volume is root-owned.

## What RouteForge does not do

- no ROA creation
Expand Down
Loading