The optional web control panel

Cipi is, and always will be, CLI-first. Everything a server needs — apps, databases, SSL, deploys, backups, firewall — is a single cipi command away over SSH. But from v4.7.0 Cipi also ships an optional web control panel: a self-hosted Laravel dashboard that manages one or more Cipi servers from the browser, over the same REST API the CLI client and WHMCS module use.

100% optional. The panel is a separate package you install only if you want it. Skip it and Cipi runs exactly as before — a lean CLI with no daemon, no web surface, and nothing extra listening. Install it and your team or clients get a friendly UI without giving up the terminal. Your server, your choice.

The panel is a thin visual layer on top of the API — it does not replace the CLI or add a proprietary control plane. Anything you do in the browser, you can still do from the terminal, and vice versa. A single panel can drive many servers, so it doubles as a lightweight multi-server cockpit.

Cipi control panel dashboard with three connected servers, CPU, memory and disk Cipi control panel dashboard with three connected servers, CPU, memory and disk
The dashboard queries every connected server at once — status, resources, services and Cipi version.

What you can do from the panel

  • Manage apps — create, edit, deploy, suspend/unsuspend, fix permissions and delete Laravel, Node (SPA / static / SSR) and custom apps; manage aliases, WWW/apex redirects, SSL (install + force HTTPS), and HTTP basic auth. Wildcard primary domains (*.example.com) are accepted.
  • Create Node apps with a framework preset (Next.js, Nuxt, SvelteKit, Astro, Remix, Vite), Node major, build/start commands, output directory and health path; edit them later, restart SSR apps blue/green, and pin a Laravel app's asset build to its own Node major (API 1.31+ / Cipi 5.4.1+). See Node apps.
  • Routing — whole-app redirects (set, enable, disable, unset), path redirects and prefix reverse proxies, with the same validation as cipi redirect and cipi proxy (API 1.31+ / Cipi 5.4.1+).
  • Deploy — deploy, rollback and unlock; structured deploy.php options; and the app's deploy audit ledger — who or what deployed each release, from where (API 1.31+ / Cipi 5.4.0+).
  • cipi.yml — the app's tab shows the file of the live release, whether it is valid, what applying would change and what blocks it; apply it as a job, and turn auto-apply after every deploy on or off, with a confirmation that says who can then change the server (API 1.35+ / Cipi 5.6.4+). See cipi.yml.
  • Search — Meilisearch status and per-app enable/disable for Laravel Scout (API 1.31+ / Cipi 5.2.2+).
  • Create Laravel apps with optional Laravel Octane (FrankenPHP) (API 1.13+ / Cipi 5.0+); list and detail views show FPM vs Octane.
  • Edit app .env, manage Composer auth.json, run Artisan, and execute whitelisted App commands (cipi app run) — requires API 1.14+ / Cipi 5.0.3+ (terminal output supports Markdown copy).
  • Pick a database engine at app create (mariadb or pgsql) and manage multi-engine databases — list, create, back up, restore, regenerate passwords (API 1.12+ / Cipi 4.8+). Deleting a database stays on the host CLI since API 1.19.
  • Browse application and server logs with type filter, pagination, and auto-refresh.
  • Watch async jobs in an interactive overlay (spinner + terminal output while polling GET /api/jobs/{id}).
  • Live dashboard — CPU, memory, disk, services, and app count via GET /api/status.
  • Server cockpit (API 1.15+ / Cipi 5.0.6+) — install PHP versions, manage SSH keys, services, SMTP notifications, HTTP healthchecks, and panel API IP whitelist from the browser. Since API 1.31 the same page shows Node runtimes, Meilisearch, the optional host packages catalog, the system monitor and Cloudflare Zero Trust status — read-only by design: installing software, changing monitor thresholds and every zt change stay with the operator on the CLI. Since API 1.33 (panel 3.1, Cipi 5.5.2+) the same page has a Disk tab: who is filling the disk, the figures of cipi disk and cipi disk db.
  • Register and switch between multiple servers from one login — the current server is picked from the header on every page, and app links carry the server so they can be bookmarked and shared.
  • One-time credentials (SSH and database passwords, deploy key, webhook URL and token) are listed with copy buttons when a job returns them, instead of being buried in CLI output.
  • Repository check and build at creation (panel 3.2, API 1.34, Cipi 5.6.0+): creating a Laravel app takes an optional build command (npm ci && npm run build) that runs on every deploy before the release goes live, and the job overlay says whether the deploy key can read the repository — after a create, or an edit that changed the repository or branch. When it cannot, it shows git's error and the command to run on the server, with a copy button: the API cannot save Git tokens, so that step stays on SSH.
  • Light and dark themes, a phone layout, and per-section fallbacks: a server whose API is older or whose token is narrower still works for everything it supports.

