cipi api

Cipi può abilitare opzionalmente un layer REST API sul server tramite cipi api <domain>. È alimentato dal package Laravel cipi/api (release corrente 1.13.0), che espone:

  • REST API — app (inclusa creazione Octane), alias, redirect www, deploy, SSL, database multi-engine, log app, stato server (/api/*)
  • Server MCP — 36 tool su /mcp (Streamable HTTP)
  • Swagger UI — riferimento interattivo su /docs

Richiede PHP 8.2+ e Laravel 12+ sull'host del pannello. Si tratta di automazione a livello server — distinta dal package per-app Cipi Agent (cipi/agent su ogni app Laravel).

Il package cipi/api

Su un server Cipi normale non installi mai il package manualmente — cipi api <domain> provisiona Laravel in /opt/cipi/api, Nginx, SSL, job queue SQLite e cipi-queue.service. Per riferimento o setup personalizzati:

bash
$ composer require cipi/api
$ php artisan vendor:publish --tag=cipi-config
$ php artisan vendor:publish --tag=cipi-assets
$ php artisan migrate
$ php artisan cipi:seed-api-user
$ php artisan cipi:token-create

Il .env del pannello usa CIPI_APPS_JSON=/etc/cipi/apps.json (o proiezione apps-public.json per campi non sensibili). Le ability dei token sono definite in config/cipi.php — elencale con php artisan cipi:token-abilities (stessa lista di cipi api token create da Cipi 4.6.3).

Sorgente e changelog: github.com/cipi-sh/api (MIT). Client wrapper: cipi-cli.

Comandi

bash
$ cipi api <domain>           # configure API at root (e.g. api.myhosting.com)
$ cipi api ssl                  # install Let's Encrypt certificate for API domain
$ cipi api token list           # list tokens
$ cipi api token create         # create a new token (choose abilities)
$ cipi api token revoke <id>    # revoke a token
$ cipi api status               # Laravel + cipi-api versions, queue worker, pending jobs, FPM pool
$ cipi api fix-permissions      # repair panel storage/database ownership (www-data)
$ cipi api update               # soft update: composer update on Laravel and API packages
$ cipi api upgrade              # full rebuild with rollback at /opt/cipi/api.old

Risoluzione problemi Panel API

Dopo cipi self-update, file di proprietà root sotto /opt/cipi/api possono impedire a PHP-FPM (www-data) di scrivere log o il database job SQLite — il browser mostra un HTTP 500 su /docs o /mcp. Cipi normalmente ripara la proprietà automaticamente durante self-update; se i problemi persistono:

bash
$ cipi api fix-permissions   # chown storage, database, bootstrap/cache, .env → www-data
$ cipi api status              # confirm Laravel version, queue worker, pending jobs

cipi api status stampa le versioni installate di Laravel e del package cipi/api, se cipi-queue.service è attivo, job asincroni in sospeso nel database SQLite del pannello e statistiche pool PHP-FPM per il vhost API (inclusi slow request quando configurati).

Da v4.7.18 (migration 4.7.15–4.7.18), i fallimenti Panel API su Ubuntu 25.10+ / 26.04 sono risolti end-to-end: sudo-rs rifiuta wildcard cipi db restore * * (l'intero file sudoers veniva ignorato — I'm afraid I can't do that), quindi la whitelist usa solo * finale; il sourcing di common.sh non interrompe più comandi read-only quando /etc/cipi è rimontato read-only; open_basedir dell'API include /usr/local/bin/ per helper log; e cipi db list mostra database vuoti e segnala errori vault/MariaDB. Esegui cipi self-update per applicare.

Creazione token e permessi granulari

L'autenticazione usa Sanctum. Ogni token può avere una o più ability che limitano le operazioni consentite:

  • apps-view — leggere app
  • apps-create — creare app
  • apps-edit — modificare app (PHP, repository, branch, dominio primario da API 1.9.0+ / Cipi 4.6.2+)
  • apps-suspend — sospendere e riattivare app
  • apps-basicauth — abilitare, disabilitare e ispezionare HTTP Basic Auth sulle app (API 1.10.0+)
  • apps-delete — eliminare app
  • deploy-manage — deploy, rollback, unlock
  • ssl-manage — installare e gestire certificati SSL
  • aliases-view — leggere alias
  • aliases-create — aggiungere alias
  • aliases-delete — rimuovere alias
  • www-manage — controparte www/apex e redirect (API 1.12.0+ / Cipi 4.8+)
  • dbs-view — elencare database
  • dbs-create — creare database
  • dbs-delete — eliminare database
  • dbs-manage — backup, restore, rigenerare password
  • status-view — leggere snapshot stato server (GET /api/status, API 1.11.6+)
  • mcp-access — accedere al server MCP

Da Cipi 4.6.3 / API 1.11.7+, cipi api token create legge la lista canonica delle ability dal package panel API (stesse voci di php artisan cipi:token-abilities sul server). La migration 4.6.3 aggiorna retroattivamente i server esistenti con la lista aggiornata (inclusi status-view, apps-suspend e apps-basicauth).

Endpoint REST

Tutti gli endpoint richiedono l'header Authorization: Bearer <token>. Le operazioni di scrittura (create, edit, delete, deploy, rollback, unlock, SSL, alias, www, database) sono asincrone: restituiscono 202 Accepted con un job_id da interrogare via GET /api/jobs/{id}. Gli endpoint read-only come GET /api/dbs, GET /api/dbs/engines, GET /api/status, GET /api/apps/{name}/www e GET /api/apps/{name}/logs (API 1.11.9+) sono sincroni. POST /api/apps accetta parametri opzionali custom (boolean) e docroot (string) per creare app personalizzate con deploy classico. Il campo repository è obbligatorio per app Laravel e opzionale per app custom: omettilo (o invia vuoto) per provisionare un sito solo SFTP allineato a Cipi v4.5.1+. Quando non c'è repository, branch viene omesso. Da API 1.12.0+ / Cipi 4.8+, la creazione app Laravel accetta anche engine opzionale (mariadb o pgsql) per scegliere il motore database. Da API 1.13.0+ / Cipi 5.0+, la creazione app Laravel accetta octane opzionale (true o "frankenphp") per provisionare Laravel Octane (FrankenPHP); octane viene rifiutato quando custom è impostato. Il tool MCP AppCreate segue le stesse regole. Mantieni il package API aggiornato con cipi api update / cipi api upgrade così validazione e OpenAPI corrispondono a questo comportamento.

POST /api/apps/{name}/suspend mette un'app offline sostituendo il vhost Nginx con una pagina di manutenzione generica HTTP 503 (HTTPS incluso) senza eliminarla, mentre POST /api/apps/{name}/unsuspend ripristina il vhost normale. Entrambi richiedono l'ability apps-suspend e restituiscono 409 se l'app è già nello stato target. Il flag suspended sopravvive alla rigenerazione vhost ed è esposto su GET /api/apps e GET /api/apps/{name}. Questi endpoint richiedono il package API 1.8.1+ e Cipi 4.5.8+ sul server.

PUT /api/apps/{name} accetta un campo domain opzionale per rinominare il dominio primario dell'app. L'API valida il formato in modo sincrono e restituisce 409 se il dominio è già usato da un'altra app (gli alias dell'app corrente sono consentiti, quindi promuovere un alias a primario funziona). Richiede il package API 1.9.0+ e Cipi 4.6.2+. Il tool MCP AppEdit accetta lo stesso parametro domain.

GET /api/apps e GET /api/apps/{name} espongono i flag booleani suspended e basic_auth per app (da apps.json). Da API 1.12.0+ espongono anche engine, www_redirect e force_https da apps-public.json / metadata app. Da API 1.13.0+ espongono octane e octane_port per app Octane.

Gli endpoint HTTP Basic Auth sotto /api/apps/{name}/basicauth/* avvolgono cipi basicauth in modo sincrono — non restituiscono un job_id. Enable accetta user e password opzionali (generati automaticamente se omessi; restituiti una volta nella risposta). Richiede l'ability apps-basicauth e il package API 1.10.0+. Questo è distinto dalla gestione auth.json di Composer — vedi cipi basicauth.

Gli endpoint WWW / apex sotto /api/apps/{name}/www/* avvolgono cipi www (API 1.12.0+ / Cipi 4.8+). GET …/www è sincrono e restituisce primary, apex, www e redirect. POST …/www/add, …/force-to-root, …/force-from-root e …/clear sono job asincroni. Richiede l'ability www-manage. Tool MCP: WwwStatus, WwwAdd, WwwForceToRoot, WwwForceFromRoot, WwwClear.

POST /api/apps/{name}/ssl/force riapplica il redirect HTTP → HTTPS senza emettere un nuovo certificato (cipi ssl force). Richiede ssl-manage e API 1.12.0+. Tool MCP: SslForce.

GET /api/dbs elenca i database in modo sincrono eseguendo sudo cipi db list sull'host (come la CLI server). Query opzionale engine=mariadb|pgsql filtra per motore (API 1.12.0+ / Cipi 4.8+). GET /api/dbs/engines elenca i motori installati e il default server (sync; MCP DbEngines). Le altre operazioni di scrittura /api/dbs/* sono job asincroni e accettano engine opzionale su create, delete, backup, restore e password. I comandi database richiedono Cipi 4.4.17+ sul server (voci cipi db … nella whitelist sudoers API); il supporto multi-engine richiede Cipi 4.8+.

GET /api/status restituisce lo stesso JSON strutturato di cipi status (sistema, risorse, servizi, pool PHP, conteggio app). Da API 1.11.8+ l'endpoint preferisce sudo cipi status sull'host e ricade su letture dirette host quando sudo non è disponibile. Da API 1.12.1+ il fallback host-read include postgresql quando l'unità systemd è installata (allineato a Cipi 4.8+). Richiede l'ability status-view (API 1.11.6+). Il tool MCP ServerStatus restituisce lo stesso payload e richiede solo mcp-access. Dal tuo laptop, usa cipi-cli status per una panoramica globale su tutti i profili server configurati, o il dettaglio per un profilo.

GET /api/apps/{name}/logs restituisce snapshot log sincroni e paginati per nginx, PHP-FPM, Laravel (se presente), worker e deploy — la controparte REST di cipi app logs e cipi-cli apps logs. Parametri query: type (default all), page (default 1, più recenti prima), per_page (default 50, max 1000). Richiede l'ability apps-view e il package API 1.11.9+. Il testo dei log è redatto per secret comuni (stessa policy di MCP AppLogs da API 1.11.5+).

Metodo Endpoint Ability richiesta
GET /api/apps apps-view
GET /api/apps/{name} apps-view
GET /api/apps/{name}/logs apps-view
POST /api/apps apps-create
PUT /api/apps/{name} apps-edit
POST /api/apps/{name}/suspend apps-suspend
POST /api/apps/{name}/unsuspend apps-suspend
DELETE /api/apps/{name} apps-delete
GET /api/apps/{name}/aliases aliases-view
POST /api/apps/{name}/aliases aliases-create
DELETE /api/apps/{name}/aliases aliases-delete
POST /api/apps/{name}/deploy deploy-manage
POST /api/apps/{name}/deploy/rollback deploy-manage
POST /api/apps/{name}/deploy/unlock deploy-manage
POST /api/apps/{name}/ssl ssl-manage
POST /api/apps/{name}/ssl/force ssl-manage
GET /api/apps/{name}/www www-manage
POST /api/apps/{name}/www/add www-manage
POST /api/apps/{name}/www/force-to-root www-manage
POST /api/apps/{name}/www/force-from-root www-manage
POST /api/apps/{name}/www/clear www-manage
GET /api/apps/{name}/basicauth apps-basicauth
POST /api/apps/{name}/basicauth/enable apps-basicauth
POST /api/apps/{name}/basicauth/disable apps-basicauth
GET /api/dbs/engines dbs-view
GET /api/dbs dbs-view
POST /api/dbs dbs-create
DELETE /api/dbs/{name} dbs-delete
POST /api/dbs/{name}/backup dbs-manage
POST /api/dbs/{name}/restore dbs-manage
POST /api/dbs/{name}/password dbs-manage
GET /api/status status-view
GET /api/jobs/{id} qualsiasi token autenticato

Esempi REST (curl)

Imposta l'URL base API e il token (da cipi api token create):

bash
export CIPI_API_URL="https://api.myserver.com"
export CIPI_API_TOKEN="your-sanctum-token"

Elenca app (sync, 200):

bash
curl -sS "${CIPI_API_URL}/api/apps" \
  -H "Authorization: Bearer ${CIPI_API_TOKEN}" \
  -H "Accept: application/json"

Stato server (sync, richiede status-view):

bash
curl -sS "${CIPI_API_URL}/api/status" \
  -H "Authorization: Bearer ${CIPI_API_TOKEN}"

Log app (sync, richiede apps-view, API 1.11.9+):

bash
curl -sS "${CIPI_API_URL}/api/apps/myapp/logs?type=deploy&page=1&per_page=50" \
  -H "Authorization: Bearer ${CIPI_API_TOKEN}" \
  -H "Accept: application/json"

Crea un'app Laravel Octane (async, API 1.13.0+ / Cipi 5.0+; richiede apps-create):

bash
curl -sS -X POST "${CIPI_API_URL}/api/apps" \
  -H "Authorization: Bearer ${CIPI_API_TOKEN}" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "domain": "shop.example.com",
    "repository": "git@github.com:you/shop.git",
    "branch": "main",
    "octane": true,
    "engine": "mariadb"
  }'

Invia "octane": "frankenphp" per lo stesso effetto. Ometti octane per PHP-FPM classico. Usa "engine": "pgsql" quando PostgreSQL è installato (API 1.12.0+ / Cipi 4.8+).

Deploy di un'app (async, 202 + job_id):

bash
curl -sS -X POST "${CIPI_API_URL}/api/apps/myapp/deploy" \
  -H "Authorization: Bearer ${CIPI_API_TOKEN}" \
  -H "Accept: application/json"

# poll until completed
curl -sS "${CIPI_API_URL}/api/jobs/JOB_ID" \
  -H "Authorization: Bearer ${CIPI_API_TOKEN}"

Backup database (async, dbs-manage) — restituisce un percorso backup reale nel result del job, non un dump anonymizzato (vedi Agent anonymizer):

bash
curl -sS -X POST "${CIPI_API_URL}/api/dbs/myapp_db/backup" \
  -H "Authorization: Bearer ${CIPI_API_TOKEN}"

Integrazione host (sudoers)

La panel API gira come www-data ed esegue comandi CLI Cipi via sudo usando /etc/sudoers.d/cipi-api — una whitelist esplicita di sottocomandi cipi. Vault e credenziali MariaDB restano dentro Cipi, non in PHP.

  • GET /api/dbs — esegue sudo cipi db list (sync). Richiede Cipi 4.4.17+ (migration aggiunge cipi db … a sudoers). Senza: sudo: a terminal is required. List/engines multi-engine richiedono Cipi 4.8+ / API 1.12.0+.
  • GET /api/status / MCP ServerStatus — preferisce sudo cipi status (API 1.11.8+); fallback host-read quando sudo fallisce (include postgresql da API 1.12.1+).
  • MCP ServiceListsudo cipi service list
  • MCP AppArtisansudo cipi app artisan <app> …
  • Job asincroni — cipi app (inclusi --octane / --engine), deploy, alias, www, ssl / ssl force, db create|delete|backup|restore|password|engines, ecc.

Dopo cipi self-update, esegui cipi api fix-permissions se /docs o /mcp restituiscono HTTP 500 (vedi risoluzione problemi sopra).

Swagger / OpenAPI

La documentazione interattiva è disponibile su /docs (Swagger UI). La spec OpenAPI è generata da public/api-docs/openapi.json e copre app (inclusi suspend, unsuspend, rename dominio, basic auth, log paginati, redirect www, creazione Octane e engine multi-engine), alias, deploy, SSL (install + force HTTPS), database (lista engine + engine opzionale sulle mutation), stato server, polling job con tipi result strutturati e schemi tool MCP. Versione package API corrente: 1.13.0.

Server MCP

Un server MCP (Model Context Protocol) è esposto su /mcp via Streamable HTTP. Da package API 1.11.1+, un token con l'ability mcp-access è sufficiente per tutti i tool MCP — le ability REST per-endpoint (apps-view, deploy-manage, apps-basicauth, www-manage, ecc.) non vengono verificate su /mcp. Il server espone 36 tool per app, alias, www, database, deploy, SSL, HTTP Basic Auth, polling job, log, Artisan e monitoraggio server. Le operazioni di scrittura che dispatchano job async restituiscono un job_id — interroga con JobShow (API 1.11.0+). Azioni basic auth e tool read-only girano in modo sincrono.

  • Applicazioni: AppList, AppShow, AppCreate (engine, octane opzionali), AppEdit, AppSuspend, AppUnsuspend, AppDelete, AppDeploy, AppDeployRollback, AppDeployUnlock, AppArtisan (solo app Laravel; rifiuta app custom e tinker)
  • HTTP Basic Auth: AppBasicAuthStatus, AppBasicAuthEnable, AppBasicAuthDisable
  • Alias: AliasList, AliasAdd, AliasRemove
  • WWW / apex: WwwStatus, WwwAdd, WwwForceToRoot, WwwForceFromRoot, WwwClear (API 1.12.0+)
  • Database: DbEngines, DbList, DbCreate, DbDelete, DbBackup, DbRestore, DbPassword (engine opzionale su list/mutation; API 1.12.0+)
  • SSL: SslInstall, SslForce (API 1.12.0+)
  • Job e log: JobShow (interroga stato job async, result parsato e output CLI), AppLogs (log app recenti per tipo: all, nginx, php, worker, deploy, laravel — come cipi app logs; equivalente REST: GET /api/apps/{name}/logs da API 1.11.9+), ApiLogShow (log Laravel recenti per l'host panel API)
  • Monitoraggio server: ServerStatus (JSON strutturato allineato a GET /api/status / cipi status), ServiceList (stato servizi di sistema via cipi service list)
Da API 1.11.5+, i tool MCP log (AppLogs, ApiLogShow) prefissano ogni risposta con un avviso contenuto produzione e redigono secret comuni prima della consegna. Output CLI sensibile da JobShow e AppArtisan è redatto; gli oggetti result strutturati del job (es. credenziali app da job create) restano intatti così gli operatori possono leggerli una volta.

Da Cipi 4.6.3, il package panel API viene soft-aggiornato ogni notte alle 04:30 via /etc/cron.d/cipi-api (cipi api update), così endpoint MCP e REST restano aggiornati senza intervento manuale.

Installazione del server MCP

L'endpoint MCP è opzionale e si carica solo quando il package MCP richiesto è installato. Per usarlo da VS Code, Cursor o Claude Desktop:

  1. Configura l'API con cipi api <domain> e cipi api ssl
  2. Crea un token con cipi api token create e seleziona almeno mcp-access
  3. Aggiungi il server MCP alla config del client (vedi sotto)

Cursor

Aggiungi a ~/.cursor/mcp.json (o Cursor → Impostazioni → MCP):

json
{
  "mcpServers": {
    "cipi-api": {
      "type": "http",
      "url": "https://<your-api-domain>/mcp",
      "headers": {
        "Authorization": "Bearer <your-token>"
      }
    }
  }
}

Cursor si connette nativamente via HTTP — nessun bridge necessario.

VS Code

VS Code (con GitHub Copilot) supporta MCP nativamente da 1.102. Aggiungi a .vscode/mcp.json o esegui MCP: Open User Configuration per un setup globale. Usa inputs per richiedere il token una volta e salvarlo in modo sicuro:

json
{
  "inputs": [
    {
      "type": "promptString",
      "id": "cipi-token",
      "description": "Cipi API Token",
      "password": true
    }
  ],
  "servers": {
    "cipi-api": {
      "type": "http",
      "url": "https://<your-api-domain>/mcp",
      "headers": {
        "Authorization": "Bearer ${input:cipi-token}"
      }
    }
  }
}

Riavvia VS Code dopo il salvataggio. Usa MCP: Add Server dalla Command Palette per un setup guidato.

Claude Code

Aggiungi il server MCP direttamente dalla CLI:

bash
$ claude mcp add --transport http cipi-api https://<your-api-domain>/mcp \
    --header "Authorization: Bearer <your-token>"

Claude Desktop

Claude Desktop richiede il bridge mcp-remote per convertire stdio in HTTP. Aggiungi a ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) o al percorso config equivalente sul tuo OS:

json
{
  "mcpServers": {
    "cipi-api": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote",
        "https://<your-api-domain>/mcp",
        "--header",
        "Authorization: Bearer <your-token>"
      ]
    }
  }
}

Installa mcp-remote una volta con npm install -g mcp-remote.

Sostituisci <your-api-domain> con il tuo dominio API (es. api.myhosting.com) e <your-token> con il token creato al passo 2.

Modulo WHMCS

Un modulo di provisioning WHMCS ufficiale è disponibile su github.com/cipi-sh/whmcs. Collega il ciclo di vita provisioning WHMCS alla REST API Cipi — automatizzando creazione app, eliminazione, certificati SSL, deploy e modifiche di configurazione per i tuoi clienti hosting. Nessuna dipendenza Composer; il modulo è un drop-in autocontenuto.

Requisiti

  • WHMCS 8.x (tipo modulo provisioning “Server”)
  • Server Cipi con API abilitata: cipi api <domain> e cipi api ssl
  • Token Sanctum Bearer con le ability richieste:
Ability Richiesta per
apps-view Test Connection, App Info
apps-create Create Account
apps-edit Change Package
apps-suspend Suspend / Unsuspend
apps-delete Terminate Account
deploy-manage Deploy, Rollback, Unlock
ssl-manage Install SSL, Auto-SSL

Installazione

  1. Copia modules/servers/cipi/ nella root WHMCS:
    your-whmcs/
    └── modules/
        └── servers/
            └── cipi/
                ├── cipi.php
                └── lib/
                    └── CipiApiClient.php
  2. In WHMCS Admin → System Settings → Servers → Add New Server:
    • Type: Cipi (Laravel hosting)
    • Hostname: URL base API (es. https://api.example.com, senza slash finale)
    • Password: token Bearer da cipi api token create
    • Secure: Sì (consigliato — abilita verifica TLS)
  3. Crea un prodotto hosting collegato a questo server e configura Module Settings:
Impostazione Descrizione Default
Versione PHP 8.2 / 8.3 / 8.4 / 8.5 8.5
Tipo app laravel o custom laravel
Repository Git (SSH) Obbligatorio per Laravel; opzionale per custom
Branch Git Branch da deployare main
SSL automatico Installa Let’s Encrypt dopo la creazione No

Tipi di app

Tipo app Equivalente Cipi Stack Git / Deploy
laravel (default) cipi app create Utente Linux isolato, pool PHP-FPM, vhost Nginx, MariaDB, worker Supervisor, release Deployer URL repository SSH obbligatorio; branch dalle impostazioni
custom cipi app create --custom Directory htdocs/, Nginx + PHP — ideale per siti statici, SPA, WordPress o app PHP generiche Opzionale: lascia Repository Git vuoto per hosting solo SFTP, o imposta un repo per deploy Git

Ciclo di vita provisioning

Azione WHMCS Chiamata API Comportamento
Test Connection GET /api/apps Valida token e raggiungibilità API
Create Account POST /api/apps Provisiona un'app Cipi (Laravel o custom); attende job async; opzionalmente installa SSL
Suspend POST /api/apps/{name}/suspend Mette l'app offline (pagina manutenzione HTTP 503) senza eliminarla; attende job async
Unsuspend POST /api/apps/{name}/unsuspend Ripristina il vhost Nginx normale dell'app; attende job async
Terminate Account DELETE /api/apps/{name} Rimuove l'app; attende job async
Change Package PUT /api/apps/{name} Aggiorna versione PHP, repository Git o branch

Suspend / Unsuspend richiedono Cipi 4.5.8+ (endpoint suspend/unsuspend), il package API 1.8.1+ e un token con l'ability apps-suspend. Sospendere sostituisce il vhost dell'app con una pagina manutenzione HTTP 503 generica; riattivare lo ripristina.

Pulsanti admin

Dalla vista servizio admin WHMCS, gli operatori possono attivare azioni one-click:

Pulsante Chiamata API Descrizione
Install SSL POST /api/apps/{name}/ssl Installa un certificato Let’s Encrypt
Deploy POST /api/apps/{name}/deploy Attiva un deploy zero-downtime
Rollback Deploy POST /api/apps/{name}/deploy/rollback Torna alla release precedente
Unlock Deploy POST /api/apps/{name}/deploy/unlock Sblocca un deploy bloccato
App Info GET /api/apps/{name} Recupera dettagli app correnti nel Module Log

Auto-SSL alla creazione

Abilita Auto SSL nelle impostazioni modulo prodotto per installare automaticamente un certificato Let’s Encrypt subito dopo il provisioning. Se l'installazione SSL fallisce, l'app viene comunque creata con successo e un warning viene loggato.

Client API completo

Il CipiApiClient incluso copre l'intera superficie REST API Cipi. Anche se una funzionalità non è collegata a un hook WHMCS, puoi usare il client in hook o addon personalizzati:

Area Metodi
App listApps, getApp, createApp, editApp, suspendApp, unsuspendApp, deleteApp
Deploy deployApp, rollbackDeploy, unlockDeploy
SSL installSsl
Alias listAliases, addAlias, removeAlias
Database listDatabases, createDatabase, deleteDatabase, backupDatabase, restoreDatabase, resetDatabasePassword
Job getJob, waitForJob

Estendere il modulo

php
// Example: add an alias from a WHMCS hook
require_once ROOTDIR . '/modules/servers/cipi/lib/CipiApiClient.php';

$client = new CipiApiClient('https://api.example.com', $token);
$client->addAlias('myapp', 'alias.example.com');

// Example: create an extra database
$client->createDatabase('myapp_extra');

// Example: backup a database
$client->backupDatabase('myapp');

Comportamento lato cliente

Il modulo non aggiunge una tab Client Area, pulsanti custom o stato live da Cipi. I clienti vedono la vista servizio WHMCS standard (dominio, stato, date rinnovo). Quando Cipi provisiona un'app genera secret monouso (password SSH, password DB, deploy key, URL webhook). La REST API non spinge automaticamente quei secret in WHMCS — dovresti estendere il modulo, scrivere un hook o consegnare le credenziali tramite il tuo workflow di supporto.

Log del modulo

Tutte le chiamate API sono loggate via logModuleCall() — Create, Terminate, Change Package, SSL, Deploy, Rollback, Unlock e App Info. Abilita Utilities → Logs → Module Log in WHMCS Admin per visibilità completa.

Codice sorgente completo, struttura progetto e linee guida contribuzione sono disponibili su GitHub. Il modulo è open source sotto licenza MIT.

cipi sync

Trasferisci, replica e fai backup di intere applicazioni Laravel tra server Cipi — inclusi configurazione, dump database, file storage, chiavi SSH, worker e crontab. Ogni archivio è criptato con AES-256-CBC e protetto da una passphrase definita dall'utente, così credenziali e dati sensibili sono al sicuro a riposo e durante il trasferimento.

Panoramica comandi

bash
$ cipi sync export  [app ...] [--with-db] [--with-storage] [--output=<path>] [--passphrase=<secret>]
$ cipi sync import  <archive.tar.gz.enc> [app ...] [--update] [--deploy] [--yes] [--passphrase=<secret>]
$ cipi sync push    [app ...] [--host=IP] [--port=22] [--with-db] [--with-storage] [--import] [--passphrase=<secret>]
$ cipi sync list    <archive.tar.gz.enc> [--passphrase=<secret>]
$ cipi sync pubkey  # display the server's sync public key for inter-server trust
$ cipi sync trust   # add a remote server's public key to cipi's authorized_keys

Crittografia archivio

Tutti gli archivi sync sono criptati di default con AES-256-CBC. Durante l'export ti viene chiesta una passphrase (minimo 8 caratteri) che protegge l'archivio. La stessa passphrase è richiesta per importarlo o ispezionarlo. Questo protegge chiavi SSH, file .env, dump database e credenziali a riposo e durante il trasferimento.

bash
# Interactive mode (default) — prompted for passphrase
$ cipi sync export --with-db
#   Enter passphrase to encrypt the archive: ********
#   Confirm passphrase: ********

# Non-interactive mode — for cron jobs and scripts
$ cipi sync export --with-db --passphrase="MyStr0ngP@ss"
Per setup automatizzati, salva la passphrase in un file sicuro e referenziala negli script: echo "MyStr0ngP@ss" > /etc/cipi/.sync_passphrase && chmod 400 /etc/cipi/.sync_passphrase. Poi usa --passphrase="$(cat /etc/cipi/.sync_passphrase)" nei job cron.

Export

Impacchetta le config app in un archivio .tar.gz.enc criptato. Opzionalmente include dump database e file storage.

bash
# Export all apps (config only)
$ cipi sync export

# Export three specific apps with database + storage
$ cipi sync export shop blog api --with-db --with-storage

# Export to a custom path (non-interactive)
$ cipi sync export --with-db --output=/root/backups/cipi-march.tar.gz --passphrase="MyStr0ngP@ss"

Cosa va nell'archivio

File Descrizione Incluso
env Il .env dell'app da /home/<app>/shared/.env Sempre
auth.json Credenziali auth Composer (se esistono) Sempre
deploy.php Config Deployer Sempre
ssh/* Deploy key, known_hosts, authorized_keys, config SSH Sempre
supervisor.conf Config queue worker Sempre
crontab Crontab dell'app (scheduler + trigger deploy) Sempre
db.sql.gz Dump MariaDB gzippato (schema + dati + routine) --with-db
storage.tar.gz Archivio di /home/<app>/shared/storage/ --with-storage

Più config globali: apps.json (filtrato alle app selezionate), databases.json, backup.json, api.json.

Import

Ripristina app da un archivio sul server corrente.

bash
# Import all apps from archive
$ cipi sync import /tmp/cipi-sync-aws01-20260306.tar.gz.enc

# Import only two apps from an archive that contains ten
$ cipi sync import /tmp/cipi-sync-aws01-20260306.tar.gz.enc shop blog --passphrase="MyStr0ngP@ss"

# Import and deploy code from Git immediately
$ cipi sync import /tmp/cipi-sync-aws01-20260306.tar.gz.enc --deploy

# Non-interactive (skip all prompts)
$ cipi sync import /tmp/cipi-sync-aws01-20260306.tar.gz.enc --yes --passphrase="MyStr0ngP@ss"

Cosa fa l'import per una NUOVA app

Quando un'app non esiste sul server target, l'import la crea da zero — equivalente a cipi app create con tutte le config precompilate dall'archivio:

  1. Utente Linux — Crea un nuovo utente con password casuale
  2. Directory — Crea /home/<app>/shared/, logs/, .ssh/, .deployer/
  3. Deploy key SSH — Ripristina dall'archivio (la stessa chiave funziona con GitHub/GitLab senza riconfigurazione)
  4. Database MariaDB — Crea database + utente con una nuova password casuale
  5. Dati database — Importa il dump se --with-db era usato durante l'export
  6. .env — Copia dall'archivio, poi sovrascrive DB_PASSWORD, DB_USERNAME, DB_DATABASE, DB_HOST con i valori del nuovo server. Tutto il resto (APP_KEY, MAIL_*, REDIS_*, variabili custom) resta com'è
  7. Pool PHP-FPM, vhost Nginx, worker Supervisor, Crontab, Deployer — Completamente configurati dai dati archivio
Alla fine dell'import, Cipi stampa le nuove password SSH e DB. Salvale — vengono mostrate una sola volta.

Controlli di sicurezza prima dell'import

L'import esegue controlli preliminari prima di toccare qualsiasi cosa:

  • App già esistente — bloccato a meno che non venga passato --update
  • Conflitto di dominio — bloccato se un'altra app usa già lo stesso dominio
  • Versione PHP mancante — avviso (l'app viene saltata; installa prima la versione con cipi php install)

Modalità update (--update)

La funzionalità chiave per la sincronizzazione ripetuta (es. replica failover). Senza --update, l'import rifiuta di toccare app già esistenti. Con --update, aggiorna le app esistenti e crea quelle nuove.

bash
$ cipi sync import /tmp/archive.tar.gz.enc --update --passphrase="MyStr0ngP@ss"

Cosa fa l'update su un'app esistente

  • Sincronizzazione .env — Il .env dell'archivio sostituisce quello locale, ma DB_PASSWORD, DB_USERNAME, DB_DATABASE e DB_HOST vengono preservati dal server locale. Tutto il resto (APP_KEY, MAIL_*, REDIS_*, variabili personalizzate) proviene dalla sorgente.
  • Dati database — Se l'archivio ha un dump, elimina tutte le tabelle (con SET FOREIGN_KEY_CHECKS=0) e reimporta. Usa le credenziali root locali.
  • Storage — Se l'archivio ha storage, estrae sopra la directory esistente (nuovi file aggiunti, esistenti sovrascritti).
  • Migrazione versione PHP — Se la sorgente usa una versione PHP diversa, l'update migra automaticamente pool FPM, Supervisor, crontab, Deployer e .env.
  • Vhost Nginx, queue worker Supervisor, config Deployer — Rigenerati dai dati dell'archivio.
  • Deploy — Se viene passato --deploy, esegue dep deploy per scaricare l'ultimo codice.

Cosa l'update NON modifica

  • Password utente Linux
  • Chiavi deploy SSH (mantenute dal primo import)
  • Credenziali utente MariaDB (il target mantiene le proprie)
  • Certificati SSL (esegui cipi ssl install separatamente)

List (ispeziona archivio)

Visualizza il contenuto di un archivio senza importare nulla.

bash
$ cipi sync list /tmp/cipi-sync-aws01-20260306.tar.gz.enc --passphrase="MyStr0ngP@ss"

Cipi Sync Archive
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  Cipi           v5.0.2
  Exported       2026-03-06T15:00:00Z
  Source         aws01 (3.120.xx.xx)
  Database       true
  Storage        true
 
  Apps
  APP            DOMAIN                       PHP    DB       STORAGE
  shop           shop.example.com             8.4    yes      yes
  blog           blog.example.com             8.4    yes      yes
  api            api.example.com              8.5    yes      yes
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Push (export + trasferimento + import)

Combina export, trasferimento rsync e import remoto in un solo comando. Gira interamente dal server sorgente.

bash
# Interactive push — prompted for target IP and passphrase
$ cipi sync push --with-db --with-storage --import

# Non-interactive push (for cron and scripts)
$ cipi sync push --host=51.195.xx.xx --port=22 --with-db --with-storage --import --passphrase="MyStr0ngP@ss"

# Push specific apps only
$ cipi sync push shop blog --host=51.195.xx.xx --with-db --import --passphrase="MyStr0ngP@ss"

# Push without auto-import (transfer only — import manually on remote)
$ cipi sync push --host=51.195.xx.xx --with-db --passphrase="MyStr0ngP@ss"

Come funziona push

  1. Passo 1: Esegue cipi sync export in locale (crittografa con passphrase)
  2. Passo 2: Trasferisce l'archivio crittografato al target via rsync
  3. Passo 3: Se viene passato --import, esegue cipi sync import --update --yes sul target via SSH

Push aggiunge sempre --update e --yes quando chiama import sul remoto. Significa: la prima esecuzione crea tutte le app, le successive le aggiornano incrementalmente. È questo che rende push sicuro da eseguire ripetutamente via cron.

Setup SSH per push

Il server sorgente ha bisogno di accesso SSH al target come utente cipi. Usa il meccanismo trust integrato per autenticazione a chiave senza password tra server Cipi:

bash
# On the SOURCE server — display its sync public key
$ cipi sync pubkey

# On the TARGET server — add the source's public key to cipi's authorized_keys
$ cipi sync trust

Una volta trust stabilito, cipi sync push si connette automaticamente come utente cipi — nessun accesso root richiesto.

Scenari pratici

Scenario 1: migra tutte le app da AWS a OVH

Hai 20 app su AWS. Hai comprato un VPS OVH e ci hai installato Cipi.

bash
# On AWS (source server)
$ cipi sync push --host=51.195.xx.xx --with-db --with-storage --import

Sul target OVH: 20 utenti Linux, 20 database, 20 vhost Nginx, pool PHP-FPM, config Supervisor, crontab — tutto creato automaticamente. Dati DB importati, storage estratto, file .env copiati con le password DB di OVH, chiavi deploy SSH preservate (le stesse chiavi funzionano con GitHub). Dopo l'import, installa SSL e aggiorna il DNS:

bash
# On OVH (target server)
$ cipi ssl install shop
$ cipi ssl install blog
# ... then update DNS A records to OVH IP

Scenario 2: replica failover programmata (cron)

Ogni 6 ore, il Server 1 sincronizza tutte le app sul Server 2. Se il Server 1 cade, cambia DNS e vai live sul Server 2.

bash
# One-time setup on Server 1 — trust Server 2 using cipi sync trust
$ cipi sync pubkey  # copy this key, then run "cipi sync trust" on Server 2
$ echo "YourStr0ngPassphrase!" > /etc/cipi/.sync_passphrase
$ chmod 400 /etc/cipi/.sync_passphrase

# First push (manual, to verify)
$ cipi sync push --host=server2-ip --with-db --with-storage --import --passphrase="$(cat /etc/cipi/.sync_passphrase)"

# Add to crontab for automatic replication
$ crontab -e
cron
0 */6 * * * /usr/local/bin/cipi sync push --host=51.195.xx.xx --port=22 --with-db --with-storage --import --passphrase="$(cat /etc/cipi/.sync_passphrase)" >> /var/log/cipi/sync-replica.log 2>&1

La finestra di perdita dati equivale all'intervallo cron (6 ore in questo esempio). Quando il Server 1 cade: cambia DNS verso il Server 2, esegui cipi ssl install per ogni app e sei live.

Scenario 3: replica su più server

cron
# Stagger by 30 minutes so exports don't run simultaneously
0 */6 * * * /usr/local/bin/cipi sync push --host=51.195.xx.xx --with-db --with-storage --import --passphrase="$(cat /etc/cipi/.sync_passphrase)" >> /var/log/cipi/sync-ovh.log 2>&1
30 */6 * * * /usr/local/bin/cipi sync push --host=164.90.xx.xx --with-db --with-storage --import --passphrase="$(cat /etc/cipi/.sync_passphrase)" >> /var/log/cipi/sync-do.log 2>&1

Scenario 4: backup crittografato giornaliero (senza trasferimento)

cron
0 3 * * * /usr/local/bin/cipi sync export --with-db --with-storage --output=/root/backups/cipi-$(date +\%Y\%m\%d).tar.gz --passphrase="$(cat /etc/cipi/.sync_passphrase)" >> /var/log/cipi/export.log 2>&1

Crea ogni notte un archivio portatile crittografato. Ripristina su qualsiasi server Cipi in qualsiasi momento con cipi sync import.

Limitazioni

  • I certificati SSL non sono inclusi nell'archivio. Esegui cipi ssl install dopo l'import su un nuovo server.
  • La sync DB è sostituzione completa, non incrementale. Ogni update elimina tutte le tabelle e reimporta.
  • La sync storage è estrazione completa, non rsync incrementale. I file eliminati sulla sorgente restano sul target.
  • Le deploy key sono le stesse su sorgente e target — nessuna riconfigurazione GitHub/GitLab necessaria.

Vault e crittografia

Cipi crittografa tutti i file di configurazione a riposo con AES-256-CBC. Il sistema Vault fornisce crittografia e decrittografia trasparenti così che i dati sensibili — password database, token API, chiavi SSH, contenuti .env — non vengono mai salvati in chiaro su disco.

Architettura

Il sistema si basa su due livelli:

  • Vault — crittografia trasparente dei file di configurazione JSON su disco (server.json, apps.json, databases.json, backup.json, smtp.json, api.json)
  • Crittografia sync — crittografia basata su passphrase degli archivi export per trasferimento sicuro tra server

Come funziona Vault

Una chiave master viene generata durante l'installazione con openssl rand -base64 32 e salvata in /etc/cipi/.vault_key (chmod 400, solo root). Ogni file di config JSON viene crittografato su disco con openssl enc -aes-256-cbc -salt -pbkdf2. I file mantengono l'estensione .json — il contenuto è semplicemente un blob crittografato invece di JSON leggibile.

La funzione vault_read rileva automaticamente se un file è in chiaro o crittografato (compatibilità retroattiva), così i server esistenti migrano senza interruzioni durante l'update.

Funzioni Vault

bash
# Core functions in lib/vault.sh
vault_init          # Generate .vault_key if not present
vault_read <file>   # Decrypt and output JSON to stdout (auto-detect plain/encrypted)
vault_write <file>  # Read JSON from stdin, encrypt and write to disk
vault_seal <file>   # Encrypt an existing plaintext file in-place
vault_get <file> <jq_query>  # Shortcut: vault_read | jq

Proiezione pubblica

Cipi genera un file apps-public.json contenente solo campi non sensibili (dominio, alias, versione PHP, branch, repository, utente, timestamp di creazione, più i flag suspended e basic_auth). Il gruppo cipi-api legge questa proiezione in chiaro invece del file crittografato, mantenendo la chiave vault riservata a root.

Crittografia archivio sync

Quando esegui cipi sync export, le config vengono decrittografate dal vault in un'area di staging, poi l'intero archivio viene crittografato con la tua passphrase. All'import, l'archivio viene decrittografato con la passphrase e le config vengono ricrittografate con la chiave vault del server di destinazione.

Se la chiave vault viene persa, i file di configurazione diventano irrecuperabili. La chiave è protetta con chmod 400 e inclusa nei backup del server. Valuta di esportarla manualmente per maggiore sicurezza.

Notifiche email

Cipi può inviare alert email in caso di errori backup, fallimenti deploy, fallimenti job cron di sistema o eventi di autenticazione rilevanti per la sicurezza. La configurazione SMTP è salvata crittografata in /etc/cipi/smtp.json e inclusa negli export sync.

Comandi

bash
$ cipi smtp configure      # interactive setup (Gmail, SendGrid, Mailgun, custom)
$ cipi smtp status          # display current notification settings
$ cipi smtp test            # send a verification email
$ cipi smtp enable          # enable notifications
$ cipi smtp disable         # disable without losing settings
$ cipi smtp delete          # remove SMTP configuration entirely

Trigger di notifica granulari

Dalla v4.6.3, puoi controllare quali eventi inviano email quando SMTP è configurato. Tutti i trigger sono attivi di default; gli eventi vengono sempre loggati in /var/log/cipi/events.log comunque.

bash
$ cipi notifications list              # all triggers grouped by category
$ cipi notifications enable <trigger>   # turn one trigger on
$ cipi notifications disable <trigger>  # turn one trigger off
$ cipi notifications enable-all          # re-enable everything
$ cipi notifications disable-all         # mute all email alerts
$ cipi notifications reset               # restore defaults (all on)

Config: /etc/cipi/notifications.json. Esegui cipi notifications list sul server per lo stato on/off live. ID trigger per cipi notifications enable|disable <trigger>:

ID trigger Categoria Evento
app_createAppApp creata
app_editAppApp modificata
app_deleteAppApp eliminata
app_suspendAppApp sospesa
app_unsuspendAppApp riattivata
app_ssh_password_resetAppReset password SSH app
app_db_password_resetAppReset password DB app
alias_addDominiAlias aggiunto
alias_removeDominiAlias rimosso
auth_createAuthauth.json Composer creato
auth_editAuthauth.json Composer modificato
auth_deleteAuthauth.json Composer eliminato
basicauth_enableBasic authHTTP basic auth attivato
basicauth_disableBasic authHTTP basic auth disattivato
deploy_successDeployDeploy riuscito
deploy_failDeployDeploy fallito
deploy_rollbackDeployRollback deploy
ssl_installSSLCertificato SSL installato
ssl_renewSSLCertificati SSL rinnovati
php_installPHPVersione PHP installata
php_switchPHPPHP di sistema cambiato
php_removePHPVersione PHP rimossa
php_upgradePHPPatch di sicurezza PHP applicate
db_createDatabaseDatabase creato
db_deleteDatabaseDatabase eliminato
worker_addWorkerWorker aggiunto
worker_removeWorkerWorker rimosso
ssh_key_addChiavi SSHChiave SSH aggiunta
ssh_key_renameChiavi SSHChiave SSH rinominata
ssh_key_removeChiavi SSHChiave SSH rimossa
ssh_loginSicurezzaLogin SSH (utenti cipi/root/sudo)
sudoSicurezzaElevazione sudo
suSicurezzasu a root da cipi
backup_failBackupBackup fallito
cron_failCronJob cron fallito
reset_root_passwordResetReset password SSH root
reset_db_passwordResetReset password root MariaDB
reset_valkey_passwordResetReset password Valkey
api_configureAPIPanel API configurata
api_updateAPIPanel API aggiornata
api_upgradeAPIPanel API aggiornata (upgrade)
api_sslAPISSL Panel API installato
git_configureGitToken provider Git configurato
sync_exportSyncApp esportate
sync_importSyncApp importate
sync_pushSyncApp inviate al remoto
service_restartServiziServizio riavviato
service_startServiziServizio avviato
service_stopServiziServizio fermato

Alert automatici

Una volta configurato, Cipi invia notifiche email per:

  • Errori backup (fallimenti upload S3, errori dump)
  • Fallimenti deploy (errori Deployer, trigger rollback)
  • Fallimenti job cron di sistema (via wrapper cipi-cron-notify)
  • Eventi ciclo di vita app — notifica quando un'app viene creata, modificata o eliminata, inclusi hostname server, nome app, dominio e versione PHP
  • Elevazione sudo e su — notifica quando un utente eleva con successo via sudo o su, inclusi chi ha eseguito, utente target (per su), chiave SSH, IP client e TTY
  • Login SSH privilegiato — notifica quando root o un sudoer accede via SSH, inclusi IP sorgente, fingerprint chiave SSH e commento chiave
  • Cambi chiavi SSH — notifica quando una chiave SSH viene aggiunta, rimossa o rinominata sull'utente cipi, inclusi hostname, IP, fingerprint, commento chiave, timestamp e conteggio chiavi rimanenti. Gli alert di rename includono anche il vecchio e il nuovo nome chiave.

Ogni notifica email include un footer con l'IP client (SSH_CLIENT) e il nome della chiave SSH usata per autenticarsi, quando applicabile. Il nome chiave viene risolto via SSH_USER_AUTH con fallback su auth.log quando necessario.

Notifiche auth di sicurezza

Cipi integra notifiche di autenticazione basate su PAM via pam_exec.so con ExposeAuthInfo attivo. Quando SMTP è configurato, il sistema invia automaticamente alert email su questi eventi rilevanti per la sicurezza:

  • Elevazione sudo e su — attivata quando un utente esegue con successo sudo o su. La notifica include username, utente target (per su), TTY, chiave SSH, IP client e timestamp.
  • Login SSH privilegiato — attivato quando root o un utente del gruppo sudo accede via SSH. La notifica include username, indirizzo IP sorgente, fingerprint chiave SSH e commento chiave (risolto da /var/log/auth.log tramite matching fingerprint su authorized_keys).
  • Cambi chiavi SSH — attivati quando una chiave SSH viene aggiunta, rimossa o rinominata sull'utente cipi via cipi ssh add, cipi ssh remove o cipi ssh rename. La notifica include hostname, IP server, fingerprint chiave, commento chiave, timestamp e conteggio chiavi rimanenti. Gli alert di rename includono anche il vecchio e il nuovo nome chiave.
  • Eventi ciclo di vita app — attivati quando un'app viene creata, modificata o eliminata. La notifica include hostname server, nome app, dominio e versione PHP.

Le notifiche girano in background in modo asincrono così non ritardano mai login o esecuzione comandi. Se SMTP non è configurato, gli hook falliscono silenziosamente senza impatto sul sistema.

Log eventi di sicurezza

Indipendentemente dalla configurazione SMTP, tutti gli eventi di notifica (cambi chiavi SSH, ciclo di vita app, reset password, sudo/su/login SSH, fallimenti cron) vengono sempre loggati in /var/log/cipi/events.log in formato compatto su una riga. Il log ruota giornalmente con retention di 1 anno via logrotate.

Wrapper cron

L'utility cipi-cron-notify avvolge i job cron di sistema e invia una notifica se il job esce con codice non-zero. Utile per monitorare task programmati critici.

Retention log (GDPR)

Cipi applica policy automatiche di rotazione log progettate per soddisfare GDPR e requisiti generali di protezione dati. I log vengono ruotati ed eliminati automaticamente — nessuna pulizia manuale necessaria.

Categoria Log Retention
Applicativi Laravel, PHP-FPM, worker, deploy, sistema 12 mesi
Sicurezza Fail2ban, firewall UFW, autenticazione, eventi Cipi (events.log) 12 mesi
HTTP / navigazione Log accesso ed errore Nginx 90 giorni
I log HTTP/navigazione (log accesso Nginx) contengono indirizzi IP, che sono dati personali ai sensi del GDPR. La retention di 90 giorni garantisce conformità al principio di minimizzazione dei dati preservando abbastanza storico per debug e analisi di sicurezza. Log applicativi e di sicurezza vengono conservati per 12 mesi per supportare audit trail e indagini su incidenti.

Valkey

Valkey è lo store in-memory che Cipi installa come parte dello stack predefinito. Dalla v4.5.6 Cipi provisiona Valkey al posto di redis-server. Eccelle in cache, session storage, message queue, broadcast in tempo reale e rate limiting.

Perché Valkey invece di Redis

Valkey è il fork veramente open source, con licenza BSD di Redis, curato dalla Linux Foundation. È nato nel 2024 dopo che Redis Inc. ha relicenziato Redis dalla permissiva licenza BSD alle source-available SSPL / RSALv2 — un cambiamento che non soddisfa più la definizione di open source. Supportato da AWS, Google Cloud, Oracle e una grande community, Valkey continua la stessa codebase collaudata sul campo sotto una licenza che resta gratuita per sempre. Lo rende perfetto per la filosofia MIT e nessun vendor lock-in di Cipi, e viene fornito nativamente nel repository Universe di Ubuntu 24.04 (pacchetti valkey-server + valkey-tools) — nessun PPA di terze parti da fidarsi.

Altrettanto importante, Valkey è un drop-in replacement: parla lo stesso protocollo RESP sulla stessa porta (127.0.0.1:6379), rispetta le stesse direttive requirepass / bind e legge lo stesso formato dati RDB/AOF. Le tue app non richiedono alcuna modifica — l'estensione phpredis e i valori REDIS_* nel .env continuano a funzionare esattamente come prima.

Come Cipi lo implementa

  • Installazionesetup.sh installa e configura Valkey (/etc/valkey/valkey.conf, servizio valkey-server), legato solo a localhost e protetto con password.
  • Gestione serviziocipi service … gestisce valkey-server (i nomi redis-server, redis e valkey sono ancora accettati come alias). Viene aggiunto alla blacklist unattended-upgrades, così Cipi lo gestisce invece di un upgrade automatico.
  • Credenziali — salvate sotto valkey_user / valkey_password in /etc/cipi/server.json (le chiavi legacy redis_* vengono ancora lette come fallback). Host: 127.0.0.1, Porta: 6379.
  • Reset passwordcipi reset valkey-password rigenera la password e riavvia il servizio (cipi reset redis-password resta come alias).

Migrazione da Redis (4.5.6 / 4.5.7)

I server esistenti passano a Valkey automaticamente con cipi self-update — nessuna modifica al .env dell'app richiesta. La migrazione riusa la password Redis corrente (recuperata da server.json o /etc/redis/redis.conf), forza un SAVE RDB e snapshot di dump.rdb/AOF, elimina redis-server, installa valkey-server + valkey-tools sulla stessa porta con lo stesso requirepass / bind, ripristina il dataset e riscrive server.json (redis_*valkey_*) e la blacklist unattended-upgrades — così cache, sessioni e job in queue sopravvivono al passaggio.

La v4.5.7 corregge il nome pacchetto in valkey-server (il pacchetto daemon di Ubuntu 24.04; la 4.5.6 usava inizialmente valkey) e rende la migrazione completamente self-contained e sicura. Abilita automaticamente il componente APT universe quando il pacchetto non viene trovato, esegue un health check post-avvio (PINGPONG con la password) e fa rollback a redis-server — ripristinando sia la password salvata che il dataset — se Valkey non può essere installato o non parte in salute. Lo snapshot del dataset viene mantenuto finché il passaggio non è verificato, poi pulito. La migrazione è idempotente: i server già su Valkey la saltano.

Integrazione Laravel

Aggiungi queste variabili al tuo .env via cipi app env myapp. I nomi variabile restano REDIS_* — è ciò che si aspettano phpredis e il driver redis di Laravel, e Valkey risponde sullo stesso socket:

env
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=your-password-from-server-json
REDIS_PORT=6379

Poi imposta i driver per ogni caso d'uso:

  • CacheCACHE_STORE=redis
  • SessionSESSION_DRIVER=redis
  • QueueQUEUE_CONNECTION=redis (poi cipi worker restart myapp)
  • BroadcastingBROADCAST_CONNECTION=redis

Installa l'estensione PHP phpredis per le migliori performance, oppure usa predis/predis come fallback pure-PHP. Entrambi parlano con Valkey in modo trasparente.

Self-update

Cipi può aggiornare se stesso da GitHub senza toccare app, database o configurazioni.

bash
$ cipi self-update --check   # check for a new version
$ cipi self-update           # update to latest

Processo di update

  1. Scarica l'ultima versione da GitHub
  2. Fa backup dell'installazione corrente in /opt/cipi.bak.YYYYMMDDHHMMSS/
  3. Sostituisce script CLI e lib
  4. Esegue eventuali script di migrazione in ordine (es. nuove direttive Nginx, nuovi pacchetti)
  5. Aggiorna il file versione

Gli script di migrazione vivono in lib/migrations/ e sono nominati per versione (es. 4.1.0.sh). Aggiornando dalla v4.0.0 alla v4.2.0, Cipi esegue automaticamente 4.1.0.sh e 4.2.0.sh in ordine. Le tue app, database e configurazioni non vengono mai toccati.

Ad esempio, la migrazione 4.5.5 applica retroattivamente alle app esistenti il nuovo alias shell ll='ls -al': aggiunge l'alias al ~/.bashrc di ogni app una volta (solo se mancante, preservando ownership), così le app create prima della 4.5.5 lo ottengono al prossimo cipi self-update.

Cron di manutenzione automatici

Cipi programma diversi job a livello root durante l'installazione. I crontab a livello app (scheduler, trigger deploy) sono separati — vedi Crontab utente.

Schedule Job
Giornaliero 02:00 cipi backup run — backup S3 per tutte le app
Giornaliero 03:00 cipi backup prune --weeks=4
Domenica 03:30 cipi php upgrade — patch di sicurezza per tutte le versioni PHP installate (avvolto da cipi-cron-notify)
Giornaliero 03:50 cipi self-update (avvolto da cipi-cron-notify)
Domenica 04:10 cipi ssl renew
Giornaliero 04:15 Manutenzione Panel API (cipi-api-maintain — prune job/metriche)
Giornaliero 04:30 cipi api update — soft-update Laravel panel + cipi/api

Dominio wildcard

Cipi non supporta i domini wildcard (*.myapp.com) nativamente. Il blocco è duplice e architetturale — non un dettaglio di configurazione.

Perché i wildcard non sono supportati

1 — La validazione dominio rifiuta *
Ogni dominio passato a cipi alias add (e cipi app create) viene validato con una regex rigorosa che richiede che la stringa inizi con [a-zA-Z0-9]. L'asterisco fallisce subito, prima che Nginx o certbot vengano toccati.

2 — Certbot usa la challenge HTTP-01, che non può emettere cert wildcard
cipi ssl install chiama certbot --nginx, che si basa sulla challenge HTTP-01 (o TLS-ALPN-01) — posizionando un file di verifica su disco e servendolo sulla porta 80. Let's Encrypt emette certificati wildcard solo via la challenge DNS-01, che richiede accesso programmatico all'API del tuo provider DNS. Cipi non si integra con nessun provider DNS, quindi anche se la validazione fosse bypassata, certbot rifiuterebbe di emettere il cert wildcard.

Alternativa consigliata — certificato Multi-SAN

Se i tuoi subdomain sono fissi e enumerabili (es. api, admin, www, staging), l'approccio corretto è aggiungere ciascuno come alias esplicito e lasciare che Cipi emetta un singolo certificato SAN che li copre tutti:

bash
$ cipi alias add myapp api.myapp.com
$ cipi alias add myapp admin.myapp.com
$ cipi alias add myapp www.myapp.com
$ cipi ssl install myapp   # single cert, SAN covers all domains

Il flag --expand di Certbot (usato internamente da Cipi) aggiunge i nuovi SAN al certificato esistente senza emetterne uno nuovo. L'elenco SAN non ha limiti significativi per l'uso tipico.

Certificato wildcard manuale (fuori da Cipi)

Se ti servono subdomain dinamici (es. <tenant>.saas.com), puoi ottenere un certificato wildcard manualmente usando un plugin DNS per certbot e posizionarlo sul server. Cipi non lo gestirà, rinnoverà o traccerà — ne possiedi tu l'intero ciclo di vita.

bash
# example with the Cloudflare DNS plugin
$ pip install certbot-dns-cloudflare
$ certbot certonly --dns-cloudflare \
    --dns-cloudflare-credentials /root/.cloudflare.ini \
    -d "*.myapp.com" -d "myapp.com"

Dopo aver ottenuto il certificato, modifica direttamente il vhost Nginx dell'app (/etc/nginx/sites-available/myapp) per referenziare i percorsi del cert wildcard e aggiungi server_name *.myapp.com myapp.com;. Poi ricarica Nginx:

bash
$ nginx -t && systemctl reload nginx
Eseguire cipi ssl install myapp dopo un setup wildcard manuale sovrascriverà le tue direttive SSL Nginx personalizzate con un certificato Let's Encrypt HTTP-01. Se gestisci un cert wildcard manualmente, evita di eseguire cipi ssl install su quell'app.

Modifica config Nginx

Per personalizzare il vhost Nginx di un'app, modifica direttamente la config del sito. Dopo le modifiche, testa e ricarica Nginx.

bash
$ sudo nano /etc/nginx/sites-available/<app>
$ sudo nginx -t && sudo systemctl reload nginx

Disinstalla Cipi

Cipi non fornisce un comando di disinstallazione integrato. Se devi rimuovere completamente Cipi da un server, segui i passi sotto in ordine. Questa procedura rimuove ogni componente che Cipi installa — utenti, servizi, pacchetti, config e dati.

Operazione distruttiva e irreversibile. Tutte le app, database, certificati SSL e configurazioni server gestite da Cipi verranno eliminati definitivamente. Fai backup di tutto ciò che ti serve prima di procedere. Dopo la disinstallazione, l'approccio consigliato è riprovisionare il server da zero.

1 — Ferma e rimuovi tutte le app

Per ogni app gestita da Cipi, rimuovi utente di sistema, home directory, database, vhost Nginx, pool PHP-FPM e config Supervisor.

bash
# List all app users (members of cipi-apps group)
$ grep cipi-apps /etc/group

# For EACH app user, remove everything
$ supervisorctl stop <app_user>:*
$ rm -f /etc/supervisor/conf.d/<app_user>.conf
$ rm -f /etc/nginx/sites-enabled/<app_user>
$ rm -f /etc/nginx/sites-available/<app_user>
$ rm -f /etc/php/*/fpm/pool.d/<app_user>.conf
$ rm -f /etc/sudoers.d/cipi-<app_user>
$ mysql -e "DROP DATABASE IF EXISTS <app_user>; DROP USER IF EXISTS '<app_user>'@'localhost'; DROP USER IF EXISTS '<app_user>'@'127.0.0.1';"
$ userdel -r <app_user>

2 — Rimuovi utente e gruppi Cipi

bash
$ userdel -r cipi
$ groupdel cipi-ssh 2>/dev/null
$ groupdel cipi-apps 2>/dev/null

3 — Rimuovi binari, librerie e dati Cipi

bash
$ rm -f /usr/local/bin/cipi
$ rm -f /usr/local/bin/cipi-worker
$ rm -f /usr/local/bin/cipi-cron-notify
$ rm -f /usr/local/bin/cipi-auth-notify
$ rm -rf /opt/cipi
$ rm -rf /etc/cipi
$ rm -rf /var/log/cipi

4 — Rimuovi Cipi API (se installata)

bash
$ systemctl stop cipi-queue 2>/dev/null
$ systemctl disable cipi-queue 2>/dev/null
$ rm -f /etc/systemd/system/cipi-queue.service
$ systemctl daemon-reload

5 — Rimuovi job cron Cipi

bash
# Edit root crontab and remove all Cipi entries
$ crontab -e
# Remove lines referencing: cipi self-update, certbot renewal, cache cleanup, RAM drop

6 — Rimuovi file di configurazione Cipi

bash
# Sudoers
$ rm -f /etc/sudoers.d/cipi-sudo
$ rm -f /etc/sudoers.d/cipi-api

# Logrotate
$ rm -f /etc/logrotate.d/cipi-app-logs
$ rm -f /etc/logrotate.d/cipi-http-logs
$ rm -f /etc/logrotate.d/cipi-security-logs

# Unattended upgrades
$ rm -f /etc/apt/apt.conf.d/50cipi-unattended-upgrades
$ rm -f /etc/apt/apt.conf.d/20cipi-auto-upgrades

# System profile and MOTD
$ rm -f /etc/profile.d/cipi-env.sh
$ echo "" > /etc/motd

# MariaDB custom config
$ rm -f /etc/mysql/mariadb.conf.d/99-cipi.cnf

# PHP custom config (all versions)
$ rm -f /etc/php/*/fpm/conf.d/99-cipi.ini

# Nginx default page
$ rm -f /etc/nginx/sites-available/default
$ rm -f /etc/nginx/sites-enabled/default

7 — Elimina pacchetti installati

Rimuovi tutti i pacchetti installati da Cipi. Salta qualsiasi pacchetto che vuoi tenere per altri scopi.

bash
$ systemctl stop nginx mariadb valkey-server fail2ban supervisor
$ systemctl stop php*-fpm

$ apt purge -y nginx* mariadb-server mariadb-client valkey-server \
    fail2ban supervisor certbot python3-certbot-nginx \
    php8.4* php8.5* nodejs

$ apt autoremove -y
$ apt autoclean

8 — Rimuovi repository APT

bash
$ add-apt-repository --remove ppa:ondrej/php -y
$ rm -f /etc/apt/sources.list.d/mariadb.list
$ rm -f /etc/apt/sources.list.d/nodesource.list
$ rm -f /etc/apt/keyrings/mariadb-keyring.pgp
$ apt update

9 — Rimuovi Composer e Deployer

bash
$ rm -f /usr/local/bin/composer
$ rm -f /usr/local/bin/dep

10 — Rimuovi file swap

bash
$ swapoff /var/swap.1
$ rm -f /var/swap.1
# Remove the swap entry from /etc/fstab
$ sed -i '/swap\.1/d' /etc/fstab

11 — Ripristina default SSH e PAM

Cipi hardening SSH (disabilita login root e auth password) e aggiunge hook PAM. Se devi ripristinare i default:

bash
# Restore sshd_config to allow password auth (if needed)
$ sed -i 's/^PasswordAuthentication no/PasswordAuthentication yes/' /etc/ssh/sshd_config
$ sed -i 's/^PermitRootLogin no/PermitRootLogin yes/' /etc/ssh/sshd_config

# Remove Cipi PAM hooks
$ sed -i '/cipi-auth-notify/d' /etc/pam.d/sshd
$ sed -i '/cipi-auth-notify/d' /etc/pam.d/sudo

# Restore sysctl
$ sed -i '/vm.swappiness/d' /etc/sysctl.conf
$ sysctl -p

$ systemctl restart sshd

12 — Reset firewall

bash
$ ufw disable
$ ufw reset
Dopo una disinstallazione completa, il server sarà privato dello stack web e dell'hardening di sicurezza. L'approccio consigliato è riprovisionare il server da un'immagine OS pulita invece di provare a riconfigurare la stessa macchina. Usa questa guida principalmente per pulire prima di un nuovo inizio, o per rimuovere selettivamente componenti Cipi tenendo i pacchetti che ti servono ancora.