Skip to main content

Docker Production Deployment

Fonrex is a self-hosted application for your own use. On a server, run the same docker-compose.yml as locally and put a reverse proxy with TLS in front of the API.

What is exposed​

ServicePublished onReach it from
fonrex-api0.0.0.0:5000The reverse proxy only — bind it to 127.0.0.1 on a server (override below)
db127.0.0.1:5432The host only
redis127.0.0.1:6379The host only (Redis has no password)

Every API route except /health, the documentation, the OpenBB discovery files and /static requires a key. Give clients outside the machine (dashboards, Google Sheets) a read-only key.

Compose override​

Create docker-compose.prod.yml:

services:
fonrex-api:
ports: !override
- "127.0.0.1:5000:5000"
deploy:
resources:
limits:
memory: 4g

db:
deploy:
resources:
limits:
memory: 4g
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d --build

!override replaces the port list instead of adding to it; it needs Docker Compose 2.24 or later.

Keep WEB_CONCURRENCY=1: the realtime streams, the WebSocket clients and the daily canary live in the API process, and each extra worker would duplicate them.

Reverse proxy (NGINX)​

server {
listen 443 ssl http2;
server_name fonrex.example.com;

ssl_certificate /etc/letsencrypt/live/fonrex.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/fonrex.example.com/privkey.pem;

location / {
proxy_pass http://127.0.0.1:5000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 120s;
}

location /ws/ {
proxy_pass http://127.0.0.1:5000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $host;
proxy_read_timeout 3600s;
}
}

Gunicorn runs with a 120-second timeout: a first ingestion or a /fundamental request querying every provider can take several seconds.

Without a server, a tunnel (zrok, Cloudflare Tunnel, Tailscale Funnel) gives a local instance an HTTPS URL — see the Google Sheets guide.

Outbound requests​

Your server's IP address makes the requests to the data sources. Websites protected by an anti-bot service may refuse a datacenter IP; route those providers through a proxy:

FONREX_PROXY_URL=http://user:password@proxy.example:8888
FONREX_PROXY_PROVIDERS=Investing,Gurufocus,wallStreetJournal

Data and backups​

The database is in the timescale_data volume. Back it up with pg_dump (see Docker Compose) before every upgrade, and keep dumps out of Git.