security, infrastructure, tutorial

CentOS下Nginx配置地理访问控制:限制仅允许特定地区/国家访问

详细指南:在CentOS系统上配置Nginx实现地理访问控制,包括GeoIP模块、MaxMind数据库、防火墙规则等多种方法

nginx centos geoip security access-control firewall devops infrastructure

概述

需求来自某好友某生产环境,有古老的应用运行于远古的操作系统之上,年久失修,无人维护。某日,或老板/或领导/或客户,心血来潮提出一些需求,比如根据访问者的地理位置来限制对网站或API的访问。以应对以下场景:

  • 合规性要求(如GDPR、数据本地化)
  • 许可证限制(某些服务仅在特定国家可用)
  • 安全防护(阻止来自特定地区的恶意流量)
  • 业务需求(仅服务特定市场)

本文将详细介绍在CentOS系统上配置Nginx实现地理访问控制的多种方法。

方法一:使用Nginx GeoIP模块(推荐)

注意:CentOS 7兼容性

在CentOS 7上,默认的Nginx包可能不包含GeoIP模块。如果遇到模块缺失问题,请参考以下解决方案:

  1. 检查现有Nginx是否支持GeoIP
    nginx -V 2>&1 | grep -o with-http_geoip_module
    
  2. 如果支持,直接使用;如果不支持,选择以下方案之一
    • 使用防火墙规则(方法二)
    • 使用第三方服务(方法三)
    • 重新编译Nginx(见下方安装步骤)

1. 安装GeoIP模块

# 安装EPEL仓库
sudo yum install -y epel-release

# 安装GeoIP工具和数据库
yum -y install GeoIP GeoIP-devel GeoIP-data.noarch GeoIP geoipupdate geoipupdate-cron

# 检查Nginx是否已安装GeoIP模块
nginx -V 2>&1 | grep -o with-http_geoip_module

# 如果没有GeoIP模块,需要重新编译Nginx
# 安装编译依赖
sudo yum groupinstall -y "Development Tools"
sudo yum install -y pcre-devel zlib-devel openssl-devel libxml2-devel libxslt-devel gd-devel perl-devel perl-ExtUtils-Embed

# 安装Google perftools(如果启用该模块)
sudo yum install -y gperftools gperftools-devel

# 下载Nginx源码并编译(如果需要)
wget http://nginx.org/download/nginx-1.28.0.tar.gz
tar -xvf nginx-1.28.0.tar.gz
cd nginx-1.28.0

# 参数从原 nginx -V 中获取,追加 --with-http_geoip_module 
./configure --prefix=/usr/share/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib64/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --http-client-body-temp-path=/var/lib/nginx/tmp/client_body --http-proxy-temp-path=/var/lib/nginx/tmp/proxy --http-fastcgi-temp-path=/var/lib/nginx/tmp/fastcgi --http-uwsgi-temp-path=/var/lib/nginx/tmp/uwsgi --http-scgi-temp-path=/var/lib/nginx/tmp/scgi --pid-path=/run/nginx.pid --lock-path=/run/lock/subsys/nginx --user=nginx --group=nginx --with-compat --with-debug --with-file-aio --with-google_perftools_module --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_degradation_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_image_filter_module=dynamic --with-http_mp4_module --with-http_perl_module=dynamic --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-http_xslt_module=dynamic --with-mail=dynamic --with-mail_ssl_module --with-pcre --with-pcre-jit --with-stream=dynamic --with-stream_ssl_module --with-stream_ssl_preread_module --with-threads --with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -m64 -mtune=generic' --with-ld-opt='-Wl,-z,relro -specs=/usr/lib/rpm/redhat/redhat-hardened-ld -Wl,-E' --with-http_geoip_module 

make && sudo make install

# 检查Nginx是否支持GeoIP模块
/usr/sbin/nginx -V 2>&1 | grep -o with-http_geoip_module

2. 下载MaxMind GeoIP数据库

