Skip to content

Self-hosting

Atlas can run on your own infrastructure. The same backend (Python/FastAPI) and frontend (React/Vite) you'd run in dev work in production with the right env, a Postgres database, and a Redis instance. This page covers the supported shape; for a single-user dev environment, see Quick Start.

Components

ComponentWhat it isHow to run
BackendPython/FastAPI appuvicorn behind a reverse proxy
FrontendReact/Vite SPAStatic build, served from a CDN or nginx
DatabasePostgreSQLAny managed or self-hosted Postgres ≥ 14
CacheRedisAny managed or self-hosted Redis ≥ 6
Docs (optional)VitePress static sitenpm run build in apps/docs/ → static deploy

Required env vars

The minimum to boot:

  • DATABASE_URL — Postgres connection string
  • REDIS_URL — Redis connection string
  • SECRET_KEY — JWT signing key. Long random string. Rotating invalidates all sessions.
  • FINNHUB_API_KEY — equity quotes
  • EODHD_API_KEY, EODHD_BASE_URL — EOD prices and fundamentals
  • CESIUM_ION_TOKEN, VITE_CESIUM_ION_TOKEN — globe rendering

Optional providers (degrade the relevant features gracefully if absent):

  • OPENSKY_USERNAME, OPENSKY_PASSWORD — anonymous access works at lower rate limits
  • MARINETRAFFIC_API_KEY — gates the AIS layer
  • STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET, STRIPE_PRICE_ID_* — only if you're running paid plans

The full list with placeholders lives in .env.example.

What NOT to do

The project's secrets-handling rules apply doubly to self-hosted deployments:

  • Never commit .env. Verify .gitignore excludes .env, .env.local, .env.*.local.
  • Never call EODHD / Finnhub / Stripe directly from the frontend. The frontend talks only to the Atlas backend, which proxies to upstream providers.
  • Never put backend-only credentials behind a VITE_* prefix. Frontend env vars are bundled into the client and become public.
  • Never log full URLs containing tokens — service modules strip the api_token query param before logging.

Deployment shapes

Three supported shapes:

Single-host

One VM, everything on it (backend + nginx serving the frontend bundle + Postgres + Redis). Lowest ops complexity, fine for personal use or small teams. ~2 vCPU / 4 GB RAM minimum.

Backend on app platform + managed DB

Backend on Fly.io / Railway / Render / Heroku-style platform; Postgres and Redis managed by the same provider. Frontend static-deployed to Cloudflare Pages or Vercel. This is the recommended shape for production.

Container orchestration

Backend image deployed to Kubernetes / ECS / Cloud Run. Standard 12-factor app — read all configuration from env, log to stdout, single process. Health check at /health.

Health and monitoring

The backend exposes a /health endpoint for liveness checks (backend/routes/health.py). Hook it up to your platform's liveness probe.

For deeper monitoring, instrument the backend with your APM of choice; structured logging is in place via the logging module — every service module uses logger = logging.getLogger(__name__).

Updating

  1. Pull the latest tag.
  2. Run database migrations (Alembic — alembic upgrade head).
  3. Restart the backend.
  4. Rebuild and redeploy the frontend (npm run build then static deploy).
  5. Smoke-test /health and a few panels.

The backend reads credentials at request time (per the _key() pattern), so credential rotation doesn't strictly require a restart — but a restart is the safe default after a config change.

Limits

  • Atlas is not designed for multi-tenant isolation between organizations on a single deployment. If you need org-level isolation, run separate deployments.
  • The OSINT data providers (OpenSky, MarineTraffic) impose their own rate limits; high-frequency or large-fleet workloads may exceed free tiers fast.

Released under the project license. Public sources only — no proprietary or restricted data.