禁止国外IP访问服务器 屏蔽国外IP
实现方式:iptables + ipset
1、安装必要工具
# 更新系统
sudo apt update
sudo apt upgrade -y
# 安装必要工具
sudo apt install iptables ipset curl wget cron -y
# 安装持久化工具
sudo apt install iptables-persistent netfilter-persistent -y
2、服务目录
sudo mkdir -p /mnt/ipfilter
sudo mkdir -p /var/log/ipfilter
cd /mnt/ipfilter
3、脚本配置
IP列表更新
sudo nano /mnt/ipfilter/update_ipsets.sh
#!/bin/bash
set -e
LOG_FILE="/var/log/ipfilter/update.log"
CHINA_IPS="/mnt/ipfilter/china_ips.txt"
ALLOWED_COUNTRIES="CN HK MO TW"
mkdir -p /var/log/ipfilter
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}
cleanup() {
rm -f /tmp/china_*.txt /tmp/cn_*.txt /tmp/ip_*.txt 2>/dev/null || true
}
error_exit() {
log "ERROR: $1"
cleanup
exit 1
}
check_command() {
if ! command -v "$1" >/dev/null 2>&1; then
error_exit "Required command '$1' not found"
fi
}
main() {
check_command "curl"
check_command "ipset"
check_command "sort"
check_command "uniq"
cleanup
SOURCES=(
"https://raw.githubusercontent.com/17mon/china_ip_list/master/china.txt"
"https://raw.githubusercontent.com/metowolf/iplist/master/data/country/CN.txt"
"https://raw.githubusercontent.com/gaoyifan/china-operator-ip/raw/ip-lists/china.txt"
"https://raw.githubusercontent.com/firehol/blocklist-ipsets/master/ipip_country/ipip_country_cn.netset"
)
TEMP_FILE="/tmp/all_ips.txt"
for url in "${SOURCES[@]}"; do
curl -s --max-time 30 "$url" 2>/dev/null | \
grep -E '^[0-9]' | grep -v '^#' | sort -u >> "$TEMP_FILE" || true
done
if [ ! -s "$TEMP_FILE" ]; then
log "无法下载IP列表,使用备份文件"
if [ -f "$CHINA_IPS.bak" ]; then
cp "$CHINA_IPS.bak" "$TEMP_FILE"
else
error_exit "没有可用的IP列表"
fi
fi
sort -u -t . -k 1,1n -k 2,2n -k 3,3n -k 4,4n "$TEMP_FILE" > "$CHINA_IPS.tmp"
grep -E '^([0-9]{1,3}\.){3}[0-9]{1,3}(/[0-9]{1,2})?$' "$CHINA_IPS.tmp" > "$CHINA_IPS"
IP_COUNT=$(wc -l < "$CHINA_IPS")
log "获取到 $IP_COUNT 个IP段"
if [ -f "$CHINA_IPS" ]; then
cp "$CHINA_IPS" "$CHINA_IPS.bak"
fi
update_ipsets
cleanup
}
update_ipsets() {
ipset destroy china-ips-temp 2>/dev/null
ipset destroy china-ips-temp-new 2>/dev/null
ipset destroy china-ips-new 2>/dev/null
if ! ipset list china-ips >/dev/null 2>&1; then
ipset create china-ips hash:net hashsize 16384 maxelem 1000000
else
OLD_COUNT=$(ipset list china-ips | grep -c '^[0-9]')
fi
if [ ! -f "$CHINA_IPS" ]; then
return 1
fi
ipset create china-ips-new hash:net hashsize 16384 maxelem 1000000
TOTAL=$(wc -l < "$CHINA_IPS")
added=0
skipped=0
count=0
while read -r ip; do
if [ -n "$ip" ]; then
if ipset add china-ips-new "$ip" 2>/dev/null; then
added=$((added + 1))
else
skipped=$((skipped + 1))
fi
fi
count=$((count + 1))
if [ $((count % 500)) -eq 0 ]; then
log "已处理 $count/$TOTAL 条IP,已添加 $added 条"
fi
done < "$CHINA_IPS"
NEW_COUNT=$(ipset list china-ips-new | grep -c "^[0-9]")
log "临时集合添加完成: 共处理 $count 条, 成功添加 $added 条, 跳过 $skipped 条"
log "临时集合实际IP数量: $NEW_COUNT"
if [ $added -gt 0 ]; then
ipset swap china-ips-new china-ips
ipset destroy china-ips-new
else
ipset destroy china-ips-new
fi
mkdir -p /mnt/ipset
ipset save > /mnt/ipset/ipset.conf
update_iptables
}
update_iptables() {
if ! iptables -L GEO_BLOCK >/dev/null 2>&1; then
iptables -N GEO_BLOCK
else
iptables -F GEO_BLOCK
fi
iptables -A GEO_BLOCK -i lo -j ACCEPT
iptables -A GEO_BLOCK -s 127.0.0.0/8 -j ACCEPT
iptables -A GEO_BLOCK -s 10.0.0.0/8 -j ACCEPT
iptables -A GEO_BLOCK -s 172.10.0.0/12 -j ACCEPT
iptables -A GEO_BLOCK -s 192.168.0.0/16 -j ACCEPT
iptables -A GEO_BLOCK -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A GEO_BLOCK -p icmp -j ACCEPT
iptables -A GEO_BLOCK -m set --match-set china-ips src -j ACCEPT
iptables -A GEO_BLOCK -m limit --limit 10/min -j LOG --log-prefix "GEO_BLOCK_DENY: "
iptables -A GEO_BLOCK -j DROP
if ! iptables -C INPUT -j GEO_BLOCK >/dev/null 2>&1; then
iptables -I INPUT 1 -j GEO_BLOCK
else
log "GEO_BLOCK链已在INPUT链中"
fi
}
main "$@"
配置文件
sudo nano /mnt/ipfilter/ipfilter.conf
# 允许访问的端口
ALLOW_PORTS="22,80,443,3306"
BLOCK_ACTION="DROP"
LOG_DENIED=true
LOG_LIMIT="10/min"
ALLOW_PRIVATE=true
ALLOW_ICMP=true
UPDATE_FREQUENCY=7
# 白名单
WHITELIST=(
"127.0.0.1/32"
"10.0.0.0/8"
"172.16.0.0/12"
"192.168.0.0/16"
)
# 黑名单
BLACKLIST=(
# 这里添加要特别屏蔽的IP
)
DATA_SOURCES=(
"https://raw.githubusercontent.com/17mon/china_ip_list/master/china.txt"
"https://raw.githubusercontent.com/metowolf/iplist/master/data/country/CN.txt"
)
IPSET_NAME="china-ips"
IPSET_HASHSIZE="16384"
IPSET_MAXELEM="1000000"
IPTABLES_CHAIN="GEO_BLOCK"
#测试模式(设置为true时,只记录不拒绝)
TEST_MODE=false
控制脚本
sudo nano /mnt/ipfilter/ipfilter.sh
#!/bin/bash
set -e
CONFIG_FILE="/mnt/ipfilter/ipfilter.conf"
LOG_FILE="/var/log/ipfilter/ipfilter.log"
if [ -f "$CONFIG_FILE" ]; then
source "$CONFIG_FILE"
else
# 默认配置
ALLOW_PORTS="22,80,443"
BLOCK_ACTION="DROP"
LOG_DENED=true
LOG_LIMIT="10/min"
fi
initialize() {
echo "初始化IP过滤系统..."
if ! ipset list china-ips >/dev/null 2>&1; then
echo "创建ipset集合..."
ipset create china-ips hash:net hashsize 16384 maxelem 1000000
fi
iptables -N GEO_BLOCK 2>/dev/null || true
iptables-save > /mnt/ipfilter/iptables.backup.$(date +%Y%m%d-%H%M%S)
iptables -F
iptables -X GEO_BLOCK 2>/dev/null
iptables -N GEO_BLOCK
iptables -P INPUT ACCEPT
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -p icmp -j ACCEPT
iptables -A INPUT -j GEO_BLOCK
echo "初始化完成"
}
start() {
echo "启动IP过滤..."
if ! ipset list china-ips >/dev/null 2>&1; then
echo "警告: china-ips集合不存在,尝试创建..."
ipset create china-ips hash:net hashsize 16384 maxelem 1000000 || {
echo "错误: 无法创建ipset集合"
return 1
}
fi
if [ ! -f "/mnt/ipfilter/china_ips.txt" ] || [ ! -s "/mnt/ipfilter/china_ips.txt" ]; then
echo "IP列表不存在或为空,开始更新..."
/mnt/ipfilter/update_ipsets.sh
fi
enable_rules
echo "IP过滤已启动"
}
stop() {
echo "停止IP过滤..."
iptables -D INPUT -j GEO_BLOCK 2>/dev/null || true
iptables -F GEO_BLOCK
iptables -P INPUT ACCEPT
iptables -P FORWARD ACCEPT
echo "IP过滤已停止"
}
enable_rules() {
echo "启用防火墙规则..."
if ! iptables -L GEO_BLOCK >/dev/null 2>&1; then
echo "创建GEO_BLOCK链..."
iptables -N GEO_BLOCK
fi
iptables -F GEO_BLOCK
echo "添加基础允许规则..."
iptables -A GEO_BLOCK -s 127.0.0.0/8 -j ACCEPT
iptables -A GEO_BLOCK -s 10.0.0.0/8 -j ACCEPT
iptables -A GEO_BLOCK -s 192.168.0.0/16 -j ACCEPT
iptables -A GEO_BLOCK -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A GEO_BLOCK -p icmp -j ACCEPT
IFS=',' read -ra PORTS <<< "$ALLOW_PORTS"
for port in "${PORTS[@]}"; do
port=$(echo "$port" | tr -d ' ')
if [[ "$port" =~ ^[0-9]+$ ]]; then
# 允许中国IP访问指定端口
iptables -A GEO_BLOCK -p tcp --dport "$port" \
-m set --match-set china-ips src -j ACCEPT
echo " 允许中国IP访问端口: $port"
fi
done
if [ "$LOG_DENIED" = true ]; then
iptables -A GEO_BLOCK -m limit --limit "$LOG_LIMIT" \
-j LOG --log-prefix "GEO_BLOCK_DENY: "
fi
iptables -A GEO_BLOCK -j "$BLOCK_ACTION"
echo "规则已启用"
}
status() {
echo "=== IP过滤系统状态 ==="
echo
echo "ipset集合状态:"
if ipset list china-ips >/dev/null 2>&1; then
ipset list china-ips | grep -E "^(Number|Size|References|Members)" | head -5
echo "IP数量: $(ipset list china-ips | grep '^[0-9]' | wc -l)"
else
echo " 未找到china-ips集合"
fi
echo
echo "iptables规则:"
iptables -L GEO_BLOCK -n --line-numbers 2>/dev/null || echo " 未找到GEO_BLOCK链"
echo
echo "最近日志:"
tail -20 /var/log/ipfilter/update.log 2>/dev/null || echo " 无日志文件"
echo
echo "系统信息:"
echo " 最后更新: $(stat -c %y /mnt/ipfilter/china_ips.txt 2>/dev/null || echo '未知')"
echo " IP列表数量: $(wc -l /mnt/ipfilter/china_ips.txt 2>/dev/null | cut -d' ' -f1 || echo '0')"
}
reload() {
echo "重新加载配置..."
stop
sleep 1
start
}
usage() {
echo "用法: $0 {start|stop|restart|status|reload|init|update}"
echo
echo "命令:"
echo " init 初始化系统"
echo " start 启动IP过滤"
echo " stop 停止IP过滤"
echo " restart 重启IP过滤"
echo " status 查看状态"
echo " reload 重新加载"
echo " update 更新IP列表"
echo
}
case "$1" in
init)
initialize
;;
start)
start
;;
stop)
stop
;;
restart)
stop
sleep 2
start
;;
status)
status
;;
reload)
reload
;;
update)
/mnt/ipfilter/update_ipsets.sh
;;
*)
usage
exit 1
;;
esac
exit 0
系统服务
sudo nano /etc/systemd/system/ipfilter.service
[Unit]
Description=IP Country Filter Service
After=network-online.target
Wants=network-online.target
Requires=network-online.target
Before=ssh.service nginx.service apache2.service
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStartPre=/bin/bash -c "iptables -C INPUT -i lo -j ACCEPT 2>/dev/null || iptables -A INPUT -i lo -j ACCEPT"
ExecStartPre=/bin/bash -c "iptables -C INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT 2>/dev/null || iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT"
ExecStart=/mnt/ipfilter/ipfilter.sh start
ExecStop=/mnt/ipfilter/ipfilter.sh stop
ExecReload=/mnt/ipfilter/ipfilter.sh reload
ExecStopPost=/bin/bash -c "if [ $? -ne 0 ]; then iptables -P INPUT ACCEPT; fi"
TimeoutStartSec=300
TimeoutStopSec=30
Restart=no
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
定时更新IP列表
sudo nano /etc/systemd/system/ipfilter.service
[Unit]
Description=IP Country Filter Service
After=network-online.target
Wants=network-online.target
Requires=network-online.target
Before=ssh.service nginx.service apache2.service
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStartPre=/bin/bash -c "iptables -C INPUT -i lo -j ACCEPT 2>/dev/null || iptables -A INPUT -i lo -j ACCEPT"
ExecStartPre=/bin/bash -c "iptables -C INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT 2>/dev/null || iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT"
ExecStart=/mnt/ipfilter/ipfilter.sh start
ExecStop=/mnt/ipfilter/ipfilter.sh stop
ExecReload=/mnt/ipfilter/ipfilter.sh reload
ExecStopPost=/bin/bash -c "if [ $? -ne 0 ]; then iptables -P INPUT ACCEPT; fi"
TimeoutStartSec=300
TimeoutStopSec=30
Restart=no
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
sudo nano /etc/systemd/system/ipfilter-update.timer
[Unit]
Description=Update IP Filter Database Weekly
Requires=ipfilter-update.service
[Timer]
OnCalendar=weekly
Persistent=true
RandomizedDelaySec=3600
[Install]
WantedBy=timers.target
4、启用禁止国外ip访问服务
1. 设置权限
sudo chmod +x /mnt/ipfilter/*.sh
sudo chown -R root:root /mnt/ipfilter
sudo chown -R root:root /var/log/ipfilter
2. 加载配置
sudo systemctl daemon-reload
3. 启用系统服务
sudo systemctl enable ipfilter.service
sudo systemctl enable ipfilter-update.timer
sudo systemctl start ipfilter.service
sudo systemctl start ipfilter-update.timer
4. 验证配置
sudo systemctl status ipfilter.service
sudo systemctl status ipfilter-update.timer
sudo ipset list china-ips | head -20
sudo iptables -L GEO_BLOCK -n -v
sudo tail -f /var/log/ipfilter/update.log
5、常用命令
# 启动/停止/重启
sudo systemctl start ipfilter
sudo systemctl stop ipfilter
sudo systemctl restart ipfilter
# 查看状态
sudo systemctl status ipfilter
sudo journalctl -u ipfilter -f
# 手动更新IP列表
sudo /mnt/ipfilter/update_ipsets.sh
# 强制更新并重启
sudo systemctl stop ipfilter
sudo /mnt/ipfilter/ipfilter.sh update
sudo systemctl start ipfilter
- 上一篇:nginx常用命令
- 下一篇:uniapp问题记录