# # 创建目录
# sudo mkdir -pv /usr/share/GeoIP

# # 下载GeoIP2数据库(需要Nginx支持geoip2模块)
# wget -P /usr/share/GeoIP https://github.com/P3TERX/GeoLite.mmdb/raw/download/GeoLite2-ASN.mmdb
# wget -P /usr/share/GeoIP https://github.com/P3TERX/GeoLite.mmdb/raw/download/GeoLite2-Country.mmdb
# wget -P /usr/share/GeoIP https://github.com/P3TERX/GeoLite.mmdb/raw/download/GeoLite2-City.mmdb
# ln -s /usr/share/GeoIP/GeoLite2-Country.mmdb /usr/share/GeoIP/GeoLite2-Country.dat

# 验证数据库文件
ls -la /usr/share/GeoIP/
geoiplookup 8.8.8.8

3. 配置Nginx

/etc/nginx/nginx.conf中添加:

# Load GeoIP module
# Note: If compiled with --with-compat, module path may be different

# Important: Check module type
# If nginx -V shows with-http_geosip_module, it's a static module, no load_module needed
# If it's a dynamic module, use the following directives:

# Dynamic module loading (if exists)
# load_module modules/ngx_http_geoip_module.so;
# Or try the following path:
# load_module /usr/lib64/nginx/modules/ngx_http_geoip_module.so;

# Static modules don't need load_module directive

# EMERGENCY FIX: If you encounter segmentation fault (SIGSEGV), use this simplified config
# Temporarily disable GeoIP functionality to ensure basic service availability

http {
    # Define allowed country codes (temporarily disabled)
    # map $geoip_country_code $allowed_country {
    #     default 0;
    #     CN 1;  # China
    #     SG 1;  # Singapore
    #     JP 1;  # Japan
    #     KR 1;  # South Korea
    # }
    
    server {
        listen 80;
        server_name domain.com;
        
        # Check country code (temporarily disabled)
        # if ($allowed_country = 0) {
        #     return 403 "Access denied from your country.";
        # }
        
        location / {
            root /var/www/html;
            index index.html;
        }
    }
}

4. 高级GeoIP配置

http {
    # Use GeoIP2 database
    geoip2 /usr/share/GeoIP/GeoLite2-Country.mmdb {
s        $geoip2_data_country_code country iso_code;
        $geoip2_data_country_name country names en;
        $geoip2_data_continent_code continent code;
    }
    
    # Define allowed regions
    map $geoip2_data_country_code $allowed_region {
        default 0;
        # Asia
        CN 1; 
        SG 1; 
        JP 1; 
        KR 1;
        # North America
        US 1; 
        CA 1;
        # Europe
        DE 1; 
        FR 1; 
        GB 1; 
        NL 1;
    }
    
    # Define allowed continents
    map $geoip2_data_continent_code $allowed_continent {
        default 0;
        AS 1;  # Asia
        NA 1;  # North America
        EU 1;  # Europe
    }
    
    server {
        listen 80;
        server_name your-domain.com;
        
        # Check access permission
        if ($allowed_region = 0) {
            return 403 "Access denied from your region.";
        }
        
        # Log access records
        log_format geo_log '$remote_addr - $remote_user [$time_local] '
                          '"$request" $status $body_bytes_sent '
                          '"$http_referer" "$http_user_agent" '
                          'Country: $geoip2_data_country_name '
                          'Continent: $geoip2_data_continent_code';
        
        access_log /var/log/nginx/geo_access.log geo_log;
        
        location / {
            root /var/www/html;
            index index.html;
        }
    }
}

方法二:使用防火墙规则(iptables/firewalld)

1. 使用iptables

# 安装iptables服务
sudo yum install -y iptables-services

# 启用iptables服务
sudo systemctl enable iptables
sudo systemctl start iptables

# 清除现有规则
sudo iptables -F
sudo iptables -X

