Bloccare il traffico per paese in Linux: GeoIP, nftables | INTROSERV
EUR
european

EUR

usa

USD

Italy It
Ex. VAT Ex. VAT 0%

Come bloccare il traffico per paese su un firewall Linux con le regole GeoIP

Livello: Professionale
Tempo stimato: ~35 minuti
Obiettivo: Configurare regole firewall GeoIP su un server Linux per limitare l'accesso per paese, usando iptables con il modulo xtables-geoip oppure nftables con gli IP set, e automatizzare gli aggiornamenti in modo che gli elenchi restino attuali.

Introduzione

Se i vostri servizi sono rivolti a una regione specifica, non c'è motivo di accettare traffico dal resto del mondo. Il blocco geografico sul firewall di Linux consente di scartare i pacchetti in base al paese di origine prima che raggiungano l'applicazione, riducendo il rumore degli attacchi brute-force e la superficie di attacco. In questa guida si bloccherà il traffico per paese su un firewall Linux con le regole firewall GeoIP: prima con iptables e xtables-addons, poi con nftables e IP set basati su CIDR, compresi gli aggiornamenti automatici del database, così che il blocco degli IP per paese resti accurato.

Prerequisiti

Prima di iniziare, assicurarsi che siano soddisfatte le seguenti condizioni:

  • Sistema operativo: Ubuntu 22.04/24.04 LTS, Debian 12/13, AlmaLinux/RHEL 9/10
  • Accesso: accesso sudo o root al server
  • Firewall: iptables 1.8+ con xtables-addons, oppure nftables 1.0+
  • Pacchetti necessari: curl, iptables, linux-headers-$(uname -r) (Debian/Ubuntu); repository EPEL abilitato (RHEL/AlmaLinux 9)

Info

Su Debian 12+, Ubuntu 22.04+ e RHEL/AlmaLinux 9+, il comando iptables è un wrapper del backend nftables (iptables-nft). Il match -m geoip funziona correttamente con questo backend.

  • Rete: una chiara comprensione dei paesi da cui i servizi devono accettare traffico
  • Conoscenze richieste: buona padronanza della riga di comando di Linux, dei concetti di base del firewall e della modifica dei file
  • Piano di emergenza: una console out-of-band funzionante (IPMI/KVM) oppure la modalità di rescue del provider, nel caso una regola blocchi l'accesso

Warning

Applicare regole firewall a livello di paese tramite una sessione SSH è intrinsecamente rischioso. Se si blocca per errore il proprio paese, si perde l'accesso. Tenere sempre pronto un accesso alternativo out-of-band e testare le regole prima di renderle permanenti.

Passaggio 1: Individuare i paesi consentiti e bloccati

Prima di toccare il firewall, definire la policy. Esistono due approcci:

  • Allowlist (consigliato): consentire solo i paesi necessari e scartare tutto il resto. È più rigoroso e sicuro.
  • Blocklist: consentire tutto e scartare paesi specifici. Più semplice, ma lascia una superficie di attacco maggiore.

In questa guida useremo l'approccio allowlist, coerente con il principio del privilegio minimo. Supponiamo che i servizi siano destinati solo a utenti di Stati Uniti, Germania e Polonia. I codici paese ISO di due lettere sono: US, DE, PL.

Info

I codici paese seguono lo standard ISO 3166-1 alpha-2. L'elenco completo è disponibile all'indirizzo https://www.iso.org/obp/ui/#search/code/. Essere precisi: un errore di battitura blocca in silenzio il traffico legittimo.

Passaggio 2: Configurare GeoIP con iptables (xtables-addons)

Questo metodo usa il modulo xt_geoip di xtables-addons, che aggiunge a iptables il match -m geoip. È uno dei modi più consolidati per bloccare gli intervalli IP per paese su Linux.

2.1 Installare xtables-addons e le dipendenze

Debian/Ubuntu:

sudo apt install -y linux-headers-$(uname -r) sudo apt update && sudo apt install -y \ xtables-addons-common libtext-csv-xs-perl unzip iptables curl

Warning

xtables-addons non è disponibile nei repository di AlmaLinux 10. Usare invece il metodo nftables (Passaggio 3) oppure compilare xtables-addons dal codice sorgente.