Panel 3.0 (October 2026) redesigned every page around the same design system as this site. Panel 3.1 adds Server → Disk. See the screenshot tour and the changelog.

Screenshot tour

Every image below is a real screenshot of the panel, taken against its demo environment — a stand-in for the panel API with three fictional servers that ships with the package (./dev/demo.sh; --reset picks up the API 1.33 disk fixtures). Domains and IPs are documentation ranges.

Apps

Laravel (PHP-FPM or Octane), Node (SPA, static, SSR) and custom PHP apps of the current server, with type filters, search and a deploy button on every row.

Apps list with Laravel, Node and custom apps Apps list with Laravel, Node and custom apps

Creating an app starts with its type. Node framework presets (Next.js, Nuxt, SvelteKit, Astro, Remix, Vite) fill the mode and show the same defaults cipi app create --node uses.

Create app dialog with the Node type selected
Create a Node SSR app with the Nuxt preset.
Job overlay with one-time credentials after creating an app
Credentials returned by the job, with reveal and copy.

App detail

A header with status, type, runtime and quick actions, then one tab per area. Tabs are part of the URL, so ?tab=deploy can be bookmarked.

App overview with details, configuration, healthcheck and search
Overview: details, configuration (PHP, Node pin, repository, branch, domain), HTTP healthcheck and Meilisearch.
Deploy tab with deploy actions, the deploy audit ledger and the deploy pipeline options Deploy tab with deploy actions, the deploy audit ledger and the deploy pipeline options
Deploy: actions, Git webhook, the hash-chained deploy audit and the structured deploy.php pipeline.
Routing tab with whole-app redirect, path redirects and reverse proxies
Routing: whole-app and path redirects, prefix proxies.
Domains and SSL tab
Domains, Let’s Encrypt and www ↔ apex.
Environment editor with masked secrets and one unsaved change
.env editing with masked secrets and change tracking.
Laravel log viewer with errors highlighted
Logs by type, paginated, with live refresh.

Jobs

Deploys, SSL, app and database operations run as async jobs on the server. The overlay polls GET /api/jobs/{id}, shows the elapsed time and colour-codes the CLI output; closing it leaves the job running.

Completed deploy job with Deployer output

Databases and server

Databases page with backup, restore and password actions
Databases: create, back up, restore, rotate passwords.
System monitor checks with states and thresholds
Monitor checks with thresholds and last alert.
Server overview with system, resources, attention list, services and PHP-FPM pools Server overview with system, resources, attention list, services and PHP-FPM pools
Server overview: system, resources, monitor and healthcheck alerts, services with restart, PHP-FPM pools.

Connections, security and phones

Connections page with the server switcher open
Connections, token rotation and the header server switcher.
Settings page during two-factor setup
Profile, password and TOTP two-factor setup.
Apps list on a phone App detail on a phone Navigation drawer on a phone

Requirements

The panel talks to your servers exclusively through the Cipi REST API. Before installing it, make sure each server you want to manage has the API enabled with a token that covers the full ability set.

