LOGO OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 开发文档 其他文档  
 
网站管理员

用Nginx轻松实现国际化访问!不同国家用户看到不同页面的完整攻略

admin
2026年2月21日 21:30 本文热度 150

前言


最近客户有个项目需要针对不同国家的用户展示不同的页面内容,说实话一开始我还想着要不要用什么复杂的CDN方案,后来发现用Nginx就能轻松搞定。今天就把整个实现过程分享给大家,包括踩过的坑和一些优化技巧。

这个需求其实挺常见的,比如做跨境电商的朋友,针对美国用户显示英文页面和美元价格,针对中国用户显示中文页面和人民币价格。或者有些网站需要根据不同地区的法律法规展示不同的内容条款。

实现原理其实很简单

核心思路就是通过Nginx的GeoIP模块来识别用户的IP地址对应的国家,然后根据国家信息将请求转发到不同的后端或者直接返回不同的静态页面。

不过这里有个关键点,Nginx默认是不带GeoIP模块的,我们需要先安装相关的模块和数据库。

第一步:准备GeoIP数据库

# CentOS/RHEL系统
yum install -y geoip-devel libmaxminddb-devel

# Ubuntu/Debian系统

apt-get install -y libgeoip-dev libmaxminddb-dev

# 下载GeoIP数据库文件

mkdir
 -p /etc/nginx/geoip
cd
 /etc/nginx/geoip

# 下载免费的GeoLite2数据库

wget https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-Country&license_key=YOUR_LICENSE_KEY&suffix=tar.gz -O GeoLite2-Country.tar.gz

这里要注意,MaxMind从2019年开始要求注册账号才能下载数据库了。你需要去他们官网注册个免费账号,然后生成license key。

解压数据库文件:

(下载不了可以后台联系找我要)

tar -xzf GeoLite2-Country.tar.gz
cp
 GeoLite2-Country_*/GeoLite2-Country.mmdb ./

检查Nginx是否支持GeoIP

nginx -V 2>&1 | grep -o with-http_geoip_module

如果没有输出,说明当前的Nginx不支持GeoIP模块,需要重新编译安装或者安装带GeoIP模块的版本。

对于CentOS,可以这样安装:

yum install -y nginx-mod-http-geoip

配置Nginx实现地理位置识别

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

http {
    # 加载GeoIP模块

    geoip_country
 /etc/nginx/geoip/GeoLite2-Country.mmdb;
  
    # 定义国家代码映射

    map
 $geoip_country_code $country_path {
        default
 /default;
        CN
 /cn;
        US
 /us;
        JP
 /jp;
        KR
 /kr;
        GB
 /gb;
        DE
 /de;
        FR
 /fr;
    }
  
    # 定义语言映射

    map
 $geoip_country_code $lang {
        default
 en;
        CN
 zh;
        JP
 ja;
        KR
 ko;
        DE
 de;
        FR
 fr;
    }
  
    server
 {
        listen
 80;
        server_name
 example.com;
      
        # 设置根目录

        root
 /var/www/html;
        index
 index.html index.php;
      
        # 根据国家跳转到不同目录

        location
 / {
            try_files
 $country_path$uri $country_path/index.html $uri /default/index.html;
        }
      
        # API接口可以返回JSON格式的国家信息

        location
 /api/country {
            add_header
 Content-Type application/json;
            return
 200 '{"country":"$geoip_country_code","country_name":"$geoip_country_name","lang":"$lang"}';
        }
    }
}

目录结构设计

按照上面的配置,我们需要创建对应的目录结构:

mkdir -p /var/www/html/{default,cn,us,jp,kr,gb,de,fr}

# 创建不同国家的首页

echo
 '<h1>Welcome to our global site!</h1>' > /var/www/html/default/index.html
echo
 '<h1>欢迎访问我们的中国站点!</h1>' > /var/www/html/cn/index.html
echo
 '<h1>Welcome to our US site!</h1>' > /var/www/html/us/index.html
echo
 '<h1>日本のサイトへようこそ!</h1>' > /var/www/html/jp/index.html

这种方式比较简单直接,但如果页面内容差异不大,可能会造成文件冗余。

更灵活的方案:动态内容替换

有时候我们不想维护多套完整的页面,只是希望替换其中的部分内容,比如货币符号、语言文本等。这时候可以用Nginx的sub_filter模块:

server {
    listen
 80;
    server_name
 shop.example.com;
    root
 /var/www/shop;
  
    # 美国用户

    location
 / {
        if
 ($geoip_country_code = "US") {
            sub_filter
 '{{CURRENCY}}' '$';
            sub_filter
 '{{LANGUAGE}}' 'en';
            sub_filter
 '{{COUNTRY_NAME}}' 'United States';
            sub_filter_once
 off;
        }
      
        # 中国用户

        if
 ($geoip_country_code = "CN") {
            sub_filter
 '{{CURRENCY}}' '¥';
            sub_filter
 '{{LANGUAGE}}' 'zh';
            sub_filter
 '{{COUNTRY_NAME}}' '中国';
            sub_filter_once
 off;
        }
      
        # 欧元区用户

        if
 ($geoip_country_code ~ "^(DE|FR|IT|ES)$") {
            sub_filter
 '{{CURRENCY}}' '€';
            sub_filter
 '{{LANGUAGE}}' 'eu';
            sub_filter
 '{{COUNTRY_NAME}}' 'Europe';
            sub_filter_once
 off;
        }
      
        try_files
 $uri $uri/ /index.html;
    }
}

然后在HTML模板中使用占位符:

<!DOCTYPE html>
<html lang="{{LANGUAGE}}">

<head>

    <title>
Shop - {{COUNTRY_NAME}}</title>
</head>

<body>

    <h1>
Welcome to our {{COUNTRY_NAME}} store!</h1>
    <p>
All prices are shown in {{CURRENCY}}.</p>
</body>

</html>

进阶配置:结合上游服务器

在实际生产环境中,我们通常需要将请求转发给不同的后端服务器,而不只是返回静态页面:

upstream china_backend {
    server
 192.168.1.10:8080;
    server
 192.168.1.11:8080;
}

upstream
 us_backend {
    server
 192.168.2.10:8080;
    server
 192.168.2.11:8080;
}

upstream
 default_backend {
    server
 192.168.3.10:8080;
    server
 192.168.3.11:8080;
}

server
 {
    listen
 80;
    server_name
 api.example.com;
  
    # 设置自定义header传递国家信息给后端

    proxy_set_header
 X-Country-Code $geoip_country_code;
    proxy_set_header
 X-Country-Name $geoip_country_name;
  
    location
 / {
        # 根据国家选择上游服务器

        if
 ($geoip_country_code = "CN") {
            proxy_pass
 http://china_backend;
            break;
        }
      
        if
 ($geoip_country_code = "US") {
            proxy_pass
 http://us_backend;
            break;
        }
      
        proxy_pass
 http://default_backend;
    }
}

处理特殊情况和优化

实际使用中会遇到一些特殊情况,需要特别处理:

# 定义白名单IP,不进行地理位置检测
geo
 $whitelist_ip {
    default
 0;
    192.168.1.0/24 1;  # 内网IP
    10.0.0.0/8 1;      # 内网IP
    127.0.0.1/32 1;    # 本地IP
}

server
 {
    listen
 80;
    server_name
 example.com;
  
    # 设置真实IP(如果使用了CDN或负载均衡)

    real_ip_header
 X-Forwarded-For;
    set_real_ip_from
 192.168.1.0/24;  # CDN的IP段
  
    location
 / {
        # 白名单IP直接访问默认页面

        if
 ($whitelist_ip) {
            root
 /var/www/html/default;
            break;
        }
      
        # 允许用户手动选择国家站点

        if
 ($arg_country) {
            set
 $manual_country $arg_country;
            root
 /var/www/html/$manual_country;
            break;
        }
      
        # 正常的GeoIP判断

        root
 /var/www/html$country_path;
        try_files
 $uri $uri/ /index.html;
    }
}

这样配置后,用户可以通过 example.com?country=cn 这样的URL手动选择要访问的国家站点。

缓存策略很重要

因为GeoIP查询还是有一定开销的,建议合理设置缓存:

# 在http块中设置
proxy_cache_path
 /var/cache/nginx levels=1:2 keys_zone=geo_cache:10m max_size=100m inactive=60m;

server
 {
    listen
 80;
    server_name
 example.com;
  
    # 缓存策略

    location
 / {
        proxy_cache
 geo_cache;
        proxy_cache_key
 "$scheme$request_method$host$request_uri$geoip_country_code";
        proxy_cache_valid
 200 10m;
      
        # 其他配置...

    }
}

调试和测试技巧

开发过程中,调试GeoIP功能还是有点麻烦的,因为你的IP通常是固定的。这里有几个技巧:

# 添加调试location
location
 /debug {
    add_header
 Content-Type text/plain;
    return
 200 "Your IP: $remote_addr\nCountry: $geoip_country_code\nCountry Name: $geoip_country_name\nPath: $country_path\nLang: $lang";
}

