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
25 changes: 19 additions & 6 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,13 +1,26 @@
DATABASE_URL=sqlite:///./routeforge.db
HTTP_TIMEOUT_SECONDS=10
CACHE_TTL_SECONDS=900
RIPESTAT_CACHE_TTL_SECONDS=900
CORS_ORIGINS=http://localhost:3000,http://127.0.0.1:3000
RIPESTAT_BASE_URL=https://stat.ripe.net/data
# General
ROUTEFORGE_DEMO_MODE=false
LOG_LEVEL=INFO

# Database (change POSTGRES_PASSWORD before production use)
POSTGRES_DB=routeforge
POSTGRES_USER=routeforge
POSTGRES_PASSWORD=change-me
DATABASE_URL=postgresql+psycopg://routeforge:change-me@postgres:5432/routeforge

# CORS (comma-separated list)
CORS_ORIGINS=http://localhost:3000

# Frontend runtime/build API target
VITE_API_URL=http://localhost:8000

# RIPEstat
RIPESTAT_BASE_URL=https://stat.ripe.net/data
RIPESTAT_CACHE_TTL_SECONDS=900
RIPESTAT_TIMEOUT_SECONDS=10
RIPESTAT_MAX_RETRIES=1
RIPESTAT_RETRY_BACKOFF_SECONDS=0.5
RIPESTAT_USE_STALE_CACHE_ON_ERROR=true

# Optional general HTTP timeout for backend calls
HTTP_TIMEOUT_SECONDS=10
36 changes: 34 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

RouteForge is a read-only routing preflight and explainability tool for BGP, RPKI, Registry/IRR and Routing Visibility checks.

Current user-facing version: **v0.4.2-alpha**.
Current user-facing version: **v0.5.0-beta**.

<!-- Screenshot gallery placeholder:
- docs/screenshots/dashboard.png
Expand Down Expand Up @@ -32,7 +32,7 @@ Routing changes often require fast but traceable checks across multiple external

## Current Alpha Status

RouteForge is a **functional alpha** release with production-like workflows for read-only validation and demo usage. Current release target: **v0.4.2-alpha**.
RouteForge is a **functional alpha** release with production-like workflows for read-only validation and demo usage. Current release target: **v0.5.0-beta**.

## Quickstart with Docker Compose

Expand Down Expand Up @@ -145,6 +145,38 @@ RouteForge is read-only by design:
- No full BGP monitoring replacement.
- No user management yet.


## Selfhosting

### Dev/Demo Start
```bash
cp .env.example .env
docker compose up --build
```

### Production Start
```bash
cp .env.example .env
# edit .env (especially POSTGRES_PASSWORD, DATABASE_URL, CORS_ORIGINS, VITE_API_URL)
docker compose -f docker-compose.prod.yml up -d --build
```

### Environment
- `.env.example` documents required production variables.
- Keep RouteForge read-only (no write operations to RIPE DB, RPKI, or routers).

### Database
- Recommended production path: PostgreSQL via `docker-compose.prod.yml`.
- Backend initializes tables on startup using SQLAlchemy `create_all`.
- Alembic exists, but migration workflows are still beta-grade.
- Database migrations are currently simple/alpha-grade and will be hardened before v1.0.

### Operations docs
- Backup/Restore: `docs/operations/backup-restore.md`
- Reverse Proxy: `docs/operations/reverse-proxy.md`
- Logging: `docs/operations/logging.md`
- Upgrades: `docs/operations/upgrades.md`

## Roadmap

See [ROADMAP.md](ROADMAP.md).
Expand Down
23 changes: 23 additions & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,28 @@
# Release Notes

## v0.5.0-beta

**Production Selfhosting Foundation**

### Highlights

- Production Docker Compose
- PostgreSQL-backed deployment path
- Healthchecks
- Backup/Restore documentation
- Reverse proxy documentation
- Logging and upgrade documentation
- Continued read-only safety model

### Known limitations

- Database migrations are currently simple/alpha-grade and will be hardened before v1.0.
- No authentication yet
- No multi-user support yet
- No write operations

---

## v0.4.2-alpha

### Highlights
Expand Down
2 changes: 1 addition & 1 deletion ROADMAP.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# RouteForge Roadmap

## Current Status
v0.3.0-alpha, functional alpha, read-only
v0.5.0-beta, beta foundation for production selfhosting, read-only

## v0.3.x
- demo polish
Expand Down
2 changes: 1 addition & 1 deletion backend/app/api/routes_health.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@

