Files changed: credentials engine/lint-report.md vault/.obsidian/workspace.json vault/docs/software/central.md vault/docs/software/conduit.md vault/runbooks/conduit-operations.md
6.4 KiB
| title | type | tags | aliases | related | updated | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Conduit — Operations Runbook | runbook |
|
|
2026-07-14 |
Conduit — Operations Runbook
When to use
Deploying a change, adding a pull source, provisioning an API key, or working the navi traffic-tile cutover/rollback for conduit. See conduit for architecture and current state.
Key facts
| Item | Value |
|---|---|
| Host / SSH | utility CT 104 — ssh zvx@100.64.0.12 |
| Deploy dir | /opt/conduit (owned conduit:conduit) |
| Virtualenv | /opt/conduit/.venv (uv-managed, editable install) |
| Systemd unit | conduit.service (single-worker — do NOT add --workers, single-flight is per-process) |
| DB / DSN env | /etc/conduit/conduit.env → CONDUIT_DB_DSN (own conduit DB on the shared Postgres 16) |
| Master key | /etc/conduit/master.key (CONDUIT_MASTER_KEY_PATH) |
| Deploy-key model | Pull-only: CT 104 pulls main via read-only deploy key ct104-conduit-deploy; cannot push (mirrors central) |
| Migration runner | conduit-migrate (forward-only SQL in sql/migrations/*.sql, tracked in schema_migrations) |
| Bind | 0.0.0.0:8010 (widened from loopback for the navi cutover, 2026-07-14) |
Deploy a change
Run on CT 104 as zvx.
# 1. Pull latest main
sudo -u conduit git -C /opt/conduit fetch origin
sudo -u conduit git -C /opt/conduit checkout main
sudo -u conduit git -C /opt/conduit pull
# 2. Install (editable, picks up code + dep changes)
sudo -u conduit bash -c 'cd /opt/conduit && uv pip install -e ".[dev]"'
# 3. Preview then apply migrations
sudo -u conduit bash -c 'cd /opt/conduit && set -a && . /etc/conduit/conduit.env && set +a && /opt/conduit/.venv/bin/conduit-migrate --check'
sudo -u conduit bash -c 'cd /opt/conduit && set -a && . /etc/conduit/conduit.env && set +a && /opt/conduit/.venv/bin/conduit-migrate'
# 4. Restart
sudo systemctl restart conduit
# 5. Verify
systemctl is-active conduit
curl -sS -o /dev/null -w '%{http_code}\n' http://localhost:8010/health # expect 200
curl -sS -o /dev/null -w '%{http_code}\n' http://localhost:8010/up/tomtom_flow_tiles/flow/8/48/95.pbf # expect 200, a live tile
Add a pull source
Sources are rows in the sources table — there is no hot-reload, app.py loads enabled sources once at startup. Any INSERT/UPDATE/DELETE requires a systemctl restart conduit to take effect.
Columns: name, url_template, api_key_alias, ttl_seconds, header_auth, enabled.
url_template contract: a Python str.format() template filled with two named substitutions —
{path}— the upstream path only (no query string), taken from the inbound request after the source name and before the first?.{key}— the decrypted API key forapi_key_alias, if set.
If the inbound request itself carries a query string, it's appended to the templated URL (& if the template already has its own ?, else ?) rather than substituted in — so caller-supplied params compose instead of colliding into a double ?. If header_auth is true, the key is injected as a header instead of into the URL.
Worked example — tomtom_flow_tiles:
sudo -u conduit bash -c 'cd /opt/conduit && set -a && . /etc/conduit/conduit.env && set +a && psql "$CONDUIT_DB_DSN" -c "
INSERT INTO sources (name, url_template, api_key_alias, ttl_seconds, header_auth)
VALUES (
'"'"'tomtom_flow_tiles'"'"',
'"'"'https://api.tomtom.com/maps/orbis/traffic/tile/{path}?key={key}&apiVersion=1'"'"',
'"'"'tomtom'"'"',
60,
false
)
ON CONFLICT (name) DO NOTHING;
"'
sudo systemctl restart conduit
Provision an API key
API keys live in Conduit's own AES-256-GCM encrypted keystore (api_keys table), addressed by the alias a source's api_key_alias references — separate from central's keystore, encrypted under Conduit's own master key (/etc/conduit/master.key).
The pattern used for tomtom: the plaintext key was decrypted from central's config.api_keys and re-encrypted under Conduit's master key, in-process, never logged in plaintext. Use the same approach for any key that already lives in central; for a brand-new key, insert it directly through the keystore's encrypt path (no plaintext in shell history or logs).
navi traffic-tile cutover (2026-07-14)
navi's /api/traffic/ tiles were repointed from central to conduit. Exact change:
On CT 104 — widen Conduit's bind:
conduit.service's ExecStart uvicorn flag was changed from loopback to mesh-reachable — --host 127.0.0.1 → --host 0.0.0.0 (the --port 8010 is unchanged). Unit backed up first (see Rollback below), then:
# edit the ExecStart --host token in /etc/systemd/system/conduit.service:
# --host 127.0.0.1 → --host 0.0.0.0
sudo systemctl daemon-reload
sudo systemctl restart conduit
On recon-vm — rewrite the nginx proxy:
/etc/nginx/sites-available/navi.echo6.co, location ^~ /api/traffic/ block changed to:
location ^~ /api/traffic/ {
rewrite ^/api/traffic/(.*)$ /up/tomtom_flow_tiles/$1 break;
proxy_pass http://central.echo6.mesh:8010;
# (existing tile-cache directives unchanged)
}
Then:
sudo nginx -t
sudo systemctl reload nginx
Verified via the real nginx path (curl through the vhost) plus fresh rows in Conduit's payloads table.
Rollback
Both pre-cutover backups exist — restore them to revert:
# CT 104 — revert the unit
sudo cp /etc/systemd/system/conduit.service.bak-precutover /etc/systemd/system/conduit.service
sudo systemctl daemon-reload
sudo systemctl restart conduit
# recon-vm — revert nginx (back to :8000, no rewrite)
sudo cp /etc/nginx/sites-available/navi.echo6.co.bak-precutover /etc/nginx/sites-available/navi.echo6.co
sudo nginx -t
sudo systemctl reload nginx
central must stay running — it's the rollback target.
Gotchas
- Single-worker only. Single-flight coalescing is per-process; adding uvicorn
--workersbreaks the "one upstream call" guarantee. Do not add workers. /uprejects HEAD (405) — GET only./upis unauthenticated, like central's auth-exempt tile endpoints. Fine for tiles; revisit before adding sensitive sources.- No source hot-reload — any
sourcestable change needssystemctl restart conduit. - central must stay running — it's the rollback target for the navi cutover, not a decommissioned dependency.