# 设置默认策略
sudo iptables -P INPUT DROP
sudo iptables -P FORWARD DROP
sudo iptables -P OUTPUT ACCEPT

# 允许本地回环
sudo iptables -A INPUT -i lo -j ACCEPT

# 允许已建立的连接
sudo iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# 允许特定国家的IP段(示例:中国)
# 中国电信
sudo iptables -A INPUT -s 1.0.1.0/24 -j ACCEPT
sudo iptables -A INPUT -s 1.0.2.0/23 -j ACCEPT
# 中国联通
sudo iptables -A INPUT -s 1.0.8.0/21 -j ACCEPT
# 中国移动
sudo iptables -A INPUT -s 1.0.32.0/19 -j ACCEPT

# 允许SSH(仅从特定IP)
sudo iptables -A INPUT -p tcp --dport 22 -s YOUR_IP -j ACCEPT

# 允许HTTP/HTTPS
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT

# 保存规则
sudo service iptables save

2. 使用firewalld(CentOS 7+)

# 安装firewalld
sudo yum install -y firewalld

# 启用firewalld
sudo systemctl enable firewalld
sudo systemctl start firewalld

# 创建自定义区域
sudo firewall-cmd --permanent --new-zone=trusted-countries

# 添加允许的IP段
sudo firewall-cmd --permanent --zone=trusted-countries --add-source=1.0.1.0/24
sudo firewall-cmd --permanent --zone=trusted-countries --add-source=1.0.2.0/23
sudo firewall-cmd --permanent --zone=trusted-countries --add-source=1.0.8.0/21

# 设置默认区域为drop
sudo firewall-cmd --set-default-zone=drop

# 配置drop区域
sudo firewall-cmd --permanent --zone=drop --add-service=ssh
sudo firewall-cmd --permanent --zone=drop --add-service=http
sudo firewall-cmd --permanent --zone=drop --add-service=https

# 重新加载配置
sudo firewall-cmd --reload

方法三:使用Nginx + 第三方服务

1. 使用Cloudflare

http {
    # Check Cloudflare CF-IPCountry header
    map $http_cf_ipcountry $allowed_country {
        default 0;
        CN 1; 
        SG 1; 
        JP 1; 
        KR 1;
    }
    
    server {
        listen 80;
        server_name your-domain.com;
        
        # Verify Cloudflare request
        if ($http_cf_connecting_ip = "") {
            return 403 "Direct access not allowed.";
        }
        
        # Check country code
        if ($allowed_country = 0) {
            return 403 "Access denied from your country.";
        }
        
        location / {
            root /var/www/html;
            index index.html;
        }
    }
}

2. 使用自定义API服务

http {
    # Define allowed country list
    map $remote_addr $allowed_country {
        default 0;
        # This can be dynamically obtained through external API
    }
    
    server {
        listen 80;
        server_name your-domain.com;
        
        # Call external API to check IP
        location /check-ip {
            internal;
            proxy_pass https://app.hanyouqing.com/api/ip?ip=$remote_addr;
            proxy_pass_request_body off;
            proxy_set_header Content-Length "";
            proxy_set_header X-Real-IP $remote_addr;
        }
        
        location / {
            # Check access permission
            auth_request /check-ip;
            
            root /var/www/html;
            index index.html;
        }
    }
}

方法四:使用Lua脚本(OpenResty)

1. 安装OpenResty

# 添加OpenResty仓库
sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://openresty.org/package/centos/openresty.repo

# 安装OpenResty
sudo yum install -y openresty openresty-resty

# 启用服务
sudo systemctl enable openresty
sudo systemctl start openresty

2. 配置Lua脚本

http {
    # Load Lua module
    lua_package_path "/etc/nginx/lua/?.lua;;";
    
    server {
        listen 80;
        server_name your-domain.com;
        
        location / {
            access_by_lua_file /etc/nginx/lua/geo_check.lua;
            
            root /var/www/html;
            index index.html;
        }
    }
}