Each managed server needs cipi api installed and a Bearer token with all abilities. See the API setup guide to generate one.
  • A running Cipi server (Ubuntu 24.04 / 26.04) to host the panel — this can be one of the servers you manage or a small dedicated box.
  • A domain or subdomain of its own, pointed at that server with a DNS A (and AAAA) record, e.g. panel.example.com. The panel is a separate Laravel application with its own Nginx vhost and certificate. It cannot share a hostname with an app, or with the API, which needs its own too, e.g. api.example.com (see a domain of its own). Since Cipi 5.7.0, Cipi refuses a domain that is already taken.
  • cipi api enabled on every server you want to control, each with a full-ability token (include www-manage, status-view, and for app tooling apps-env, apps-auth, apps-artisan, apps-run, apps-deploy-config). For Node apps, redirects and proxies, managed servers need API 1.31+ and Cipi 5.4.1+ (the 5.4.1 migration opens those commands to the panel sudoers); the deploy audit needs Cipi 5.4.0+. Server → Disk needs API 1.33+, the disk-view ability and Cipi 5.5.2+ (migration 5.5.2). The app's cipi.yml tab needs API 1.35+, the yml-view / yml-manage abilities and Cipi 5.6.4+. For server cockpit (PHP, SSH, services, SMTP, health, IP whitelist), managed servers need API 1.15+ and Cipi 5.0.6+. For .env / auth.json / Artisan / App commands, managed servers need API 1.14+ and Cipi 5.0.3+. For Octane create and FPM/Octane indicators, API 1.13+ and Cipi 5.0+. For multi-engine MariaDB/PostgreSQL and www redirects, API 1.12+ and Cipi 4.8+.

A token covering everything the panel uses (API 1.35):

bash
cipi api token create --name=gui --abilities=apps-view,apps-create,apps-edit,apps-delete,apps-suspend,apps-basicauth,apps-env,apps-auth,apps-artisan,apps-run,apps-deploy-config,aliases-view,aliases-create,aliases-delete,www-manage,redirects-view,redirects-manage,proxies-view,proxies-manage,node-view,node-manage,search-view,search-manage,deploy-manage,ssl-manage,dbs-view,dbs-create,dbs-manage,php-view,php-manage,ssh-view,ssh-manage,services-view,services-manage,smtp-view,smtp-manage,health-view,health-manage,packages-view,monitor-view,zt-view,disk-view,yml-view,yml-manage,ip-whitelist-view,ip-whitelist-manage,status-view

PHP, the FPM pool, the Nginx vhost and the scheduler are all provisioned for you by the installer — you do not set up a Laravel environment by hand.

Installation — cipi gui <domain>

One command provisions the whole panel on a Cipi server: a dedicated PHP-FPM pool, an Nginx vhost for your domain, and a scheduler cron job. The Laravel app is bundled at /opt/cipi/gui, the same model used by the cipi-api package.

bash
cipi gui panel.example.com

The installer prompts interactively for the first administrator account — an email and a password. The password must satisfy the panel's policy:

  • Minimum 12 characters.
  • At least one uppercase, one lowercase, one digit, and one special character.
  • No more than 4 identical consecutive characters.

Configuration is written to /etc/cipi/gui.json. Once the command finishes, open your domain in a browser and log in with the admin account you just created.

The domain you pass is the panel's alone. If you have an app on example.com on the same server, the panel goes on a subdomain such as panel.example.com, not on example.com or one of the app's aliases. Cipi refuses those, and refuses the API's domain. Picked the wrong one? cipi gui move changes it.

The panel is served over plain HTTP until you issue a certificate. Run cipi gui ssl right after installation to secure it.

SSL — cipi gui ssl

Issue a free Let's Encrypt certificate for the panel's domain and switch it to HTTPS. The panel is HTTPS-aware and sets the correct forwarded headers behind the Cipi Nginx vhost.

bash
cipi gui ssl

The certificate renews automatically through the same ACME renewal that Cipi uses for app domains. Since 5.7.0 a failed certbot run is reported as a failure (exit 1). Before, the command could print “SSL installed” anyway.

Changing domain — cipi gui move

Moves the panel to a new domain or subdomain. Admin accounts, 2FA enrolments and saved server connections stay; admins sign in again, since their sessions belong to the old domain.