Dopo l'installazione, verificare che il modulo sia disponibile:

modinfo xt_geoip

L'output previsto include una riga come:

filename: /lib/modules/.../xt_geoip.ko description: Xtables: country matching via GeoIP

Se modinfo restituisce un errore, il modulo non è stato installato correttamente. Verificare che gli header del kernel corrispondano alla versione del kernel in esecuzione.

2.2 Scaricare e generare il database GeoIP

Il modulo xt_geoip richiede un database locale con la corrispondenza tra paesi e indirizzi IP. Viene distribuito come file CSV che vanno convertiti in formato binario.

Creare la directory di lavoro e quella del database:

sudo mkdir -p /usr/share/xt_geoip

Scaricare i dati GeoIP CSV più recenti. La fonte originale fornisce i dati tramite gli strumenti di xtables-addons:

cd /tmp /usr/libexec/xtables-addons/xt_geoip_dl

Convertire il CSV scaricato in formato binario:

/usr/libexec/xtables-addons/xt_geoip_build -D /usr/share/xt_geoip *.csv

Output previsto: un elenco dei codici paese in elaborazione:

4540 IPv4 ranges for ZA 1071 IPv6 ranges for ZA 147 IPv4 ranges for ZW 94 IPv6 ranges for ZW ...

2.3 Applicare le regole iptables con match GeoIP

Creare ora le vere e proprie regole firewall GeoIP. Lo script seguente consente il traffico dai paesi scelti e scarta tutto il resto nella catena INPUT.

Eseguire prima il backup delle regole attuali:

sudo iptables-save > /tmp/iptables-backup-$(date +%Y%m%d).rules

Applicare la allowlist dei paesi:

# Allow loopback sudo iptables -A INPUT -i lo -j ACCEPT # Allow established and related connections sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT # Allow traffic from US, DE, PL only sudo iptables -A INPUT -m geoip --src-cc US,DE,PL -j ACCEPT # Log dropped packets sudo iptables -A INPUT -j LOG --log-prefix "GEOIP-DROP: " --log-level 4 # Drop everything else sudo iptables -A INPUT -j DROP

Warning

La regola finale DROP blocca tutto il traffico che non corrisponde alla allowlist. Assicurarsi che il paese di provenienza della connessione SSH sia incluso, altrimenti si verrà bloccati immediatamente. In caso di dubbio, aggiungere prima del DROP una regola ACCEPT temporanea per il proprio IP: sudo iptables -I INPUT -s <YOUR_IP_ADDRESS> -j ACCEPT.

Verificare che le regole siano attive:

sudo iptables -L INPUT -v --line-numbers

Output previsto:

Chain INPUT (policy ACCEPT) num target prot opt source destination 1 ACCEPT all -- anywhere anywhere /* loopback */ 2 ACCEPT all -- anywhere anywhere ctstate RELATED,ESTABLISHED 3 ACCEPT all -- anywhere anywhere -m geoip --source-country US,DE,PL 4 LOG all -- anywhere anywhere LOG level warning prefix "GEOIP-DROP: " 5 DROP all -- anywhere anywhere

2.4 Rendere persistenti le regole iptables dopo il riavvio

Le regole applicate con iptables vanno perse al riavvio. Salvarle:

Debian/Ubuntu:

sudo apt install iptables-persistent -y sudo netfilter-persistent save

AlmaLinux/RHEL:

sudo service iptables save

Passaggio 3: Configurare GeoIP con nftables (IP set)

Se il sistema usa nftables (predefinito su Debian 11+, Ubuntu 22.04+ e RHEL 9+), si può ottenere lo stesso risultato con IP set popolati con blocchi CIDR a livello di paese. Questo approccio non richiede moduli del kernel oltre a quelli già forniti da nftables.

3.1 Ottenere gli intervalli IP dei paesi

Scaricare gli elenchi CIDR dei paesi che si vogliono consentire. Diverse fonti pubbliche li mettono a disposizione, ad esempio ipdeny.com:

sudo mkdir -p /etc/nftables/geoip cd /etc/nftables/geoip # Download CIDR blocks for US, DE, PL for CC in us de pl; do sudo curl -sS -o /etc/nftables/geoip/${CC}.zone \ "https://www.ipdeny.com/ipblocks/data/aggregated/${CC}-aggregated.zone"; done

