Introduzione al Deployment di Laravel
Il passaggio dallo sviluppo locale all'ambiente di produzione è uno dei momenti più critici per ogni sviluppatore web. Mentre in locale utilizziamo spesso strumenti come php artisan serve o Laravel Sail (Docker), in produzione abbiamo bisogno di un'infrastruttura robusta, sicura e performante.
Il deployment di un'applicazione Laravel su un server Ubuntu (tipicamente una VPS come DigitalOcean, AWS EC2 o Linode) richiede la configurazione di quello che viene chiamato stack LEMP: Linux, Nginx, MySQL e PHP. In questo articolo analizzeremo non solo il "come", ma anche il "perché" di ogni singolo passaggio, trasformando un server vuoto in una macchina pronta a servire migliaia di utenti.
1. Preparazione del Server e Installazione delle Dipendenze
Prima di caricare il codice, dobbiamo assicurarci che il sistema operativo sia aggiornato e che tutte le estensioni PHP richieste da Laravel siano installate. Laravel non è solo PHP; richiede diverse estensioni per gestire sessioni, database, crittografia e manipolazione di immagini.
Aggiornamento del Sistema
Il primo passo è sempre l'aggiornamento dei pacchetti di sistema per evitare vulnerabilità di sicurezza.
sudo apt update && sudo apt upgrade -y
Installazione di Nginx, MySQL e PHP
Utilizzeremo Nginx come server web per la sua efficienza nel gestire le connessioni concorrenti rispetto ad Apache. Per PHP, installeremo la versione più recente supportata dalla tua versione di Laravel (in questo esempio useremo PHP 8.2).
# Installazione Nginx
sudo apt install nginx -y
# Installazione MySQL
sudo apt install mysql-server -y
# Installazione PHP e estensioni comuni per Laravel
sudo apt install php8.2-fpm php8.2-mysql php8.2-mbstring php8.2-xml php8.2-bcmath php8.2-curl php8.2-zip -y
Perché PHP-FPM?
Nginx non processa il codice PHP nativamente. Utilizza PHP-FPM (FastCGI Process Manager), che agisce come un gestore di processi separato. Nginx riceve la richiesta HTTP e, se si tratta di un file .php, la passa a PHP-FPM tramite un socket Unix, ottenendo poi la risposta da restituire al client.
2. Configurazione del Database e dell'Utente
La sicurezza inizia dal database. Non dovremmo mai utilizzare l'utente root per le connessioni dell'applicazione. Creeremo un database dedicato e un utente con permessi limitati.
Setup di MySQL
Accediamo alla console di MySQL:
sudo mysql
Eseguiamo i seguenti comandi SQL:
CREATE DATABASE laravel_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'laravel_user'@'localhost' IDENTIFIED BY 'password_sicura_123';
GRANT ALL PRIVILEGES ON laravel_db.* TO 'laravel_user'@'localhost';
FLUSH PRIVILEGES;
EXIT;
L'uso di utf8mb4 è fondamentale per supportare correttamente tutti i caratteri, inclusi gli emoji, che sono ormai standard in ogni applicazione web moderna.
3. Deployment del Codice e Gestione dei Permessi
Esistono vari modi per portare il codice sul server: Git (raccomandato), FTP o CI/CD pipeline. Useremo Git per mantenere il controllo delle versioni.
Clonazione del Progetto
Spostiamoci nella directory /var/www e cloniamo il repository:
cd /var/www
sudo git clone https://github.com/tuousername/tuo-progetto.git laravel-app
cd laravel-app
Installazione di Composer
Composer è essenziale per gestire le dipendenze di PHP. Lo installiamo globalmente:
curl -sS https://getcomposer.org/installer | php
sudo mv composer.phar /usr/local/bin/composer
Ora installiamo le dipendenze per la produzione. È cruciale usare il flag --no-dev per evitare di installare pacchetti di testing (come PHPUnit) che rallenterebbero l'app e potrebbero creare falle di sicurezza.
composer install --no-dev --optimize-autoloader
Gestione dei Permessi (Il punto critico)
Uno degli errori più comuni in Laravel è il problema dei permessi su storage e bootstrap/cache. Il server web (Nginx) gira sotto l'utente www-data, ma i file sono stati clonati dall'utente ubuntu. Se www-data non può scrivere in queste cartelle, l'app crasherà con un errore 500.
# Cambia il proprietario di tutte le cartelle all'utente www-data
sudo chown -R www-data:www-data /var/www/laravel-app
# Assicurati che storage e cache siano scrivibili
sudo chmod -R 775 /var/www/laravel-app/storage
sudo chmod -R 775 /var/www/laravel-app/bootstrap/cache
4. Configurazione dell'Ambiente (.env)
Il file .env contiene le credenziali sensibili e non deve mai essere commitato su Git. Dobbiamo crearlo manualmente sul server.
cp .env.example .env
nano .env
Modifica i seguenti parametri fondamentali:
APP_ENV=productionAPP_DEBUG=false(Fondamentale! Se lasciato a true, gli errori mostreranno password e chiavi al pubblico)APP_URL=https://tuodominio.comDB_DATABASE=laravel_dbDB_USERNAME=laravel_userDB_PASSWORD=password_sicura_123
Dopo aver salvato, generiamo la chiave dell'applicazione e lanciamo le migrazioni:
php artisan key:generate
php artisan migrate --force
Il flag --force è necessario perché in ambiente di produzione Laravel chiede conferma prima di eseguire migrazioni che potrebbero cancellare dati.
5. Configurazione di Nginx per Laravel
Nginx deve essere istruito su come gestire le richieste. Il punto di ingresso di ogni applicazione Laravel è il file public/index.php. Se non configuriamo correttamente il "root", l'utente potrebbe accedere a file sensibili come .env.
Creiamo un nuovo file di configurazione:
sudo nano /etc/nginx/sites-available/laravel-app
Inseriamo la seguente configurazione:
server {
listen 80;
server_name tuodominio.com www.tuodominio.com;
root /var/www/laravel-app/public;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-Content-Type-Options "nosniff";
index index.php;
charset utf-8;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
error_page 404 /index.php;
location ~ \\.php$ {
fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
}
location ~ \\.ht {
deny all;
}
}
Attivazione del sito
Abilitiamo la configurazione creando un link simbolico e riavviamo Nginx:
sudo ln -s /etc/nginx/sites-available/laravel-app /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl restart nginx
6. Ottimizzazioni per la Produzione
Un'app Laravel installata non è ancora un'app ottimizzata. In produzione, leggere i file di configurazione e le rotte a ogni richiesta è inefficiente.
Caching
Eseguiamo i comandi di ottimizzazione per mettere in cache le configurazioni e le rotte:
php artisan config:cache
php artisan route:cache
php artisan view:cache
Questi comandi trasformano i file di configurazione in un singolo file PHP veloce da leggere, riducendo drasticamente i tempi di risposta.
Queue Worker e Scheduler
Se la tua app invia email o processa job in background, hai bisogno di un processo che monitori la coda. Non puoi lanciarlo manualmente; serve un gestore di processi come Supervisor.
Installazione di Supervisor:
sudo apt install supervisor -y
Crea un file di configurazione in /etc/supervisor/conf.d/laravel-worker.conf per assicurarti che php artisan queue:work sia sempre attivo e venga riavviato in caso di crash.
Esempi Pratici: Casi d'Uso Reali
Caso 1: Gestione di Asset Statici
Se usi Vite o Laravel Mix, ricorda che i file CSS e JS devono essere compilati. Non installare Node.js sul server di produzione se puoi evitarlo.
Best Practice: Compila gli asset localmente o tramite GitHub Actions e carica la cartella public/build sul server. Questo riduce il carico di memoria del server.
Caso 2: Implementazione di SSL con Certbot
Un sito in produzione senza HTTPS non è accettabile. Utilizziamo Let's Encrypt:
sudo apt install certbot python3-certbot-nginx -y
sudo certbot --nginx -d tuodominio.com -d www.tuodominio.com
Certbot modificherà automaticamente il file di Nginx per reindirizzare tutto il traffico HTTP verso HTTPS.
Errori Comuni e FAQ
Q: Ricevo un errore "500 Internal Server Error" senza dettagli.
A: Quasi certamente è un problema di permessi sulla cartella storage. Verifica con ls -l che l'utente www-data sia il proprietario.
Q: Le immagini carrate dagli utenti non sono visibili.
A: Laravel salva i file in storage/app/public, ma Nginx serve i file da public/. Devi creare il link simbolico:
php artisan storage:link
Q: Perché non posso usare sudo php artisan migrate?
A: Eseguire i comandi come root può cambiare la proprietà dei file generati (es. i log), causando errori di scrittura successivi. Usa sempre l'utente del server o specifica l'utente: sudo -u www-data php artisan migrate.
Prossimi Passi
Ora che la tua applicazione è online, puoi implementare strategie più avanzate per migliorare la scalabilità e la manutenzione:
- CI/CD Pipeline: Configura GitHub Actions per automatizzare il deploy. Invece di fare
git pullmanualmente, crea uno script che esegua il pull, installi le dipendenze, pulisca la cache e faccia il migrate. - Monitoring: Installa strumenti come Sentry o Bugsnag per ricevere notifiche in tempo reale quando un utente riscontra un errore in produzione.
- Redis: Sostituisci il driver di sessione e cache da
filearedisper migliorare le performance di I/O. - Backup Automatici: Configura un cron job per eseguire
mysqldumpquotidianamente e salvare il backup su un servizio esterno come AWS S3.
Il deployment è un processo iterativo. Inizia con questa configurazione solida e scala l'infrastruttura man mano che la tua base utenti cresce.