bash
cipi gui move panel.newdomain.com            # move and issue the new certificate
cipi gui move panel.newdomain.com --no-ssl   # move now, certificate later (cipi gui ssl)
  1. Point the new domain at the server first (DNS A/AAAA record).
  2. The Nginx vhost is rewritten for the new domain. If nginx -t rejects it, the old vhost goes back and nothing else changes.
  3. /etc/cipi/gui.json and APP_URL are updated.
  4. SSL: the old domain's certificate is deleted, so nothing keeps renewing it, and one is issued for the new domain. If that fails, the panel is already on the new domain over HTTP: fix DNS or port 80 and run cipi gui ssl.

The managed servers need no change: the panel calls their API URLs, and their IP whitelists are by IP, not by domain. To move a managed server's API instead, run cipi api move on that server and update its URL under Connections.

Cloudflare Zero Trust: a panel routed through the tunnel is tied to its hostname (DNS record, tunnel route, Access app). Run cipi zt hostname remove --gui before the move, then cipi zt hostname add --gui and cipi zt access enable --gui after it. cipi gui move refuses to run until the hostname is off the tunnel.

Two-factor authentication (TOTP)

The panel uses classic session login and supports optional TOTP two-factor authentication. Each administrator can enrol an authenticator app (Google Authenticator, 1Password, Aegis, …) from their profile. 2FA is opt-in per user, not forced.

If an administrator loses access to their second factor, an operator with shell access can clear it from the server with cipi gui reset-user, which rewrites the account and removes the 2FA enrolment.

Updating — gui update vs gui upgrade

The panel ships as the cipi/gui Composer package, so updates are ordinary Composer updates plus migrations. Two commands cover the common cases:

cipi gui update — soft update

Runs composer update cipi/gui, applies database migrations, and refreshes the compiled theme. This is the day-to-day update path.

bash
cipi gui update

cipi gui upgrade — full rebuild

Rebuilds the panel from scratch. Use it after a major release, or if an environment has drifted and a clean reinstall of the app code is the fastest way back to a known-good state.

bash
cipi gui upgrade

cipi gui refresh-theme — theme only

Recompiles and reloads the panel theme without touching code or the database — handy after a theme tweak.

bash
cipi gui refresh-theme

Operations

cipi gui status

Report the panel's current status — whether it is installed, its domain, and the health of its services.

bash
cipi gui status

cipi gui fix-permissions

Repair the panel's PHP-FPM open_basedir restriction and all runtime file permissions. Run it if the panel starts throwing permission or autoload errors after an update — including the HTTP 500 after cipi gui upgrade / soft update fixed in 5.0.18 (Composer symlink for cipi/gui outside open_basedir).

bash
cipi gui fix-permissions

cipi gui reset-user

Rewrite an administrator's email, name and password, and clear their 2FA enrolment — the recovery path when someone is locked out. reset-password is an alias for the same command.

bash
cipi gui reset-user

Removing the panel — cipi gui remove

Uninstall the panel: its Nginx vhost, PHP-FPM pool, scheduler, application, config and the Let's Encrypt certificate of its domain. A certificate that an app still uses is kept. Your servers and apps are untouched, since the panel is only a client of the API. uninstall is an alias, and --force skips the confirmation prompt. A panel on the Cloudflare tunnel must come off it first (cipi zt hostname remove --gui).

bash
cipi gui remove
cipi gui remove --force

Removing the panel is the ultimate expression of its optionality: uninstall it any time and Cipi is back to a pure CLI, exactly as it was before. The API on each server stays; remove it separately with cipi api remove if nothing else uses it.

Architecture

The panel is a standard Laravel application (12 or 13, Livewire 3.6+ or 4) distributed as the cipi/gui package from its own repository (cipi-sh/gui) and installed via a Composer VCS entry tracking dev-main. It lives at /opt/cipi/gui, mirroring how the cipi-api package is bundled.

AspectDetail
FrameworkLaravel 12 or 13, Livewire 3.6+ or 4 — no asset build step
Packagecipi/gui (GitHub cipi-sh/gui, Composer VCS dev-main)
Install path/opt/cipi/gui
Config/etc/cipi/gui.json
IsolationPHP-FPM open_basedir restricted to /opt/cipi/gui/ and /opt/cipi/cipi-gui/ (since 5.0.18)
AuthSession login + optional TOTP 2FA
JobsNo local queue worker — remote async jobs are polled through each managed server's cipi api