# 允许通过header模拟不同国家

location
 / {
    if
 ($http_x_debug_country) {
        set
 $geoip_country_code $http_x_debug_country;
    }
  
    # 其他配置...

}

测试的时候可以这样:

# 正常访问看到的国家信息
curl http://example.com/debug

# 模拟美国用户

curl -H "X-Debug-Country: US" http://example.com/debug

性能监控不能忽视

这种基于GeoIP的路由会增加一些延迟,建议加上监控:

# 记录处理时间
log_format
 geo_log '$remote_addr - $remote_user [$time_local] "$request" '
                   '$status $body_bytes_sent "$http_referer" '

                   '"$http_user_agent" $request_time $geoip_country_code'
;

server
 {
    access_log
 /var/log/nginx/geo_access.log geo_log;
  
    # 其他配置...

}

然后可以用awstats或者其他日志分析工具来分析不同国家用户的访问情况和响应时间。

遇到的坑和解决方案

部署过程中踩了几个坑,分享给大家避免:

坑1:GeoIP数据库更新问题
MaxMind的免费数据库每月更新,如果不及时更新,可能会出现IP识别不准确的问题。建议写个定时脚本:

#!/bin/bash
# update_geoip.sh

cd
 /etc/nginx/geoip
wget -O GeoLite2-Country-new.tar.gz "https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-Country&license_key=YOUR_LICENSE_KEY&suffix=tar.gz"
tar -xzf GeoLite2-Country-new.tar.gz
cp
 GeoLite2-Country_*/GeoLite2-Country.mmdb ./GeoLite2-Country.mmdb.new
mv
 GeoLite2-Country.mmdb.new GeoLite2-Country.mmdb
nginx -s reload
rm
 -rf GeoLite2-Country_* GeoLite2-Country-new.tar.gz

加到crontab里每月执行一次:

0 2 1 * * /path/to/update_geoip.sh

坑2:CDN和负载均衡器的IP问题
如果网站使用了CDN,Nginx获取到的IP是CDN节点的IP,不是真实用户IP。需要配置:

set_real_ip_from 103.21.244.0/22;  # Cloudflare IP段,根据实际CDN调整
real_ip_header
 CF-Connecting-IP;    # Cloudflare的真实IP头

坑3:移动网络的IP识别
移动网络的IP经常变动,而且有些运营商会用代理,导致地理位置识别不准。这种情况下可以结合浏览器的地理位置API:

// 前端JavaScript辅助识别
navigator.geolocation.getCurrentPosition(function(position) {
    fetch
('/api/update-location', {
        method
: 'POST',
        headers
: {'Content-Type': 'application/json'},
        body
: JSON.stringify({
            lat
: position.coords.latitude,
            lng
: position.coords.longitude
        })
    });
});

安全性考虑

这种基于地理位置的访问控制还有安全方面的考虑:

# 限制某些国家访问敏感接口
location
 /admin {
    # 只允许特定国家访问

    if
 ($geoip_country_code !~ "^(US|CN|JP)$") {
        return
 403 "Access denied from your location";
    }
  
    # 其他安全配置

    auth_basic
 "Admin Area";
    auth_basic_user_file
 /etc/nginx/.htpasswd;
}

# 对某些国家做更严格的频率限制

http
 {
    # 为不同国家设置不同的限制策略

    map
 $geoip_country_code $rate_limit_key {
        default
 $binary_remote_addr;
        ~^(CN|RU|KP)$ $binary_remote_addr;  # 对某些国家使用更严格限制
    }
  
    limit_req_zone
 $rate_limit_key zone=by_country:10m rate=1r/s;
  
    server
 {
        location
 / {
            limit_req
 zone=by_country burst=5;
            # 其他配置...

        }
    }
}

实际使用下来,这套方案还是很稳定的。我们线上跑了几个月,基本没出过什么问题。用户体验也提升不少,不同国家的用户都能看到符合本地化需求的内容。

当然,如果你的网站访问量特别大,也可以考虑把GeoIP判断逻辑前置到CDN层面,比如用Cloudflare的Workers或者AWS的Lambda@Edge来实现,这样可以进一步减少源站的压力。

总的来说,Nginx的GeoIP功能还是很强大的,配合一些创意可以实现很多有意思的功能。比如我见过有人用它来做A/B测试,不同地区的用户看到不同版本的页面,然后统计转化率。


阅读原文:原文链接


该文章在 2026/2/22 23:43:14 编辑过
关键字查询
相关文章
正在查询...
点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
Copyright 2010-2026 ClickSun All Rights Reserved