Pheme (web)

Pheme is Kraite's dedicated web host — the box that serves every public surface (admin, console, kraite.com, syntax) and nothing else. It does no exchange execution, no scheduler work, no step routing. It exists so that web traffic and trading runtime can fail independently.

This is the server lens view. For the box that creates the trading steps pheme reads from the DB, see athena.


What runs on Pheme

VhostNotes
admin.kraite.comOperator UI — Laravel app reading from the shared kraite DB on hyperion
console.kraite.comNew admin-style panel — same Laravel stack as admin
kraite.comPublic marketing site (with www.kraite.com canonicalising to apex)
syntax.kraite.comPublic docs site (this site) — Next.js static export, no PHP

Stack: nginx 1.28.3 terminating TLS, php8.5-fpm for the three Laravel apps, Let's Encrypt certs issued via the Cloudflare DNS-01 plugin (so the cert path works even with Cloudflare proxy in front), Cloudflare Full (strict) SSL mode end-to-end.


What does NOT run on Pheme

  • No Horizon (deferred — a pheme-web supervisor is reserved for future use; currently every Laravel app runs QUEUE_CONNECTION=sync).
  • No exchange API calls. No outbound trading traffic of any kind.
  • No step-router consumer — the StepRouter explicitly excludes pheme from its candidate pool (per the router-env-filter rule), so trading work never lands here even by accident.
  • No scheduler crontab (athena owns that).
  • No WebSocket daemons (athena owns those).

Connectivity model

Pheme reaches hyperion (MySQL + Redis) over the private network kraite-net (10.0.0.0/16) at 10.0.0.2. The shared kraite DB user ([email protected].%) already covers pheme's 10.0.0.9; no GRANT changes were needed when pheme joined the fleet. Hyperion's UFW allows 3306 + 6379 from 10.0.0.0/16.

For ops:

  • Public SSH: ssh -i ~/.ssh/id_ed25519_kraite [email protected] (root SSH is prohibit-password — key-only — same as the rest of the fleet).
  • Per-host user pattern: pheme (uid 1000, sudo NOPASSWD).

Why web was split off from athena

Architectural decision

The 2026-05-24 fleet rebuild briefly folded the web role into athena. In practice the web stack on athena never got fully wired — diagnosing syntax.kraite.com returning 522 from Cloudflare on 2026-06-01 surfaced that all four web hostnames pointed at hyperion (which serves no HTTP) and athena had no nginx vhosts at all. Rather than wire web onto a box that's already carrying the scheduler + dispatch daemon + two WS daemons + a Horizon supervisor, splitting web to its own host gives a clean cleanroom, smaller per-role blast radius (athena reboot doesn't take down operator UI, pheme reboot doesn't touch trading), and independent scaling for the web stack as kraite.com traffic grows.


Failure isolation

A reboot of pheme takes down the four public vhosts for the duration of the reboot — Cloudflare absorbs the gap and visitors see the CF error page. Trading is unaffected: athena keeps dispatching, workers keep draining, the exchanges don't care. This is the smallest non-trivial blast radius in the fleet (after the workers).

A reboot of athena does NOT take pheme offline — pheme's Laravel apps read from hyperion directly and don't depend on athena for anything. Visitors hitting the operator UI during an athena reboot see the site, but underlying data may look stale (no new steps being created), and any artisan command on pheme that recurses into ingestion's SSH-bridged calls (admin's optional KRAITE_INGESTION_SSH_* path) will fail until athena returns.