Proxy Client con Tinyproxy

Guida tecnica completa alla configurazione di un proxy client locale su Linux (Zorin OS/Ubuntu 24.04) per forzare tutto il traffico TCP attraverso un proxy HTTP trasparente. La guida copre l'installazione e configurazione di tinyproxy, dante (SOCKS5) e redsocks, la gestione delle regole iptables per evitare loop di reindirizzamento, la persistenza tramite systemd, i limiti del setup rispetto a DNS/UDP/QUIC e il confronto con le VPN, con indicazioni di hardening e troubleshooting.

Immagine generata con IA
Immagine generata con IA
Riassunto generato automaticamente tramite intelligenza artificiale:

Questo articolo descrive come configurare un proxy client HTTP trasparente su Linux utilizzando tinyproxy, redsocks e iptables per incanalare tutto il traffico TCP locale attraverso il proxy. L'architettura proposta permette il controllo centralizzato del traffico di rete per scopi di filtraggio, logging e debugging.

Proxy client con tinyproxy

Questa guida descrive la configurazione di un proxy client locale su Linux (Ubuntu 24.04) in grado di forzare tutto il traffico TCP generato dal sistema attraverso un proxy HTTP trasparente. L'obiettivo è ottenere un controllo centralizzato del traffico in uscita, utile per scenari di filtraggio, logging, debugging applicativo o instradamento verso un proxy remoto.

L'architettura si basa sulla combinazione di quattro componenti, ciascuno con un ruolo ben definito:

Applicazione → iptables (REDIRECT) → redsocks → tinyproxy → Internet
                                    ↘ danted (SOCKS5) → Internet (opzionale)
Componente Porta Protocollo Ruolo
tinyproxy 3128 HTTP proxy Proxy finale che si connette a Internet
danted 1080 SOCKS5 Proxy SOCKS per connessioni esplicite
redsocks 12345 http-connect Ponte trasparente tra iptables e tinyproxy
iptables OUTPUT / PREROUTING REDIRECT Forza tutto il traffico TCP locale verso redsocks

È importante avere chiaro fin da subito un punto: questo schema opera esclusivamente a livello di trasporto (TCP). Le implicazioni di questa scelta architetturale (DNS, UDP, QUIC) sono trattate in una sezione dedicata più avanti, ma vanno tenute presenti durante tutta la configurazione.

Prerequisiti

Per seguire questa guida è necessario disporre di:

  • Una distribuzione Linux basata su Debian/Ubuntu (Ubuntu 24.04)
  • Accesso sudo
  • Una connessione Internet attiva e funzionante

Installazione dei pacchetti necessari

Tutti i componenti richiesti sono disponibili nei repository ufficiali:

sudo apt install -y tinyproxy dante-server redsocks iptables-persistent

Configurazione di tinyproxy

Il file di configurazione di riferimento è /etc/tinyproxy/tinyproxy.conf. Le modifiche necessarie sono riassunte nella tabella seguente.

Direttiva Valore Descrizione
Port 3128 Porta di ascolto del proxy
Listen 127.0.0.1 Ascolta solo su localhost, non esposto in rete
ConnectPort tutte le righe commentate Permette il metodo CONNECT su qualsiasi porta
MaxClients 1000 Aumentato per gestire un carico più elevato di connessioni

Le modifiche possono essere applicate rapidamente tramite sed:

sudo sed -i 's/^Port 8888$/Port 3128/' /etc/tinyproxy/tinyproxy.conf
sudo sed -i 's/^#Listen 192.168.0.1$/Listen 127.0.0.1/' /etc/tinyproxy/tinyproxy.conf
sudo sed -i 's/^ConnectPort/#ConnectPort/g' /etc/tinyproxy/tinyproxy.conf
sudo sed -i 's/^MaxClients 100$/MaxClients 1000/' /etc/tinyproxy/tinyproxy.conf

Va sottolineato che rimuovere le restrizioni su ConnectPort è accettabile solo perché il servizio resta vincolato a 127.0.0.1: in un'implementazione esposta a una rete più ampia, questa direttiva andrebbe invece configurata con un elenco controllato di porte consentite, per limitare l'abuso del proxy come relay verso porte arbitrarie.

A questo punto il servizio può essere avviato e abilitato al boot:

sudo systemctl enable --now tinyproxy

Configurazione di dante-server (SOCKS5)

Dante fornisce un endpoint SOCKS5 utilizzabile da applicazioni che supportano questo protocollo direttamente, senza passare per il tunnel iptables. Il file di configurazione è /etc/danted.conf:

logoutput: syslog
internal: 127.0.0.1 port = 1080
external: wlp0s20f3
socksmethod: none
user.privileged: proxy
user.unprivileged: nobody
client pass {
    from: 127.0.0.0/8 to: 0.0.0.0/0
    log: error
}
socks pass {
    from: 127.0.0.0/8 to: 0.0.0.0/0
    log: error
}

Il parametro external deve corrispondere all'interfaccia di rete attualmente in uso. Per individuarla automaticamente:

ip route get 1 | awk '{print $5}'

Una nota importante riguarda la direttiva socksmethod: nelle versioni più recenti del progetto Dante, la vecchia direttiva method è stata deprecata a favore di socksmethod. Usare la sintassi corretta è essenziale, perché un file con la direttiva obsoleta impedisce l'avvio del servizio.

Avvio e abilitazione:

sudo systemctl enable --now danted

Configurazione di redsocks

redsocks agisce da ponte tra le regole iptables e tinyproxy, traducendo le connessioni intercettate in richieste http-connect. Il file di configurazione è /etc/redsocks.conf:

base {
    log_debug = off;
    log_info = on;
    log = "syslog:daemon";
    daemon = on;
    user = redsocks;
    group = redsocks;
    redirector = iptables;
}
redsocks {
    local_ip = 127.0.0.1;
    local_port = 12345;
    ip = 127.0.0.1;
    port = 3128;
    type = http-connect;
}

Avvio e abilitazione:

sudo systemctl enable --now redsocks

Prima di procedere con iptables, è utile verificare con quale utente di sistema vengono eseguiti effettivamente tinyproxy e redsocks, poiché questa informazione è indispensabile per il passo successivo:

systemctl show -p User tinyproxy.service
systemctl show -p User redsocks.service

Configurazione di iptables

Il problema dei loop di reindirizzamento

Quando iptables reindirizza tutto il traffico TCP verso redsocks, anche le connessioni generate dai proxy stessi (tinyproxy che si connette a Internet, dante che inoltra richieste) vengono intercettate, creando un loop infinito che si manifesta tipicamente con timeout su tutte le connessioni HTTPS.

La soluzione

La strategia consiste nell'usare la tabella mangle per marcare i pacchetti generati dai processi proxy, e successivamente far saltare tali pacchetti nella catena REDSOCKS della tabella nat:

iptables -t mangle -A OUTPUT -m owner --uid-owner tinyproxy -j MARK --set-mark 1
iptables -t mangle -A OUTPUT -m owner --uid-owner redsocks -j MARK --set-mark 1
iptables -t mangle -A OUTPUT -m owner --uid-owner proxy -j MARK --set-mark 1

Poi, nella catena REDSOCKS (tabella nat):

iptables -t nat -A REDSOCKS -m mark --mark 1 -j RETURN

La regola con --uid-owner proxy è mantenuta come fallback per compatibilità con setup legacy in cui alcuni servizi girano sotto l'utente storico proxy; tuttavia, se il comando systemctl show -p User eseguito in precedenza restituisce un nome utente diverso (ad esempio _tinyproxy), è necessario sostituirlo nella regola corrispondente.

Script completo

Lo script seguente raccoglie tutte le regole ed è pensato per essere salvato in /etc/iptables-rules.sh:

#!/bin/bash
iptables -t nat -N REDSOCKS 2>/dev/null || iptables -t nat -F REDSOCKS
iptables -t mangle -A OUTPUT -m owner --uid-owner tinyproxy -j MARK --set-mark 1 2>/dev/null
iptables -t mangle -A OUTPUT -m owner --uid-owner redsocks -j MARK --set-mark 1 2>/dev/null
iptables -t mangle -A OUTPUT -m owner --uid-owner proxy -j MARK --set-mark 1 2>/dev/null
iptables -t nat -A REDSOCKS -m mark --mark 1 -j RETURN
for net in 0.0.0.0/8 10.0.0.0/8 127.0.0.0/8 169.254.0.0/16 172.16.0.0/12 192.168.0.0/16 224.0.0.0/4 240.0.0.0/4; do
    iptables -t nat -A REDSOCKS -d "$net" -j RETURN
done
iptables -t nat -A REDSOCKS -p tcp --dport 3128 -j RETURN
iptables -t nat -A REDSOCKS -p tcp --dport 1080 -j RETURN
iptables -t nat -A REDSOCKS -p tcp --dport 12345 -j RETURN
iptables -t nat -A REDSOCKS -p tcp -j REDIRECT --to-ports 12345
iptables -t nat -A OUTPUT -p tcp -j REDSOCKS
iptables -t nat -A PREROUTING -p tcp -j REDSOCKS