3. 创建Lua脚本

-- /etc/nginx/lua/geo_check.lua
local cjson = require "cjson"

-- Allowed country codes
local allowed_countries = {
    CN = true,  -- China
    SG = true,  -- Singapore
    JP = true,  -- Japan
    KR = true   -- South Korea
}

-- Get client IP
local client_ip = ngx.var.remote_addr

-- Call GeoIP API
local http = require "resty.http"
local httpc = http.new()

local res, err = httpc:request_uri("http://ip-api.com/json/" .. client_ip, {
    method = "GET",
    headers = {
        ["User-Agent"] = "nginx-geo-check"
    }
})

if not res then
    ngx.log(ngx.ERR, "Failed to request GeoIP API: ", err)
    ngx.status = 500
    ngx.say("Internal server error")
    ngx.exit(500)
end

-- Parse response
local data = cjson.decode(res.body)
if not data or not data.countryCode then
    ngx.log(ngx.ERR, "Invalid response from GeoIP API")
    ngx.status = 500
    ngx.say("Internal server error")
    ngx.exit(500)
end

-- Check country code
local country_code = data.countryCode
if not allowed_countries[country_code] then
    ngx.log(ngx.WARN, "Access denied from country: ", country_code, " IP: ", client_ip)
    ngx.status = 403
    ngx.say("Access denied from your country.")
    ngx.exit(403)
end

-- Log access record
ngx.log(ngx.INFO, "Access granted from country: ", country_code, " IP: ", client_ip)

方法五:使用fail2ban进行动态封禁

1. 安装fail2ban

# 安装fail2ban
sudo yum install -y fail2ban

# 启用服务
sudo systemctl enable fail2ban
sudo systemctl start fail2ban

2. 配置fail2ban

# /etc/fail2ban/jail.local
[nginx-geo]
enabled = true
port = http,https
filter = nginx-geo
logpath = /var/log/nginx/access.log
maxretry = 3
bantime = 3600
findtime = 600

# 自定义过滤器
[Definition]
failregex = ^<HOST>.*"GET.*" 403.*"Access denied from your country"
ignoreregex =

3. 创建自定义过滤器

# /etc/fail2ban/filter.d/nginx-geo.conf
[Definition]
failregex = ^<HOST>.*"GET.*" 403.*"Access denied from your country"
ignoreregex =

性能优化建议

1. 缓存GeoIP查询结果

http {
    # Use Redis cache for GeoIP results
    lua_shared_dict geo_cache 10m;
    
    # Cache configuration
    proxy_cache_path /var/cache/nginx/geo_cache levels=1:2 keys_zone=geo_cache:10m max_size=100m inactive=60m;
    
    server {
        location / {
            # Use cache
            proxy_cache geo_cache;
            proxy_cache_valid 200 1h;
            proxy_cache_key "$remote_addr";
            
            # Other configurations...
        }
    }
}

2. 使用CDN边缘计算

http {
    # Check CDN headers
    map $http_x_forwarded_for $real_ip {
        default $remote_addr;
        "~^([^,]+)" $1;
    }
    
    # Use real IP for GeoIP lookup
    geoip_country /usr/share/GeoIP/GeoIP.dat;
}

监控和日志

1. 访问日志配置

http {
    # Custom log format
    log_format geo_access '$remote_addr - $remote_user [$time_local] '
                          '"$request" $status $body_bytes_sent '
                          '"$http_referer" "$http_user_agent" '
                          'Country: $geoip_country_code '
                          'Country_Name: $geoip_country_name';
    
    server {
        access_log /var/log/nginx/geo_access.log geo_access;
        
        # Log denied access
        location / {
            if ($allowed_country = 0) {
                access_log /var/log/nginx/geo_denied.log geo_access;
                return 403 "Access denied from your country.";
            }
        }
    }
}

2. 监控脚本

