Architecture
Request path
Section titled “Request path” visitor │ nginx :443 ← TLS, HTTP/2 (HTTP/3 where available) │ ┌────────────────┴────────────────┐ │ │ page cache HIT cache MISS / BYPASS served from disk, │ no PHP involved PHP-FPM (per-site pool, user, jail) │ MariaDB · APCu object cacheA cache hit never reaches PHP. That single fact accounts for most of the performance difference in the benchmarks.
Control plane
Section titled “Control plane”browser ──nginx :443──▶ panel-api (user: slipstream, unprivileged) │ SQLite /var/lib/slipstream/state.db │ desired state · tasks · audit · drift hashes ▼ Unix socket 0660 root:slipstream + shared secret panel-agent (root) │ useradd · nginx render+reload · FPM pools │ MariaDB · wp-cli · restic · certbot · purges ▼ the data planepanel-api listens on 127.0.0.1:5252 and is reached only through nginx, which is the sole public
ingress.
Three design rules
Section titled “Three design rules”- panel-api never runs shell commands. It manipulates desired state and calls typed agent
commands (
CreateSite,DeployRelease,RestoreSnapshot, …). It holds no root and no capabilities, so a bug in the HTTP layer cannot become a system compromise. - panel-agent is stateless. Desired state arrives with each command. The agent renders configuration from it and executes argv arrays only — there is no string-built shell anywhere in the privileged path.
- SQLite is the single source of truth. Rendered files are hashed and recorded; the drift checker compares reality against the record and surfaces differences rather than silently overwriting them.
Site layout
Section titled “Site layout”/srv/sites/example.com/├── current -> releases/20260726-151844 # atomic promote and rollback├── releases/… # immutable code releases├── shared/│ ├── uploads/ # persistent data, symlinked in│ └── wp-config.php # credentials never live in a release├── logs/ # php-error.log, db-latest.sql└── tmp/sessions/ # this site's private tmp and sessionsPer site: a dedicated Unix user (slip-site-<id>), a dedicated PHP-FPM pool and socket, an
open_basedir jail, a dedicated MariaDB database and user with a connection cap, its own APCu
segment, and its own cache directory.
The Velocity Engine
Section titled “The Velocity Engine”Rendered into nginx per site, per profile (Balanced / Commerce / Maximum):
- FastCGI full-page cache for anonymous traffic;
- bypass rules for POST, query strings, and login/cart/checkout/admin cookies and URIs;
- request coalescing (
fastcgi_cache_lock) so an expired hot page is regenerated once, not 500 times; - stale-while-revalidate and stale-if-error (
fastcgi_cache_use_stale,fastcgi_cache_background_update); - pre-compressed storage — PHP compresses its own output, nginx caches the compressed body, and
the cache key includes a normalised
Accept-Encodingbucket so hits are served verbatim with no per-request gzip; - precise invalidation: the WordPress mu-plugin reports content changes and the agent deletes exactly the affected cache entries. No purge module, no full flushes;
open_file_cachefor static assets, so hot files are not re-opened and re-stat’ed per request.
Sizing is calculated, not fixed: OPcache and worker counts per pool from the site’s memory budget, and the InnoDB buffer pool from the machine.
Performance Guard
Section titled “Performance Guard”POST /api/sites/{id}/safe-push:
- probe production (baseline) and staging (candidate) over loopback with the correct
Hostheader, discarding warm-up; - compare p50/p95 latency, error rate, database query count and peak memory — the last two from the connector’s own per-request metrics;
- verdict: pass deploys staging’s code to production as an immutable release and promotes it;
warn requires an explicit
force; block refuses and stores the report on the deployment record.
Recovery
Section titled “Recovery”Restic snapshots — site tree plus a logical database dump, captured together in one snapshot — to any supported backend, encrypted client-side. A verified restore is an actual restore into a scratch directory plus a repository check, a tree and dump sanity check, and a measured duration that becomes the recovery-time estimate shown in the panel.
Repository layout
Section titled “Repository layout”cmd/panel-api unprivileged API server (embeds ui/dist)cmd/panel-agent privileged agent daemoncmd/slipctl command-line clientinternal/api HTTP handlers, auth, RBAC, SSEinternal/agent provisioning, releases, staging, backups, certs, files, driftinternal/rpc the API↔agent socket protocolinternal/state SQLite desired state, migrations, modelsinternal/engine web-server abstraction + the nginx rendererinternal/phpfpm FPM pool renderer, OPcache and worker sizinginternal/tune hardware probe and MariaDB auto-tunerinternal/velocity cache policy and purge logicinternal/guard Performance Guard regression gateinternal/sysprobe memory, CPU and disk factsui/ React + TypeScript + Vite panel UIconnector/ WordPress mu-plugin: precise purge, metrics, magic logininstaller/ install.sh + systemd unitsscripts/ e2e-verify.sh and release toolingbench/ benchmark suitedocs/ this documentationDeliberate non-goals
Section titled “Deliberate non-goals”Slipstream does not do email hosting, DNS, domain registration, billing, resellers, or Docker/Kubernetes orchestration. Each of those is a product in its own right, and a panel that does all of them badly is worse than one that does hosting well.
Multi-server support and an alternative engine (Caddy or FrankenPHP) plug in behind the existing
engine.Renderer abstraction and node-role fields in state, if and when benchmarks justify them.
Dependencies
Section titled “Dependencies”Deliberately few. SQLite for state — no separate database server. No Redis unless a site asks for it, no message broker, no ORM, no search engine. The Go binaries are static, so there is no runtime to install and nothing to keep in step with the OS.