Verificare che i file contengano intervalli CIDR:

head -5 /etc/nftables/geoip/us.zone

Output previsto (intervalli CIDR, uno per riga):

1.178.0.0/23 1.178.4.0/22 1.178.8.0/21 ...

3.2 Generare e caricare la configurazione nftables

Creare uno script che legge i file CIDR e genera un set nftables. Salvarlo come /etc/nftables/geoip-update.sh:

sudo nano /etc/nftables/geoip-update.sh

Incollare quanto segue:

#!/bin/bash # Generate nftables set from country CIDR files set -euo pipefail GEOIP_DIR="/etc/nftables/geoip" OUTPUT="/etc/nftables/geoip-sets.nft" echo "define ALLOWED_COUNTRIES = {" > "$OUTPUT" for zone_file in "$GEOIP_DIR"/*.zone; do while IFS= read -r cidr; do && continue echo " ${cidr}," >> "$OUTPUT" done < "$zone_file" done echo "}" >> "$OUTPUT" echo "GeoIP set generated: $(wc -l < "$OUTPUT") lines"

Renderlo eseguibile:

sudo chmod +x /etc/nftables/geoip-update.sh

Eseguire lo script:

sudo /etc/nftables/geoip-update.sh

Ora fare riferimento a questo set nella configurazione di nftables:

# Debian/Ubuntu: sudo nano /etc/nftables.conf # AlmaLinux/RHEL: sudo nano /etc/sysconfig/nftables.conf

Aggiungere l'include e usare il set nella catena input:

#!/usr/sbin/nft -f flush ruleset include "/etc/nftables/geoip-sets.nft" table inet filter { chain input { type filter hook input priority 0; policy drop; ct state invalid drop iif lo accept ct state established,related accept # Allow ICMP ip protocol icmp accept ip6 nexthdr icmpv6 accept # GeoIP: allow only listed countries ip saddr $ALLOWED_COUNTRIES accept # Log dropped packets log prefix "geoip-drop: " level info # Everything else is dropped by policy } chain forward { type filter hook forward priority 0; policy drop; } chain output { type filter hook output priority 0; policy accept; } }

Convalidare la sintassi prima di applicare la configurazione:

sudo nft -c -f /etc/nftables.conf

Se non compaiono errori, applicare la configurazione e verificarla:

sudo nft -f /etc/nftables.conf sudo systemctl enable --now nftables sudo nft list ruleset | head -20

Tip

Con IP set molto grandi (oltre 100.000 voci), nftables si comporta decisamente meglio di iptables. Il match basato sui set di nftables usa internamente tabelle hash, quindi le prestazioni di ricerca restano costanti indipendentemente dalla dimensione del set.

Passaggio 4: Automatizzare gli aggiornamenti del database GeoIP

Le associazioni tra IP e paese cambiano di continuo. Un database del mese scorso presenterà lacune. Pianificare aggiornamenti automatici con cron.

4.1 Creare lo script di aggiornamento

Creare /usr/local/sbin/geoip-refresh.sh:

sudo nano /usr/local/sbin/geoip-refresh.sh

Per iptables (xtables-addons):

#!/bin/bash set -euo pipefail cd /tmp /usr/libexec/xtables-addons/xt_geoip_dl /usr/libexec/xtables-addons/xt_geoip_build \ -D /usr/share/xt_geoip *.csv rm -f /tmp/*.csv /tmp/*.zip logger "GeoIP database updated successfully"

Per nftables:

#!/bin/bash set -euo pipefail GEOIP_DIR="/etc/nftables/geoip" for CC in us de pl; do curl -sS -o "${GEOIP_DIR}/${CC}.zone" \ "https://www.ipdeny.com/ipblocks/data/aggregated/${CC}-aggregated.zone" done /etc/nftables/geoip-update.sh systemctl reload nftables logger "GeoIP nftables sets updated and reloaded"

Renderlo eseguibile:

sudo chmod +x /usr/local/sbin/geoip-refresh.sh

4.2 Pianificare con cron

Prima di pianificare l'attività cron, assicurarsi che il servizio nftables sia abilitato e in esecuzione (se si usa il metodo nftables):