#!/bin/bash
# /usr/local/bin/nginx-geo-monitor.sh

LOG_FILE="/var/log/nginx/geo_access.log"
DENIED_LOG="/var/log/nginx/geo_denied.log"
ALERT_EMAIL="[email protected]"

# 统计访问量
TOTAL_ACCESS=$(wc -l < "$LOG_FILE")
DENIED_ACCESS=$(wc -l < "$DENIED_LOG")

# 计算拒绝率
if [ $TOTAL_ACCESS -gt 0 ]; then
    DENIED_RATE=$(echo "scale=2; $DENIED_ACCESS * 100 / $TOTAL_ACCESS" | bc)
    
    # 如果拒绝率超过10%,发送告警
    if (( $(echo "$DENIED_RATE > 10" | bc -l) )); then
        echo "High access denial rate: ${DENIED_RATE}%" | \
        mail -s "Nginx Geo Access Alert" "$ALERT_EMAIL"
    fi
fi

# 输出统计信息
echo "Total access: $TOTAL_ACCESS"
echo "Denied access: $DENIED_ACCESS"
echo "Denial rate: ${DENIED_RATE}%"

安全注意事项

1. 防止IP伪造

http {
    # Check real IP
    real_ip_header X-Forwarded-For;
    real_ip_recursive on;
    
    # Verify proxy headers
    if ($http_x_forwarded_for !~ "^$") {
        set $real_ip $http_x_forwarded_for;
    }
    
    # Use real IP for GeoIP lookup
    geoip_country /usr/share/GeoIP/GeoIP.dat;
}

2. 限制API调用频率

http {
    # Limit GeoIP API call frequency
    limit_req_zone $remote_addr zone=geo_api:10m rate=10r/m;
    
    server {
        location /geo-api {
            limit_req zone=geo_api burst=5 nodelay;
            
            # API configuration...
        }
    }
}

故障排除

1. 常见问题

# 检查GeoIP模块是否加载
nginx -V 2>&1 | grep -o with-http_geoip_module

# 检查GeoIP数据库文件
ls -la /usr/share/GeoIP/

# 测试GeoIP查询
geoiplookup 8.8.8.8

# 检查Nginx配置语法
nginx -t

# 查看Nginx错误日志
tail -f /var/log/nginx/error.log

# CentOS 7特定问题排查
# 1. 检查可用的Nginx模块包
yum search nginx | grep module

# 2. 检查EPEL仓库是否启用
yum repolist | grep epel

# 3. 如果Nginx没有GeoIP模块,检查是否支持动态模块加载
nginx -V 2>&1 | grep -o with-compat

# 4. 检查系统架构和Nginx版本
uname -m
nginx -v

# 5. 编译依赖问题排查
# 检查是否安装了必要的开发库
rpm -qa | grep -E "(libxml2-devel|libxslt-devel|pcre-devel|zlib-devel|openssl-devel)"

# 如果缺少依赖,安装它们
# sudo yum install -y libxml2-devel libxslt-devel pcre-devel zlib-devel openssl-devel

2. 调试配置

http {
    # Enable debug logging
    error_log /var/log/nginx/debug.log debug;
    
    # Add debug info to response headers
    add_header X-Debug-Country $geoip_country_code always;
    add_header X-Debug-IP $remote_addr always;
}

3. 编译故障排除

# 常见编译错误及解决方案

# 1. libxml2/libxslt 缺失
# 错误:./configure: error: the HTTP XSLT module requires the libxml2/libxslt libraries
# 解决:sudo yum install -y libxml2-devel libxslt-devel

# 2. PCRE 缺失
# 错误:./configure: error: the HTTP rewrite module requires the PCRE library
# 解决:sudo yum install -y pcre-devel

# 3. OpenSSL 缺失
# 错误:./configure: error: SSL modules require the OpenSSL library
# 解决:sudo yum install -y openssl-devel

