Magnemite
Deployment

Environment reference

Every variable the hub, the dashboard and the agent read.

.env is what the stack needs to boot and connect. What is tuned while it runs — concurrency, intervals, retention, heartbeat, the monitoring ceilings — lives in Settings → Tuning and is not an env var. Values that moved there are ignored in silence if left behind in .env.

With docker compose these come from .env at the repo root (copy .env.example). On Coolify the SERVICE_* ones are generated and shown in the resource's Environment tab.

URLs

VariableDefaultWhat it is
EDGE_PORT8090Host port the edge publishes, plain HTTP. Your proxy terminates TLS and forwards here. Compose only.
MAGNEMITE_PUBLIC_URL—Base URL handed to agents. Artifact URLs are built from it, so it must be what the boxes can reach. On Coolify it defaults to the edge's generated domain (SERVICE_URL_EDGE); set it to override a stale one.
MAGNEMITE_DASHBOARD_URLMAGNEMITE_PUBLIC_URLThe dashboard's own origin — auth callbacks and notification links. On Coolify it defaults to the web service's generated domain (SERVICE_URL_WEB), which is a different host from the agents' one.
BETTER_AUTH_URLMAGNEMITE_DASHBOARD_URLOnly when neither of the above is the right origin for auth callbacks. A bare host with no scheme is accepted.
HUB_URLhttp://hub:3001Where the dashboard reaches the hub's internal API, over the compose network.

Database

VariableDefaultWhat it is
DATABASE_URL—Required everywhere: no deployment runs a database of its own. Resolved from inside the containers, so not a host-published port.
DB_PROVIDERmysqlmysql (also covers MariaDB) or postgresql. Must match DATABASE_URL; changing it needs a rebuild, not a restart.

Auth and the first admin

VariableDefaultWhat it is
AUTH_SECRET—Signs Better Auth cookies. openssl rand -base64 32. Coolify: SERVICE_BASE64_64_AUTHSECRET.
ADMIN_EMAIL[email protected]Login identifier. Nothing is sent to it, but it must be well-formed — admin@localhost is rejected.
ADMIN_PASSWORD—Admin password. Coolify: SERVICE_PASSWORD_ADMIN.

Both live on the hub service: the hub syncs the admin account to them on every boot, and there is no .env inside the container. Changing ADMIN_PASSWORD and restarting the hub is the way back in if the login is lost. Changing ADMIN_EMAIL renames that one account rather than adding another, so the old address stops working as a login.

Hub

VariableDefaultWhat it is
HUB_PORT · HUB_HOST3001 · 0.0.0.0Where the hub listens.
HUB_INTERNAL_SECRET—Shared secret for web → hub internal calls. Coolify: SERVICE_PASSWORD_HUBSECRET.
ARTIFACT_DIR/data/artifactsWhere cached bundles live. Must match the volume Caddy mounts as /srv/artifacts.
SERVE_ARTIFACTSfalseServe /files/* from Node. true only for local development without Caddy.
AGENT_AUTO_UPDATEtrueTell boxes on an older build to update themselves.
AGENT_BIN_DIR/app/agent-binWhere the hub image keeps those binaries.
LOG_LEVELinfo in prodpino level: trace … fatal. PRISMA_LOG=1 logs every query — development only.

Web push

Optional; see Notifications. Without a keypair web push is simply unavailable, and the Notifications tab says so rather than offering a button that cannot work.

VariableDefaultWhat it is
VAPID_PUBLIC_KEY—Handed to the browser at subscribe time. Needed by both the hub and the web.
VAPID_PRIVATE_KEY—Signs each push. Hub only — it must never reach the browser.
VAPID_SUBJECTmailto:[email protected]Contact address for the push service. A mailto: or https: URL; required by the spec.

Generate the pair once:

npx web-push generate-vapid-keys

The keypair is identity, not a setting

A push service only accepts a message signed by the key it saw when the browser subscribed, so regenerating the pair silently unsubscribes every browser that already opted in. Back it up with AUTH_SECRET, and change it only when you mean to start over.

The Discord webhook, the ntfy topic and which events go where are not here — those are set on Settings → Notifications, because they are changed while running rather than at boot.

Rotom

Optional; see Rotom.

VariableWhat it is
ROTOM_ENABLEDfalse by default.
ROTOM_URLRotomNG's HTTP listener, usually :7072. /api is appended.
ROTOM_SECRETMatches secret under http_listener in the Rotom config.
ROTOM_BASIC_USERNAME · ROTOM_BASIC_PASSWORDBasicAuth for a proxy in front of Rotom.

The agent's own configuration

Per-box, in /data/adb/magnemite/config.json or as flags:

FlagConfig keyWhat it is
-serverserverUrlThe hub URL — MAGNEMITE_PUBLIC_URL, never the dashboard's.
-enroll-tokenenrollmentTokenUsed once on first run, then deleted from the config.
-namenameFriendly name for the box.
-config—Path to config.json.
-work-dir—Scratch directory for downloads and extraction.
-serialserialReport this serial instead of ro.serialno. Needed on Redroid.
-reboot-commandrebootCommandWhat a reboot from the hub runs. Default reboot.
-fake-root—Simulate an Android box. See testing without hardware.
-fake-serial—Serial to report in -fake-root mode.
-version—Print the agent version and exit.

Not env vars

Version sources are rows in the database (Settings → Version sources). Automatic rollouts, canary, soak, attempts, backoff, cooldown and the rollout window are per app target (Settings → Apps). Everything fleet-wide and numeric — concurrency, stall timeout, heartbeat, offline timeout, sample interval, retention, monitoring graces and ceilings — is in Settings → Tuning. The Discord webhook, the ntfy topic and the rest of where notifications go are in Settings → Notifications.

On this page