Deploy di WordPress con Cipi: app custom e auto-deploy da GitHub
Di Andrea Pollastri · Ultimo aggiornamento: · lettura gratuita, nessun paywall
Cipi è Laravel-first, ma ospita anche WordPress come app custom: utente Linux isolato, pool PHP-FPM, vhost Nginx, pull Git in htdocs. Questa guida va da un VPS Ubuntu vuoto a un sito che si deploya da solo a ogni push su main.
Perché un'app custom (non Laravel)
Cipi supporta due tipi di app. Il default è Laravel: utente di sistema proprio, PHP-FPM o Octane, MariaDB, .env, worker Supervisor, crontab e release Deployer zero-downtime sotto current/shared. WordPress non è niente di tutto questo.
Un'app custom (cipi app create --custom) è la forma giusta:
- Deploy classico in
htdocs— niente swap di symlinkcurrent/shared.cipi deploy blogfa pull del repo in/home/blog/htdocs. - Nginx è già pronto per WordPress:
index index.html index.phpetry_files $uri $uri/ /index.php?$args. - Git è opzionale. Salta il repository per upload solo SFTP; collegalo dopo con
cipi app edit blog --repository=…. - Niente database, niente
.env, niente cron, niente code finché non li aggiungi. WordPress ha bisogno di un database — lo crei nello step successivo.
I deploy custom non sono zero-downtime. Tieni i diff di tema e plugin piccoli, fai backup del database prima delle release rischiose e lascia che GitHub Actions sia il gate così un check rosso non arriva mai in produzione. Per i pattern zero-downtime Laravel, usa la guida CI/CD per Laravel.
Come strutturare il repo WordPress
Tratta Git come fonte di verità per il codice, non per i segreti o i media. Un repo che sopravvive all'auto-deploy è fatto così:
wordpress-site/
.gitignore
.github/workflows/deploy.yml
wp-admin/
wp-includes/
wp-content/themes/your-theme/
wp-content/plugins/your-plugin/
wp-config-sample.php
index.php
…
Metti questo in .gitignore così un pull non sovrascrive mai lo stato del sito live:
wp-config.php
wp-content/uploads/
wp-content/cache/
wp-content/upgrade/
wp-content/backup-db/
.htaccess
Siccome le app custom fanno pull in htdocs invece di scambiare una directory di release, i file untracked restano sul disco. È così che upload e wp-config.php sopravvivono a ogni deploy.
- Core in Git è il workflow più semplice da agenzia: tema, plugin e WordPress stesso versionati insieme.
- Composer / Bedrock funziona uguale — imposta
--docroot=web(opublic) se il front controller non è alla root del repo. - Non committare i segreti di produzione. Genera i salt sul server; non pushare mai un
wp-config.phplive.
Crea l'app custom
Cipi deve già essere installato su un VPS Ubuntu fresco:
Entra via SSH come cipi, poi sudo -s. Crea l'app WordPress in modo non interattivo (PHP 8.3 è un match sicuro per WordPress attuale; lo cambi dopo con cipi app edit):
$ cipi app create --custom --user=blog \
--domain=blog.example.com \
--repository=git@github.com:you/wordpress-site.git \
--branch=main \
--php=8.3
Questo provvede:
- Utente Linux
bloge home/home/blog - Pool PHP-FPM su 8.3 e un vhost Nginx per
blog.example.com - Deploy key SSH per il repository
- Config Deployer che fa pull in
/home/blog/htdocs
Se hai già salvato un Personal Access Token GitHub, Cipi aggiunge anche la deploy key e un webhook sul provider in automatico:
$ cipi git github-token ghp_xxxxxxxxxxxxxxxxxxxx
$ cipi git status
I token fine-grained servono Administration e Webhooks impostati su Read and write sul repo target; i token classici servono lo scope repo. I dettagli sono nella documentazione del Git auto-setup.
Solo SFTP (niente Git per ora) — ometti il repository e carica i file in ~/htdocs come utente dell'app:
$ cipi app create --custom --user=blog --domain=blog.example.com --php=8.3
Database, DNS e SSL
Le app custom non ricevono un database. Crealo dopo che l'app esiste — MariaDB è il default e quello che WordPress si aspetta:
$ cipi db create --name=blog
Cipi stampa nome database, utente, password e un URL mariadb+ssh:// per TablePlus o DBeaver. Copia quei valori; vanno in wp-config.php sul server, non in Git.
Punta i record DNS A di blog.example.com e www.blog.example.com al VPS, poi:
$ cipi alias add blog www.blog.example.com
$ cipi www add blog
$ cipi ssl install blog
cipi ssl install emette un certificato Let’s Encrypt che copre tutti gli alias (SAN) e attiva il redirect HTTPS. cipi www tiene apex e www canonici. Vedi SSL e redirect www.
Primo deploy e wp-config.php
Fai pull del repository una volta, poi scrivi la config come utente dell'app così la ownership dei file resta corretta:
$ cipi deploy blog
$ su - blog
blog@server:~$ cd ~/htdocs
blog@server:~/htdocs$ cp wp-config-sample.php wp-config.php
blog@server:~/htdocs$ nano wp-config.php
Valori minimi di produzione (usa le credenziali di cipi db create):
define('DB_NAME', 'blog');
define('DB_USER', 'blog');
define('DB_PASSWORD', 'the-password-cipi-printed');
define('DB_HOST', '127.0.0.1');
define('DB_CHARSET', 'utf8mb4');
define('DB_COLLATE', '');
define('DISALLOW_FILE_EDIT', true);
define('DISABLE_WP_CRON', true);
define('WP_MEMORY_LIMIT', '256M');
Genera salt nuovi da api.wordpress.org/secret-key e incollali al posto dei placeholder. Apri https://blog.example.com e completa l'installer WordPress nel browser.
wp-config.php è untracked. Un cipi deploy successivo non lo cancella. Se ricloni tutta la home, ricrea il file con le stesse credenziali database (cipi db password blog se le hai perse).
Pipeline GitHub Actions (consigliata)
Il webhook Cipi Agent (https://your-app.com/cipi/webhook) è una route dentro un'app Laravel. Su WordPress non esiste. Per l'auto-deploy, fai in modo che GitHub entri via SSH sul server ed esegua cipi deploy — lo stesso pipeline SSH deploy che Cipi documenta per le release Laravel con gate.
Scegli un solo trigger. Se il Git auto-setup ha già creato un webhook sul provider, disabilitalo (o non crearlo mai) prima di aggiungere Actions. Due deploy sulla stessa push litigano sul lock file.
1. Chiave SSH dedicata per la CI
Genera una chiave ed25519 sul portatile. Aggiungi la chiave pubblica sul server; salva quella privata come secret GitHub. Non riusare le deploy key Git né la tua chiave SSH personale.
# sul portatile
$ ssh-keygen -t ed25519 -C "ci-deploy-blog" -f ~/.ssh/ci_deploy_blog -N ""
$ ssh-copy-id -i ~/.ssh/ci_deploy_blog.pub cipi@your-server-ip
$ cat ~/.ssh/ci_deploy_blog
Nel repository GitHub: Settings → Secrets and variables → Actions. Crea:
SERVER_HOST— IP o hostname del VPSSERVER_SSH_KEY— contenuto intero della chiave privata
2. File del workflow
Mettilo in .github/workflows/deploy.yml:
name: Deploy WordPress
on:
push:
branches: [main]
workflow_dispatch:
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Guard tracked secrets
run: |
if git ls-files --error-unmatch wp-config.php >/dev/null 2>&1; then
echo "wp-config.php must not be committed"
exit 1
fi
- name: PHP syntax
uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
coverage: none
- name: Lint theme and plugins
run: |
find wp-content/themes wp-content/plugins -name '*.php' -print0 \
| xargs -0 -n1 php -l
deploy:
runs-on: ubuntu-latest
needs: check
steps:
- name: Deploy via Cipi
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.SERVER_HOST }}
username: cipi
key: ${{ secrets.SERVER_SSH_KEY }}
script: sudo cipi deploy blog
Cosa ci guadagni:
- Un quality gate — un
wp-config.phpcommittato o un errore di parse PHP non arrivano mai sul VPS. - Un comando sul server — Cipi fa pull di
maininhtdocscon il binario PHP dell'app. - Replay manuale —
workflow_dispatchrideploya lo stesso commit senza un'altra push.
Proteggi main: niente push dirette, status check obbligatori, branch di breve vita. Le stesse abitudini trunk-based della guida CI/CD Laravel, senza fingere che WordPress abbia Pest e Pint.
Osserva il deploy dal server:
$ cipi app logs blog --type=deploy
3. Opzionale: backup prima della release
I cambi di schema WordPress sono spesso irreversibili. Snapshot di MariaDB prima, poi deploy:
script: |
sudo cipi db backup blog
sudo cipi deploy blog
Ripristina con cipi db restore blog backup.sql.gz se una release va male. Le app custom non hanno un symlink di release a cui tornare — senza dump del database non c'è undo. Vedi cipi db.
Percorso più semplice: Git auto-setup
Se non ti servono gate CI (sito da solo, commit fidati), salta Actions e lascia che Cipi colleghi GitHub per te:
$ cipi git github-token ghp_xxxxxxxxxxxxxxxxxxxx
$ cipi app create --custom --user=blog --domain=blog.example.com \
--repository=git@github.com:you/wordpress-site.git --branch=main --php=8.3
Su app create, Cipi aggiunge la deploy key SSH e un webhook sul repository. Il riepilogo mostra auto-configured ✓. Una push su main esegue la stessa pipeline cipi deploy senza un file YAML.
Se hai creato l'app prima di salvare un token, stampa i valori e aggiungili a mano:
$ cipi deploy blog --key # Settings → Deploy keys
$ cipi deploy blog --webhook # Settings → Webhooks
Non puntare un sito WordPress all'URL Laravel Agent /cipi/webhook. Quella route esiste solo dopo composer require cipi/agent dentro un'app Laravel. WordPress usa il webhook del provider che Cipi stampa, oppure GitHub Actions via SSH — non entrambi.
Cron, backup e operazioni di tutti i giorni
Sostituisci WP-Cron con il cron di sistema
Le app custom non ricevono un crontab. Con DISABLE_WP_CRON impostato, chiama wp-cron.php dal crontab dell'utente dell'app:
$ su - blog
blog@server:~$ crontab -e
*/5 * * * * /usr/bin/php8.3 /home/blog/htdocs/wp-cron.php >/dev/null 2>&1
Allinea il binario PHP alla versione passata ad app create. Dopo cipi app edit blog --php=8.4, aggiorna il path nel crontab.
Backup
cipi db backup blog— dump MariaDB (schedulalo di notte nel crontab di root o chiamalo da Actions).- Tieni
wp-content/uploadssul server (e nei backup off-site). Non è in Git. - Backup off-site S3-compatible:
cipi backup.
Comandi utili
| Comando | Cosa fa |
|---|---|
cipi deploy blog |
Pull di main in htdocs |
cipi app logs blog --type=deploy |
Storico deploy |
cipi app logs blog --type=php |
Errori PHP-FPM |
cipi app edit blog --php=8.4 |
Hot-swap PHP |
cipi app edit blog --branch=staging |
Cambia il branch di deploy |
cipi db backup blog |
Dump MariaDB |
cipi ssl install blog |
Rinnova Let’s Encrypt (SAN) |
Mettilo in pratica con Cipi
Cipi è la CLI di deploy gratuita e open source usata in questa guida: un comando trasforma un VPS Ubuntu fresco in un server hardened per Laravel e per app PHP custom come WordPress — Nginx, PHP-FPM, MariaDB, SSL e deploy Git inclusi.
Domande frequenti
Devo creare WordPress come app Laravel o come app custom in Cipi?
Sempre come app custom. Le app Laravel si aspettano artisan, Composer, un file .env e il layout releases/current. WordPress è un sito PHP classico: cipi app create --custom deploya in htdocs con Nginx già impostato per index.php.
Cipi crea un database per un'app custom WordPress?
No. Le app custom arrivano senza database, .env, cron o queue worker. Dopo aver creato l'app, esegui cipi db create --name=<app> (MariaDB di default) e metti quelle credenziali in wp-config.php sul server.
Un deploy Git cancella gli upload di WordPress?
No, se sono untracked. Le app custom fanno pull in htdocs invece di scambiare un symlink releases. Tieni wp-content/uploads e wp-config.php fuori da Git così media e segreti sopravvivono a ogni cipi deploy.
Posso usare il webhook Cipi Agent per WordPress?
No. La route /cipi/webhook vive dentro un'app Laravel tramite il pacchetto cipi/agent. Per WordPress, lancia i deploy da GitHub Actions via SSH con sudo cipi deploy, oppure usa il Git auto-setup di Cipi (deploy key più webhook del provider) se non ti servono gate CI.
Il deploy di WordPress su Cipi è zero-downtime?
No. Le app custom usano il deploy classico in htdocs — non c'è swap del symlink current/shared. Tieni i diff di tema e plugin piccoli, fai un cipi db backup prima delle release rischiose e usa GitHub Actions così un check rosso non arriva mai sul server.