# 4. Zlib 缺失
# 错误:./configure: error: the HTTP gzip module requires the zlib library
# 解决:sudo yum install -y zlib-devel

# 5. Google perftools 缺失
# 错误:./configure: error: the Google perftools module requires the Google perftools library
# 解决:sudo yum install -y gperftools gperftools-devel

# 6. 权限问题
# 错误:make: *** [install] Error 1
# 解决:确保使用 sudo 运行 make install

# 7. 内存不足
# 错误:make: *** [build] Error 1
# 解决:增加swap空间或使用 make -j1 限制并发编译

# 验证编译结果
nginx -V 2>&1 | grep -o with-http_geoip_module

4. 运行时故障排除

# Worker进程崩溃问题排查

# 1. 检查Nginx配置语法
nginx -t

# 2. 检查错误日志
tail -f /var/log/nginx/error.log

# 3. 检查访问日志
tail -f /var/log/nginx/access.log

# 4. 检查系统资源
free -h
df -h
top

# 5. 检查Nginx进程状态
ps aux | grep nginx
systemctl status nginx

# 6. 检查模块加载
nginx -V 2>&1 | grep -o with-http_geoip_module

# 7. 检查GeoIP数据库文件
ls -la /usr/share/GeoIP/
file /usr/share/GeoIP/GeoLite2-Country.dat

# 8. 测试GeoIP功能
geoiplookup 8.8.8.8
geoiplookup 127.0.0.1

# 9. 段错误(SIGSEGV)问题解决
# 错误:worker process exited on signal 11 (SIGSEGV)
# 可能原因:
# - GeoIP数据库文件损坏或格式不正确
# - 模块编译问题
# - 内存不足
# - 配置语法错误

# 解决步骤:
# a) 重新下载GeoIP数据库
wget -O /usr/share/GeoIP/GeoLite2-Country.dat https://github.com/P3TERX/GeoLite.mmdb/raw/download/GeoLite2-Country.mmdb

# b) 验证数据库文件完整性
file /usr/share/GeoIP/GeoLite2-Country.dat
md5sum /usr/share/GeoIP/GeoLite2-Country.dat

# c) 使用简化配置测试
# 临时注释掉GeoIP相关配置,测试基本功能

# d) 检查系统内存
free -h
# 如果内存不足,增加swap或减少worker_processes

# 模块文件缺失问题排查
# 1. 检查模块是否被编译为静态模块(内置)
nginx -V 2>&1 | grep -o with-http_geoip_module

# 2. 如果是静态模块,不需要 load_module 指令
# 3. 如果是动态模块,检查文件路径:
find /usr/share/nginx -name "*geoip*" -type f
find /usr/lib64/nginx/modules -name "*geoip*" -type f 2>/dev/null

# 4. 检查编译日志中是否有错误
# 查看 make 输出中是否有 "error" 或 "failed" 关键词

# 5. 如果模块文件缺失,可能的解决方案:
# a) 重新编译,确保没有编译错误
# b) 检查是否使用了 --with-compat 选项(支持动态模块)
# c) 确认模块路径配置正确
# d) 使用静态编译(移除 --with-compat 选项)

# 6. 完整的模块问题解决步骤:
# 步骤1:检查模块类型
nginx -V 2>&1 | grep -o with-http_geoip_module

# 步骤2:如果是静态模块,修改nginx.conf(移除load_module)
# 如果是动态模块,查找模块文件位置
find /usr/share/nginx -name "*geoip*" -type f
find /usr/lib64/nginx/modules -name "*geoip*" -type f 2>/dev/null

# 步骤3:如果找不到模块文件,重新编译
# 使用静态编译(推荐):
# ./configure --prefix=/usr/share/nginx --sbin-path=/usr/sbin/nginx --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --user=nginx --group=nginx --with-http_ssl_module --with-http_realip_module --with-http_geoip_module --with-pcre --with-http_gzip_static_module --with-http_stub_status_module

