Skip to content

Latest commit

 

History

History
170 lines (113 loc) · 6.07 KB

File metadata and controls

170 lines (113 loc) · 6.07 KB

Docker & Docker Hub

CVE Radar ships as a single container: Express API + built Vite UI on port 3001.

Docker Hub page content (short + full overview, UI checklist): docs/dockerhub/
Push to Hub via API: DOCKERHUB_USERNAME=raminnietzsche DOCKERHUB_TOKEN=... npm run dockerhub:update

Pull from Docker Hub

docker pull raminnietzsche/cve-radar:latest
docker run --rm -p 3001:3001 raminnietzsche/cve-radar:latest

Optional NVD rate limits — pass an API key:

docker run --rm -p 3001:3001 -e NVD_API_KEY=your-key raminnietzsche/cve-radar:latest

Production API authentication (optional shared secret):

docker run --rm -p 3001:3001 \
  -e API_SECRET=your-long-random-secret \
  -e VITE_API_KEY=your-long-random-secret \
  raminnietzsche/cve-radar:latest

When API_SECRET is set, clients must send X-Api-Key or Authorization: Bearer. GET /api/health remains open for probes. See SECURITY.md.

Compose (published image):

docker compose -f docker-compose.hub.yml up -d

Production secrets (Docker Secrets / *_FILE env): see docs/self-hosted/SECRETS.md and docker-compose.secrets.example.yml.

Open http://localhost:3001

Build locally

docker compose up --build
# or
docker build -t cve-radar:local .
docker run --rm -p 3001:3001 cve-radar:local

CI publish (maintainers)

Workflow: .github/workflows/release-docker-hub.yml

On git tag v* (e.g. v1.1.0), GitHub Actions builds and pushes to:

docker.io/<DOCKERHUB_USERNAME>/cve-radar

GitHub secrets (CI publish)

The workflow job uses environment: docker. Add secrets in either place:

Where Path
Recommended Settings → Environmentsdocker → Environment secrets
Alternative Settings → Secrets and variablesActions → Repository secrets
Secret Description
DOCKERHUB_USERNAME Docker Hub user or org (e.g. raminnietzsche)
DOCKERHUB_TOKEN Access token with Read, Write, and Delete

Important: Read/Write alone can push images but Hub returns 403 insufficient scope when updating description/overview via API. Regenerate the token with Delete checked, then update the secret in Environments → docker.

Repository-level secrets alone are not visible to the job unless you remove environment: docker from the workflow or duplicate the secrets under the docker environment.

After secrets are set, create a release tag (git push origin v1.1.0) to publish X.Y.Z and latest. Pushes to main alone do not publish a new Hub image.

Tag cleanup

Remove legacy sha-*, X.Y, and X tags (keeps latest and full semver X.Y.Z):

DOCKERHUB_USERNAME=raminnietzsche DOCKERHUB_TOKEN='dckr_pat_...' npm run dockerhub:prune

Dry run: DRY_RUN=1 npm run dockerhub:prune

Container runtime (optional)

Variable Purpose
NVD_API_KEY NVD upstream rate limit
RATE_LIMIT_SCAN_PER_MIN App middleware: max POST /scan per IP/min (default 12)
RATE_LIMIT_WATCH_PER_MIN App middleware: max POST /watch per IP/min (default 120)
TRUST_PROXY_HOPS When behind nginx/Traefik, set to 1 so rate limits use the real client IP from the trusted proxy (default: socket address only; X-Forwarded-For is ignored)
SCAN_TIMEOUT_MS Abort long scan/watch requests
REDIS_URL Optional Redis URL for shared NVD/GitHub/OSV/RSS/translation cache across replicas (e.g. redis://redis:6379 in Compose)
CACHE_MAX_ENTRIES In-memory cache cap when Redis is not used (default 2000)
DATA_DIR Writable server data root (default ./data; Compose uses /app/data volume)

Redis (multi-instance)

When you run more than one CVE-Radar container behind a load balancer, set REDIS_URL so upstream API responses are cached once for all replicas. docker compose up (local build) starts a redis:7-alpine sidecar and wires REDIS_URL=redis://redis:6379 automatically.

Without REDIS_URL, each process keeps its own in-memory cache (default for npm run dev).

Verify shared cache: curl -s 'http://localhost:3001/api/health?detailed=true' | jq .cache should show "backend": "redis" when Redis is connected.

PostgreSQL scan history (optional)

Set DATABASE_URL to persist scan metadata server-side (stack, mode, counts, source health). Without it, history endpoints return 503 DATABASE_DISABLED and scans behave as today (client-only localStorage cache).

DATABASE_URL=postgres://user:pass@postgres:5432/cve_radar

Read API (v1 only):

  • GET /api/v1/scans/history?limit=50
  • GET /api/v1/scans/trends?days=30

Schema migration runs automatically from server/db/migrations/001_scan_history.sql on first pool connect.

Local Postgres with Compose profile:

# .env — when postgres profile is active
DATABASE_URL=postgres://cve_radar:cve_radar@127.0.0.1:5432/cve_radar

docker compose --profile postgres up --build

Persistent data volume

docker compose up mounts a named volume at /app/data so container recreation does not wipe server-side state (future mirror caches, audit files, etc.).

docker compose up --build -d
docker compose exec cve-radar sh -c 'echo ok > /app/data/.persist-test'
docker compose restart cve-radar
docker compose exec cve-radar cat /app/data/.persist-test   # → ok

Hub image (no local build):

docker compose -f docker-compose.hub.yml up -d

Backup:

docker run --rm -v cve-radar-data:/data -v "$PWD":/backup alpine \
  tar czf /backup/cve-radar-data.tgz -C /data .

Restore: extract archive into a new volume before compose up.

See Release process for tagging workflow.

Manual push (local)

docker login
docker build -t raminnietzsche/cve-radar:latest .
docker push raminnietzsche/cve-radar:latest

Replace raminnietzsche with your Docker Hub namespace if different.