Nginx GeoIP + 多 CDN:一个域名给不同国家用户返回不同站
能。主流方案四种:路径、子域、独立域名、CDN 边缘路由。面试场景里"一个域名给不同人看不同站"的最优解是 Nginx GeoIP2 模块 + 多 upstream,或者更省事的 Cloudflare Workers 边缘路由。三个大坑必须注意:GeoIP 数据库每月更新、CDN 反代后要 set_real_ip_from、国内源站必须备案。
主流方案对比
| 方案 | 例子 | 优劣 |
|---|---|---|
| 同一域名 + 路径 | site.com/cn/、site.com/intl/ | 最简单,SEO 不分流 |
| 子域名 | cn.site.com、www.site.com | 各自独立部署,SEO 分流 |
| 完全独立域名 | site.cn、site.com | 品牌独立,本地化最强 |
| CDN 边缘路由 | site.com 一个域名,CDN 分配 | 一个域名给不同人看不同站——本文方案 |
一个域名给不同人访问不同站
原理:用户访问的是同一个 URL,但 DNS 解析结果不同 → 走不同 CDN 节点 → 返回不同内容。
DNS智能解析
↓
中国用户 IP ──────┼────── 国际用户 IP
↓ ↓
阿里云 CDN Cloudflare CDN
(国内节点) (海外节点)
↓ ↓
site.cn 内容 site.com 内容
↓ ↓
└─────── 用户看到的同一个 site.com ───────┘
↑ ↑
但内容不一样
关键四件套:
-
GeoDNS / 智能 DNS 解析
- DNS 根据用户 IP 的地理位置返回不同 A记录/CNAME
- 阿里云 DNS / DNSPod / Cloudflare 都支持
- 配置示例:
中国 IP → 国内 CDN,海外 IP → 海外 CDN
-
CDN 边缘节点
- 各 CDN 在不同地域有节点
- 国内用阿里云/腾讯云 CDN(要备案)
- 海外用 Cloudflare/Fastly(不用备案)
-
源站分离
- 国内源站部署在国内机房(访问快+备案合规)
- 海外源站部署在 AWS/Cloudflare/Vercel
-
回源策略
- 边缘节点找不到资源时回源拉取
- 国内CDN → 国内源站,海外CDN → 海外源站
Nginx GeoIP2 实现方案(最推荐)
需要编译 Nginx 时带 --with-http_geoip2_module,OpenResty 默认带。
# /etc/nginx/geoip.conf
load_module "modules/ngx_http_geoip2_module.so"; # OpenResty
http {
# 加载 GeoIP2 数据库(MaxMind 免费版)
geoip2 /usr/share/GeoIP/GeoLite2-Country.mmdb {
$geoip2_data_country_iso_code country iso_code;
}
# 映射国家代码 → 内部变量
map $geoip2_data_country_iso_code $backend {
default "intl";
CN "cn";
HK "cn"; # 香港也走国内
MO "cn"; # 澳门也走国内
TW "intl"; # 台湾按国际
}
server {
listen 80;
server_name site.com;
# 方式 A:跳转到不同子域
return 301 https://$backend.site.com$request_uri;
# 或者方式 B:proxy_pass 到不同 upstream
location / {
proxy_pass http://${backend}_backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Country $geoip2_data_country_iso_code;
}
}
upstream cn_backend { server 192.168.1.10:3000; }
upstream intl_backend { server 10.0.0.5:3000; }
}
Cloudflare 实现(零运维方案)
如果用 Cloudflare 做 CDN,连数据库都不用管——点几下配置就行。
Cloudflare Dashboard → Rules → Transform Rules
→ 匹配条件: ip.src.country == "CN"
→ 动作: Set dynamic link to different origin
或者用 Cloudflare Workers:
export default {
async fetch(request) {
const country = request.cf?.country
const url = new URL(request.url)
if (country === 'CN' || country === 'HK' || country === 'MO') {
url.hostname = 'cn-site.example.com'
} else {
url.hostname = 'intl-site.example.com'
}
return fetch(url, request)
}
}
重要:Cloudflare Workers 是边缘函数,不能用在国内源站——国内用户绕到海外节点违规。但用 Cloudflare 服务国际用户就没问题。
GeoIP 数据库
| 数据库 | 精度 | 价格 | 来源 |
|---|---|---|---|
| MaxMind GeoLite2 | 国家/城市级 | 免费(需注册) | maxmind.com |
| IP2Location | 国家/城市/经纬度 | 商业付费 | ip2location.com |
| 淘宝 IP 库 | 国内精确 | 免费 | ip.taobao.com |
| Cloudflare 内置 | 国家/地区 | 免费 | request.cf.country |
免费 GeoLite2 数据库的命令:
# Ubuntu 安装依赖
apt-get install libmaxminddb0 libmaxminddb-dev mmdb-bin
# 下载免费数据库(需注册账号拿 license key)
mmdbupdate --license-key=YOUR_KEY --output-dir=/usr/share/GeoIP GeoLite2-Country GeoLite2-City
三大坑(实战必踩)
坑 1:MaxMind 数据库要更新
# GeoLite2 每月更新一次,要做定时任务
0 0 1 * * /usr/local/bin/mmdbupdate ...
不更新 → IP 段错配 → 误判。
坑 2:CDN 反代后拿不到真实 IP
# 必须 set real IP
set_real_ip_from 0.0.0.0/0; # 信任所有 CDN
real_ip_header X-Forwarded-For;
real_ip_recursive on;
否则 $remote_addr 是 CDN 节点 IP,全是同一个国家,全错。
坑 3:国内合规
国内源站必须备案。GeoIP 路由到国内源站之前,备案号要通过审核。Cloudflare/海外 CDN 不需要备案,但只用海外服务器给国内用户访问,速度慢且合规风险高。
完整生产方案(实战推荐)
用户访问 site.com
↓
Cloudflare CDN(全球加速 + WAF)
↓ Cloudflare Workers 判断国家
├── CN/HK/MO → 国内源站(阿里云 ECS,备案过)
│ ↓
│ Nginx (geoip2 验证 + 静态缓存)
│ ↓
│ Node/PHP 应用 + 国内数据库
│
└── 其他 → 海外源站(Vercel / Cloudflare Pages)
↓
静态站 + Cloudflare Workers(边缘函数)
高频追问
Q1:GeoIP 数据库免费版精度够吗?
国家级够,城市级对国内还行,海外 IP 经常落到临近城市。商业版 IP2Location / MaxMind Insights 精确到城市经纬度。
Q2:怎么动态配置国家列表?
用 Consul / Nacos + Lua 脚本热更新 Nginx 配置。或者用 Map + Lua + Redis,IP 查询走 Redis 缓存。
Q3:用户 IP 被 CDN 篡改怎么办?
信任 CDN 的
X-Forwarded-For,但要限定 CDN IP 段(set_real_ip_from)。不要信任所有 IP。
Q4:怎么测试不同国家的访问?
- 用 VPN/代理
- curl 指定
X-Forwarded-For: 8.8.8.8(仅测试用)- 用 Cloudflare 的
cf-ipcountry调试 header
Q5:用户用 VPN 怎么办?
没办法完美解决,靠用户主动切换。提供明显的"国际版 / 国内版"切换按钮。
一句话答题模板
能,用 Nginx GeoIP2 模块就能做,原理是加载 MaxMind GeoLite2 数据库(免费注册拿 key)在 Nginx 里识别
$geoip2_data_country_iso_code,用map映射成cn/intl内部变量,再proxy_pass到不同 upstream。但生产环境更推荐 Cloudflare CDN 边缘路由 + 国内备案源站 + 海外源站的组合:Cloudflare Workers 在边缘判断路由,国内走备案过的国内源站,海外走 Vercel/Cloudflare Pages。三大坑必须注意:GeoIP 数据库每月要更新、CDN 反代后要 set_real_ip_from 拿真实 IP、国内源站必须备案。
如果您觉得这篇文章有帮助,请点个赞吧~
评论
请登录后发表评论
去登录