bg-tutorials

Come configurare un certificato SSL in HAProxy

HAProxy è un load balancer TCP e HTTP che termina il TLS, quindi decifra il traffico ai margini e inoltra HTTP semplice ai server backend. Questo lo rende l’unica macchina lungo il percorso che ha bisogno del certificato, e lo vuole in una forma specifica: un unico file, contenente il certificato, eventuali intermedi e la chiave privata.

Questa guida copre l’intero percorso: generare una CSR, assemblare il file PEM, scrivere il frontend e il backend, verificare la configurazione e ricaricarla senza interrompere le connessioni attive. I comandi sono stati eseguiti su HAProxy 3.4, l’attuale ramo a supporto a lungo termine, rilasciato a giugno 2026 e mantenuto fino al Q2 2031.

Cosa si aspetta HAProxy: un unico file PEM

La maggior parte dei server richiede il certificato, la catena e la chiave come tre impostazioni separate. HAProxy ne richiede una sola. Il suo manuale di configurazione descrive la parola chiave crt come qualcosa che indica “un file PEM contenente sia i certificati richiesti che eventuali chiavi private associate”, costruito concatenando file PEM, e aggiunge che “se la CA richiede un certificato intermedio, anche questo può essere concatenato in questo file”.

Vale la pena conoscere due comportamenti prima di iniziare, perché fanno risparmiare lavoro in seguito:

  • La chiave può stare accanto al certificato invece che al suo interno. Se il file non contiene una chiave privata, HAProxy cerca lo stesso percorso con .key aggiunto. Quindi mydomain.pem più mydomain.pem.key funziona esattamente come un unico file combinato.
  • Puoi indirizzare crt verso una directory. HAProxy carica ogni file che trova lì e seleziona il certificato corretto per ogni richiesta usando SNI. È così che si servono più siti da un unico frontend senza dover avere una riga bind per ciascuno.

Genera la CSR e la chiave privata

Una CSR è la richiesta codificata che consegni all’Autorità di Certificazione. Generala sulla macchina HAProxy, o ovunque tu possa mantenere sicura la chiave privata, poiché la chiave non deve mai lasciare il tuo controllo.

openssl req -new -newkey rsa:2048 -nodes 
  -keyout mydomain.key -out mydomain.csr 
  -subj "/C=US/ST=California/L=San Jose/O=Your Company/CN=mydomain.com" 
  -addext "subjectAltName=DNS:mydomain.com,DNS:www.mydomain.com"

La riga -addext non è opzionale nella pratica. I browser hanno smesso da anni di confrontare i nomi host con il Common Name e leggono solo il Subject Alternative Name, quindi una CSR che contiene solo un CN produce un certificato che fallisce in ogni browser attuale. Elenca ogni nome che il certificato deve coprire, incluso il dominio nudo e la forma www se servi entrambi.

Rimuovi le opzioni -subj e -addext se preferisci essere interrogato per ogni campo. In entrambi i casi finirai con due file: mydomain.csr da inviare, e mydomain.key da conservare. Conferma che la CSR contenga ciò che ti aspetti prima di inviarla, sia con il nostro decodificatore CSR che localmente:

openssl req -noout -text -verify -in mydomain.csr

Verifica che le voci SAN siano elencate e che la firma sia verificata. Se preferisci non usare affatto la riga di comando, il nostro generatore di CSR produce la stessa coppia direttamente nel browser. Maggiori informazioni sui comandi sottostanti sono disponibili nella nostra guida ai comandi OpenSSL.

Ottieni l’emissione del certificato

Invia la CSR alla CA, scegli il tipo di certificato adatto a ciò che stai proteggendo e completa la validazione. Un certificato a singolo dominio copre un solo nome host, un wildcard copre ogni sottodominio di primo livello, e un certificato multi-dominio (SAN) copre un elenco di nomi non correlati. Dietro un load balancer, il multi-dominio è la scelta comune, poiché un’istanza HAProxy solitamente serve da frontend a più siti.

