Laravel Octane on FrankenPHP — the framework stays in memory, next to classic FPM apps. Reverb for WebSockets. PostgreSQL beside MariaDB, chosen per app. 5.8.4 says whether a deploy is running right now, whoever started it — cipi deploy <app> --status — and the panel shows it live; 5.8.5 writes the panel API's IP whitelist atomically and names the cause when /etc/cipi is read-only. 5.8 gives every app an environment label — a staging app reads cipi-staging.yml before cipi.yml, and deploy.branch in each file picks the branch. 5.8.2 makes the installer wait until you have saved the credentials, has cipi api and cipi gui check the DNS and issue the certificate themselves, prints the credentials again with cipi credentials, and signs you into the panel through Entra ID or Google. 5.8.1 fixes cipi deploy exiting 1 after a successful deploy. 5.7.0 moves the panel API or the GUI to a new domain with one command — tokens, admins and history stay, the certificate follows — and keeps a panel off the domain of an app. 5.6.3 brings in the PHP security release of 2026-10-21: cipi php upgrade runs every night, says which PHP — and which Octane binary — is still vulnerable, and every FPM pool closes the two known attack paths. 5.6.2 keeps PostgreSQL intact when a restore fails — wipe and import in one transaction, empty dumps refused. 5.2 adds opt-in CrowdSec: engine and a registered firewall bouncer, no WAF. 5.3 puts Cloudflare Zero Trust one opt-in command away — tunnel, Access, a dark origin — watches the server itself every five minutes, and sends every alert to Slack, Discord, Telegram or ntfy as well as email. 5.3.1 hands your auditor a read-only evidence bundle, and moves sites or hands a path to another service without touching a vhost. 5.4 deploys Next.js, Nuxt, SvelteKit, Astro and Vite apps next to Laravel — blue/green for SSR — and writes every deploy, however it started, into a hash-chained ledger. 5.5 tells you which app is filling the disk and alerts before it does, keeps app users out of SSH, and gives every client's Cloudflare account its own token. 5.5.1 makes wildcard certificates install and renew end to end — Cipi writes the HTTPS vhost itself — and cipi/sdk brings the panel API to PHP and Laravel. 5.5.2 lets that API, cipi-cli disk and the control panel answer which app is filling the disk, and makes cipi.yml name the asset build, the pre-deploy snapshot and the backup profiles the same way the server does. 5.6 walks you through cipi app create with menus, checks the deploy key can read your repository before you leave the wizard, and ships one backup to as many S3 buckets as you like. Same one-command server. Everything Cipi 5, tagged by release.
Everything Cipi 5 adds, at a glance. Tiles tagged since 5.0 shipped with Cipi 5; since 5.2, since 5.3, since 5.4, since 5.5, since 5.5.1 and since 5.6 are new in this line; cipi/sdk is the PHP client of the panel API, installed with Composer. Tap any tile to jump into the docs.
Boot the framework once and keep it in memory. Octane apps and classic PHP-FPM apps run side by side on the same server — Nginx proxies to the Octane process, Supervisor keeps it alive, every deploy reloads it cleanly.
Two engines on one box. Pick per app or set a server-wide default — env, backups and restores follow.
Supervised, and restarted on every release.
WebSockets done properly since 5.1.2: generated credentials, wss:// from the certificate, a
proxy that no longer swallows /appointments.
Run the build inside the release, right after dependencies. Fail-closed, so broken assets never reach production — and compiled files never reach your repository.
Cron on or off per app, from the CLI.
Switch runtime on a live app, both ways.
Opt in per app or per deploy and Cipi dumps the database before the release goes out. A bad migration becomes recoverable instead of fatal.
Clone a production app onto a new domain.
No app can starve the box any more.
Issue and renew through a Cloudflare DNS-01 challenge when a public HTTP endpoint isn't an option. HTTP-01 stays the default.
Every 5 minutes. Email after 3 failures.
www or apex, aliased and 301'd for you.
Restore the redirect without reissuing.
Scope, schedule, destination and retention per profile. A 30-minute local database copy next to an encrypted nightly full copy on S3. Files and databases stored separately; tenant databases discovered from the engine. Retention is mandatory.
See every tunable and which layer set it. Writes FPM and CLI together, server-wide or
--app=. Whitelist only.
Aliases, PHP, extra databases, workers, healthcheck and backups — in the repo.
plan, apply, auto after every deploy. Fail-closed:
it never creates an app and never runs a shell command.
A request matching no app used to land on a random vhost. Now :80 and
:443 close it with an empty reply.
The release that just went live is probed immediately — not after three five-minute failures. Opt in to roll it back automatically. Migrations are not undone; the email says so.
Multi-tenant apps need *.example.com. Nginx already could; Cipi now accepts
it.
Opt-in IP reputation that reads the logs your vhosts actually write. The engine ships with a registered firewall bouncer, because decisions without one ban nothing at all. It refuses to start behind an unconfigured reverse proxy, and it allowlists the SSH session you enable it from. There is no WAF.
A high-port TLS listener and a one-shot token. One GET allowlists your IP and unbans it in CrowdSec and fail2ban. Not a login, not an SSH key.
sha256 of the live release against the manifest written at deploy, then ClamAV over the upload directories only. 04:40, every night.
bash and zsh, written by setup.sh and every self-update. Verbs, sub-commands, flags and your app names. No dotfile to edit.
A single Rust binary next to Nginx — not a container. Listens on 127.0.0.1. Cipi writes the index prefix so two apps cannot share a key. Opt-in: nothing installs until you ask.
Image optimisers, ffmpeg, convert, pdftotext — from Ubuntu's repos, and only those. The allowlist is the feature. Chromium is refused on purpose.
Cursor Origin, AWS CodeCommit, Bitbucket Cloud and Azure DevOps — recognised from the clone URL, the same way GitHub always was. Save the credentials, create the app, and Cipi registers the deploy key and the webhook where the forge has one.
Declare deploy.post and the steps run from the live release after every deploy — cipi deploy and the webhook alike. Allowlisted runners only: artisan, npm, composer, one php or node script. No free shell, and no yml auto required.
Nginx, MariaDB, PostgreSQL and Valkey stay off unattended-upgrades on purpose — a database restart is not a 4am surprise. Now you have the switch: patch-level, scoped, and never on a cron.
cipi.yml is not a public URLA custom app serves htdocs/, so a committed cipi.yml answered over HTTP. Every vhost now denies it at any path, Laravel included — applied on update, without touching certbot's block.
A locally-managed Cloudflare Tunnel, Nginx that logs the real visitor, fail2ban taught the edge ranges — and not a single port closed. Route an app, put Access in front of staging or the GUI, carry SSH over the tunnel. Opt-in, like CrowdSec.
lock http refuses while an app still renews over HTTP-01, then closes 80/443 — or lets only Cloudflare in. lock ssh refuses unless the tunnel already carries SSH. The way back is one command.
Disk, certificate expiry, services, queue workers, 5xx spikes, read-only filesystems, load — every five minutes. One alert when it breaks, one when it recovers, a reminder while it stays broken. No dashboards.
Slack, Discord, Telegram, ntfy or a JSON webhook, for every trigger Cipi already had — deploys, backups, scans, logins, the monitor. A five-second timeout, so a dead webhook never stalls a deploy.
Seventeen read-only controls mapped to ISO/IEC 27001:2022 and SOC 2 — SSH, firewall, patching, TLS, accounts, API tokens, deploys, backups, logging. A root-only bundle with the raw output behind every finding, checksummed. No secrets inside, and the gaps stated up front.
Every name of the app, www included, to the new home — path and query kept, certificate still renewing. Or redirect single paths and prefixes. Stored in apps.json, so no vhost rebuild ever drops them.
/api/ to a Node service, /events/ unbuffered for SSE — WebSocket and forwarded headers included. Ports Cipi already uses are refused, and if nginx -t fails, everything is put back.
Node apps are a real app type now. A Vite SPA with client routes that survive reload, a pre-rendered site with real 404s, or an SSR server that switches blue/green only after the new release answers its health path. Releases, rollback, webhook and SSL, same as Laravel.
Official builds checked against SHASUMS256.txt, one server-wide default for
Laravel asset builds, and per-app pins. Node 20 is end of life — servers move to 22.
CLI, panel, webhook, dep over SSH or an MCP client inside the app — root reads
the origin, operator and commit from /proc, keeps the app's claims apart, and
chains each line to the one before it. Mirrored to syslog.
www redirect, basic auth by hash, redirects and proxies, Meilisearch, recipe options, limits,
forced HTTPS, required .env names, crons and a Node app's build — and the panel
API 1.31 plus the GUI drive the same features from the browser.
The monitor says the disk is filling up; cipi disk says who. Every filesystem, then every app, largest first — files, database, total and share of the disk. cipi disk db adds every MariaDB, PostgreSQL, Valkey and Meilisearch database in MB, including the ones no app owns. Since 5.5.2 the panel API (1.33), cipi-cli disk and Server → Disk in the GUI read the same figures.
Give an app a number of GB for files and database together. At 90% you get a warning, over it a critical alert, back under a recovery — by email and every chat channel. The app keeps writing; its repository can't raise the limit.
Turn off SSH and SFTP from other machines for one app user, or for all of them and every app created later. Deploys keep running over ssh localhost; the rule is validated with sshd -t before it goes live.
How many failed SSH logins before fail2ban bans — 3 by default, now 1 to 100. Checked before reload, kept across updates.
Named DNS-01 tokens; each wildcard renews with its own.
Dated Laravel logs were rotated a second time, never compressed, never deleted — and cipi app logs read the empty file. Now one laravel.log, compressed from day two, gone after a year. The migration folds the history in.
<Tab> where youAfter sudo cipi, with or without bash-completion; in sudo -s, su, tmux and screen; and with app names for the cipi user. Arrives with cipi self-update.
Certbot only issues and renews now; Cipi writes the HTTPS vhost itself. A wildcard certificate is installed instead of stopping at certbot's question, every tenant is redirected to HTTPS, and no alias, redirect or Octane change drops it again. cipi ssl status shows the names a certificate does not cover.
Apps, deploys, domains, databases and the server from Laravel, Symfony or a plain script, with one Sanctum token. wait() polls queued jobs, Laravel gets a facade, and the token stays out of logs and exceptions.
The in-app MCP speaks every current revision up to 2026-07-28, with annotated tools, structured results and secret redaction — eleven tools plus rollback, audit ledger and backups through cipi/sdk. php artisan cipi:yml validate gives the server's verdict locally, and the anonymizer finally handles PostgreSQL, with consistent fake values and a schema scan that writes the config for you.
cipi app create opens with menus: Laravel, custom or a Node SPA, static or SSR app; then PHP-FPM or Octane; then MariaDB or PostgreSQL. Enter takes the default. It also asks for your asset build, so the first deploy ships compiled assets. cipi db create asks for the engine the same way.
The deploy key is tested against the repository and its branch before the summary. If it cannot read it, Cipi offers to save or replace the GitHub, GitLab, Bitbucket, Azure DevOps or Origin token, adds the key and checks again.
Named S3 destinations with their own keys, on any provider or region. A profile ships to all of them; retention, verify and fetch follow. Your existing bucket stays the default.
A PostgreSQL restore that fails says so, and why — and since 5.6.2 the database stays as it was. Dumps from a newer PostgreSQL still go in.
The panel API or the GUI moves to another domain with its tokens, admins and history, and its certificate follows. A domain that belongs to an app is refused.
Every app carries an environment label. A staging app reads cipi-staging.yml before cipi.yml, and deploy.branch in each file picks the branch it deploys. The server chooses the file, never the commit.
Several SSH keys, a plan before the first package, the credentials in one layout — and nothing
else on screen until you confirm they are in your password manager. Then the panel API and the
GUI as two questions: cipi api and cipi gui check the DNS, install
and issue the certificate themselves. Lost the summary? cipi credentials prints it
again, export gives a CSV. And the panel signs you in through Entra ID or Google.
The honest before-and-after. Left is what running these things used to cost you. Right is Cipi 5, tagged by release.
cipi ini for both SAPIs, server-wide or per app
cipi.yml in git, applied on deploy
*.example.com wildcards
convert
→
An allowlisted cipi package — Chromium refused
deploy.post in the repo, allowlisted runners only
apt upgrade and hope MariaDB comes back
→
Scoped, patch-level, one service at a time
cipi.yml since 5.2.3
Downloadable from a custom app's own domain
→
Denied at any path, on every vhost
notifications disable kept sending
→
An explicit false stays false
apps.json, rolled back if nginx -t fails
/index.html fallback
/ in cipi status
→
Every app: files, database, % of the disk
laravel.log, compressed, 365 days
jail.local by hand, lost on update
→
cipi firewall attempts 5, kept
The complete Cipi 5 addition to the CLI. Same syntax you already know, same one binary. Tagged since 5.0, since 5.1, since 5.2, since 5.3, since 5.4, since 5.5 or since 5.6 — down to the 5.6.0 release.
cipi credentials [export]The install credentials again — root,
databases, Valkey, Meilisearch, backup key, with connection URLs — or a CSV for your password
manager since 5.8.2cipi api <domain>DNS check, install, certificate and a token in
one command; cipi gui <domain> the same, admin account included
since 5.8.2cipi gui sso set --issuer=… --client-id=…Single sign-on for the
panel over OpenID Connect — Entra ID, Google, Okta, Keycloak; only on|off,
disable since 5.8.2cipi app create --env=stagingGive an app an environment label;
it reads cipi-staging.yml before cipi.yml. Also on app edit
and app clone since 5.8cipi app create --octaneCreate a Laravel app served by Octane
on FrankenPHP since 5.0cipi app convert <app> --to=octane|fpmMove an existing app
between runtimes since 5.0cipi app reverb enable|disable|statusRealtime websockets for an
app since 5.0cipi worker horizon enable|disable|statusHorizon instead of
plain queue workers since 5.0cipi schedule on|off|status <app>Toggle the Laravel
scheduler per app since 5.0cipi app edit --node-build='…'Run a frontend build on every
deploy since 5.0cipi app edit --no-node-buildRemove the build step
again since 5.0cipi app clone <app> --domain=…Instant staging copy of a
production app since 5.0cipi deploy --snapshotDump the database before the release goes
out since 5.0cipi app limits <app>Cap FPM children, memory, Octane and
queue workers since 5.0cipi db install|uninstall pgsqlAdd or remove PostgreSQL next to
MariaDB since 5.0cipi db default mariadb|pgsqlChoose the engine used when you
omit the flag since 5.0cipi db enginesInstalled engines, ports and current
default since 5.0cipi ssl dns set --provider=cloudflareStore the credentials for
DNS-01 challenges since 5.0cipi ssl install --dns=cloudflare --wildcardIssue wildcard
certificates via DNS since 5.0cipi ssl force <app>Re-apply the HTTP to HTTPS
redirect since 5.0cipi www add|force-to-root|force-from-rootCanonical host and
permanent redirects since 5.0cipi health set|unset|check|list [--json]Built-in HTTP monitoring and
alerts since 5.0cipi api ip-whitelist show|add|set|allow-allRestrict panel API / MCP by IP since 5.0cipi app webhook recreate [--rotate-secret]Recreate GitHub/GitLab deploy webhook since 5.0cipi smtp configure --host=… --port=…Non-interactive SMTP for API/scripts since 5.0cipi app env|run|deploy-configNon-interactive app tooling for API/GUI since 5.0cipi backup profile add|edit|listBackup strategies: what, how often, where, how long since 5.1cipi backup verify|status|fetch --encryptIntegrity check, overdue watchdog, client-side AES-256 since 5.1cipi ini list|set|unsetphp.ini for FPM and CLI, server-wide or per app since 5.1cipi yml generate|plan|apply|autoPer-project cipi.yml that travels with the code since 5.1cipi yml generate --saveWrite /home/<app>/cipi.yml. deploy.node_build builds assets before go-live; a dropped backup profile leaves the schedule since 5.5.2cipi nginx default-server on|offClose unmatched Host requests with 444 since 5.1cipi health set --rollback-on-unhealthyUndo a release that fails its post-deploy check since 5.1cipi health postdeploy <app>Run the post-deploy probe on demand since 5.1cipi deploy --log[=N]Show the timestamped deploy log since 5.1cipi alias add <app> '*.example.com'Wildcard domain aliases since 5.1cipi crowdsec enable|disable|statusOpt-in IP reputation: engine plus a registered firewall bouncer since 5.2cipi crowdsec allow|unallow <ip|cidr>Never ban an address, or drop an extra allow since 5.2cipi crowdsec rescue token|rotateBreak-glass TLS listener and its one-shot token since 5.2cipi scan enable|disable|statusNightly integrity check plus ClamAV on upload dirs since 5.2cipi scan [<app>] | report | manifestRun now, read the last report, re-baseline a manifest since 5.2cipi completion bash|zsh [--print]Shell tab-completion — already installed for you since 5.2cipi git refresh [app]Re-sync GitHub/GitLab deploy keys and webhooks since 5.2.1cipi app fix-permissions [app]Restore an app home to the permission model Cipi created it with since 5.2.1cipi search install|enable|disable|statusMeilisearch for Laravel Scout — native binary, 127.0.0.1 only since 5.2.2cipi search key show|rotateApp key or master key; rotating the master rewrites every .env since 5.2.2cipi search upgrade|removeIn-place store upgrade, or put the old binary back since 5.2.2cipi package list|install|removeAllowlisted host binaries from Ubuntu's repos since 5.2.2cipi git origin-token|bitbucket-token|azure-tokenCredentials for Cursor Origin, Bitbucket Cloud and Azure DevOps since 5.2.3cipi git codecommit-token <key> <secret> <iam-user>AWS IAM credentials — the deploy key goes up via UploadSSHPublicKey since 5.2.3cipi yml post-deploy <app>Run the repo's declared deploy.post steps now, against current/ since 5.2.3cipi nginx upgrade [--yes]Patch installed nginx packages, nginx -t, then reload since 5.2.3cipi db upgrade [mariadb|pgsql] [--yes]Patch one database engine, or every installed one since 5.2.3cipi service upgrade [name] [--yes]The generic entry, and the home for Valkey — all is refused since 5.2.3cipi zt token set --token= --account=Cloudflare API token, root-only — not the DNS-01 file since 5.3cipi zt enable|disable|status|refreshTunnel and Nginx real_ip, ports left open; disable restores UFW since 5.3cipi zt hostname add|remove <app|--gui>Route an app or the panel through the tunnel since 5.3cipi zt access enable|disable <app|--gui>Cloudflare Access in front, Git webhook path bypassed since 5.3cipi zt ssh enable --hostname=SSH over the tunnel — port 22 stays open since 5.3cipi zt lock http|ssh [--yes]Close the origin, with refusals that keep you in since 5.3cipi zt unlock http | cipi zt ssh unlockReopen 80/443 or port 22 since 5.3cipi zt origin-cert <app>Optional 15-year Cloudflare Origin CA certificate since 5.3cipi monitor [--json] | list | testRun the server checks now, see their state, send a sample alert since 5.3cipi monitor enable|disable|set <check>Toggle a check or change its thresholds since 5.3cipi notifications channel add <type> <id>Slack, Discord, Telegram, ntfy or webhook since 5.3cipi notifications channel list|test|enable|disable|removeMasked secrets; test one channel or all since 5.3cipi compliance [check] [--days=90] [--json]17 read-only controls; exits 1 on any fail since 5.3.1cipi compliance report [--out=] [--no-archive]Evidence bundle, SHA256SUMS and a checksummed archive since 5.3.1cipi compliance list|controlsPast reports, and the ISO 27001 / SOC 2 mapping since 5.3.1cipi redirect set <app> --to=<url>Every name of the app in one hop; enable|disable|unset since 5.3.1cipi redirect add|remove|list <app>Exact or prefix path redirects, 301/302/307/308 since 5.3.1cipi proxy add|remove|list <app>A URL prefix to another upstream, WebSocket included since 5.3.1cipi app create --node=spa|static|ssrNode frontends; --framework=next|nuxt|sveltekit|astro|remix|vite since 5.4cipi app edit <app> --node-version=24|defaultPin one app's Node major, or follow the server since 5.4cipi node install|list|upgrade|removeChecksum-verified official Node builds, LTS majors since 5.4cipi node default <major>|systemServer-wide Node for Laravel builds, app run, deploy.post since 5.4cipi node status|restart|logs <app>Slots, zero-downtime restart, serving-slot log since 5.4cipi deploy <app> --audit [--days=90] [--json]The app's records from the deploy ledger since 5.4cipi disk [--json]Every filesystem, then every app: files, database, total, % of disk since 5.5cipi disk db [--json]MariaDB, PostgreSQL, Valkey and Meilisearch, in MB since 5.5cipi app limits <app> --disk=<GB>|noneSoft disk limit: alerts at 90% and over, blocks nothing since 5.5cipi monitor set app_disk --warn= --minutes=Tune the per-app disk check and its measurement cache since 5.5cipi firewall attempts [<1-100>|default]Failed SSH logins before fail2ban bans — default 3 since 5.5cipi ssh apps [--json]Every app user's SSH/SFTP access, and what new apps get since 5.5cipi ssh apps enable|disable <app>|--allOne app user, or all and the apps created later since 5.5cipi ssl dns set --name= --token=Another Cloudflare account for DNS-01 — any number since 5.5cipi ssl install <app> --dns=cloudflare --account=Issue with that account; renewals follow it since 5.5cipi ssl dns list|remove <name>Accounts and their certificates; remove refused while in use since 5.5cipi ssl statusCertificates, then every app: what it is served with, which names are not covered since 5.5.1cipi ssl install <app> --httpBack from DNS-01 to HTTP-01 on purpose — a plain install now keeps DNS-01 since 5.5.1cipi ssl install <app> --dns=cloudflare --no-wildcardDrop the remembered *.<apex> on the next issue since 5.5.1cipi app create --node-build=CMDThe Laravel asset build, set at creation (the wizard asks for it) since 5.6cipi git check [app]Can the deploy key read the repository and its branch? since 5.6cipi backup destination add|edit|list|show|test|removeNamed S3 buckets, each with its own keys since 5.6cipi backup profile edit <name> --dest=local,s3,<name>Ship one profile to several destinations since 5.6cipi php upgradeNightly; patch level of every PHP and Octane binary, exit 1 while one is vulnerable since 5.6.3cipi php list --jsonpatch, security and security_floor per version since 5.6.3cipi yml plan <app> --jsonThe whole plan as one object; also cipi yml auto <app> status --json since 5.6.4cipi api move <domain> [--no-ssl]API, MCP and docs to a new domain; old certificate deleted, new one issued since 5.7cipi gui move <domain>The control panel to a new domain; admins, 2FA and connections stay since 5.7cipi api remove [--force]Everything cipi api <domain> set up; apps and the GUI untouched since 5.7Server management from the REST API and optional web GUI — plus non-interactive flags for scripts.
The newest rows need cipi self-update to 5.5.2 (disk over the API, and the cipi.yml names below) and panel API
1.33; wildcard HTTPS needs 5.5.1. cipi/sdk installs with Composer wherever your PHP runs.
GET /api/php and install; remove and default stay on the CLI
cipi user keys
GET /api/services and restart from the panel
cipi smtp configure --host=…
--json on CLI
api/* and /mcp
cipi app webhook recreate [--rotate-secret]
open_basedir
cipi redirect / cipi proxy as root only
→
REST, MCP and GUI — same validation, never --force
GET /api/apps/{name}/deploy/audit + a GUI view
composer require cipi/sdk — every endpoint, wait(), Laravel facade
tools/list page
Run the updater and Cipi rebuilds vhosts, pools, Deployer templates and app metadata in place — without touching your code or your data.
cipi.yml auto and post-deploy rollback, CrowdSec, the nightly scan, Meilisearch, cipi package, Cloudflare Zero Trust, chat
channels, Node apps, disk limits, cipi ssh apps and extra backup buckets stay off until you ask. cipi compliance and cipi disk only read. The server monitor is on, and quiet until something
breaks.
LOG_CHANNEL=single
and gracefully restarts running workers, Horizon, Octane and Reverb — a few seconds of
reconnects, as on a deploy. What it does.
nginx -t, the vhost of apps with a
wildcard name, a Cloudflare Origin CA certificate or a certificate that never reached
the vhost — the previous file is put back if nginx refuses the new one. No certificate is
requested, nothing is deployed. What it does.