SkyHub configuration lives in four independent surfaces, each read by a different service at a different moment in its lifecycle. This page is the cross-service index: it names every variable, its default, and what it controls, then points you at the per-service deep-dive pages. Use it to answer “which var controls X?” and “why does dev behave differently from prod?” — the answer is almost always a default that differs between a Python os.getenv() fallback and the .env / tfvars template that ships alongside it.
For the detailed treatment of a surface — startup validation order, footguns, and the exact code path that reads each value — follow the per-service links: Gateway env vars · Dashboard build & config · Drone OS services · AWS environments & Terraform. This page is the flat, copy-pasteable index across all of them.

The four config surfaces

Gateway config is evaluated at import time. settings.py raises RuntimeError the moment it is imported if JWT_SECRET_KEY is empty on a non-local deployment — before any validation function runs. Dashboard config, by contrast, is frozen into the JavaScript bundle at build time: changing environment.prod.ts requires a rebuild and redeploy, not a restart. See Startup & validation.

Default mismatches you must reconcile

The single most common source of “works in dev, breaks in prod” is a Python fallback in settings.py that disagrees with the value shipped in the env template or baked into the production task definition. These are the known divergences:
Never assume the settings.py fallback is what runs in production. Treat the deployed env (docker-compose defaults for local, the ECS task definition / SSM for prod) as authoritative and the Python fallback as a last-resort safety net.

Gateway Service (skyhub_gateway_service)

Every constant below is defined in src/application/settings.py unless noted. Defaults shown are the Python os.getenv() fallback. Secrets are redacted — supply real values via .env (local) or SSM (prod).
IS_LOCAL_ENVIRONMENT is derived (DEPLOYMENT_ENVIRONMENT == "local"), not a raw env var. Note DEPLOYMENT_ENVIRONMENT (local/server) and APP_ENVIRONMENT (dev/production) are two different switches — see Startup & validation.
Assembled into postgresql://… in src/connector/db_connection.py. See Migrations & DB connection and the Database schema reference.
JWT_ACCESS_TOKEN_EXPIRES (10 min) and JWT_REFRESH_TOKEN_EXPIRES (12 h) are hardcoded timedeltas in main.py, not env-configurable — despite older docs listing them as env vars. The JWT blocklist is an in-memory set; revocation does not survive a restart or scale across workers without a shared store.
The 10.71.* trust and jumphost routing are covered in VPN middleware & jumphost and Network topology.
See Rosbridge connection.
Full container lifecycle: SITL lifecycle and Gateway build & runtime.
Applied to every newly created SITL drone (fence + battery + logging defaults).
See Janus video rooms.
Path footgun: .env.example sets OTEL_EXPORTER_OTLP_ENDPOINT=http://<office-docker-host>:4318/v1/traces, but the exporters append /v1/traces and /v1/logs to the base — baking a signal-specific path into the base var makes the log exporter target /v1/traces/v1/logs. Use the bare base (http://host:4318). Details in OpenTelemetry & SigNoz.
See Stripe billing & vehicle limits.
MAIL_* and APP_ENVIRONMENT bypass settings.py (read via os.getenv directly) — easy to miss when auditing configuration.
These are consumed by containers/docker-entrypoint.sh or docker-compose.yml — not by settings.py. See Gateway build & runtime.

Dashboard (skyhub_dashboard)

The Angular SPA has no runtime env vars — configuration is a TypeScript object in src/environments/environment*.ts, and angular.json swaps one file in at build time via fileReplacements. Change a value → rebuild and redeploy. The five files and the build configuration that selects each:

Keys and per-environment values

environment.ts is the dev default (production: false) yet it already carries the live Stripe key and the prod Janus / ws_proxy / assets URLs — only its url points at localhost. environment.e2e.ts deliberately targets the real production API (https://prod.skyhub.ai:5000), so Playwright smoke runs hit prod. Full build/deploy detail: Dashboard build & config · App state & video.

SkyCore Drone OS (skyhub_core)

The on-drone stack is a docker-compose microservice bundle configured through a single .env (template .env.example). Every value uses the ${VAR:-default} pattern, so unset vars fall back to the compose default. COMPOSE_PROFILES decides which containers even start. Below are the load-bearing groups; see Drone OS services for the exhaustive per-module treatment.
core and gamepad are no longer profiles — they are the two halves of the single skyhub service, selected by SKYHUB_ROLE. The camera and slam profiles went with the camera-proxy and isaac-slam containers.IP_OVERRIDE is central to the Redis message bus — see Redis message bus and Redis channels & MAVLink port map.

AWS infrastructure (skyhub_terraform)

Terraform inputs live in environments/<env>/inputs.tf (declarations) and are set per environment in environments/prod/settings.tfvars (prod) — dev supplies values on the CLI. Applied with terraform apply -var-file=settings.tfvars. The provisioned topology (ECS Fargate on 172.31.0.0/16, the single t4g.nano WireGuard jumphost at public <prod-ingress-ip>, self-hosted Postgres/Redis) is described in AWS environments & state and Production config. Prod ingress is nginx running on that t4g.nano WireGuard EC2, acting as a TLS-terminating reverse proxy in front of the ECS services — there is no Cloudflare tunnel or ALB/ELB in prod. GATEWAY_CLOUDFLARE_PORT / 2053 is only a local/optional dev-compose artifact and is not used in production.

Secrets hygiene

Several real secrets are committed in these repos as dev conveniences and must be overridden in production (via SSM for the gateway, CI secrets for the frontend, and a non-committed tfvars for Terraform):
  • Gateway .env.example: a working JWT_SECRET_KEY, MAIL_PASSWORD, and an OTEL signoz-access-token.
  • Dashboard environment.ts / environment.prod.ts: a live Stripe publishable key and the Mapbox token (baked into the shipped JS bundle).
  • Terraform settings.tfvars: a GitHub PAT and a Slack webhook.
Production gateway secrets come from AWS SSM Parameter Store, injected into the ECS task — never from the committed .env.example. settings.py hard-fails on a missing JWT_SECRET_KEY whenever DEPLOYMENT_ENVIRONMENT != local, which is the primary guard against shipping the insecure default.

Gateway env vars (detailed)

Startup validation order, footguns, and the code path reading each gateway value.

Dashboard build & config

The five Angular environment files, build configurations, and CI/deploy flow.

Drone OS services

On-drone container profiles and how COMPOSE_PROFILES selects them.

Environments & Terraform state

tfvars, remote state, and the prod/dev environment split.

HTTP & Socket.IO API reference

Full endpoint and event reference for the gateway.

Redis channels & MAVLink ports

Where IP_OVERRIDE, ports, and channel naming come together.