sudo systemctl enable --now nftables

Eseguire l'aggiornamento ogni settimana:

sudo crontab -e

Aggiungere:

0 3 * * 0 /usr/local/sbin/geoip-refresh.sh >> /var/log/geoip-update.log 2>&1

Viene eseguito ogni domenica alle 3:00. Dopo la prima esecuzione pianificata, verificare che abbia funzionato:

cat /var/log/geoip-update.log

Passaggio 5: Verifica e test

5.1 Test da un paese consentito

Da una macchina situata in uno dei paesi consentiti, connettersi via SSH oppure effettuare una richiesta HTTP:

curl -v http://<YOUR_SERVER_IP>

La connessione dovrebbe riuscire normalmente.

5.2 Simulare un paese bloccato

Usare curl con un IP noto di un paese bloccato tramite proxy, oppure testare in locale rimuovendo temporaneamente il proprio paese dalla allowlist e provando a connettersi da un secondo terminale.

Info

Servizi online come https://ipinfo.io permettono di verificare in quale paese è registrato un determinato IP. Usare curl https://ipinfo.io/<YOUR_IP_ADDRESS> per confermarlo.

5.3 Controllare i contatori del firewall

iptables:

sudo iptables -L INPUT -v -n

Osservare i contatori dei pacchetti sulla regola DROP: dovrebbero aumentare man mano che arriva traffico bloccato.

nftables:

sudo nft list chain inet filter input

5.4 Monitorare i log di sistema

Controllare nel log di sistema la presenza di pacchetti scartati:

sudo journalctl -k --since "1 hour ago" | grep -i "geoip-drop"

Warning

Se si osserva un volume elevato di messaggi del log del kernel sui pacchetti scartati e il sistema smette di rispondere, la causa può essere un flood di log. Nel caso peggiore, ciò può causare un kernel panic. Se sono stati configurati il parametro crashkernel e il servizio kdump, un kernel panic produrrà un crash dump (vmcore) in /var/crash che sarà possibile analizzare in seguito. Senza kdump si ottiene soltanto un riavvio e nessuna diagnostica. Una breve panoramica è riportata nella sezione seguente.

Passaggio 6: Proteggersi dal kernel panic durante le modifiche al firewall

Modifiche aggressive al firewall su un server di produzione molto carico, in particolare quelle che causano improvvisi picchi di traffico o flood di log, possono in rari casi portare a un kernel panic. Se succede e non ci si è preparati, non si ottiene nulla: solo un riavvio e nessun dato su che cosa sia andato storto.

Kdump è il meccanismo standard di Linux per acquisire un crash dump quando si verifica un kernel panic. Usa kexec per avviare un secondo kernel di cattura (capture kernel), che scrive su disco l'immagine della memoria (vmcore) prima del riavvio del sistema.

Per avere la diagnostica disponibile:

  1. Verificare che kdump sia installato e abilitato. Su RHEL/AlmaLinux di solito è preinstallato. Su Debian/Ubuntu:

    sudo apt install kdump-tools kexec-tools -y

  2. Verificare che il parametro crashkernel sia impostato nella configurazione del bootloader:

    cat /proc/cmdline | grep crashkernel

    Dovrebbe comparire qualcosa come crashkernel=256M. Se manca, è necessario configurare il parametro crashkernel in GRUB e riavviare. La quantità esatta di memoria da riservare per kdump su Linux dipende dalla RAM totale: 256M è un valore predefinito sicuro per server con 4 GB o più.

  3. Verificare che il servizio kdump sia attivo:

    sudo systemctl status kdump

Info

Se si verifica davvero un kernel panic, il sistema userà kexec per avviare il kernel di cattura, scriverà il vmcore in /var/crash e poi si riavvierà normalmente. A quel punto sarà possibile eseguire l'analisi del vmcore su Linux con l'utilità crash per individuare la causa. È una parte standard della risoluzione dei problemi di kernel panic su Linux sui sistemi di produzione. Per una guida completa su come abilitare kdump su Linux e sulla configurazione di kexec e kdump su Linux, consultare un tutorial dedicato a kdump.

