Deploy
One agent instance runs one project, typically on a dedicated VM. There are two install paths: the older compile-on-the-VM make deploy (for developers and the dogfood host), and the release-binary steelframe agent install (for operators without a compiler).
Environment variables
Section titled “Environment variables”The agent reads these from the process environment:
| Variable | Default | Description |
|---|---|---|
STEELFRAME_HOST | 0.0.0.0 | Bind address; set 127.0.0.1 behind nginx |
STEELFRAME_PORT | 7700 | Bind port |
STEELFRAME_DB_URL | file:steelframe.db | Turso/libsql database URL |
STEELFRAME_MASTER_KEY | — | Master key for credential encryption and session signing |
STEELFRAME_TMP | — | Sandbox root (disk-backed on a systemd unit) |
STEELFRAME_LOG_FILE | — | Log file; self-heal scans it for panics |
Everything else (repo, labels, timeouts, App id, coding runtime) lives in the DB config table and is edited via the TUI, GUI, or API.
Path A: make deploy from a checkout
Section titled “Path A: make deploy from a checkout”On the VM, as the steelframe user (create it first if needed):
cp infra/secrets.mk.example infra/secrets.mk && $EDITOR infra/secrets.mkmake deploymake deploy is idempotent — the same command handles first-time setup and updates.
infra/secrets.mk holds everything per-VM (gitignored):
HOST := agent.example.comSTEELFRAME_MASTER_KEY := …OAUTH2_PROXY_CLIENT_ID := …OAUTH2_PROXY_CLIENT_SECRET := …OAUTH2_PROXY_COOKIE_SECRET := …The OAuth credentials come from a GitHub OAuth App with callback https://<HOST>/oauth2/callback.
The orchestrator runs three sub-makes:
| Sub-make | What it installs |
|---|---|
infra/steelframe | Host tools (gcx), RustFS sidecar, the agent binary, the systemd unit |
infra/oauth2-proxy | oauth2-proxy binary + unit in front of the agent |
infra/nginx | Reverse proxy + TLS for HOST |
infra/steelframe targets:
deploy—install-tools install-rustfs install-bin install-unit restart status.deploy-source— the same withoutinstall-tools, for a source-profile host with no Grafana/gcx.install-rustfs— installs the RustFS sidecar (session-memory WAL on127.0.0.1:9000, console127.0.0.1:9001, data at/opt/steelframe/data/rustfs).install-unit— renderssteelframe.service.tplwith the master key and installs it to/etc/systemd/system/.status— fails the deploy if the unit is not active or crash-looping.
The unit runs as user steelframe, WorkingDirectory=/opt/steelframe, DB at /opt/steelframe/data/steelframe.db, Delegate=yes, Restart=always.
Path B: steelframe agent install
Section titled “Path B: steelframe agent install”On a host with the release binary and no compiler:
steelframe setupsudo STEELFRAME_MASTER_KEY=… steelframe agent installsteelframe setup installs host tools (git, gh, gcx, kubectl, sqlite3, rustfs) and the Cloudflare security-audit skill and one coding runtime, then persists coding_runtime to the DB.
steelframe agent install:
- Refuses to run without
STEELFRAME_MASTER_KEY. - Creates the
steelframeuser and/opt/steelframe(data,tmp,logs). - Installs the binary to
/opt/steelframe/steelframe. - Writes
/opt/steelframe/agent.env(mode0600) with the master key and env. - Renders a unit with
ExecStartPre=-/opt/steelframe/steelframe update,ExecStart=/opt/steelframe/steelframe agent run, andRestart=always. - Configures and starts the RustFS sidecar.
TLS and SSO are still make -C infra deploy (nginx + oauth2-proxy); agent install does not replace certbot or oauth2-proxy.
GitHub App
Section titled “GitHub App”Production GitHub operations should use a dedicated GitHub App so commits and PRs use a consistent bot identity. Without an App, ambient gh auth on the agent host is used, which is fine for local development but not production.
Gotchas
Section titled “Gotchas”make deploymust run as thesteelframeuser; it fails ifHOSTor any secret is missing.- Secrets stay in
infra/secrets.mk(gitignored) or/opt/steelframe/agent.env(mode0600); never commit them. - The agent binds
127.0.0.1:7700and is reached through nginx. On the dogfood host the tree is a user unit at~/opt/steelframe. delivery_profile=sourceskipsproduction_monitor; usedeploy-sourceso gcx is not required.- RustFS must be up before the agent; the unit declares
After=/Wants=onsteelframe-rustfs.service.