Guida Completa al Deploy di Laravel su Ubuntu: Dalla Configurazione al Server di Produzione

Intermedio
DevOps e deployment

Impara a configurare un server Ubuntu per ospitare un'applicazione Laravel in produzione, gestendo Nginx, PHP-FPM, MySQL e la sicurezza del server.

Pubblicato
Tag
PHP laravel Deployment nginx Ubuntu Server Setup

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=production
  • APP_DEBUG=false (Fondamentale! Se lasciato a true, gli errori mostreranno password e chiavi al pubblico)
  • APP_URL=https://tuodominio.com
  • DB_DATABASE=laravel_db
  • DB_USERNAME=laravel_user
  • DB_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:

  1. CI/CD Pipeline: Configura GitHub Actions per automatizzare il deploy. Invece di fare git pull manualmente, crea uno script che esegua il pull, installi le dipendenze, pulisca la cache e faccia il migrate.
  2. Monitoring: Installa strumenti come Sentry o Bugsnag per ricevere notifiche in tempo reale quando un utente riscontra un errore in produzione.
  3. Redis: Sostituisci il driver di sessione e cache da file a redis per migliorare le performance di I/O.
  4. Backup Automatici: Configura un cron job per eseguire mysqldump quotidianamente 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.