+39 3662317539/+34 620899163
info@simonecosci.com

Prawner: un comando per aprire (e chiudere) un sito WordPress su un VPS condiviso

Sviluppo Siti Web a Tenerife

Prawner: un comando per aprire (e chiudere) un sito WordPress su un VPS condiviso

Il VPS su cui gira anche questo sito ospita più siti WordPress, non solo il mio. Aprirne
uno nuovo a mano — utente di sistema, database, WordPress via WP-CLI, vhost nginx,
certificato — è una sequenza di una decina di comandi che vanno bene solo se li rifai
sempre nello stesso ordine, con gli stessi permessi, senza saltarne uno. La prima volta
va bene farlo a mano. La quinta, è il momento sbagliato per scoprire che nel vhost del
terzo sito manca il blocco che nega l’esecuzione PHP dentro uploads/.

Ho scritto Prawner per questo, ed è open source,
MIT.

Il problema: convenzioni che si sfaldano

Con un solo sito, “come ho fatto l’ultima volta” è una memoria affidabile. Con più siti
sullo stesso VPS, ogni provisioning manuale è un’occasione per introdurre una piccola
incoerenza: un permesso diverso, un vhost senza uno dei blocchi di hardening, una
password del database finita per sbaglio in un file dentro la docroot invece che fuori.
Nessuno di questi errori si nota subito. Si notano quando è già un problema.

La soluzione: quattro comandi, sempre le stesse convenzioni

wp-site.sh (il binario che Prawner installa) fa quattro cose:

wp-site.sh list                                              # tabella di tutti i siti
wp-site.sh create example.com --admin-email admin@esempio.it # provisioning completo
wp-site.sh cert example.com                                  # certificato TLS
wp-site.sh remove example.com                                # rimozione con backup

create fa, nell’ordine: utente di sistema dedicato, database MySQL, download e
installazione di WordPress via WP-CLI, permessi di filesystem corretti, vhost nginx già
sottoposto a hardening — e verifica che il DNS del dominio punti davvero al server
prima di procedere, non dopo. cert chiede il certificato con certbot (plugin nginx)
e allinea home/siteurl di WordPress all’URL https, così non resta un sito che
risponde in TLS ma si crede ancora in HTTP.

Tutto segue convenzioni fisse — docroot in /var/www/<dominio>/wordpress/, vhost in
/etc/nginx/sites-available/<slug>, credenziali in /root/wp-sites/<dominio>.txt — e
ogni convenzione è sovrascrivibile con una variabile d’ambiente, se il setup del VPS è
diverso dal mio.

Rimuovere un sito è la parte che mi preoccupava di più

create è ripetibile: se sbaglio qualcosa, lo vedo e lo correggo. remove no — cancella
un database e dei file, e un database cancellato non torna indietro con un --dry-run.
Per questo remove fa tre cose nell’ordine, sempre:

  1. Backup completo prima di toccare qualunque cosa: dump del database, archivio dei
    file, vhost e credenziali, tutto in /var/backups/wp-site/<dominio>-<timestamp>/.
  2. Conferma esplicita: bisogna scrivere il nome del dominio per intero. Non un [y/N]
    che si preme per abitudine.
  3. Solo a quel punto smonta vhost, database, certificato e file.

È lo stesso principio che uso in Higgins
per pubblicare i contenuti di questo blog: verificare prima, agire con un ordine preciso
dopo, e non fidarsi della memoria per i passaggi che contano.

Cosa evitare

  • Non eseguirlo su un VPS di cui non hai il controllo pieno. Lo script gira sempre
    come root: tocca /etc/nginx, crea e rimuove utenti di sistema e database MySQL. Va
    bene per un VPS dedicato ai tuoi siti, non per un ambiente condiviso con altri.
  • Non saltare la verifica del DNS. create e cert controllano che il dominio
    risolva verso l’IP del server prima di agire — è una verifica scomoda se stai testando
    in fretta, ma evita di emettere un certificato per un dominio che ancora punta altrove.
  • Le credenziali non stanno mai nella docroot. Password del database e
    dell’amministratore WordPress sono generate casualmente e salvate solo in
    /root/wp-sites/<dominio>.txt, permessi 600 — mai in un file dentro la cartella
    pubblica del sito, dove un errore di configurazione di nginx potrebbe renderlo
    scaricabile.
  • Il vhost generato non è “e basta”. Include già il blocco che nega l’esecuzione PHP
    in wp-content/uploads/, il deny su wp-config.php/xmlrpc.php/dotfile, e
    DISALLOW_FILE_EDIT in wp-config.php. Punti di hardening piccoli, ma sono esattamente
    quelli che si dimenticano scrivendo un vhost a mano alle undici di sera.

Il codice, il README con tutte le variabili d’ambiente sovrascrivibili e la licenza MIT
sono su github.com/simonecosci/prawner.