Download Latest Version Version 5.4.1 source code.zip (705.2 kB) Google Add to Preferred Sources
Home / 5.3.1
Name Modified Size InfoDownloads / Week
Parent folder
README.md 2026-09-17 6.7 kB
Version 5.3.1 source code.tar.gz 2026-09-17 518.5 kB
Version 5.3.1 source code.zip 2026-09-17 615.5 kB
Totals: 3 Items   1.1 MB 0

[5.3.1] — 2026-09-17

Added — Compliance evidence (cipi compliance)

Cipi cannot be ISO 27001 or SOC 2 certified: there is no organisation or service to audit, only software on your server. What a team under audit needs is evidence that the deploy platform meets the controls, in a form the auditor accepts. cipi compliance collects that evidence. It is read-only: no check changes the server, runs apt update, or writes config.

  • cipi compliance [check] [--days=90] [--json] — runs 17 controls and prints pass / warn / fail / info / n/a. Exits 1 on any fail, so it can gate CI or cron.
  • cipi compliance report [--days=90] [--out=/abs/path] [--no-archive] [--json] — writes /var/log/cipi/compliance/<host>-<UTC time>/ with report.md (for the auditor), report.json, evidence/<control>/… (the raw command output behind each finding) and SHA256SUMS, plus a .tar.gz and its .sha256. Everything is root-only (700/600). The command prints the archive SHA-256 so you can record it outside the server. The run is logged to cipi.log.
  • cipi compliance list / cipi compliance controls — past reports with their counts, and the control catalog with its mapping.
  • Controls and mapping (ISO/IEC 27001:2022 Annex A · SOC 2 TSC): ssh (effective sshd -T), firewall (ufw default deny), intrusion (fail2ban jails, CrowdSec), patching (unattended-upgrades, pending security updates from the cached lists, reboot-required), kernel (CIS network sysctls), tls (nginx -T protocols, HSTS, Let's Encrypt expiry and key type), accounts (UID 0, empty passwords, accounts not managed by Cipi, sudoers), ssh_keys (fingerprints; RSA < 3072 and DSA flagged), api_tokens (no expiry, expired, unused for the period, * ability, IP allowlist *), gui_2fa, secrets (encrypted and root-only config, key file modes), deploys (deploy log banners: trigger, branch, release, commit SHA from Deployer's REVISION, result, rollbacks), backups (schedule freshness, off-site copy, encryption), logging (remote forwarding, auth.log history, journald, auditd), monitoring (monitor cron, disabled checks, alert delivery, muted triggers), time (NTP), malware (cipi scan).
  • No secrets in the bundle. Panel SQLite databases are read as their owner with sqlite3 -readonly (PHP PDO fallback), using named columns only. Token hashes, password hashes and 2FA secrets are never selected. SSH keys are exported as fingerprints only, and backup credentials are not exported.
  • Honest about gaps. secrets is at best a warn: the vault uses AES-256-CBC without a MAC, so it is not authenticated encryption, and the report says so before an auditor has to ask. backups notes that restore tests are not recorded. deploys notes that the person who ran a CLI deploy is in auth.log, not in the deploy log. Cipi's own design choices appear as notes, not failures: password SFTP login for cipi-apps users, and nginx, databases and PHP kept off unattended-upgrades.

Added — Redirects (cipi redirect) and prefix proxies (cipi proxy)

Both are rendered by _create_nginx_vhost from apps.json (redirect, redirects[], proxies[]), so they survive every vhost regeneration (alias, www, basic auth, PHP switch, cipi sync import), and certbot clones them into :443 like every other location.

  • cipi redirect set <app> --to=<url> [--301|--302|--307|--308] [--no-path] — every name of the app, www host included, redirects in one hop. The path and query are kept by default (old.com/a?bhttps://new.com/a?b). ACME stays public, so the old name's certificate keeps renewing. Refuses a target served by the app itself (loop).
  • cipi redirect enable|disable <app> toggles the saved target; unset forgets it.
  • cipi redirect add <app> <from> <to> [--301|--302|--307|--308] [--no-path] — path redirects. <to> is a same-app /path or an http(s):// URL. A <from> ending in / is a prefix: the rest of the raw request URI is appended (/blog/x?yhttps://blog.example.com/x?y), and /blog without the slash goes to the target too; --no-path sends everything to <to> as is. Otherwise <from> is exact and only the query string is carried over (unless <to> has its own). Adding an existing <from> updates it. remove, list [--json].
  • cipi proxy add <app> <prefix> <http(s)://upstream> [--strip-prefix] [--preserve-host] [--timeout=60] [--no-buffering] [--force]location ^~ <prefix> with proxy_pass. Without --strip-prefix the URI goes upstream unchanged; with it, /api/users<upstream>/users and X-Forwarded-Prefix is sent. An upstream with a path (http://h/v1) always replaces the prefix, so it requires --strip-prefix. WebSocket upgrade, X-Real-IP, X-Forwarded-For/-Proto/-Host, proxy_ssl_server_name for HTTPS upstreams. Host is the upstream's unless --preserve-host. --no-buffering is for SSE, long polling and streamed downloads. Basic auth, when on, covers the prefix. remove, list [--json].
  • Path redirects and proxies keep working while the app redirect is on — they are more specific than location /, so a moved site can keep /api/ where it was.
  • Validation. Paths and URLs are limited to a charset with no quotes, $, ;, braces or whitespace, so a rule cannot inject nginx directives. Source paths must be written decoded (nginx matches the decoded URI). Refused: /, the ACME challenge, /favicon.ico, /robots.txt, /index.php, /cipi/webhook, Reverb's /app and /apps on a Reverb app, and any path another redirect or proxy already occupies (e.g. a redirect and a proxy on /api/). Redirects that would loop back into themselves are refused.
  • Loopback guard. A proxy to 127.0.0.1/localhost on a port Cipi already uses — nginx itself (80/443), SSH, MariaDB, PostgreSQL, Valkey, Meilisearch, another app's Octane or Reverb — is refused without --force. An upstream hostname that does not resolve is refused (nginx resolves it at reload); one that does not answer within 5s is only a warning.
  • Safe apply. nginx -t must pass before the change. If nginx refuses the new vhost, apps.json and the vhost are restored and the command exits 1.
  • cipi app show lists the app redirect, path redirects and proxy prefixes. Two notification triggers: redirect_change, proxy_change (on by default). Shell completion and cipi help redirect|proxy.

CLI only for now: the panel API sudoers are unchanged.

No migration: nothing is installed, scheduled or enabled.

Source: README.md, updated 2026-09-17