@router.get('/health')
def health() -> dict:
return {"status": "ok"}
return {"status": "ok", "version": "v0.5.0-beta"}
2 changes: 1 addition & 1 deletion backend/app/api/routes_system.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
def system_info():
return {
'name': 'RouteForge',
'version': 'v0.4.2-alpha',
'version': 'v0.5.0-beta',
'demo_mode': settings.demo_mode,
'read_only': True,
'data_sources': ['RIPEstat', 'RIPEstat Whois/Registry'],
Expand Down
2 changes: 1 addition & 1 deletion backend/app/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from app.config import settings
from app.database import Base, engine

app = FastAPI(title="RouteForge", version="0.4.2")
app = FastAPI(title="RouteForge", version="0.5.0")

app.add_middleware(
CORSMiddleware,
Expand Down
2 changes: 1 addition & 1 deletion backend/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "routeforge-backend"
version = "0.4.2"
version = "0.5.0"
description = "RouteForge backend"
requires-python = ">=3.12"
dependencies = [
Expand Down
59 changes: 59 additions & 0 deletions docker-compose.prod.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
services:
postgres:
image: postgres:16-alpine
restart: unless-stopped
env_file:
- .env
environment:
POSTGRES_DB: ${POSTGRES_DB}
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- routeforge_postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
interval: 10s
timeout: 5s
retries: 5
start_period: 15s

backend:
build:
context: ./backend
restart: unless-stopped
env_file:
- .env
environment:
DATABASE_URL: ${DATABASE_URL}
depends_on:
postgres:
condition: service_healthy
ports:
- "8000:8000"
healthcheck:
test: ["CMD-SHELL", "python -c \"import urllib.request; urllib.request.urlopen('http://localhost:8000/health')\""]
interval: 15s
timeout: 5s
retries: 5
start_period: 20s

frontend:
build:
context: ./frontend
args:
VITE_API_URL: ${VITE_API_URL}
restart: unless-stopped
depends_on:
backend:
condition: service_healthy
ports:
- "3000:80"
healthcheck:
test: ["CMD-SHELL", "wget -q -O /dev/null http://localhost/ || exit 1"]
interval: 30s
timeout: 5s
retries: 5
start_period: 10s

volumes:
routeforge_postgres_data:
32 changes: 32 additions & 0 deletions docs/operations/backup-restore.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Backup and Restore

## What to back up
- PostgreSQL data (logical dump and/or Docker volume snapshot).
- `.env` and any reverse proxy configuration.
- Optional exported reports if you archive them outside the DB.

## PostgreSQL backup
```bash
docker compose -f docker-compose.prod.yml exec postgres pg_dump -U routeforge routeforge > routeforge-backup.sql
```

## PostgreSQL restore
```bash
cat routeforge-backup.sql | docker compose -f docker-compose.prod.yml exec -T postgres psql -U routeforge routeforge
```

## Docker volume notes
- The persistent database volume is `routeforge_postgres_data`.
- For crash-consistent volume snapshots, stop writes first (or stop backend temporarily).

## Configuration backup
- Back up `.env` separately from database dumps.
- Keep secrets in a secure secret manager or encrypted backup location.

## Verification after restore
- Start stack and check backend health:
```bash
curl http://localhost:8000/health
```
- Open UI and verify report history is present.
- If using demo/SQLite setups, back up the SQLite file separately.
26 changes: 26 additions & 0 deletions docs/operations/logging.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Logging

## Docker Compose logs
```bash
docker compose -f docker-compose.prod.yml logs -f
docker compose -f docker-compose.prod.yml logs -f backend
docker compose -f docker-compose.prod.yml logs -f frontend
docker compose -f docker-compose.prod.yml logs -f postgres
```

## Backend logs
- Backend logs are emitted to container stdout/stderr.
- Use `LOG_LEVEL` in `.env` (for example `INFO` or `DEBUG`) to tune verbosity.

## Frontend logs
- Nginx access/error logs are available via frontend container logs.

## Diagnostics in reports
- RIPEstat request diagnostics and fallback behavior are surfaced in reports.
- Use these fields to distinguish source errors vs. app errors.

## Troubleshooting checklist
- Confirm `/health` is `ok`.
- Check Postgres health and credentials (`DATABASE_URL`).
- Validate `CORS_ORIGINS` and `VITE_API_URL` alignment.
- Inspect retry/fallback diagnostics for upstream RIPEstat outages.
41 changes: 41 additions & 0 deletions docs/operations/reverse-proxy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Reverse Proxy

## Recommended patterns
1. **Simple port exposure**: publish `3000` (frontend) and optionally `8000` (backend) on trusted networks.
2. **Domain + reverse proxy**: expose only proxy, keep backend internal where possible.

## Nginx Proxy Manager example
- Proxy Host domain `routeforge.example.com` -> `frontend:80`.
- Add advanced location `/api` -> `backend:8000`.
- Optional `/health` -> `backend:8000/health`.
- Enable HTTPS certificate (Let's Encrypt recommended).

## Classic Nginx example
```nginx
server {
listen 443 ssl;
server_name routeforge.example.com;

location / {
proxy_pass http://frontend:80;
proxy_set_header Host $host;
}

location /api/ {
proxy_pass http://backend:8000/api/;
proxy_set_header Host $host;
}

location /health {
proxy_pass http://backend:8000/health;
}
}
```

## HTTPS and CORS
- Prefer HTTPS termination at proxy.
- Set `CORS_ORIGINS` to the public frontend origin(s).
- RouteForge currently does not require websocket proxy settings.

## Security note
- Avoid exposing backend directly to the internet if frontend is already proxied.
21 changes: 21 additions & 0 deletions docs/operations/upgrades.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Upgrades

1. Read release notes before upgrade.
2. Create backup before changing containers.
3. Pull/update code and rebuild images.

```bash
git pull
docker compose -f docker-compose.prod.yml build
docker compose -f docker-compose.prod.yml up -d
curl http://localhost:8000/health
```

## Post-upgrade checks
- Verify backend health endpoint response.
- Open frontend and run a sample check.
- Verify existing reports can still be viewed.

## Notes on database changes
- Current migration handling is still beta-grade.
- Database migrations are currently simple/alpha-grade and will be hardened before v1.0.
16 changes: 11 additions & 5 deletions frontend/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
FROM node:22-alpine
FROM node:22-alpine AS build
WORKDIR /app
COPY package.json ./
RUN npm install
COPY package*.json ./
RUN npm ci
COPY . .
EXPOSE 3000
CMD ["npm", "run", "dev"]
ARG VITE_API_URL=http://localhost:8000
ENV VITE_API_URL=${VITE_API_URL}
RUN npm run build

FROM nginx:1.27-alpine
COPY --from=build /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
4 changes: 2 additions & 2 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "routeforge-frontend",
"version": "0.4.2",
"version": "0.5.0",
"private": true,
"type": "module",
"scripts": {
Expand Down
Loading
Loading