Because it holds no local queue worker and stores no server state of its own, the panel stays stateless with respect to your infrastructure: it authenticates to each server's API, submits jobs, and polls their status. Tear the panel down and rebuild it elsewhere without touching a single managed server.

API coverage

The GUI consumes the Cipi API through 1.33. Panel 3.1 adds Server → Disk: the filesystem /home is on, every app largest first (files, database, total, share of the disk, soft limit — flagged once over the limit or past 90% of it) and every database per engine. It reads GET /api/disk and GET /api/disk/dbs (API 1.33+, Cipi 5.5.2+, ability disk-view). Sizes are measured when the tab opens, so those two requests use their own timeout (180 seconds, CIPI_GUI_HTTP_DISK_TIMEOUT). An older server shows “not available” for that tab. Soft disk limits and Cloudflare DNS accounts have been on the API since 1.32 (the PHP SDK calls them); the panel shows the limit and points at cipi app limits and cipi ssl dns on the host to change them. cipi ssh apps and cipi firewall attempts stay on the host CLI. Keep the panel and each managed server's cipi/api package current (cipi gui update / cipi api update) so create forms and list fields match the server.

Area Coverage
Server GET /api/status; Manage page: PHP, DB engines, Node runtimes (GET /api/node), SSH keys, services, SMTP, search (GET /api/search), packages (GET /api/packages), monitor (GET /api/monitor), Zero Trust (GET /api/zt), disk usage (GET /api/disk, GET /api/disk/dbs, Server → Disk, panel 3.1 / API 1.33+ / Cipi 5.5.2+), IP whitelist (API 1.15–1.33)
Apps CRUD, suspend/unsuspend, fix-permissions (POST /api/apps/{name}/fix-permissions), basic auth, logs, .env, auth.json, Artisan, App commands (app run); create accepts engine (mariadb/pgsql), octane (FrankenPHP, API 1.13+) and Node (node, framework, node_version, build, start, output, health_path, API 1.31+); env/auth/run need API 1.14+; list/show expose octane / octane_port, node / node_mode / node_version and redirect / redirects / proxies; wildcard primary domains; webhook recreate and secret rotation; per-app HTTP healthcheck
Deploy config Structured Deployer knobs via /api/apps/{name}/deploy-config (API 1.14+)
cipi.yml Status and plan (GET /api/apps/{name}/yml), apply (POST …/yml/apply, job app-yml-apply), auto-apply (POST …/yml/auto/enable|disable) — API 1.35+ / Cipi 5.6.4+, yml-view / yml-manage
Aliases List, add, remove
WWW Status, add counterpart, force-to-root / force-from-root, clear (www-manage; API 1.12+)
Routing Whole-app and path redirects (/api/apps/{name}/redirect*), prefix reverse proxies (/api/apps/{name}/proxies) — API 1.31+ / Cipi 5.4.1+
Node GET /api/node, GET /api/apps/{name}/node, POST /api/apps/{name}/node/restart (SSR blue/green) — API 1.31+ / Cipi 5.4.1+
Search GET /api/search; POST /api/apps/{name}/search/enable and …/disable (API 1.31+)
Deploy Deploy, rollback, unlock; deploy audit ledger (GET /api/apps/{name}/deploy/audit, API 1.31+ / Cipi 5.4.0+)
SSL Install Let's Encrypt, force HTTPS redirect
Databases Engines + list (sync); create, backup, restore and password with optional engine (async; API 1.12+) — backup and restore have their own buttons since panel 3.0. Database deletion is host-CLI only since API 1.19
Health Server-wide list (GET /api/health) on the Server page; per-app set, unset and check now (API 1.16+)
Jobs Poll status, CLI output and the parsed result (credentials, backup file, webhook token)
Prefer the terminal? See the CLI client for the same API-driven management from your shell, or the cipi api and WHMCS module for automation. Package source: cipi-sh/gui.