Le righe relative alle reti private garantiscono che il traffico verso indirizzi locali (LAN, loopback, multicast) non venga mai instradato verso il proxy, mentre le righe sulle porte 3128/1080/12345 evitano che il traffico destinato ai proxy stessi venga nuovamente reindirizzato.

Per applicare lo script:

sudo chmod +x /etc/iptables-rules.sh
sudo /etc/iptables-rules.sh

Rendere le regole persistenti e affidabili

Il modo più semplice per salvare le regole consiste nell'usare iptables-persistent:

sudo iptables-save | sudo tee /etc/iptables/rules.v4 > /dev/null

Questo approccio, però, ha un limite: al boot le regole vengono ripristinate da rules.v4 molto presto, potenzialmente prima che tinyproxy, danted e redsocks abbiano avviato i rispettivi processi con i relativi utenti, causando il fallimento silenzioso delle marcature --uid-owner. Un approccio più robusto consiste nel creare una unit systemd dedicata che applichi lo script dopo l'avvio dei servizi proxy.

File /etc/systemd/system/iptables-rules.service:

[Unit]
Description=Applica le regole iptables per il proxy trasparente
After=network-online.target tinyproxy.service danted.service redsocks.service
Wants=network-online.target
[Service]
Type=oneshot
ExecStart=/etc/iptables-rules.sh
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target

E abilitarla con:

sudo systemctl daemon-reload
sudo systemctl enable iptables-rules.service

Da notare che su Ubuntu 24.04 il comando iptables è in realtà un frontend per nftables (backend iptables-nft). Le regole impostate restano pienamente compatibili e funzionanti, ma è possibile ispezionarne l'equivalente nativo in qualsiasi momento con:

sudo nft list ruleset

Gestione di DNS e traffico UDP/QUIC

L'intera architettura descritta opera esclusivamente sul traffico TCP. Questo ha due conseguenze pratiche fondamentali, spesso trascurate, che è importante conoscere prima di considerare il setup "completo".

Risoluzione DNS. Le query DNS utilizzano tipicamente UDP sulla porta 53 e non vengono intercettate dalle regole iptables definite sopra. Significa che, anche con tutto il traffico HTTP/HTTPS instradato attraverso il proxy, le richieste DNS continuano a uscire direttamente verso il resolver configurato sul sistema, esponendo i nomi di dominio visitati. Per mitigare questo problema, le opzioni principali sono:

  • Configurare systemd-resolved per utilizzare DNS over TLS (DoT) verso un resolver attendibile, in modo che le query siano comunque cifrate anche se non transitano dal proxy.
  • Installare un resolver locale come unbound con supporto DoH/DoT.
  • Se l'obiettivo primario è l'anonimato completo (e non solo il filtraggio), valutare l'uso di una VPN, che instrada anche il traffico UDP, incluso il DNS.

Traffico QUIC/HTTP-3. I browser moderni (Chrome, Edge, Firefox) tentano di default connessioni HTTP/3 basate su QUIC, che viaggia su UDP/443. Questo traffico bypassa completamente redsocks e tinyproxy, uscendo direttamente verso Internet. Per garantire che tutto il traffico web passi effettivamente dal proxy, è possibile forzare il fallback a TCP/TLS bloccando UDP/443 in uscita:

sudo iptables -A OUTPUT -p udp --dport 443 -j REJECT

In presenza di questa regola, i browser ricadono automaticamente su HTTP/2 over TCP, che viene correttamente intercettato dal tunnel.

IPv6. Lo script copre solo IPv4 (non a caso i comandi di verifica nella guida usano il flag -4). Se il sistema dispone di connettività IPv6 attiva, il traffico verso destinazioni IPv6 bypassa interamente il proxy. Le due opzioni più comuni sono replicare le stesse regole con ip6tables/nft per IPv6, oppure, più semplicemente, disabilitare temporaneamente IPv6 sull'interfaccia di rete durante l'utilizzo del tunnel:

sudo sysctl -w net.ipv6.conf.all.disable_ipv6=1
sudo sysctl -w net.ipv6.conf.default.disable_ipv6=1

Verifica del funzionamento

Una volta avviati tutti i servizi e applicate le regole iptables, è possibile verificare che il traffico venga effettivamente instradato attraverso il proxy confrontando l'IP pubblico restituito dai diversi percorsi:

curl -4 http://ifconfig.me
curl -4 https://ifconfig.me
curl --socks5 127.0.0.1:1080 -4 http://ifconfig.me
curl --socks5 127.0.0.1:1080 -4 https://ifconfig.me
curl --proxy http://127.0.0.1:3128 -4 http://ifconfig.me
curl --proxy http://127.0.0.1:3128 -4 https://ifconfig.me

Tutti i comandi dovrebbero restituire lo stesso indirizzo IP pubblico, confermando che il traffico forzato da iptables, quello instradato via SOCKS5 e quello passato direttamente a tinyproxy escono tutti dal medesimo punto.

Disattivazione del tunnel

Per rimuovere temporaneamente il reindirizzamento, senza disinstallare i servizi:

sudo iptables -t nat -F REDSOCKS
sudo iptables -t nat -D OUTPUT -p tcp -j REDSOCKS
sudo iptables -t nat -D PREROUTING -p tcp -j REDSOCKS
sudo iptables -t nat -X REDSOCKS

Per riattivare il tunnel è sufficiente rieseguire /etc/iptables-rules.sh (o riavviare la unit iptables-rules.service se è stata configurata).

Proxy locale e proxy remoto

Questa guida configura un proxy locale, in cui tinyproxy è installato sulla stessa macchina che genera il traffico. In questa modalità, il traffico esce comunque dall'IP pubblico assegnato dal proprio operatore.

Schema del proxy locale:

Browser → tinyproxy (locale, :3128) → router → Internet

Le caratteristiche principali sono:

  • IP visibile: quello dell'utente (es. un IP italiano)
  • Latenza: minima, con un solo hop aggiuntivo (redsocks → tinyproxy)
  • Privacy: il proxy vede il traffico in chiaro, mitigato dalla cifratura HTTPS end-to-end
  • Scopo principale: controllo, filtro e centralizzazione del traffico

Lo schema del proxy remoto, invece, prevede che tinyproxy funga da intermediario verso un secondo proxy ospitato in un altro paese:

Browser → tinyproxy (locale, :3128) → proxy remoto (es. Olanda) → Internet

In questo caso, l'IP pubblico osservato dai servizi remoti diventa quello del server remoto. tinyproxy supporta upstream HTTP, SOCKS4 e SOCKS5:

upstream socks5 185.xxx.xxx.xxx:1080

oppure, con autenticazione:

upstream http user:pass@proxy-remoto.com:8080

È inoltre possibile effettuare un instradamento selettivo, in cui solo determinati domini transitano attraverso il proxy remoto:

upstream socks5 proxy-remoto.com:1080 ".example.com"
upstream none ".sito-interno.local"
upstream http proxy-remoto.com:8080

Per individuare un proxy remoto da utilizzare come upstream, le opzioni principali sono:

  • Servizi commerciali specializzati (BrightData, Oxylabs, Smartproxy, NetNut)
  • Un VPS affittato in un altro paese, sul quale installare autonomamente tinyproxy o dante
  • Liste pubbliche di proxy gratuiti, generalmente instabili e poco sicure, da evitare in contesti che richiedono affidabilità

Proxy vs VPN

La scelta tra proxy e VPN dipende dall'obiettivo. La tabella seguente riassume le differenze principali.

