插件窝 干货文章 如何使用Nginx实现基于地理位置的访问控制

如何使用Nginx实现基于地理位置的访问控制

GeoIP Nginx 数据库 country 684    来源:    2025-04-13

使用Nginx实现基于地理位置的访问控制

Nginx可以通过GeoIP模块来实现基于地理位置的访问控制,允许您根据访问者的IP地址所在国家或地区来允许或拒绝访问。以下是完整的实现步骤:

1. 安装必要的模块

对于Nginx官方版本:

# 安装GeoIP数据库和模块
sudo apt-get install libgeoip1 geoip-database libnginx-mod-http-geoip  # Debian/Ubuntu
sudo yum install geoip geoip-devel nginx-module-geoip                # CentOS/RHEL

对于编译安装的Nginx:

需要添加--with-http_geoip_module参数重新编译Nginx。

2. 下载GeoIP数据库

# 下载国家数据库
wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz
gunzip GeoIP.dat.gz

# 下载城市数据库(可选)
wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz
gunzip GeoLiteCity.dat.gz

3. 配置Nginx

在nginx.conf的http块中添加以下配置:

http {
    # 加载GeoIP数据库
    geoip_country /path/to/GeoIP.dat;
    geoip_city /path/to/GeoLiteCity.dat;  # 可选

    # 创建变量映射国家代码
    map $geoip_country_code $allowed_country {
        default no;
        US yes;  # 允许美国
        CA yes;  # 允许加拿大
        GB yes;  # 允许英国
        # 添加更多允许的国家代码...
    }
}

4. 在server或location块中应用访问控制

server {
    listen 80;
    server_name example.com;

    # 基于国家代码的访问控制
    if ($allowed_country = no) {
        return 403;  # 拒绝访问
        # 或者重定向到其他页面
        # return 301 https://example.com/access-denied;
    }

    # 其他配置...
}

5. 高级用法

根据城市限制访问

geoip_city /path/to/GeoLiteCity.dat;

location / {
    if ($geoip_city = "New York") {
        return 403;
    }
    # 其他配置...
}

根据地区限制特定内容

location /us-only-content {
    if ($geoip_country_code != US) {
        return 404;
    }
    # 其他配置...
}

记录地理位置信息

log_format geo_log '$remote_addr - $geoip_country_name - $geoip_city - "$request"';
access_log /var/log/nginx/geo_access.log geo_log;

6. 更新GeoIP数据库

GeoIP数据库需要定期更新以保持准确性:

# 创建更新脚本 /usr/local/bin/update_geoip.sh
#!/bin/bash
wget -O /tmp/GeoIP.dat.gz http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz
gunzip -c /tmp/GeoIP.dat.gz > /path/to/GeoIP.dat
rm /tmp/GeoIP.dat.gz
service nginx reload

# 设置定时任务
crontab -e
# 添加每月1号更新
0 0 1 * * /usr/local/bin/update_geoip.sh

7. 替代方案:使用Nginx+Lua

如果需要更复杂的地理位置逻辑,可以考虑使用OpenResty(Nginx+Lua):

http {
    lua_shared_dict geoip 10m;

    init_by_lua_block {
        local geo = require "resty.maxminddb"
        geo.init("/path/to/GeoLite2-City.mmdb")
    }

    server {
        location / {
            access_by_lua_block {
                local geo = require "resty.maxminddb"
                local res, err = geo.lookup(ngx.var.remote_addr)

                if res and res.country and res.country.iso_code == "CN" then
                    ngx.exit(403)
                end
            }
        }
    }
}

注意事项

  1. GeoIP数据库的准确性有限,特别是对于移动网络和VPN用户
  2. 频繁的IP数据库查询可能影响性能
  3. 考虑GDPR等隐私法规的要求
  4. 对于高流量网站,建议使用商业版的MaxMind GeoIP2数据库

通过以上配置,您可以有效地实现基于地理位置的访问控制,保护您的网站内容或服务。