La CA restituisce un archivio contenente il tuo certificato e la catena intermedia, solitamente come file CA bundle. Entrambi sono già in formato PEM, che è ciò di cui hai bisogno. Pianifica il rinnovo ora piuttosto che dopo: dal 15 marzo 2026 un certificato TLS pubblicamente affidabile può essere valido per non più di 200 giorni, scendendo a 100 giorni a marzo 2027 e a 47 giorni a marzo 2029, quindi la sostituzione manuale smetterà presto di essere praticabile.

Costruisci il file PEM che HAProxy leggerà

Crea una directory per i certificati e assembla il file lì. Mantieni tutto in un unico posto fin dall’inizio; suddividerlo tra una home directory, /etc/haproxy e /etc/ssl è il modo in cui si finisce per modificare un file mentre HAProxy ne legge un altro.

sudo mkdir -p /etc/haproxy/certs
sudo chmod 700 /etc/haproxy/certs

Concatena il certificato, poi gli intermedi, poi la chiave privata. Il reindirizzamento deve essere eseguito come root, quindi passa il flusso a tee piuttosto che scrivere sudo cat ... > /etc/haproxy/certs/..., che fallisce con un errore di permesso perché la shell apre il file di output come il tuo stesso utente prima ancora che sudo venga eseguito:

cat mydomain.crt intermediate.crt mydomain.key 
  | sudo tee /etc/haproxy/certs/mydomain.pem > /dev/null

Quel file ora contiene la tua chiave privata in chiaro, quindi bloccalo prima di procedere oltre:

sudo chown root:root /etc/haproxy/certs/mydomain.pem
sudo chmod 600 /etc/haproxy/certs/mydomain.pem

I permessi riservati solo a root sono corretti qui, non un ostacolo. HAProxy viene avviato con privilegi da superutente, che il suo manuale nota essere necessari perché possa in seguito passare al proprio utente non privilegiato, e legge il certificato durante quell’avvio. Non c’è bisogno di ampliare i permessi affinché l’utente haproxy possa leggere la chiave, e non dovresti farlo.

Se hai costruito la CSR su una macchina diversa, copia prima i file e poi elimina le copie dalla directory di transito:

scp mydomain.crt intermediate.crt mydomain.key sysadmin@haproxy-server:/home/sysadmin/

Configura HAProxy

Apri /etc/haproxy/haproxy.cfg in un editor da terminale direttamente sul server, come nano o vim. Modificalo sul posto piuttosto che su una workstation, così non ricaricherai mai un file diverso da quello che hai testato.

Il frontend

Un frontend può accettare sia HTTP semplice che HTTPS. Vincola la porta 80 per il reindirizzamento, vincola la porta 443 con il certificato e invia tutto il resto al backend:

frontend web_frontend
    mode http
    bind *:80
    bind *:443 ssl crt /etc/haproxy/certs/mydomain.pem alpn h2,http/1.1

    http-request redirect scheme https code 301 unless { ssl_fc }

    default_backend web_servers

alpn h2,http/1.1 offre HTTP/2 e ricade su HTTP/1.1. Il reindirizzamento scatta solo quando la richiesta non è arrivata tramite TLS, che è ciò che verifica ssl_fc, quindi le richieste sulla porta 443 passano direttamente.

Metti ogni opzione TLS su quell’unica riga bind

È qui che le configurazioni HAProxy sbagliano più spesso, e fallisce silenziosamente. Le guide presentano spesso l’hardening TLS come un secondo passo, mostrando una nuova riga bind per la porta 443 con opzioni aggiuntive. Se aggiungi quella riga invece di modificare quella esistente, finisci con due righe bind per la stessa porta, e HAProxy non si lamenta. Si avvia e apre due socket di ascolto separati sulla porta 443 con impostazioni TLS diverse. Su quale socket finisca una determinata connessione non è qualcosa che controlli, quindi il tuo hardening copre all’incirca metà del tuo traffico.