# 模块选择建议
# 如果遇到多个模块依赖问题,建议只启用必要的模块:
# - --with-http_ssl_module (HTTPS支持)
# - --with-http_realip_module (真实IP获取)
# - --with-http_geoip_module (地理IP功能)
# - --with-pcre (正则表达式支持)
# - --with-http_gzip_static_module (静态gzip支持)
# - --with-http_stub_status_module (状态监控)

# 模块文件缺失问题排查
# 1. 检查模块是否被编译为静态模块(内置)
nginx -V 2>&1 | grep -o with-http_geoip_module

# 2. 如果是静态模块,不需要 load_module 指令
# 3. 如果是动态模块,检查文件路径:
find /usr/share/nginx -name "*geoip*" -type f
find /usr/lib64/nginx/modules -name "*geoip*" -type f 2>/dev/null

# 4. 检查编译日志中是否有错误
# 查看 make 输出中是否有 "error" 或 "failed" 关键词

总结

本文介绍了在CentOS系统上配置Nginx实现地理访问控制的多种方法:

  1. Nginx GeoIP模块:最直接和高效的方法,适合大多数场景
  2. 防火墙规则:系统级别的控制,性能最好但配置复杂
  3. 第三方服务:利用CDN或云服务的地理信息,部署简单
  4. Lua脚本:最灵活的方法,可以实现复杂的业务逻辑
  5. fail2ban:动态封禁恶意IP,提高安全性

CentOS 7 特别建议

由于CentOS 7的Nginx包可能不包含GeoIP模块,建议按以下优先级选择:

  1. 首选:使用防火墙规则(方法二)- 系统级别控制,性能最佳
  2. 备选:使用第三方服务(方法三)- 部署简单,维护成本低
  3. 高级:重新编译Nginx - 功能完整但需要技术能力
  4. 灵活:使用Lua脚本(方法四)- 适合复杂业务逻辑

选择合适的方法取决于您的具体需求、性能要求和维护能力。对于生产环境,建议使用Nginx GeoIP模块配合MaxMind数据库,这是最稳定和高效的解决方案。

相关资源

附录:紧急故障排除指南

段错误(SIGSEGV)快速修复

如果您遇到 worker process exited on signal 11 错误,请按以下步骤操作:

步骤1:立即停止Nginx

sudo systemctl stop nginx
sudo pkill -f nginx

步骤2:备份当前配置

sudo cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.backup.$(date +%Y%m%d_%H%M%S)

步骤3:使用简化配置

创建一个最小化的配置文件 /etc/nginx/nginx.conf

user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

events {
    worker_connections 1024;
}

http {
    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for"';

    access_log /var/log/nginx/access.log main;
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;

    server {
        listen 80 default_server;
        server_name _;
        root /var/www/html;
        index index.html index.htm;

        location / {
            try_files $uri $uri/ =404;
        }
    }
}

步骤4:测试配置

sudo nginx -t

步骤5:启动服务

sudo systemctl start nginx
sudo systemctl status nginx

步骤6:测试基本功能

curl localhost

步骤7:逐步恢复GeoIP功能

一旦基本服务正常,可以逐步添加GeoIP功能,每次添加后都要测试:

# 1. 先添加GeoIP配置(不启用访问控制)
# 2. 测试GeoIP模块是否正常工作
# 3. 再添加访问控制逻辑
# 4. 测试完整功能

常见问题检查清单

  • Nginx配置语法正确 (nginx -t)
  • GeoIP数据库文件存在且完整
  • 系统内存充足 (free -h)
  • 磁盘空间充足 (df -h)
  • 模块正确编译 (nginx -V)
  • 权限设置正确 (ls -la /usr/share/GeoIP/)
  • 防火墙规则正确
  • SELinux设置正确
YH

Youqing Han

DevOps Engineer

Share this article:

Stay Updated

Get the latest DevOps insights and best practices delivered to your inbox

No spam, unsubscribe at any time