Risoluzione dei problemi

  • Accesso SSH bloccato: usare la console out-of-band o la modalità di rescue.
  • modinfo xt_geoip: not found: installare linux-headers-$(uname -r).
  • iptables: command not found (Debian 13): installare iptables con sudo apt install iptables.
  • nftables.service is not active: eseguire sudo systemctl enable --now nftables.
  • /etc/sysconfig/nftables.conf vuoto su AlmaLinux: usare questo percorso al posto di /etc/nftables.conf per configurare le regole.

Rollback

Per annullare il blocco per paese e ripristinare l'accesso aperto:

iptables: ripristino dal backup:

sudo iptables-restore < /tmp/iptables-backup-*.rules

Info

Se le regole GeoIP sono state applicate su un server senza una precedente configurazione del firewall, il file di backup sarà vuoto. In tal caso, usare i comandi di svuotamento e impostazione della policy riportati sotto al posto di iptables-restore.

Oppure svuotare tutte le regole:

sudo iptables -F INPUT sudo iptables -P INPUT ACCEPT

Warning

Lo svuotamento con policy ACCEPT elimina ogni protezione del firewall. Applicare subito dopo il proprio set standard di regole di sicurezza.

nftables: ripristino della configurazione predefinita:

sudo nft flush ruleset

Quindi ripristinare la configurazione di base di nftables (senza GeoIP):

sudo nft -f /etc/nftables.conf.backup

Per rimuovere completamente i componenti GeoIP:

sudo rm -rf /etc/nftables/geoip sudo rm -f /etc/nftables/geoip-sets.nft /etc/nftables/geoip-update.sh sudo crontab -l | grep -v geoip-refresh | sudo crontab -

Rimuovere xtables-addons (se installato):

Debian/Ubuntu:

sudo apt remove xtables-addons-common -y

AlmaLinux/RHEL:

sudo dnf remove xtables-addons -y

Conclusione

Il server ora usa le regole firewall GeoIP per bloccare il traffico per paese su Linux, tramite iptables con xt_geoip oppure tramite nftables con IP set basati su CIDR. Il database si aggiorna automaticamente, si dispone di un piano di rollback e, con kdump configurato per catturare i crash dump in caso di kernel panic, l'ambiente di produzione è protetto sia dalle minacce ordinarie sia dagli scenari peggiori.

Versione del documento: 1.0
Ultimo aggiornamento: maggio 2026
Responsabile: Team di documentazione tecnica

VAT

  • Other

    Ex. VAT

    0%
  • austria

    Austria

    20%
  • Belgium

    Belgium

    21%
  • Bulgaria

    Bulgaria

    20%
  • Croatia

    Croatia

    25%
  • Cyprus

    Cyprus

    19%
  • Czech Republic

    Czech Republic

    21%
  • Denmark

    Denmark

    25%
  • Estonia

    Estonia

    22%
  • France

    France

    20%
  • Finland

    Finland

    24%
  • Germany

    Germany

    19%
  • Greece

    Greece

    24%
  • Hungary

    Hungary

    27%
  • Ireland

    Ireland

    23%
  • Italy

    Italy

    22%
  • Latvia

    Latvia

    21%
  • Lithuania

    Lithuania

    21%
  • Luxembourg

    Luxembourg

    17%
  • Malta

    Malta

    18%
  • Netherlands

    Netherlands

    21%
  • Poland

    Poland

    23%
  • Portugal

    Portugal

    23%
  • Romania

    Romania

    19%
  • Slovakia

    Slovakia

    20%
  • Slovenia

    Slovenia

    22%
  • Spain

    Spain

    21%
  • Sweden

    Sweden

    25%
  • USA

    USA

    0%
european
states
  • germany
  • Español
  • Italiano
  • Poland
  • Русский
  • Slovenski
  • Türkçe
  • ukraine
  • kingdom
  • French
  • Hrvatska
  • Other
  • Austria
  • Belgium
  • Bulgaria
  • Croatia
  • Cyprus
  • Czech Republic
  • Denmark
  • Estonia
  • Finland
  • France
  • Germany
  • Greece
  • Hungary
  • Ireland
  • Italy
  • Latvia
  • Lithuania
  • Luxembourg
  • Malta
  • Netherlands
  • Poland
  • Portugal
  • Romania
  • Slovakia
  • Slovenia
  • Spain
  • Sweden
  • USA