Nemmeno il controllo della configurazione lo rileva, e la sua stessa documentazione spiega il perché: -c “esegue solo un controllo dei file di configurazione ed esce prima di tentare il bind“. Un listener duplicato è una condizione che si verifica al momento del bind, quindi un controllo sintattico non lo vedrà mai.

Imposta invece delle impostazioni globali predefinite, così ogni riga bind nel file le eredita e non c’è nulla da duplicare:

global
    ssl-default-bind-options ssl-min-ver TLSv1.2 prefer-client-ciphers
    ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305
    ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256

Vale la pena sapere prima di copiare quel blocco ovunque: ssl-min-ver ha già come predefinito TLSv1.2, secondo le stesse parole di HAProxy. Impostarlo su TLSv1.2 non cambia nulla e documenta solamente l’intento, il che va bene, ma non è il miglioramento di sicurezza che viene spesso presentato come tale. Le due impostazioni di cifratura fanno un lavoro reale, e sono separate di proposito: ssl-default-bind-ciphers si applica a TLS 1.2 e versioni precedenti, ssl-default-bind-ciphersuites si applica a TLS 1.3. Imposta solo la prima e le tue suite TLS 1.3 rimarranno ai loro valori predefiniti.

Il backend

Assegna a ogni server un indirizzo reale. Questo conta più di quanto sembri:

backend web_servers
    mode http
    balance roundrobin
    option httpchk GET /
    server web1 10.0.0.11:80 check
    server web2 10.0.0.12:80 check

Una riga server scritta come server web1 :80 check, con l’indirizzo omesso, non genera un errore. HAProxy la accetta e risolve l’indirizzo mancante come 0.0.0.0, che il suo manuale tratta come un valore speciale che significa che la connessione viene inoltrata allo stesso indirizzo IP a cui si è connesso il client. Quell’indirizzo è HAProxy stesso, quindi il backend punta silenziosamente alla porta 80 di HAProxy stesso, che è il frontend che hai appena configurato. Il traffico torna in ciclo nel reindirizzamento invece di raggiungere qualsiasi applicazione, e i controlli sanitari risultano sani perché qualcosa è realmente in ascolto. Se un load balancer risponde a ogni richiesta HTTPS con un reindirizzamento verso se stesso, controlla prima le righe server.

Poiché HAProxy termina il TLS, i backend ricevono HTTP semplice sulla porta 80 e non hanno bisogno di un proprio certificato. Se la policy richiede la crittografia anche su quel tratto, aggiungi ssl verify required e un file CA alle righe server e puntale invece alla porta 443.

Passa lo schema originale al backend. Poiché il backend ora riceve HTTP semplice, un’applicazione che genera URL assoluti, come fanno WordPress, Django e Rails, le genererà con http://, il che emerge come contenuto misto o come un ciclo di reindirizzamento che l’applicazione stessa crea. Aggiungi una riga al frontend:

http-request set-header X-Forwarded-Proto https if { ssl_fc }

e una al backend, che passa anche l’indirizzo IP reale del client:

option forwardfor

La maggior parte dei framework deve poi essere istruita a fidarsi di quelle intestazioni; quella parte si configura nell’applicazione, non in HAProxy.

Controlla la configurazione prima di applicarla

Non riavviare mai un load balancer su un file non verificato. Convalida prima:

sudo haproxy -c -V -f /etc/haproxy/haproxy.cfg

Con -V stampa Configuration file is valid in caso di successo e restituisce stato di uscita zero. Senza di esso, il successo è silenzioso. Eventuali avvisi vengono segnalati indipendentemente dalla validità del file, quindi leggi l’output invece di fidarti dell’assenza di testo rosso.

Ricarica piuttosto che riavviare

sudo systemctl reload haproxy

