Skip to content

Configuration

Environment variables

VarUsed byNotes
MINMCS_MISSIONapi.pyMission name — db filename + display label (default minscs).
MINMCS_XTCEimporters.pyPath to the XTCE file the model is built from; if unset, searches upward from CWD for minscs.xtce.
MINMCS_DATABASE (or MINMCS_DB_URL)core.pySQL connection string; default sqlite:///<mission>.db. MINMCS_DATABASE takes precedence, MINMCS_DB_URL is kept for back-compat.
MINMCS_TC_SCHEDULINGcore.pyOpt in to on-board execution times (1/true/yes/on). Also needs the model to define a schedule-insert command — see Telecommand uplink.
MINMCS_LINKbin/data_proxy.pyGround link type; only EGSE is currently supported.
MINMCS_TM_SOURCE_HOST / _PORTbin/data_proxy.py, bin/egse_link.pyTM connection the bridge opens (default localhost:9310).
MINMCS_TC_TARGET_HOST / _PORTbin/data_proxy.py, bin/egse_link.pyTC connection the bridge opens (default <tm host>:9311). Match this to MINMCS_TM_SOURCE_HOST/_PORT for the real EGSE tool — see Ground link bridge.
MINMCS_API_URLbin/data_proxy.pyAPI base URL the bridge talks to (default http://localhost:9300). Compose-only — not set in the committed .env.example, since the bridge’s own default already works both for non-Docker local runs and for the host-networked minmcs-data-proxy container.
MINMCS_INFLUXDB_URL / _TOKEN / _ORG / _BUCKETtelemetry.pyAll four required to enable time-series (and, effectively, relational parameter) storage — see Telemetry ingest.
VITE_MINMCS_APIUI build/devBackend base URL, default http://localhost:9300. Read from the root .env by docker-compose.yaml and passed to the UI image as a build arg — build time, not run time, so changing it needs a rebuild.

Pointing the UI at a different API host

VITE_MINMCS_API is resolved in the operator’s browser, not inside the compose network. So it has to name an address that’s reachable from wherever the dashboard is opened — the host’s name or IP, never the internal minmcs-api:9300. Set it in the root .env:

VITE_MINMCS_API=http://mcs-host:9300

Or override it for a single invocation (the shell environment wins over .env):

VITE_MINMCS_API=http://mcs-host:9300 docker compose up --build

Vite inlines this value into the bundle at npm run build, so the --build matters: a plain docker compose up reuses whatever image was already compiled with the old URL. To rebuild just the UI, run docker compose build minmcs-ui && docker compose up -d minmcs-ui.

Building with Docker

$ docker compose up --build

This runs five services, one container each. Four of them share the minmcs-network bridge; minmcs-data-proxy is the exception (see below).

serviceroleport
minmcs-postgresTimescaleDB (packettm/packettc/paramtm tables)
minmcs-apiFastAPI (Dockerfile.minmcs-api, uv-managed)9300
minmcs-data-proxythe ground-link bridge. Same image as minmcs-api, but with its entrypoint overridden to bin/data_proxy.py. Runs with network_mode: host
minmcs-uibuilt SPA behind nginx (Dockerfile.minmcs-ui, two-stage: npm run build then nginx:stable-alpine)8080
minmcs-influxdboptional time-series store8086

containers/nginx/default.conf proxies /ws and /api/ to minmcs-api:9300, and serves the built SPA for everything else (try_files ... /index.html, history-mode routing).

Why the bridge uses host networking

The real EGSE ground-link tool binds its socket to 127.0.0.1 only. That’s INADDR_LOOPBACK, hardcoded in its own egse/egse.c, with no flag to change it. A loopback-bound socket is unreachable from a bridged container at any address: host.docker.internal resolves fine to the docker0 gateway, but the connection itself then fails with ECONNREFUSED. The bridge reports that as:

[proxy] tm downlink connection failed: [Errno 111] Connection refused

So minmcs-data-proxy runs in the host’s network namespace (network_mode: host) instead of the bridge network, and dials the ground link exactly as a host-side uv run python bin/data_proxy.py would — localhost:21001 with the repo’s example .env (the code’s own built-in fallback, if nothing is configured at all, is 9310/9311 — see the environment variables table above).

Two consequences follow from host networking:

  • The compose DNS name minmcs-api doesn’t resolve for this service, so its MINMCS_API_URL has to point at the API’s published port instead: http://localhost:9300.
  • Host networking is a Linux feature. On Docker Desktop, minmcs-data-proxy needs a ground link that listens on a routable address instead of loopback-only.

Expect a few POST failed (ConnectionError) lines at startup — the bridge comes up before the API is listening, and retries with backoff.

Three named volumesminmcs-postgres-data, minmcs-influxdb-data, and minmcs-influxdb-config — outlive docker compose down (only -v removes them). This matters after a schema change: there’s no migration tooling, and SQLModel.metadata.create_all only creates missing tables — it never adds columns to an existing one. So after a schema change, either drop the volumes (losing data) or add the new columns by hand, e.g.:

$ docker exec minmcs-postgres psql -U postgres -d minmcs \
  -c "ALTER TABLE packettc ADD COLUMN IF NOT EXISTS <col> <type>"

Get the exact Postgres type from the SQLModel column definition rather than guessing it: CreateTable(PacketTC.__table__).compile(dialect=postgresql.dialect()). The same idea applies to the SQLite file used outside Docker, but simpler — just delete it and let create_all rebuild it, since there’s nothing in it worth migrating.

Last updated on