Se gestisci server, scrivi script di automazione o distribuisci applicazioni in un'infrastruttura aziendale, prima o poi ti troverai di fronte alla necessità di instradare il traffico curl o wget attraverso un proxy. Questo può essere un proxy aziendale, un modo per aggirare le geo-restrizioni durante il download di pacchetti, o la rotazione degli IP durante richieste massicce a API esterne. In questo articolo, ci concentreremo solo sulla pratica: comandi, configurazioni, esempi di codice senza fronzoli.
1. Come curl e wget funzionano con i proxy: meccanismi di base
Prima di immergersi nelle configurazioni, è importante capire cosa succede sotto il cofano. Entrambi gli strumenti supportano due protocolli proxy principali: HTTP/HTTPS e SOCKS5. La meccanica è diversa e questo influisce su quale tipo di proxy scegliere per un compito specifico.
Proxy HTTP funziona come intermediario a livello di protocollo applicativo. Quando curl invia una richiesta attraverso un proxy HTTP, dice letteralmente al server proxy: "fai una richiesta GET a questo URL al posto mio". Per il traffico HTTPS viene utilizzato il metodo CONNECT: curl chiede al proxy di stabilire un tunnel verso l'host di destinazione, dopo di che il handshake TLS avviene direttamente tra il client e il server di destinazione. Questo è importante: in questo caso, il proxy non vede il contenuto del traffico HTTPS.
SOCKS5 opera a un livello più basso: instrada le connessioni TCP/UDP senza legarsi al protocollo di livello applicativo. Questo rende SOCKS5 più versatile: può instradare non solo HTTP/HTTPS, ma anche altri protocolli. Inoltre, SOCKS5 supporta la risoluzione DNS lato server proxy: questo è critico per prevenire perdite DNS.
💡 Differenza chiave per la pratica:
Se devi semplicemente scaricare un file o fare una richiesta API, un proxy HTTP è sufficiente. Se hai bisogno di completa anonimato, di aggirare le perdite DNS o di lavorare con protocolli non standard, utilizza SOCKS5.
curl supporta entrambi i protocolli nativamente sin dalle prime versioni. wget storicamente ha avuto un supporto più limitato per SOCKS5: nelle versioni precedenti (fino alla 1.19) non c'è affatto supporto per SOCKS5, solo per proxy HTTP. Questo deve essere considerato quando si scrivono script che devono funzionare su diverse distribuzioni.
Puoi controllare la versione di wget con il comando wget --version. Per curl, usa curl --version, lì potrai anche vedere con quali protocolli è stata compilata la libreria libcurl.
2. Variabili d'ambiente: il modo più veloce per configurare
Il modo più elegante per configurare un proxy per curl e wget è attraverso le variabili d'ambiente. Questo funziona a livello di sistema: non è necessario modificare ogni script, basta impostare le variabili una volta nella sessione o aggiungerle al profilo utente.
Entrambi gli strumenti leggono le stesse variabili standard:
# Per il traffico HTTP export http_proxy="http://proxy.example.com:3128" # Per il traffico HTTPS export https_proxy="http://proxy.example.com:3128" # Duplichiamo in maiuscolo (alcuni programmi leggono solo queste) export HTTP_PROXY="http://proxy.example.com:3128" export HTTPS_PROXY="http://proxy.example.com:3128" # Per FTP (se necessario) export ftp_proxy="http://proxy.example.com:3128" # Eccezioni — indirizzi che NON passano attraverso il proxy export no_proxy="localhost,127.0.0.1,::1,192.168.0.0/16,.internal.company.com"
Un aspetto importante: curl è sensibile al maiuscolo/minuscolo delle variabili a seconda della versione. Per evitare sorprese, imposta sempre entrambe le versioni: in minuscolo e maiuscolo. Questa è una pratica standard in DevOps.
Per applicare le impostazioni in modo permanente per un utente specifico, aggiungi le righe a ~/.bashrc o ~/.profile. Per script e servizi di sistema, usa /etc/environment o nel file unit di systemd tramite la direttiva Environment=.
# /etc/systemd/system/myservice.service
[Service]
Environment="http_proxy=http://proxy.example.com:3128"
Environment="https_proxy=http://proxy.example.com:3128"
Environment="no_proxy=localhost,127.0.0.1"
ExecStart=/usr/bin/myapp
Se il proxy richiede autenticazione, il nome utente e la password vengono inseriti direttamente nell'URL della variabile:
export http_proxy="http://username:[email protected]:3128" export https_proxy="http://username:[email protected]:3128"
⚠️ Sicurezza:
Non memorizzare le password in chiaro in .bashrc o nelle variabili d'ambiente sui server di produzione. Utilizza soluzioni di vault (HashiCorp Vault, AWS Secrets Manager) o almeno limita i diritti sul file delle variabili.
3. Flag curl per lavorare con i proxy: analisi completa
curl offre un ricco insieme di flag per gestire i proxy direttamente dalla riga di comando. Questo è utile quando è necessario fare una richiesta una tantum attraverso un proxy, senza modificare le impostazioni di sistema.
Il flag principale è -x o --proxy:
# Proxy HTTP di base curl -x http://proxy.example.com:3128 https://api.example.com/data # Forma breve curl -x proxy.example.com:3128 https://api.example.com/data # Con specifica del protocollo curl --proxy http://proxy.example.com:3128 https://api.example.com/data # Controllare l'IP esterno attraverso il proxy curl -x http://proxy.example.com:3128 https://api.ipify.org
Per ignorare le variabili d'ambiente e stabilire una connessione diretta (bypassando il proxy configurato), si utilizza il flag --noproxy:
# Ignorare il proxy per un host specifico curl --noproxy "internal.company.com" https://internal.company.com/api # Ignorare completamente il proxy (anche se sono impostate le variabili d'ambiente) curl --noproxy "*" https://api.example.com/data
Flag utili per il debugging delle connessioni proxy:
# Modalità verbose: mostra tutti gli header, incluso CONNECT al proxy curl -v -x http://proxy.example.com:3128 https://api.example.com/data # Solo gli header della risposta curl -I -x http://proxy.example.com:3128 https://api.example.com/data # Mostrare il tempo di connessione attraverso il proxy curl -w "Connect: %{time_connect}s\nTotal: %{time_total}s\n" \ -x http://proxy.example.com:3128 \ -o /dev/null -s https://api.example.com/data
Configurare il proxy tramite il file di configurazione ~/.curlrc è comodo se non si desidera specificare i flag ogni volta:
# ~/.curlrc
proxy = http://proxy.example.com:3128
proxy-user = username:password
noproxy = localhost,127.0.0.1,.internal.company.com
Per script di sistema, puoi creare un file di configurazione separato e specificarlo esplicitamente tramite curl -K /path/to/config — questo consente di avere profili proxy diversi per compiti diversi.
4. Configurazione del proxy in wget: flag e file di configurazione
wget è meno flessibile di curl, ma per compiti tipici — scaricare file, mirrorare siti in modo ricorsivo — le sue capacità sono più che sufficienti. Il proxy in wget può essere configurato in tre modi: tramite variabili d'ambiente (già trattate), tramite flag della riga di comando e tramite il file di configurazione ~/.wgetrc.
Flag della riga di comando wget per il proxy:
# Proxy HTTP tramite flag wget -e use_proxy=yes \ -e http_proxy=http://proxy.example.com:3128 \ https://example.com/file.tar.gz # HTTPS tramite proxy wget -e use_proxy=yes \ -e https_proxy=http://proxy.example.com:3128 \ https://example.com/file.tar.gz # Con autenticazione wget -e use_proxy=yes \ -e http_proxy=http://username:[email protected]:3128 \ https://example.com/file.tar.gz # Disabilitare il proxy per un comando specifico (se sono impostate le variabili d'ambiente) wget --no-proxy https://internal.company.com/file.tar.gz
Il file di configurazione ~/.wgetrc è il modo preferito per una configurazione permanente:
# ~/.wgetrc use_proxy = on http_proxy = http://proxy.example.com:3128 https_proxy = http://proxy.example.com:3128 ftp_proxy = http://proxy.example.com:3128 no_proxy = localhost,127.0.0.1,.internal.company.com # Se il proxy richiede autenticazione proxy_user = username proxy_password = secretpassword
Per applicazioni di sistema (tutti gli utenti) si utilizza /etc/wgetrc — lo stesso formato, ma applicato globalmente. Utile per server dove tutte le operazioni di download devono passare attraverso un proxy aziendale.
Esempio pratico: download ricorsivo di un sito tramite proxy con limitazione della profondità e della velocità:
wget -e use_proxy=yes \
-e http_proxy=http://proxy.example.com:3128 \
--recursive \
--level=2 \
--limit-rate=500k \
--wait=1 \
--random-wait \
--user-agent="Mozilla/5.0 (compatible; Googlebot/2.1)" \
https://example.com/docs/
5. Proxy SOCKS5 in curl e wget: configurazione ed esempi
SOCKS5 è un protocollo più preferibile per compiti in cui l'anonimato è importante o per lavorare con porte non standard. Per gli amministratori di sistema e gli ingegneri DevOps, SOCKS5 è spesso utilizzato quando si lavora attraverso tunnel SSH, così come quando ci si connette a proxy residenziali, che simulano il traffico di utenti reali.
In curl, SOCKS5 è supportato tramite un prefisso speciale nell'URL del proxy:
# SOCKS5 con risoluzione DNS lato client (potenziale perdita DNS!) curl --socks5 proxy.example.com:1080 https://api.example.com/data # SOCKS5 con risoluzione DNS lato proxy (consigliato!) curl --socks5-hostname proxy.example.com:1080 https://api.example.com/data # Tramite flag -x con specifica del protocollo curl -x socks5h://proxy.example.com:1080 https://api.example.com/data # Con autenticazione curl -x socks5h://username:[email protected]:1080 https://api.example.com/data # SOCKS5 tramite variabile d'ambiente export all_proxy="socks5h://proxy.example.com:1080" curl https://api.example.com/data
📌 socks5 vs socks5h — qual è la differenza?
socks5 — la richiesta DNS viene eseguita localmente, attraverso il proxy passa solo la connessione TCP per IP. Possibile perdita DNS.socks5h (h = hostname) — la richiesta DNS viene eseguita sul server proxy. Massima anonimato. Consigliato per la maggior parte dei compiti.
Uno scenario popolare in DevOps è l'uso di SSH come proxy SOCKS5 per tunnelare il traffico attraverso un bastion host:
# Apriamo un tunnel SSH con SOCKS5 sulla porta locale 1080 ssh -D 1080 -f -C -q -N [email protected] # Ora utilizziamo questo tunnel in curl curl -x socks5h://localhost:1080 https://internal-api.private.network/data # Oppure tramite variabile d'ambiente per tutte le richieste nella sessione export all_proxy="socks5h://localhost:1080" wget https://internal-resource.private.network/file.tar.gz
wget supporta SOCKS5 a partire dalla versione 1.19. Nelle versioni più vecchie (CentOS 7, Ubuntu 16.04) sarà necessario utilizzare soluzioni alternative: proxychains, tsocks, o passare a curl per compiti che richiedono SOCKS5.
6. Autenticazione sul proxy: login e password
La maggior parte dei proxy commerciali e dei server proxy aziendali richiede autenticazione. Ci sono diversi modi per trasmettere le credenziali, ognuno con i propri vantaggi e svantaggi in termini di sicurezza.
Metodo 1: Credenziali nell'URL — semplice, ma non sicuro (la password è visibile nell'elenco dei processi):
curl -x http://user:p%[email protected]:3128 https://api.example.com/data # I caratteri speciali nella password devono essere URL-encoded: @ → %40, : → %3A
Metodo 2: Flag --proxy-user in curl — la password non deve essere specificata nella riga di comando, curl la richiederà interattivamente:
# Login e password nel flag (ancora visibili in ps aux) curl -x http://proxy.example.com:3128 \ --proxy-user "username:password" \ https://api.example.com/data # Solo login — curl chiederà la password interattivamente curl -x http://proxy.example.com:3128 \ --proxy-user "username" \ https://api.example.com/data
Metodo 3: Tramite file .netrc — il più sicuro per gli script:
# ~/.netrc machine proxy.example.com login username password secretpassword # Limitiamo i diritti di accesso al file chmod 600 ~/.netrc # Utilizziamo in curl curl -x http://proxy.example.com:3128 --proxy-netrc https://api.example.com/data
Metodo 4: Tramite variabili d'ambiente da un vault segreto — consigliato per CI/CD e ambienti di produzione:
# Nello script leggiamo le credenziali dalle variabili (impostate da CI/CD)
#!/bin/bash
PROXY_URL="http://${PROXY_USER}:${PROXY_PASS}@proxy.example.com:3128"
curl -x "${PROXY_URL}" https://api.example.com/data
Tabella di confronto dei metodi di autenticazione:
| Metodo | Comodità | Sicurezza | Adatto per |
|---|---|---|---|
| URL (user:pass@host) | ⭐⭐⭐ | ⭐ | Test |
| Flag --proxy-user | ⭐⭐⭐ | ⭐⭐ | Comandi singoli |
| File .netrc | ⭐⭐ | ⭐⭐⭐ | Script locali |
| Variabili d'ambiente da vault | ⭐⭐ | ⭐⭐⭐⭐⭐ | CI/CD, produzione |
7. Eccezioni e no_proxy: come aggirare il proxy per indirizzi locali
Negli ambienti aziendali e cloud, è spesso necessaria una configurazione fine: il traffico esterno — tramite proxy, interno — direttamente. La variabile no_proxy (o NO_PROXY) consente di specificare un elenco di eccezioni.
# Eccezioni di base export no_proxy="localhost,127.0.0.1,::1" # Eccezione per dominio (con punto — tutti i sottodomini) export no_proxy="localhost,127.0.0.1,.internal.company.com,.corp.local" # Eccezione per intervallo IP (la notazione CIDR non funziona ovunque!) export no_proxy="localhost,127.0.0.1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16" # Per AWS: escludiamo l'endpoint dei metadati e gli indirizzi interni export no_proxy="localhost,127.0.0.1,169.254.169.254,.amazonaws.com.internal"
⚠️ Importante caratteristica di no_proxy:
La notazione CIDR (10.0.0.0/8) non è supportata da tutti gli strumenti. curl la supporta a partire dalla versione 7.86.0. wget — non la supporta affatto. Per compatibilità, è meglio elencare IP specifici o maschere come 10. (tutto ciò che inizia con 10.).
Esempio pratico per un ambiente Kubernetes, dove è necessario escludere l'API server e i servizi interni:
export no_proxy="localhost,127.0.0.1,10.96.0.0/12,10.244.0.0/16,.cluster.local,.svc,.default"
export NO_PROXY="${no_proxy}"
8. Proxy in CI/CD: GitHub Actions, GitLab CI, Docker
Configurare il proxy nei pipeline CI/CD è uno dei compiti più comuni per gli ingegneri DevOps che lavorano in reti aziendali o con accesso limitato a Internet. Esaminiamo configurazioni specifiche per piattaforme popolari.
GitHub Actions
# .github/workflows/deploy.yml
name: Deploy
on: [push]
jobs:
deploy:
runs-on: ubuntu-latest
env:
http_proxy: ${{ secrets.PROXY_URL }}
https_proxy: ${{ secrets.PROXY_URL }}
no_proxy: "localhost,127.0.0.1,.github.com"
steps:
- uses: actions/checkout@v3
- name: Download dependencies
run: |
curl -x "${http_proxy}" https://external-api.example.com/config.json -o config.json
wget -e use_proxy=yes -e http_proxy="${http_proxy}" https://releases.example.com/app-v1.0.tar.gz
GitLab CI
# .gitlab-ci.yml
variables:
http_proxy: "http://proxy.company.com:3128"
https_proxy: "http://proxy.company.com:3128"
no_proxy: "localhost,127.0.0.1,.gitlab.company.com"
build:
stage: build
script:
- curl -x "${http_proxy}" https://registry.npmjs.org/package -o package.json
- wget -e use_proxy=yes -e http_proxy="${http_proxy}" https://example.com/resource.tar.gz
Docker: proxy durante la costruzione delle immagini
# Passaggio del proxy tramite argomenti di build docker build \ --build-arg http_proxy=http://proxy.example.com:3128 \ --build-arg https_proxy=http://proxy.example.com:3128 \ --build-arg no_proxy=localhost,127.0.0.1 \ -t myapp:latest . # Nel Dockerfile utilizziamo ARG per ottenere le variabili
# Dockerfile FROM ubuntu:22.04 ARG http_proxy ARG https_proxy ARG no_proxy ENV http_proxy=${http_proxy} ENV https_proxy=${https_proxy} ENV no_proxy=${no_proxy} RUN apt-get update && apt-get install -y curl wget RUN curl -x "${http_proxy}" https://example.com/setup.sh | bash # Pulisci le variabili proxy nell'immagine finale (opzionale) ENV http_proxy="" ENV https_proxy=""
Impostazione globale del proxy per il daemon Docker (per docker pull tramite proxy):
# /etc/systemd/system/docker.service.d/proxy.conf [Service] Environment="HTTP_PROXY=http://proxy.example.com:3128" Environment="HTTPS_PROXY=http://proxy.example.com:3128" Environment="NO_PROXY=localhost,127.0.0.1,.internal.registry.com" # Riavvia Docker systemctl daemon-reload systemctl restart docker
9. Rotazione dei proxy negli script bash
Se hai bisogno di fare un gran numero di richieste a API o servizi esterni, la rotazione dei proxy consente di distribuire il carico e evitare blocchi per IP. Questo è particolarmente rilevante durante il monitoraggio dei prezzi, la raccolta di dati o il testing della disponibilità delle risorse da diverse regioni.
Per tali compiti, i proxy di data center sono molto adatti: offrono alta velocità e stabilità durante richieste massicce.
#!/bin/bash # rotate_proxy.sh — rotazione dei proxy da una lista PROXY_LIST=( "http://user:[email protected]:3128" "http://user:[email protected]:3128" "http://user:[email protected]:3128" "http://user:[email protected]:3128" ) URLS_FILE="urls.txt" OUTPUT_DIR="./results" mkdir -p "${OUTPUT_DIR}" PROXY_COUNT=${#PROXY_LIST[@]} INDEX=0 while IFS= read -r url; do PROXY="${PROXY_LIST[$INDEX]}" FILENAME=$(echo "${url}" | md5sum | cut -d' ' -f1) echo "Richiesta: ${url} tramite proxy $((INDEX + 1))/${PROXY_COUNT}" curl -x "${PROXY}" \ --max-time 30 \ --retry 3 \ --retry-delay 2 \ --silent \ --output "${OUTPUT_DIR}/${FILENAME}.html" \ "${url}" if [ $? -eq 0 ]; then echo " ✓ Successo" else echo " ✗ Fallito, provando il prossimo proxy..." INDEX=$(( (INDEX + 1) % PROXY_COUNT )) curl -x "${PROXY_LIST[$INDEX]}" \ --max-time 30 \ --silent \ --output "${OUTPUT_DIR}/${FILENAME}.html" \ "${url}" fi # Passiamo al prossimo proxy INDEX=$(( (INDEX + 1) % PROXY_COUNT )) # Piccola pausa tra le richieste sleep 0.5 done < "${URLS_FILE}" echo "Fatto! Risultati salvati in ${OUTPUT_DIR}"
Una versione più avanzata — controllare la funzionalità del proxy prima dell'uso:
#!/bin/bash # check_proxy.sh — verifica la disponibilità del proxy check_proxy() { local proxy_url="$1" local test_url="https://api.ipify.org" result=$(curl -x "${proxy_url}" \ --max-time 10 \ --silent \ --write-out "%{http_code}" \ --output /dev/null \ "${test_url}") if [ "${result}" -eq 200 ]; then echo "VIVO" else echo "MORTO" fi } # Otteniamo l'IP esterno tramite il proxy get_proxy_ip() { local proxy_url="$1" curl -x "${proxy_url}" --max-time 10 --silent https://api.ipify.org } PROXY="http://user:[email protected]:3128" STATUS=$(check_proxy "${PROXY}") echo "Stato del proxy: ${STATUS}" if [ "${STATUS}" == "VIVO" ]; then EXTERNAL_IP=$(get_proxy_ip "${PROXY}") echo "IP esterno tramite proxy: ${EXTERNAL_IP}" fi
10. Debugging e errori comuni
Lavorare con i proxy comporta inevitabilmente errori — soprattutto durante la configurazione iniziale. Esaminiamo i problemi più comuni e i modi per diagnosticarli.
Diagnostica tramite modalità verbose
# Output dettagliato di curl curl -vvv -x http://proxy.example.com:3128 https://api.example.com/data 2>&1 | head -50 # Cosa osservare nell'output: # * Connesso a proxy.example.com — connessione al proxy stabilita # CONNECT api.example.com:443 — richiesta di tunnel # HTTP/1.1 200 Connection established — tunnel aperto # * SSL connection using TLS — TLS funziona # Debugging wget wget -d -e use_proxy=yes -e http_proxy=http://proxy.example.com:3128 https://api.example.com/data
Errori comuni e soluzioni
| Errore | Causa | Soluzione |
|---|---|---|
407 Proxy Authentication Required |
Credenziali non fornite | Aggiungere user:pass nell'URL del proxy o flag --proxy-user |
Connection refused |
Porta errata o proxy non disponibile | Controllare la porta: nc -zv proxy.host 3128 |
SSL certificate error |
Proxy aziendale con ispezione SSL | Aggiungere il CA aziendale: --cacert /path/to/ca.crt |
Could not resolve proxy |
DNS non risolve il nome del proxy | Utilizzare l'IP invece del nome o controllare il DNS |
Timeout |
Proxy lento o sovraccarico | Aumentare il timeout: --max-time 60 |