La distinzione è reale su un load balancer. Una ricarica avvia un nuovo processo e segnala a quello vecchio di “finire ciò che stanno facendo e di uscire”, quindi le richieste già in transito si completano normalmente. Un riavvio segnala al vecchio processo di “terminare immediatamente senza finire ciò che stavano facendo”, il che interrompe le connessioni attive, inclusi upload e chiamate API di lunga durata. Usa il riavvio solo quando una ricarica non può recepire la modifica, come dopo aver alterato le impostazioni di processo della sezione globale.

Conferma che il servizio sia tornato attivo e sia in ascolto su entrambe le porte:

sudo systemctl status haproxy
sudo ss -tlnp | grep haproxy

Esattamente un socket in ascolto per porta è ciò che vuoi qui. Due sulla porta 443 significa che hai la riga bind duplicata descritta sopra.

Verifica che il certificato venga servito

Controlla cosa presenta effettivamente HAProxy, inclusa la catena, direttamente dal server:

openssl s_client -connect mydomain.com:443 -servername mydomain.com < /dev/null

Leggi la sezione Certificate chain in alto nell’output. Il tuo certificato dovrebbe apparire alla profondità 0 e l’intermedio alla profondità 1. Se la profondità 1 manca, l’intermedio non è mai arrivato nel file PEM, e il sito funzionerà in alcuni browser mentre fallirà in altri. Ignora la riga Verify return code quando valuti questo aspetto: riporta solo il verdetto della catena, e può risultare positiva in situazioni che non hanno nulla a che fare con ciò che stai testando.

Poi conferma dall’esterno, dove il risultato riflette ciò che ottengono i visitatori reali. Il nostro SSL Checker segnala il certificato, la catena e la data di scadenza.

Rinnovi e automazione

Sostituire il file PEM è l’intera procedura di rinnovo: ricostruiscilo dal nuovo certificato e dalla stessa chiave o da una nuova, poi ricarica. Nulla nella configurazione di HAProxy fa riferimento alla data di scadenza, quindi non è necessaria alcuna modifica alla configurazione fintanto che il percorso del file rimane lo stesso.

Con l’accorciarsi delle durate dei certificati, vale la pena impostare l’automazione fin da ora. HAProxy ha ottenuto un client ACME integrato nella versione 3.2, configurato tramite una sezione acme. Trattalo per ora come un’anteprima piuttosto che come infrastruttura di produzione: è ancora contrassegnato come sperimentale nella 3.4 e richiede expose-experimental-directives nella sezione globale, supporta solo i tipi di sfida http-01, dns-01 e dns-persist-01, e i certificati che genera devono essere estratti dal socket delle statistiche per arrivare sul disco. Il tipo dns-persist-01, aggiunto nella 3.4, usa un record TXT statico che viene impostato una volta e non cambia mai tra i rinnovi, quindi non richiede accesso in scrittura all’API del provider DNS a ogni rinnovo. L’alternativa consolidata è eseguire un client ACME esterno e far sì che il suo passo di deploy ricostruisca il file PEM e ricarichi HAProxy, che è lo stesso schema descritto nella nostra guida ACME per Apache e NGINX.

Domande frequenti

In che ordine vanno inseriti il certificato, la catena e la chiave nel file PEM?

Prima il tuo certificato, poi eventuali intermedi, poi la chiave privata. Il manuale di HAProxy descrive il file come costruito concatenando file PEM e afferma che l’intermedio può essere concatenato al suo interno. Se preferisci mantenere la chiave separata, omettila del tutto e salvala con lo stesso percorso con .key aggiunto, che HAProxy carica automaticamente.

Perché il mio sito HTTPS si reindirizza a se stesso in un ciclo?