Caratteristica Proxy (locale/remoto) VPN
Cifratura Solo a livello applicativo (HTTPS) Tutto il traffico, tramite tunnel cifrato
Supporto UDP No, solo TCP Sì (DNS, VoIP, gaming, QUIC)
Ambito del traffico TCP, configurabile per singola applicazione Intero sistema, tramite interfaccia di rete virtuale
Overhead Leggero, basso overhead Leggero overhead crittografico
Anonimato dell'IP Sì, con proxy remoto
Bypass geografico Sì, ma limitato al traffico TCP Sì, su tutto il traffico
Configurazione Relativamente semplice (URL o variabili d'ambiente) Richiede un client o un'app dedicata
Protezione da DNS leak Dipende dal setup, richiede configurazione aggiuntiva Generalmente inclusa di default
Trasparenza verso il server remoto Il server vede il proxy come client Il server vede il server VPN come client

In sintesi, conviene optare per un proxy quando l'obiettivo è cambiare l'IP visibile per il browser o per una singola applicazione, in un ambiente controllato, oppure quando si necessita di funzionalità di caching o filtraggio. Una VPN è invece preferibile quando si vuole cifrare l'intero traffico di sistema (non solo HTTP), quando si utilizzano applicazioni che richiedono UDP, su reti Wi-Fi pubbliche non affidabili, oppure quando l'obiettivo è bypassare blocchi di rete completi.

Esempio pratico

Per estendere il setup descritto in questa guida con un proxy remoto come upstream, è possibile procedere come segue.

Innanzitutto occorre individuare un proxy SOCKS5 remoto raggiungibile, ad esempio all'indirizzo 185.x.x.x:1080. Successivamente, va aggiunta la seguente riga al file /etc/tinyproxy/tinyproxy.conf:

upstream socks5 185.x.x.x:1080

A questo punto è necessario riavviare il servizio:

sudo systemctl restart tinyproxy

Da questo momento, tutto il traffico già forzato da iptables (tramite redsockstinyproxy) uscirà dall'IP del proxy remoto.

È inoltre possibile combinare gli approcci, instradando solo determinati domini verso il proxy remoto e lasciando tutto il resto in uscita diretta:

upstream socks5 proxy-remoto.com:1080 ".netflix.com" ".disneyplus.com"

Hardening e best practice di sicurezza

Sebbene tutti i servizi siano configurati per restare in ascolto esclusivamente su 127.0.0.1, è buona norma applicare alcune misure aggiuntive di difesa in profondità, in particolare su sistemi che potrebbero essere collegati a reti non affidabili:

  • Verificare periodicamente che nessun servizio sia in ascolto su interfacce diverse da loopback, con sudo ss -tlnp.
  • Bloccare esplicitamente l'accesso esterno alle porte dei proxy tramite ufw, anche se già vincolate a localhost, come ulteriore livello di protezione:
sudo ufw deny in on wlp0s20f3 to any port 3128
sudo ufw deny in on wlp0s20f3 to any port 1080
sudo ufw deny in on wlp0s20f3 to any port 12345
  • Mantenere aggiornati i pacchetti tinyproxy, dante-server e redsocks, poiché si tratta di servizi esposti, anche solo localmente, all'elaborazione di traffico di rete arbitrario.
  • Evitare di eseguire qualsiasi componente del tunnel come utente root: tutti i servizi indicati in questa guida vengono installati con utenti dedicati a privilegi minimi.
  • Se si utilizza un upstream remoto con credenziali (upstream http user:pass@...), evitare di salvare le credenziali in chiaro in file con permessi troppo permissivi: verificare che /etc/tinyproxy/tinyproxy.conf sia leggibile solo da root e dall'utente del servizio.

Riepilogo dei file di configurazione

File Descrizione
/etc/tinyproxy/tinyproxy.conf Configurazione del proxy HTTP tinyproxy
/etc/danted.conf Configurazione del proxy SOCKS5 dante
/etc/redsocks.conf Configurazione di redsocks
/etc/iptables-rules.sh Script delle regole iptables per il reindirizzamento trasparente
/etc/iptables/rules.v4 Regole iptables persistenti caricate al boot
/etc/systemd/system/iptables-rules.service Unit systemd per applicare le regole con il corretto ordine di avvio

Risoluzione dei problemi più comuni

Tra i problemi più frequenti che si possono riscontrare durante la configurazione di questo setup, i principali sono i seguenti.

Le connessioni HTTPS vanno in timeout. La causa più probabile è un loop di reindirizzamento generato da iptables, in cui le connessioni dei proxy vengono nuovamente intercettate da loro stesse. La soluzione consiste nel verificare che le marcature nella tabella mangle corrispondano effettivamente agli utenti reali con cui girano tinyproxy e redsocks, utilizzando systemctl show -p User.

Il sistema restituisce l'errore "Maximum number of connections reached". In questo caso la causa è quasi sempre un valore di MaxClients troppo basso in tinyproxy. La soluzione è aumentare il parametro (ad esempio a 1000) e riavviare il servizio.

Il servizio dante non si avvia. La causa tipica è l'uso della direttiva obsoleta method, sostituita da socksmethod nelle versioni recenti di Dante. La soluzione è verificare la sintassi corretta in /etc/danted.conf e correggere la direttiva.

Il traffico non viene completamente instradato attraverso il proxy nonostante le regole iptables siano attive. In questo caso la causa è quasi sempre il traffico UDP (DNS o QUIC/HTTP-3), che per progettazione non viene intercettato da questo setup. La soluzione consiste nell'applicare le misure descritte nella sezione dedicata alla gestione di DNS e UDP/QUIC.

Articolo scritto con il supporto di LLM per la formattazione e la struttura del codice.

Commenti