curl permette di fare dal terminale ciò che di solito fa un browser: chiedere una pagina a un server, scaricare un file, inviare dati a un servizio. Serve a controllare se un sito risponde, a provare un'API, a verificare un reindirizzamento o un certificato, e a scaricare file negli script.
Cos'è
curl sta per client URL: un programma "cliente" che lavora a partire da un indirizzo (URL). È un progetto libero, in costante sviluppo da oltre vent'anni, e la sua libreria libcurl è usata da moltissimi altri programmi. Oltre a HTTP e HTTPS parla altri protocolli (FTP, SFTP, SCP, SMTP e molti altri), ma nell'uso quotidiano si tratta quasi sempre di web. Su Debian e Ubuntu è nel pacchetto curl, che nelle installazioni minime può mancare: sudo apt install curl.
Prima di cominciare: richiesta e risposta HTTP
Per usare bene curl serve un'idea di come dialoga il web. Il client invia una richiesta, il server restituisce una risposta composta da:
- un codice di stato numerico, che dice com'è andata;
- delle intestazioni (headers), informazioni sulla risposta: tipo di contenuto, data, server, eventuali reindirizzamenti;
- il corpo (body), cioè il contenuto vero e proprio: la pagina HTML, un file, dei dati JSON.
| Codice | Significato |
|---|---|
200 | Tutto bene |
301, 302 | Reindirizzamento permanente o temporaneo: il contenuto è altrove (campo Location) |
304 | Non modificato (contenuto già in cache) |
401, 403 | Serve autenticazione / accesso vietato |
404 | Non trovato |
429 | Troppe richieste |
500, 502, 503 | Errore del server / del servizio a monte / servizio non disponibile |
Cosa fa
Invia la richiesta all'indirizzo indicato e stampa il corpo della risposta sullo standard output, cioè a schermo. Non salva nulla su disco a meno che tu non lo chieda con -o o -O. Non segue i reindirizzamenti, non esegue JavaScript e non mostra le intestazioni, se non glielo chiedi.
Come si usa
$ curl [opzioni] URLGli indirizzi negli esempi (example.org, miosito.example) sono d'esempio: sostituiscili con i tuoi. Un consiglio per tutto l'articolo: scrivi gli URL tra virgolette, perché caratteri come &, ? e [ hanno un significato per la shell.
Esempio 1: leggere una pagina
$ curl https://example.org | head -n 5
<!doctype html>
<html>
<head>
<title>Example Domain</title>
...Il corpo della risposta (qui l'HTML della pagina) arriva sullo standard output, e quindi si può passare ad altri comandi con la pipe, come head, grep o wc.
Esempio 2: salvare in un file con -o e -O
$ curl -o pagina.html https://example.org
$ curl -O https://example.org/archivio.tar.gz
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 2048k 100 2048k 0 0 5120k 0 --:--:-- --:--:-- --:--:-- 5120kCon -o nome scegli tu il nome del file; con -O (maiuscola) usa il nome presente nell'indirizzo, come archivio.tar.gz. La tabella è l'indicatore di avanzamento, che compare solo quando l'output non va a schermo. Un archivio scaricato così si può poi estrarre con tar.
Esempio 3: seguire i reindirizzamenti con -L
$ curl http://miosito.example
<html><head><title>301 Moved Permanently</title>...
$ curl -L http://miosito.exampleMolti siti rispondono con un reindirizzamento (per esempio da http a https, o dal vecchio al nuovo indirizzo). Senza -L (location) curl si ferma e ti mostra la pagina del reindirizzamento. Con -L lo segue fino alla destinazione finale.
Esempio 4: vedere solo le intestazioni con -I
$ curl -I https://example.org
HTTP/2 200
date: Sun, 18 Oct 2026 04:35:12 GMT
content-type: text/html; charset=UTF-8
content-length: 1256
server: nginxCon -I (maiuscola) curl invia una richiesta di tipo HEAD e mostra solo codice di stato e intestazioni, senza scaricare il corpo. È il modo più rapido per controllare che un sito risponda. Con -i (minuscola) vengono mostrate le intestazioni e il corpo.
Esempio 5: controllare un reindirizzamento (per esempio dopo una migrazione)
$ curl -sIL http://vecchio.example | grep -iE '^(HTTP|location)'
HTTP/1.1 301 Moved Permanently
Location: https://www.nuovo.example/
HTTP/2 200Con -s (silenzioso) si toglie l'indicatore di avanzamento, con -IL si seguono i reindirizzamenti mostrando solo le intestazioni, e grep tiene soltanto le righe del codice di stato e della destinazione. È utile, per esempio, per verificare che i reindirizzamenti 301 dopo il cambio di dominio di un sito siano quelli attesi.
Esempio 6: solo il codice di stato e i tempi con -w
$ curl -s -o /dev/null -w "%{http_code}\n" https://example.org
200
$ curl -s -o /dev/null -w "codice: %{http_code}\ntempo totale: %{time_total}s\n" https://example.org
codice: 200
tempo totale: 0.231542sCon -o /dev/null si scarta il corpo, e con -w (write-out) si stampa un messaggio personalizzato con variabili tra %{...}. Le più utili: http_code (il codice), time_total (durata complessiva), time_namelookup (tempo del DNS), time_connect (tempo per collegarsi), time_starttransfer (attesa del primo byte), size_download (byte ricevuti) e, con -L, url_effective (indirizzo finale dopo i reindirizzamenti).
Esempio 7: nessun rumore, ma gli errori sì: -sS e -f
$ curl -sS https://example.org/inesistente
<html><head><title>404 Not Found</title>...
$ curl -sSf https://example.org/inesistente
curl: (22) The requested URL returned error: 404Con -s curl tace anche in caso di errore; aggiungendo -S mostra almeno i messaggi d'errore. Con -f (fail), in caso di errore HTTP (404, 500...) non stampa il corpo e restituisce un codice di uscita diverso da zero. Senza -f, un 404 per curl è comunque una risposta ricevuta con successo, e il codice di uscita sarà 0. La combinazione -sSf è quella da usare negli script.
Esempio 8: inviare dati di un modulo con -d
$ curl -d "nome=Enzo&citta=Salerno" https://miosito.example/iscrizione
$ curl --data-urlencode "messaggio=Ciao, città!" https://miosito.example/iscrizioneCon -d curl invia i dati nel corpo di una richiesta POST, come farebbe un modulo web (codifica application/x-www-form-urlencoded). Non serve aggiungere -X POST: -d lo implica già. Per testo con spazi o caratteri speciali si usa --data-urlencode, che li codifica correttamente.
Esempio 9: inviare e ricevere JSON
$ curl -s -X POST https://miosito.example/api/messaggi \
-H "Content-Type: application/json" \
-d '{"titolo": "Prova", "testo": "Ciao dal terminale"}'
$ curl -s -d @messaggio.json -H "Content-Type: application/json" https://miosito.example/api/messaggiPer le API bisogna dire al server che i dati sono in formato JSON, con l'intestazione Content-Type impostata con -H. I dati si scrivono tra apici singoli, in modo che le virgolette interne non vengano toccate dalla shell, oppure si leggono da un file con @nomefile. Lo stesso schema serve a provare un webhook di uno strumento di automazione come n8n: curl -X POST URL_DEL_WEBHOOK -H "Content-Type: application/json" -d '{"prova": true}'. L'opzione -X serve quando il metodo non è GET né POST: -X PUT, -X PATCH, -X DELETE.
Esempio 10: leggere i dati di un'API
$ curl -s "https://miosito.example/jsonapi/node/article?page[limit]=3" -g \
-H "Accept: application/vnd.api+json" | head -c 300Con -H "Accept: ..." si chiede al servizio il formato desiderato. L'opzione -g (globoff) è qui indispensabile: curl interpreta le parentesi quadre come un intervallo da espandere (vedi più avanti), e il parametro page[limit]=3, tipico di API come JSON:API di Drupal, darebbe un errore. Per leggere comodamente il risultato si può passare l'output a jq (sudo apt install jq), che lo formatta e permette di estrarre singoli campi.
Esempio 11: autenticazione e intestazioni
$ curl -u enzo https://miosito.example/area-riservata
Enter host password for user 'enzo':
$ curl -H "Authorization: Bearer $TOKEN" https://miosito.example/api/dati
$ curl -A "Mozilla/5.0" -e "https://miosito.example/" https://miosito.example/paginaCon -u utente si usa l'autenticazione di base: se non scrivi la password, curl la chiede, ed è la forma da preferire. Molte API usano un token, inviato nell'intestazione Authorization; qui è preso da una variabile d'ambiente. Con -A si imposta l'identificativo del programma (User-Agent) e con -e la pagina di provenienza (Referer).
Esempio 12: caricare un file
$ curl -F "file=@foto.jpg" -F "descrizione=Tramonto a Salerno" https://miosito.example/carica
$ curl -T backup.tar.gz https://miosito.example/archivio/backup.tar.gzCon -F si invia un modulo con allegati (multipart, come il pulsante "scegli file" di una pagina web), indicando i file con @. Con -T si carica un file con una richiesta PUT sul percorso indicato, se il server lo prevede.
Esempio 13: scaricare più file e gli intervalli
$ curl -O https://example.org/a.pdf -O https://example.org/b.pdf
$ curl -O "https://example.org/foto[1-3].jpg"
$ curl -O "https://example.org/{doc,note}.txt"Si possono indicare più indirizzi, ciascuno con il suo -O. curl sa anche espandere da solo intervalli tra parentesi quadre ([1-3] scarica foto1.jpg, foto2.jpg e foto3.jpg) ed elenchi tra graffe ({doc,note}), e per questo l'indirizzo va messo tra virgolette, altrimenti la shell interverrebbe prima.
Esempio 14: download robusti: tentativi, tempi e ripresa
$ curl -fL --retry 3 --connect-timeout 5 -m 60 -O https://example.org/grande.iso
$ curl -C - -O https://example.org/grande.iso
$ curl --limit-rate 1m -O https://example.org/grande.isoCon --retry 3 in caso di errori temporanei curl riprova fino a tre volte; --connect-timeout 5 rinuncia se non riesce a collegarsi entro 5 secondi; -m 60 (max-time) interrompe tutto dopo 60 secondi. Se un download si interrompe, -C - lo riprende da dove era arrivato. Con --limit-rate si limita la velocità, per non saturare la connessione.
Esempio 15: provare un server prima di cambiare il DNS
$ curl -I --resolve miosito.example:443:203.0.113.10 https://miosito.example
$ curl -I -H "Host: miosito.example" http://203.0.113.10Con --resolve nome:porta:indirizzo si dice a curl di usare un indirizzo scelto da te per quel nome, ignorando il DNS. Così, durante una migrazione, puoi verificare che il nuovo server risponda correttamente (certificato compreso) prima di spostare il dominio. La seconda forma invia la richiesta all'indirizzo IP specificando a mano il nome del sito, ma non funziona con HTTPS, perché il certificato verrebbe controllato sull'indirizzo e non sul nome.
Esempio 16: controllare la scadenza del certificato
$ curl -vI https://example.org 2>&1 | grep -E 'subject:|expire date:'
* subject: CN=example.org
* expire date: Nov 20 23:59:59 2026 GMTCon -v (verbose) curl mostra tutti i dettagli della comunicazione, comprese le informazioni sul certificato, e le invia al canale degli errori. Per questo serve 2>&1 prima di passare il tutto a grep. Un controllo veloce per non farsi sorprendere da un certificato scaduto.
Esempio 17: copiare una richiesta dal browser
Nel browser, apri gli strumenti per sviluppatori (F12), scheda "Rete", clicca col tasto destro su una richiesta e scegli Copia come cURL. Ottieni il comando completo di intestazioni e dati, che puoi incollare nel terminale e rieseguire: è il modo più rapido per riprodurre e analizzare ciò che fa una pagina.
Esempio 18: il tuo indirizzo IP pubblico
$ curl -s https://ifconfig.me
203.0.113.25Servizi come questo rispondono con l'indirizzo da cui arriva la richiesta. Sei però comunque in contatto con un servizio esterno: usalo con questa consapevolezza.
Esempio 19: uso negli script
#!/bin/bash
URL="${1:?Indica l'indirizzo da controllare}"
CODICE=$(curl -s -o /dev/null -m 10 -w "%{http_code}" "$URL")
if [ "$CODICE" = "200" ]; then
echo "OK: $URL risponde (200)"
else
echo "PROBLEMA: $URL ha risposto con codice $CODICE" >&2
exit 1
fiSe non riesce nemmeno a collegarsi (sito spento, DNS che non risponde), curl restituisce come codice 000. Lo script si può eseguire a intervalli regolari per sorvegliare un sito.
Un altro uso tipico è lo scaricamento di un file con controlli:
if curl -fsSL --retry 3 -o "$HOME/aggiornamento.tar.gz" "https://example.org/aggiornamento.tar.gz"; then
echo "Scaricato"
else
echo "Download fallito" >&2
exit 1
fiOpzioni utili
-o file/-O: salva in un file con un nome scelto / con il nome presente nell'indirizzo (-OJusa il nome indicato dal server).-L: segue i reindirizzamenti.-I: solo le intestazioni;-i: intestazioni e corpo;-v: dettagli completi della comunicazione.-s/-S: silenzioso / mostra comunque gli errori.-f: considera un errore le risposte 4xx e 5xx.-w formato: stampa informazioni sulla richiesta (codice, tempi, dimensioni).-d dati/--data-urlencode/-F campo=valore: invia dati (modulo, dati codificati, modulo con file).-X metodo: sceglie il metodo HTTP (PUT,DELETE...).-H "Intestazione: valore": aggiunge un'intestazione.-u utente: autenticazione di base;-A: User-Agent;-e: Referer.-b/-c file: invia / salva i cookie.-m secondi: durata massima;--connect-timeout: attesa massima per collegarsi;--retry N: tentativi.-C -: riprende un download interrotto;--limit-rate: limita la velocità.-g: disattiva l'espansione di[]e{}negli indirizzi.--resolve nome:porta:ip: forza l'indirizzo di un nome.-4/-6: forza IPv4 o IPv6.
Attenzione a
- Gli URL vanno tra virgolette:
curl https://example.org/pagina?a=1&b=2senza virgolette viene interpretato dalla shell, che con la&manda il comando in secondo piano e ignora il resto. - Per default non si seguono i reindirizzamenti: se ottieni una pagina strana o vuota, prova con
-L(o guarda il codice con-I). - Un 404 non è un errore, senza
-f: il codice di uscita è 0 e il corpo stampato è la pagina d'errore. Con-fil codice di uscita è 22. - Codici di uscita utili nei controlli:
0tutto bene,6nome non risolto (DNS),7collegamento rifiutato o impossibile,22errore HTTP (con-f),28tempo scaduto,35e60problemi con il certificato o la connessione cifrata. - Non disattivare i controlli di sicurezza: l'opzione
-k(--insecure) ignora gli errori di certificato e rende la connessione vulnerabile a intercettazioni. Serve al massimo per una prova su una macchina tua; per risolvere un errore di certificato, meglio capirne la causa (scaduto, nome sbagliato, catena incompleta). - I segreti sulla riga di comando:
-u utente:passworde i token scritti per esteso restano nella cronologia dei comandi (history) e sono visibili nell'elenco dei processi mentre il comando gira. Meglio far chiedere la password acurl, usare una variabile letta da un file protetto, o il file~/.netrccon l'opzione-n. - Non eseguire quello che scarichi senza leggerlo: istruzioni come
curl -fsSL URL | sh(o peggio| sudo bash) eseguono sul tuo computer uno script mai visto. Scaricalo in un file, leggilo e solo dopo eseguilo. - Con
-de un file:-d @filetoglie gli a capo dal contenuto. Per inviare un file così com'è (JSON formattato, dati binari) usa--data-binary @file. -X POSTsuperfluo: con-do-Fil metodo è già POST. Forzare un metodo diverso con-Xsenza che serva può causare comportamenti inattesi con i reindirizzamenti.- Contenuto binario a schermo: se per sbaglio scrivi un archivio o un'immagine sul terminale,
curlsi rifiuta e avvisa. Se il terminale si riempie di simboli, scrivireset. - Non esegue JavaScript: le pagine che si costruiscono nel browser possono risultare quasi vuote. Spesso i dati arrivano da un'API che si può interrogare direttamente (la scheda "Rete" del browser la rivela).
- L'indicatore di avanzamento nei registri: se redirigi l'output di
curlin un file di registro, l'indicatore di avanzamento finisce nei messaggi di errore. Usa-s(con-Sper gli errori). - Rispetto per i servizi altrui: non inviare richieste a raffica a siti che non gestisci, rispetta i limiti e i termini d'uso, e identificati con un
User-Agentchiaro quando automatizzi. - Proxy:
curlusa le variabili d'ambientehttp_proxyehttps_proxy. Se le risposte sembrano strane, controllale;--noproxy '*'le ignora. curlowget?curlè il più versatile per interrogare servizi e API e per gli script;wgetè più comodo per scaricare interi siti o cartelle in modo ricorsivo.
Riepilogo
| Comando | Cosa fa |
|---|---|
curl URL | Stampa a schermo il corpo della risposta |
curl -O URL | Scarica il file con il suo nome |
curl -o nome URL | Scarica con un nome scelto |
curl -L URL | Segue i reindirizzamenti |
curl -I URL | Solo le intestazioni (codice di stato incluso) |
curl -sIL URL | grep -iE '^(HTTP|location)' | Mostra la catena dei reindirizzamenti |
curl -s -o /dev/null -w "%{http_code}" URL | Solo il codice di stato |
curl -sSf URL | Silenzioso ma con errori, fallisce sugli errori HTTP |
curl -d "a=1&b=2" URL | Invia dati di un modulo (POST) |
curl -H "Content-Type: application/json" -d '{…}' URL | Invia JSON |
curl -F "file=@foto.jpg" URL | Carica un file |
curl -u utente URL | Autenticazione con password chiesta in modo riservato |
curl -C - -O URL | Riprende un download interrotto |
curl --resolve nome:443:IP URL | Prova un server prima di cambiare il DNS |
curl -vI URL 2>&1 | grep 'expire date' | Controlla la scadenza del certificato |