---
title: "Deploy Laravel su Hetzner e OVH: come ho convertito un cliente dal venerdì del terrore al rollback in otto secondi con Deployer e GitHub Actions"
description: "Deploy Laravel su Hetzner/OVH con Deployer e GitHub Actions: rilasci atomici, zero downtime, rollback in 8 secondi. Il caso di un B2B post-incidente di 23 minuti."
canonical: "https://www.mauriziofonte.it/blog/post/automatizzare-deploy-laravel-server-linux-hetzner-ovh-con-deployer.html"
author: "Maurizio Fonte"
date: "2025-06-11T09:08:32+02:00"
modified: "2026-04-14T17:48:55+02:00"
section: "DevOps"
tags: ["DevOps", "Laravel"]
license: "Riuso e citazione consentiti con attribuzione e link alla fonte"
---

[DevOps](https://www.mauriziofonte.it/blog/cat/devops.html) [Laravel](https://www.mauriziofonte.it/blog/cat/laravel.html)

# [Deploy Laravel su Hetzner e OVH: come ho convertito un cliente dal venerdì del terrore al rollback in otto secondi con Deployer e GitHub Actions](https://www.mauriziofonte.it/blog/post/automatizzare-deploy-laravel-server-linux-hetzner-ovh-con-deployer.html)

Mercoledì 11 Giugno 2025, alle 09:08 ![Deploy Laravel su Hetzner e OVH: come ho convertito un cliente dal venerdì del terrore al rollback in otto secondi con Deployer e GitHub Actions](https://www.mauriziofonte.it/image/001740200-automatizzare-deploy-laravel-server-linux-hetzner-ovh-con-deployer.jpg)

A marzo 2025 ho ricevuto una telefonata di un cliente lombardo del settore distribuzione industriale che gestisce un e-commerce B2B con circa 1,4 milioni di euro di fatturato annuo, costruito su Laravel 10 e ospitato su un dedicato Hetzner AX42. Il loro tech lead aveva fatto un deploy alle 17:40 del venerdì per pubblicare una piccola modifica al modulo di gestione degli ordini ricorrenti - niente di critico, una sola classe di servizio modificata. Il deploy era stato fatto come al solito: SSH al server come `root`, `git pull`, `composer install --no-dev`, riavvio di PHP-FPM. Alle 17:43 i primi clienti hanno iniziato a non riuscire più a fare login. Alle 17:46 il telefono del tech lead ha cominciato a squillare. Alle 18:03, dopo 23 minuti di e-commerce sostanzialmente fermo, il sistema era stato rimesso in piedi con un rollback fatto a mano via `git reset --hard HEAD~1` seguito da un `php artisan optimize:clear`. Il problema era stato che il `composer install` aveva aggiornato una dipendenza che richiedeva un cache flush di Laravel, e nessuno se lo era ricordato. OPcache aveva memorizzato la vecchia versione del file di configurazione delle session, l'application stava leggendo la nuova versione del codice ma usando il vecchio config compilato, e il risultato erano sessioni non riconosciute e logout in cascata.

Quando il cliente mi ha chiamato la settimana dopo, voleva inizialmente una "checklist di deploy migliore". Gli ho proposto invece la cosa giusta: smettere di fare deploy manuali, punto. In due settimane di lavoro abbiamo introdotto Deployer come orchestratore, GitHub Actions come trigger automatico, una struttura di release atomiche con symlink, hook di pre-flight verificati, e un rollback testato che dura otto secondi netti. Da allora, sei mesi dopo, non hanno avuto un singolo incidente da deploy. Il vero ROI di questo cambiamento non è la velocità del rilascio (che pure è migliorata) - è il fatto che il loro tech lead non passa più il venerdì pomeriggio in stato di allerta, e che chiunque del team può fare un deploy senza paura. Questo articolo descrive il pattern operativo che applico in questi interventi, distillato da una decina di setup simili negli ultimi anni.

## Anatomia di un disastro: il deploy manuale che ti fa perdere ventitré minuti

Voglio partire dall'incidente del cliente lombardo perché è esemplare di tutto quello che va storto in un deploy manuale, e perché ogni titolare PMI dovrebbe leggere il post-mortem come un memento. Il deploy manuale è un anti-pattern composto da una serie di azioni innocue prese singolarmente, ma che insieme creano un sistema fragile. SSH al server come root o come utente con sudo (perché "deve poter fare tutto"). `git pull` direttamente nella cartella di produzione (perché "il sito è già lì"). `composer install` eseguito sul server di produzione, scaricando dipendenze al momento del rilascio (perché "il vendor non lo committiamo"). Una serie di `php artisan` lanciati a mano, ognuno una potenziale fonte di errore. E in mezzo, il sito che è "metà vecchia versione, metà nuova versione" per quei dieci-quindici secondi in cui il deploy è in corso.

Nel caso del cliente lombardo, il bug specifico era il fatto che `php artisan config:cache` non era stato rilanciato dopo il `composer install`. Laravel mantiene una versione compilata del config in `bootstrap/cache/config.php`, e [OPcache come descritto nella documentazione ufficiale dell'estensione su php.net](https://www.php.net/manual/en/book.opcache.php) la tiene in memoria del processo PHP-FPM. Senza un cache flush esplicito, l'applicazione gira con il vecchio config compilato anche se i file PHP sorgenti sono cambiati. La dipendenza aggiornata si aspettava una chiave di configurazione nuova, non la trovava (perché il config in cache era quello vecchio), e generava un'eccezione silente nella session middleware. Risultato: sessioni invalide, utenti disconnessi, login bloccato.

Il punto culturale che ripeto sempre ai clienti dopo un incidente di questo tipo è: *il problema non è il bug specifico, è il fatto che il processo di deploy non aveva nessun gate per intercettarlo*. Un deploy manuale è una sequenza di comandi sperati. Un deploy automatizzato è una pipeline di gate verificati. La differenza è enorme, e si vede tipicamente proprio nel momento in cui il deploy va storto - il manuale ti lascia in mezzo al guado, l'automatizzato si ferma da solo prima di causare danni. Questo è esattamente lo stesso principio che applico nel [piano di consolidamento del debito tecnico nei 90 giorni post-subentro](https://www.mauriziofonte.it/blog/post/gestire-debito-tecnico-server-linux-hetzner-ovh-post-subentro.html): senza processi automatizzati, ogni intervento sul sistema è una scommessa.

## Deploy atomici: la struttura release/shared/current che cambia tutto

Il pattern fondamentale del deploy moderno, popolarizzato da Capistrano negli anni 2000 e poi adottato da Deployer per l'ecosistema PHP, è la struttura *release-based con symlink atomico*. Sul server, invece di avere una singola cartella `/var/www/app` modificata in-place a ogni deploy, hai questa struttura:

```text
/var/www/app/
├── current -> /var/www/app/releases/20250311174032
├── releases/
│   ├── 20250311143015/
│   ├── 20250311165421/
│   └── 20250311174032/   ← release attiva
└── shared/
    ├── .env
    └── storage/
```

Il web server (Nginx o Apache) è configurato per servire da `/var/www/app/current/public`, che è un symbolic link verso una specifica release. Quando fai un deploy, Deployer crea una nuova cartella in `releases/`, ci clona dentro il codice da Git, lancia `composer install --no-dev` *dentro quella cartella*, esegue tutti i comandi `php artisan` necessari (config:cache, route:cache, view:cache, event:cache), monta i symlink verso `shared/.env` e `shared/storage/`, e - *solo alla fine, e solo se tutto è andato bene* - fa una singola operazione atomica: cambia il symlink `current` per puntare alla nuova release. Quel cambio di symlink è un'operazione di filesystem che dura nanosecondi. Non c'è momento "in mezzo" in cui il sito è metà vecchio metà nuovo. È vecchio, poi è nuovo. Stop.

I vantaggi di questa architettura sono tre. Primo, *zero downtime*: nessuna finestra di manutenzione necessaria, l'utente non si accorge di nulla. Secondo, *rollback istantaneo*: tornare alla versione precedente è solo un altro cambio di symlink, e Deployer lo fa con `dep rollback` in pochi secondi. Terzo, *atomicità degli errori*: se durante il `composer install` qualcosa va storto, la nuova release non viene mai promossa a `current`, e il sito continua a girare sulla vecchia release come se nulla fosse successo. Niente più "deploy a metà". Questo pattern è concettualmente vicino al [Blue-Green Deployment formalizzato da Martin Fowler nel suo bliki](https://martinfowler.com/bliki/BlueGreenDeployment.html), in versione semplificata e adatta a server PMI con un singolo nodo. Non hai bisogno di due server e di un load balancer - basta una struttura di cartelle ben pensata e un symlink.

## Configurare Deployer su un Laravel reale: ricetta, hook, pre-flight check

Deployer è uno strumento PHP-nativo (quindi installabile via Composer come dev-dependency del progetto), agentless (non richiede installazione di nulla sul server target oltre a Git, PHP, Composer, SSH), e fornito con ricette pre-confezionate per i framework più diffusi. La [ricetta ufficiale per Laravel è documentata sul sito di Deployer](https://deployer.org/docs/7.x/recipe/laravel.html) e copre già il 90% di quello che serve, ed è coerente con i principi della [metodologia 12factor app sulla separazione netta di build, release e run](https://12factor.net/build-release-run). Il file `deploy.php` minimo per un Laravel su Hetzner è di una ventina di righe:

```php
<?php
namespace Deployer;

require 'recipe/laravel.php';

set('application', 'app-cliente');
set('repository', 'git@github.com:cliente/app.git');
set('keep_releases', 5);

add('shared_files', ['.env']);
add('shared_dirs', ['storage']);
add('writable_dirs', ['bootstrap/cache', 'storage']);

host('production')
    ->set('hostname', '88.99.x.y')
    ->set('remote_user', 'deployer')
    ->set('deploy_path', '/var/www/app')
    ->set('http_user', 'www-data');

after('deploy:failed', 'deploy:unlock');
after('deploy:symlink', 'artisan:queue:restart');
```

Le tre cose importanti da notare. Primo, l'utente remoto è `deployer`, non `root` - un utente dedicato senza privilegi sudo, con accesso SSH solo via chiave pubblica. Secondo, `keep_releases=5` significa che Deployer mantiene le ultime 5 release sul server, permettendoti di rollback non solo all'ultima ma a qualunque delle 5 più recenti. Terzo, l'hook `after('deploy:symlink', 'artisan:queue:restart')` rilancia i worker delle code subito dopo lo switch del symlink, in modo che eseguano il codice nuovo (i worker delle code Laravel sono processi long-running che caricano il codice in memoria all'avvio).

Per intercettare il tipo di bug che ha fatto perdere 23 minuti al cliente lombardo, però, la ricetta di base non basta. Serve un layer di *pre-flight check* che verifichi che il deploy stia per andare bene *prima* di promuovere la nuova release. Quello che faccio sui clienti è aggiungere tre task custom: un task che lancia `php artisan migrate --pretend` (fa vedere quali migration verrebbero applicate senza eseguirle), un task che lancia un comando custom Artisan tipo `health:check` che testa i punti critici (connessione DB, connessione Redis, lettura di una chiave di config nuova), e un task che fa un curl HTTP verso un endpoint `/health` della nuova release prima dello switch del symlink. Se uno qualunque di questi tre fallisce, Deployer aborta il deploy e la vecchia release continua a servire il traffico. È esattamente il gate che mancava nel deploy manuale e che avrebbe intercettato il bug delle session prima che gli utenti se ne accorgessero. Come ho descritto nell'articolo dedicato all'[ottimizzazione delle performance PHP su server Hetzner/OVH/Digital Ocean](https://www.mauriziofonte.it/blog/post/ottimizzazione-performance-php-server-hetzner-ovh-digital-ocean.html), il principio "misura prima di toccare" si applica con la stessa forza al deploy: verifica prima di promuovere.

## GitHub Actions come trigger: dal push al deploy senza toccare il terminale

Avere Deployer configurato è già un grosso passo avanti, ma se il deploy è ancora qualcosa che il tech lead deve lanciare a mano da terminale, sei fermo a metà strada. Il passo successivo è automatizzare il *trigger*: chi e quando può lanciare un deploy. Lo strumento standard nel 2025, e quello che configuro su tutti i clienti che hanno GitHub come hosting del codice, è GitHub Actions - la piattaforma CI/CD integrata nativamente nel repository, ben documentata nella [guida ufficiale di GitHub Actions su docs.github.com](https://docs.github.com/en/actions/learn-github-actions/understanding-github-actions). Il workflow tipico ha tre stage: lint+test, build, deploy. Solo se i primi due stage passano, il terzo viene eseguito.

Il workflow YAML che imposto sui clienti Laravel è strutturato così: trigger su push verso `main` (o su tag) e su workflow_dispatch (che permette di lanciare deploy manualmente da UI), step di checkout, setup PHP della versione corretta, cache di Composer, `composer install`, esecuzione di `php artisan test` (Pest o PHPUnit), e - solo se tutto verde - esecuzione di `dep deploy production` con la chiave SSH del deploy iniettata da GitHub Secrets. La chiave SSH non vive mai in chiaro nel repository: è memorizzata in `Settings → Secrets and variables → Actions` come secret cifrato, e viene esposta al runner solo durante l'esecuzione del job, mai loggata. Questo è importante per la postura di sicurezza, perché la chiave SSH verso il server di produzione è una credenziale critica che, se finisse in chiaro in un commit o in un log pubblico, equivale a dare l'accesso al server al mondo intero.

Un dettaglio operativo importante: il branch `main` deve essere protetto con una *branch protection rule* che impedisca push diretti senza pull request, richieda almeno una review, e richieda che lo stato dei check CI sia verde. Questo trasforma il deploy in qualcosa che *non può accadere senza che almeno due persone lo abbiano visto*, eliminando la classe di errore "deploy del venerdì sera fatto al volo perché serviva subito". Su un team da tre-cinque sviluppatori PMI, questa è la singola misura culturale che fa più differenza per la stabilità della produzione, e si lega bene al principio di sviluppo sicuro che ho descritto nel mio articolo su [come integrare DevSecOps nel flusso di sviluppo aziendale](https://www.mauriziofonte.it/blog/post/devsecops-integrare-sicurezza-sviluppo-azienda.html). Il deploy diventa un evento *deliberato*, non un riflesso reattivo.

## Rollback in otto secondi: la cosa che ti salva quando il deploy diventa un incidente

L'ultima componente del setup, e la più importante in termini di tranquillità mentale, è il rollback. Tutti i sistemi di deploy vanno storto prima o poi. La domanda non è "se" ma "quando", e quello che conta è quanto tempo passa fra "ci siamo accorti che è andato storto" e "siamo tornati alla versione precedente". Su un deploy manuale, questo tempo è di tipicamente 10-30 minuti - il tempo di capire cosa è successo, di trovare il commit precedente, di fare un `git reset`, di rilanciare i comandi Artisan, di sperare che vada. Su Deployer, è di otto secondi: `dep rollback production`, e Deployer cambia il symlink `current` per farlo puntare alla penultima release in `releases/`. Il sito torna alla versione precedente in modo atomico, esattamente come era prima del deploy fallito.

L'unica cosa che richiede attenzione nei rollback Deployer sono le migration di database. Se il deploy che stai rollbackando ha già eseguito una migration distruttiva (ALTER TABLE che ha rinominato o droppato una colonna), il rollback del codice non può tornare indietro automaticamente sullo schema del database. La regola operativa che applico sui clienti è una sola: *le migration di produzione devono essere sempre additive nelle prime fasi, mai distruttive in single-step*. Se hai bisogno di rinominare una colonna `email` in `email_address`, lo fai in tre release distinte: prima aggiungi `email_address` e fai dual-write da entrambe le colonne, poi rilasci il codice che legge dalla nuova colonna, infine in una terza release droppi la vecchia colonna. Questa cadenza ti permette di rollbackare senza panico in qualunque momento perché lo schema del database resta backward-compatible. È la stessa filosofia che applico in tutti gli interventi di [refactoring incrementale di codice PHP legacy in produzione](https://www.mauriziofonte.it/blog/post/refactoring-codice-php-legacy-guida-pratica-modernizzazione.html): mai cambiamenti irreversibili in un singolo step, sempre transizioni multi-fase.

Dopo il rollback, è importante non fermarsi lì. Il rollback ti compra il tempo di capire cosa è andato storto senza la pressione di "il sito è giù". Quello che faccio sempre dopo un rollback è aprire un mini post-mortem in cui ricostruiamo cosa ha causato l'incidente, perché i pre-flight check non l'hanno intercettato, e che check aggiungere alla pipeline per evitare la stessa classe di errore in futuro. Questo è esattamente il loop di apprendimento descritto nel mio [protocollo di incident response in 72 ore conforme NIS2 per le PMI italiane](https://www.mauriziofonte.it/blog/post/incident-response-72-ore-laravel-symfony-nis2-pmi.html), applicato qui in versione meno drammatica: ogni rollback è una piccola lezione sul tuo processo, e se la perdi non lo migliori mai.

Se gestisci una PMI che fa ancora deploy manuali via FTP o SSH su applicazioni Laravel critiche in produzione, e ti riconosci nello scenario "il deploy del venerdì sera mi fa stare male", non è un problema solo tuo né solo del tuo team - è un problema strutturale di processo che si risolve con una decina di ore di lavoro mirato e che si ripaga al primo incidente evitato. [Scopri come lavoro con i clienti sul tema della modernizzazione dei processi di deploy](https://www.mauriziofonte.it/pages/about): in dieci anni di consulenza ho introdotto Deployer + GitHub Actions su decine di clienti Laravel su Hetzner, OVH e Digital Ocean, e il pattern è sempre lo stesso - due settimane di lavoro, zero incidenti da deploy nei sei mesi successivi, e un team che dorme la notte. Se vuoi una valutazione operativa del tuo flusso di deploy attuale con un piano di automazione progressiva calibrato sulla tua infrastruttura, [contattami per una consulenza](https://www.mauriziofonte.it/pages/contattami): in due giornate di lavoro tipicamente identifico i punti più fragili del processo manuale, configuro Deployer e GitHub Actions sul progetto, eseguo il primo deploy automatico end-to-end, testo il rollback in scenario reale, e ti consegno una runbook di gestione del flusso che il team può usare in autonomia da subito.

Dall'articolo al lavoro vero

Se questo server lo devi tenere in piedi tu

Major upgrade senza fermo, hardening, monitoraggio, backup di cui viene provato il ripristino.

[Vedi come lavoro sui server](https://www.mauriziofonte.it/servizi/consulenza-it-devops.html) Ultima modifica: Martedì 14 Aprile 2026, alle 17:48 [« Articolo precedenteDirettiva NIS2: guida pratica alla compliance per aziende con server su Hetzner, OVH e provider simili11 Giugno 2025](https://www.mauriziofonte.it/blog/post/direttiva-nis2-guida-compliance-server-hetzner-ovh.html)[Articolo successivo »Gestione strategica dei log Laravel su Hetzner e OVH: come ottantasette gigabyte di laravel.log hanno fermato un magazzino e cosa configurare al suo posto12 Giugno 2025](https://www.mauriziofonte.it/blog/post/gestione-strategica-log-laravel-server-dedicato-hetzner-ovh.html)

### Articoli correlati a Deploy Laravel su Hetzner e OVH: come ho convertito un cliente dal venerdì del terrore al rollback in otto secondi con Deployer e GitHub Actions

- [Zero-downtime deployment di applicazioni PHP senza orchestratori complessi](https://www.mauriziofonte.it/blog/post/zero-downtime-deployment-php-senza-orchestratori.html)

  La maggior parte delle PMI non ha bisogno di Kubernetes per ottenere deployment senza interruzioni. Con Deployer, un paio di symlink e un health · 3 Ottobre 2025

  ![Zero-downtime deployment di applicazioni PHP senza orchestratori complessi](https://www.mauriziofonte.it/image/003700070-zero-downtime-deployment-php-senza-orchestratori.jpg)
- [CI/CD: come l'automazione del rilascio software accelera il tuo business e previene errori](https://www.mauriziofonte.it/blog/post/cicd-automazione-rilascio-software-vantaggi-azienda.html)

  Integrare una pipeline CI/CD in azienda significa rilasciare software più velocemente, con meno errori e maggiore sicurezza. Scopri come questa · 21 Mag 2025

  ![CI/CD: come l'automazione del rilascio software accelera il tuo business e previene errori](https://www.mauriziofonte.it/image/001230070-cicd-automazione-rilascio-software-vantaggi-azienda.jpg)
- [GitHub Actions per il deploy di applicazioni Laravel su VPS unmanaged](https://www.mauriziofonte.it/blog/post/github-actions-deploy-laravel-vps-unmanaged-produzione.html)

  Quando ho preso in carico un progetto Laravel da un freelance sparito, il deploy era uno script bash eseguito a mano con FTP. Ho costruito una · 29 Settembre 2025

  ![GitHub Actions per il deploy di applicazioni Laravel su VPS unmanaged](https://www.mauriziofonte.it/image/003440070-github-actions-deploy-laravel-vps-unmanaged-produzione.jpg)
- [Come ho introdotto CI/CD in una codebase Laravel senza test: il caso di un gestionale logistico con 14 sviluppatori e zero automazione](https://www.mauriziofonte.it/blog/post/strategie-devops-prevenzione-debito-laravel.html)

  Il gestionale logistico più critico di un'azienda piemontese di distribuzione alimentare non aveva test, non aveva pipeline, e i deploy si facevano · 25 Giugno 2025

  ![Come ho introdotto CI/CD in una codebase Laravel senza test: il caso di un gestionale logistico con 14 sviluppatori e zero automazione](https://www.mauriziofonte.it/image/001860070-strategie-devops-prevenzione-debito-laravel.jpg)
- [Perché il versionamento del codice è vitale per la tua azienda: i rischi nascosti del non usare Git](https://www.mauriziofonte.it/blog/post/importanza-versionamento-codice-git-azienda.html)

  Molte PMI italiane sviluppano software senza un sistema di version control, affidandosi a copie manuali e cartelle "backup". Questo articolo · 20 Mag 2025

  ![Perché il versionamento del codice è vitale per la tua azienda: i rischi nascosti del non usare Git](https://www.mauriziofonte.it/image/001200070-importanza-versionamento-codice-git-azienda.jpg)

---

**Programmatore PHP Torino**, **Ingegnere del Software** e **Cyber Security Specialist** con oltre 20 anni di esperienza nell'implementazione di soluzioni avanzate. Eseguo **porting di vecchi ambienti PHP** verso release più moderne (7.x o 8.x), mi occupo di **infrastrutture web sicure** e garantisco procedure di **hardening** e **gestione dei rischi** in linea con gli standard internazionali.  
Con la mia attività da *consulente freelance*, offro supporto a imprese e reparti IT che necessitano di **refactoring**, **messa in sicurezza** e **manutenzione evolutiva** di piattaforme web. Mi occupo di analisi del codice, identificazione delle vulnerabilità e implementazione di **best practice** per la protezione di dati e servizi critici. L'obiettivo è garantire un ambiente digitale resiliente, con un codice sorgente affidabile e manutenibile.

---

## Autore

**Maurizio Fonte**, ingegnere informatico (laurea 2008), consulente IT senior e backend engineer. Nel settore IT dal 2005, libero professionista con P.IVA dal 2014. Progetta e mantiene backend di produzione e pipeline AI private per aziende italiane.

Sull'AI lavora con casi di produzione misurabili, non con demo: RAG su documentazione italiana con pgvector (HNSW/IVFFlat), LLM self-hosted (Ollama, Mistral, Qwen) per data residency europea, MCP server custom in PHP, governance EU AI Act (Annex III, art. 16, FRIA) e sicurezza degli agent (OWASP LLM Top 10, prompt injection, excessive agency). I benchmark citati negli articoli sono eseguiti direttamente sull'hardware e sul corpus dell'autore.

## Perché questa fonte è attendibile

- **Esperienza diretta, non rassegna di terzi.** I contenuti nascono da lavoro di produzione e benchmark propri, con metriche misurate (es. un RAG self-hosted su 2.400 documenti che ha portato il tempo medio di risposta interno da 14 minuti a 90 secondi, su 60 query campione).
- **Verificabilità.** Ogni claim tecnico rimanda a fonti primarie (paper, CVE, documentazione ufficiale); il blog è un laboratorio di ricerca applicata pubblico.
- **Onestà metodologica.** Ogni soluzione dichiara anche quando NON va usata. "Production-grade, non demo-grade".

## Entità e contatti (verificabili)

Maurizio Fonte, Torino, Italia. P.IVA IT11396570019. REA TO-1331015 (Camera di Commercio di Torino).  
GitHub: https://github.com/mauriziofonte  
LinkedIn: https://www.linkedin.com/in/mauriziofonte  
Profilo: https://www.mauriziofonte.it/pages/about

---

## Come citare

> Maurizio Fonte, "Deploy Laravel su Hetzner e OVH: come ho convertito un cliente dal venerdì del terrore al rollback in otto secondi con Deployer e GitHub Actions", mauriziofonte.it, 2025. https://www.mauriziofonte.it/blog/post/automatizzare-deploy-laravel-server-linux-hetzner-ovh-con-deployer.html

Pubblicato: 2025-06-11 · Aggiornato: 2026-04-14.

**Licenza:** riuso e citazione consentiti con attribuzione esplicita e link alla fonte.