Solitamente una riga server del backend senza indirizzo, come server web1 :80 check. HAProxy risolve l’indirizzo vuoto come 0.0.0.0, e quell’indirizzo significa che la connessione viene inoltrata allo stesso indirizzo IP a cui si è connesso il client, che è HAProxy stesso. Il backend quindi punta alla porta 80 di HAProxy stesso, che è il frontend che emette il reindirizzamento da HTTP a HTTPS. Assegna a ogni riga server un indirizzo IP o un nome host reale.

Posso avere due righe bind per la porta 443 nello stesso frontend?

Puoi, ed è proprio quello il problema. HAProxy non le unisce né avvisa, e haproxy -c passa il controllo perché esce prima di tentare il bind. Ottieni due socket in ascolto su una porta con qualunque opzione TLS diversa presente su ciascuna riga, quindi un’impostazione presente solo su una di esse si applica solo a una parte del tuo traffico. Mantieni una riga bind per porta e metti le impostazioni TLS condivise in ssl-default-bind-options.

Aggiungere ssl-min-ver TLSv1.2 rafforza qualcosa?

Non da solo. HAProxy documenta il valore predefinito di ssl-min-ver come già TLSv1.2, quindi impostarlo sullo stesso valore registra il tuo intento senza cambiare il comportamento. Il vero rafforzamento deriva dalle impostazioni di cifratura, e ricorda che TLS 1.3 richiede ssl-default-bind-ciphersuites mentre TLS 1.2 e versioni precedenti usano ssl-default-bind-ciphers.

I miei server backend hanno bisogno anch’essi di certificati?

Non nella configurazione standard. HAProxy termina il TLS ai margini e inoltra HTTP semplice, motivo per cui solo il load balancer detiene il certificato. Aggiungi ssl verify required con un file CA sulle righe server solo se la tua policy richiede che anche il tratto interno sia crittografato.

Come posso servire più domini da un’unica istanza HAProxy?

Punta crt verso una directory invece che verso un file. HAProxy carica ogni certificato al suo interno e sceglie quello giusto per ogni richiesta usando SNI, quindi una singola riga bind li copre tutti. Un certificato multi-dominio (SAN) è l’altra strada, e si adatta a un insieme di nomi che si rinnovano insieme.

Quale versione di HAProxy dovrei usare?

Il ramo 3.4, rilasciato a giugno 2026, è l’attuale versione a supporto a lungo termine ed è mantenuto fino al Q2 2031. I rami con numerazione pari di HAProxy sono quelli LTS, con circa cinque anni di manutenzione, mentre i rami con numerazione dispari come il 3.3 ricevono da 12 a 18 mesi. Tutto in questa guida si applica alla versione 3.0 e successive; solo il client ACME integrato richiede la 3.2 o successiva.

Se il certificato è installato ma i browser continuano a lamentarsi, le nostre guide agli errori SSL comuni coprono le cause abituali, il più delle volte una catena incompleta o un nome che il certificato non elenca.

Risparmia il 10% sui certificati SSL ordinando oggi stesso da SSL Dragon!

Emissione rapida, crittografia avanzata, affidabilità del browser al 99,99%, assistenza dedicata e garanzia di rimborso entro 25 giorni. Codice coupon: SAVE10

Un'immagine dettagliata di un drago in volo
Scritto da

Scrittore di contenuti con esperienza, specializzato in certificati SSL. Trasforma intricati argomenti di cybersicurezza in contenuti chiari e coinvolgenti. Contribuisci a migliorare la sicurezza digitale attraverso narrazioni d'impatto.

Avatar of Sergiu Rosca
Technical Review by Sergiu Rosca

Sergiu Rosca is the core web developer behind SSL Dragon. He manages the technical infrastructure, platform performance, and backend integrations that keep the site running smoothly and securely. At SSL Dragon, Sergiu shares practical insights on web development, site optimization, and technical troubleshooting.

All SSL Dragon installation guides are tested on live server environments and undergo a strict peer-review process to ensure your infrastructure remains secure. Read our full Editorial Policy.