Lab 24 – Routing e NAT sull'host: masquerading, port forwarding e configurazione routed
Dipendenze
Sezione intitolata “Dipendenze”- Lab precedenti:
- Nodo:
desopve04, il nodo autonomo: le prove non toccano il cluster. - Router:
rtr-core(172.27.199.1), il router MikroTik RouterOS del laboratorio, gateway della rete di gestione: la sua configurazione di base è nel Lab 01 e ci si accede conssh [email protected]. In questo lab fa la parte del router del provider. - Template:
debian-13-standard_13.6-1_amd64.tar.zstnello storagelocaldidesopve04(Lab 09, oppurepveam download local debian-13-standard_13.6-1_amd64.tar.zst). - Client di prova:
desopve01e il DCdesopve-dc01(172.27.199.20). - Proxy:
proxy.proxmox.community:3128per i pacchetti nei container. - Credenziali:
root/<password-lab>sui nodi,admin/<password-lab>surtr-core→ Appendice B.
Obiettivi
Sezione intitolata “Obiettivi”- Dare ai guest una rete privata che esce verso il resto della rete con l’indirizzo del nodo (masquerading).
- Pubblicare un servizio di un guest privato su una porta del nodo (port forwarding).
- Instradare verso il nodo una subnet “aggiuntiva”, come fanno i provider con i server dedicati, e dare ai guest indirizzi propri senza NAT.
- Scrivere regole
post-upche non si duplicano quando la rete viene ricaricata.
Come funziona
Sezione intitolata “Come funziona”Tre modi di collegare i guest
Sezione intitolata “Tre modi di collegare i guest”| Modo | Come vedono i guest gli altri | Come vedono gli altri i guest | Quando si usa |
|---|---|---|---|
| Bridged (lab 20) | i guest sono sulla stessa rete fisica del nodo | con il loro indirizzo | quasi sempre: datacenter, LAN aziendale |
| Masquerading (NAT) | escono con l’indirizzo del nodo | non li vedono (solo con il port forwarding) | un solo indirizzo disponibile, laboratori, reti di test |
| Routed | il nodo fa da router tra la loro subnet e la rete esterna | con il loro indirizzo, se qualcuno instrada la subnet verso il nodo | server dedicati presso un provider, che non accetta MAC sconosciuti sulla sua rete |
Il nodo come router
Sezione intitolata “Il nodo come router”Per inoltrare pacchetti tra le sue interfacce, il nodo deve avere attivo l’IP forwarding (net.ipv4.ip_forward = 1). Un bridge senza porte (bridge-ports none) è una rete che esiste solo dentro il nodo: i guest collegati lì escono solo passando dal nodo, che li instrada.
Masquerading e port forwarding
Sezione intitolata “Masquerading e port forwarding”Il masquerading è un NAT sorgente: i pacchetti dei guest escono da vmbr0 con l’indirizzo del nodo al posto del loro. La tabella conntrack del kernel ricorda ogni connessione e riporta le risposte al guest giusto. Gli altri host non vedono la rete privata e non hanno bisogno di conoscerla.
Il port forwarding è un NAT di destinazione (DNAT): una connessione che arriva a una porta del nodo viene girata a un indirizzo e una porta della rete privata.
Configurazione routed
Sezione intitolata “Configurazione routed”Un provider assegna al server un indirizzo principale e, spesso, una subnet aggiuntiva instradata verso l’indirizzo principale. Il nodo mette la subnet su un bridge interno e la instrada: i guest hanno indirizzi propri, raggiungibili dall’esterno, senza NAT. Nel laboratorio la route sul router del provider la mettiamo noi su rtr-core.
Una variante della documentazione di Proxmox usa il proxy ARP (proxy_arp sull’interfaccia esterna): il nodo risponde alle richieste ARP per gli indirizzi dei guest, così il router del provider li raggiunge anche senza una route dedicata. In questo lab si usa la route statica, che è la forma più chiara.
Le regole nel file di rete
Sezione intitolata “Le regole nel file di rete”La GUI non gestisce il NAT: le regole si aggiungono a mano in /etc/network/interfaces con post-up (eseguite quando l’interfaccia sale) e post-down (quando scende). Proxmox conserva queste righe anche quando poi modifichi la rete dalla GUI.
Procedura
Sezione intitolata “Procedura”1. I due bridge interni dalla GUI
Sezione intitolata “1. I due bridge interni dalla GUI”-
Copia di sicurezza della rete:
root@desopve04 cp /etc/network/interfaces /root/interfaces.bak-lab24 -
Nodo desopve04 → System → Network → Create → Linux Bridge. Name
vmbr9, IPv4/CIDR192.168.100.1/24, Bridge ports vuoto, nessun gateway. Commentorete privata con NAT.
-
Un secondo bridge per la configurazione routed: Name
vmbr8, IPv4/CIDR10.99.99.1/28(la “subnet aggiuntiva” del provider), Bridge ports vuoto, commentosubnet instradata.
-
Apply Configuration:

-
Attiva l’IP forwarding in modo permanente:
root@desopve04 echo "net.ipv4.ip_forward = 1" > /etc/sysctl.d/80-ip-forward.confsysctl -p /etc/sysctl.d/80-ip-forward.confOutput net.ipv4.ip_forward = 1
2. Masquerading
Sezione intitolata “2. Masquerading”-
Aggiungi al blocco di
vmbr9in/etc/network/interfacesle due righe del NAT e ricarica la rete:auto vmbr9iface vmbr9 inet staticaddress 192.168.100.1/24bridge-ports nonebridge-stp offbridge-fd 0post-up iptables -t nat -A POSTROUTING -s 192.168.100.0/24 -o vmbr0 -j MASQUERADEpost-down iptables -t nat -D POSTROUTING -s 192.168.100.0/24 -o vmbr0 -j MASQUERADE#rete privata con NATroot@desopve04 ifreload -aiptables -t nat -S POSTROUTINGOutput -P POSTROUTING ACCEPT-A POSTROUTING -s 192.168.100.0/24 -o vmbr0 -j MASQUERADE -
Crea il CT 402 sulla rete privata, con il nodo come gateway:
root@desopve04 pct create 402 local:vztmpl/debian-13-standard_13.6-1_amd64.tar.zst \--hostname nat-ct1 --memory 512 --cores 1 --rootfs local-lvm:4 \--net0 name=eth0,bridge=vmbr9,ip=192.168.100.10/24,gw=192.168.100.1 \--nameserver 172.27.199.20 --searchdomain proxmox.community \--unprivileged 1 --features nesting=1 --password '<password-lab>' --start 1 -
Il container raggiunge il DC e risolve i nomi:
root@desopve04 pct exec 402 -- ip routeOutput default via 192.168.100.1 dev eth0 proto kernel onlink192.168.100.0/24 dev eth0 proto kernel scope link src 192.168.100.10root@desopve04 pct exec 402 -- ping -c3 -W1 172.27.199.20 | tail -2Output 3 packets transmitted, 3 received, 0% packet loss, time 2074msrtt min/avg/max/mdev = 0.743/0.820/0.862/0.054 msroot@desopve04 pct exec 402 -- getent hosts desopve-dc01.proxmox.communityOutput 172.27.199.20 desopve-dc01.proxmox.community172.32.199.20 desopve-dc01.proxmox.community -
Su
vmbr0i pacchetti escono con l’indirizzo del nodo, e la tabella conntrack ricorda a chi riportare la risposta:root@desopve04 tcpdump -ni vmbr0 icmp and host 172.27.199.20Output 19:59:00.253879 IP 172.27.199.24 > 172.27.199.20: ICMP echo request, id 347, seq 1, length 6419:59:00.254872 IP 172.27.199.20 > 172.27.199.24: ICMP echo reply, id 347, seq 1, length 64root@desopve04 conntrack -L -p icmpOutput icmp 1 24 src=192.168.100.10 dst=172.27.199.20 type=8 code=0 id=347 src=172.27.199.20 dst=172.27.199.24 type=0 code=0 id=347 mark=0 use=1La riga di conntrack ha due metà: la richiesta come l’ha mandata il container (
src=192.168.100.10) e la risposta come arriva dal DC (dst=172.27.199.24). -
Prova senza masquerading. Togli la regola e riprova:
root@desopve04 iptables -t nat -D POSTROUTING -s 192.168.100.0/24 -o vmbr0 -j MASQUERADEpct exec 402 -- ping -c3 -W1 172.27.199.20 | tail -1Output 3 packets transmitted, 0 received, 100% packet loss, time 2055msroot@desopve04 tcpdump -ni vmbr0 icmp and host 172.27.199.20Output 19:59:08.670035 IP 192.168.100.10 > 172.27.199.20: ICMP echo request, id 348, seq 1, length 6419:59:09.700834 IP 192.168.100.10 > 172.27.199.20: ICMP echo request, id 348, seq 2, length 6419:59:10.725095 IP 192.168.100.10 > 172.27.199.20: ICMP echo request, id 348, seq 3, length 64Il nodo inoltra le richieste con l’indirizzo privato: il DC non sa dove si trovi la
192.168.100.0/24, manda le risposte al suo gateway, e queste si perdono. Rimetti la regola (iptables -t nat -A ...) e il ping torna a funzionare. -
Il container installa i pacchetti attraverso il NAT e il proxy del laboratorio:
root@desopve04 pct exec 402 -- sh -c 'echo "Acquire::http::Proxy \"http://proxy.proxmox.community:3128\";" > /etc/apt/apt.conf.d/80proxy'pct exec 402 -- apt-get updatepct exec 402 -- apt-get install -y nginxpct exec 402 -- sh -c 'echo "nat-ct1: servizio raggiunto con il port forwarding" > /var/www/html/index.html'
3. Port forwarding
Sezione intitolata “3. Port forwarding”-
Aggiungi a
vmbr9le righe del DNAT: la porta 8080 del nodo va alla porta 80 del container.post-up iptables -t nat -A PREROUTING -i vmbr0 -p tcp --dport 8080 -j DNAT --to-destination 192.168.100.10:80post-down iptables -t nat -D PREROUTING -i vmbr0 -p tcp --dport 8080 -j DNAT --to-destination 192.168.100.10:80 -
Attenzione al
ifreload. Ricaricando la rete dopo la modifica, ifupdown2 riesegue ipost-updivmbr9: anche la regola di masquerading già presente viene aggiunta una seconda volta.root@desopve04 ifreload -aiptables -t nat -S | grep -E "DNAT|MASQ"Output -A PREROUTING -i vmbr0 -p tcp -m tcp --dport 8080 -j DNAT --to-destination 192.168.100.10:80-A POSTROUTING -s 192.168.100.0/24 -o vmbr0 -j MASQUERADE-A POSTROUTING -s 192.168.100.0/24 -o vmbr0 -j MASQUERADEIl DNAT, appena aggiunto al file, compare una volta; il masquerading, che c’era già, due.
ifreload -ariesegue tutti ipost-updel bridge a ogni ricarica, anche se il file non è cambiato: con un’altra ricarica i DNAT diventerebbero due e i MASQUERADE tre. Le regole doppie non rompono nulla subito, ma si accumulano, e unpost-downne toglie una sola. La soluzione è aggiungere una regola solo se manca:iptables -C(check) fallisce se la regola non c’è, e solo allora-Ala aggiunge. Il blocco finale divmbr9:auto vmbr9iface vmbr9 inet staticaddress 192.168.100.1/24bridge-ports nonebridge-stp offbridge-fd 0post-up iptables -t nat -C POSTROUTING -s 192.168.100.0/24 -o vmbr0 -j MASQUERADE 2>/dev/null || iptables -t nat -A POSTROUTING -s 192.168.100.0/24 -o vmbr0 -j MASQUERADEpost-down iptables -t nat -D POSTROUTING -s 192.168.100.0/24 -o vmbr0 -j MASQUERADEpost-up iptables -t nat -C PREROUTING -i vmbr0 -p tcp --dport 8080 -j DNAT --to-destination 192.168.100.10:80 2>/dev/null || iptables -t nat -A PREROUTING -i vmbr0 -p tcp --dport 8080 -j DNAT --to-destination 192.168.100.10:80post-down iptables -t nat -D PREROUTING -i vmbr0 -p tcp --dport 8080 -j DNAT --to-destination 192.168.100.10:80#rete privata con NATTolte a mano le copie in più (
iptables -t nat -D ...una volta per regola), due ricariche di fila non duplicano più nulla:root@desopve04 ifreload -a; ifreload -aiptables -t nat -S | grep -E "DNAT|MASQ"Output -A PREROUTING -i vmbr0 -p tcp -m tcp --dport 8080 -j DNAT --to-destination 192.168.100.10:80-A POSTROUTING -s 192.168.100.0/24 -o vmbr0 -j MASQUERADE -
Il servizio del container è raggiungibile dalla rete di gestione sulla porta 8080 del nodo:
root@desopve01 curl -s http://172.27.199.24:8080/Output nat-ct1: servizio raggiunto con il port forwardingroot@desopve01 curl -s -i http://172.27.199.24:8080/ | head -3Output HTTP/1.1 200 OKServer: nginxDate: Mon, 09 Nov 2026 18:59:43 GMT -
Dal nodo stesso, invece, non funziona:
root@desopve04 curl -s -m 5 http://172.27.199.24:8080/ || echo "nessuna risposta (codice $?)"Output nessuna risposta (codice 7)root@desopve04 iptables -t nat -L PREROUTING -n -vOutput Chain PREROUTING (policy ACCEPT 41 packets, 2952 bytes)pkts bytes target prot opt in out source destination2 120 DNAT tcp -- vmbr0 * 0.0.0.0/0 0.0.0.0/0 tcp dpt:8080 to:192.168.100.10:80Le connessioni che nascono sul nodo non passano dalla catena
PREROUTING(passano daOUTPUT), e la regola chiede pacchetti in arrivo davmbr0. I contatori mostrano i 2 pacchetti arrivati dagli altri host.
4. Configurazione routed
Sezione intitolata “4. Configurazione routed”-
Crea il CT 403 sulla subnet instradata, con il nodo come gateway:
root@desopve04 pct create 403 local:vztmpl/debian-13-standard_13.6-1_amd64.tar.zst \--hostname routed-ct1 --memory 512 --cores 1 --rootfs local-lvm:4 \--net0 name=eth0,bridge=vmbr8,ip=10.99.99.2/28,gw=10.99.99.1 \--nameserver 172.27.199.20 --searchdomain proxmox.community \--unprivileged 1 --features nesting=1 --password '<password-lab>' --start 1 -
Finché il router non sa che la subnet sta dietro
desopve04, il container è irraggiungibile:root@desopve01 ping -c2 -W1 10.99.99.2 | tail -1Output 2 packets transmitted, 0 received, +2 errors, 100% packet loss, time 1001ms -
Sul router (qui
rtr-core, in produzione il router del provider) si instrada la subnet verso l’indirizzo principale del nodo:RouterOS — rtr-core /ip route add dst-address=10.99.99.0/28 gateway=172.27.199.24 comment="subnet instradata verso desopve04 (lab 24)"/ip route print where dst-address=10.99.99.0/28Output Flags: A - ACTIVE; s - STATICColumns: DST-ADDRESS, GATEWAY, ROUTING-TABLE, DISTANCE# DST-ADDRESS GATEWAY ROUTING-TABLE DISTANCE;;; subnet instradata verso desopve04 (lab 24)0 As 10.99.99.0/28 172.27.199.24 main 1 -
Ora il container è raggiungibile con il suo indirizzo, e
traceroutemostra il percorso: router, nodo, container.root@desopve01 ping -c3 -W1 10.99.99.2 | tail -2Output 3 packets transmitted, 3 received, 0% packet loss, time 2052msrtt min/avg/max/mdev = 0.633/0.776/0.907/0.112 msroot@desopve01 traceroute -n -w1 -q1 10.99.99.2Output traceroute to 10.99.99.2 (10.99.99.2), 30 hops max, 60 byte packets1 172.27.199.1 0.440 ms2 172.27.199.24 0.684 ms3 10.99.99.2 0.783 ms -
Al contrario del masquerading, chi riceve il traffico vede l’indirizzo vero del container. Avvia la cattura su
vmbr0e, da un secondo terminale, fai partire un ping dal container (pct exec 403 -- ping -c1 172.27.199.20):root@desopve04 tcpdump -ni vmbr0 icmp and host 172.27.199.20Output 20:00:13.717794 IP 10.99.99.2 > 172.27.199.20: ICMP echo request, id 344, seq 1, length 6420:00:13.718992 IP 172.27.199.20 > 10.99.99.2: ICMP echo reply, id 344, seq 1, length 64root@desopve04 ip route | grep -E "vmbr8|vmbr9"Output 10.99.99.0/28 dev vmbr8 proto kernel scope link src 10.99.99.1192.168.100.0/24 dev vmbr9 proto kernel scope link src 192.168.100.1Il nodo non ha regole di NAT per la
10.99.99.0/28: si limita a instradare, perché le due reti sono collegate alle sue interfacce.
Verifica e test
Sezione intitolata “Verifica e test”| Prova | Risultato |
|---|---|
| CT sulla rete privata verso il DC, con masquerading | 0% di perdita; su vmbr0 si vede l’indirizzo del nodo |
| Stesso test senza la regola MASQUERADE | 100% di perdita: il DC non sa dove rispondere |
apt nel container privato |
funziona tramite il NAT e il proxy |
Port forwarding 8080 → CT 402:80 da desopve01 |
pagina del container, HTTP 200 |
| Port forwarding dal nodo stesso | non funziona: il traffico locale non passa da PREROUTING |
ifreload con post-up iptables -A |
regole duplicate; con -C ... || -A nessun duplicato |
| Subnet instradata senza route sul router | irraggiungibile |
Subnet instradata con la route su rtr-core |
raggiungibile in 3 salti, senza NAT |
Stato finale del lab
Sezione intitolata “Stato finale del lab”desopve04:vmbr9192.168.100.1/24 senza porte, con masquerading versovmbr0e DNAT172.27.199.24:8080→192.168.100.10:80;vmbr810.99.99.1/28 senza porte, subnet instradata;- IP forwarding attivo (
/etc/sysctl.d/80-ip-forward.conf); - copia della rete precedente in
/root/interfaces.bak-lab24; - OVS (
vmbr2,bond1,vlan10) invariato dal lab 23.
- Container su
desopve04, tutti accesi:- CT 401
ovs-ct1(lab 23); - CT 402
nat-ct1suvmbr9, 192.168.100.10, con nginx; - CT 403
routed-ct1suvmbr8, 10.99.99.2/28.
- CT 401
rtr-core: route statica10.99.99.0/28via172.27.199.24.
Cosa hai imparato
Sezione intitolata “Cosa hai imparato”- Un bridge senza porte è una rete interna al nodo; con l’IP forwarding il nodo la instrada.
- Il masquerading nasconde i guest dietro l’indirizzo del nodo: conntrack riporta le risposte, gli altri host non vedono la rete privata.
- Il port forwarding pubblica un servizio privato su una porta del nodo, ma non vale per le connessioni che nascono sul nodo stesso.
- Con la configurazione routed i guest hanno indirizzi propri senza NAT: serve che il router a monte instradi la subnet verso il nodo.
- Le regole
post-upvengono rieseguite a ogniifreload: coniptables -C ... || iptables -A ...non si duplicano.