首页/文章/前端部署

Nginx GeoIP + 多 CDN:一个域名给不同国家用户返回不同站

2026-08-27
2074 字约 7 分钟
...

能。主流方案四种:路径、子域、独立域名、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 ───────┘
              ↑                ↑
                  但内容不一样

关键四件套:

  1. GeoDNS / 智能 DNS 解析

    • DNS 根据用户 IP 的地理位置返回不同 A记录/CNAME
    • 阿里云 DNS / DNSPod / Cloudflare 都支持
    • 配置示例:中国 IP → 国内 CDN,海外 IP → 海外 CDN
  2. CDN 边缘节点

    • 各 CDN 在不同地域有节点
    • 国内用阿里云/腾讯云 CDN(要备案)
    • 海外用 Cloudflare/Fastly(不用备案)
  3. 源站分离

    • 国内源站部署在国内机房(访问快+备案合规)
    • 海外源站部署在 AWS/Cloudflare/Vercel
  4. 回源策略

    • 边缘节点找不到资源时回源拉取
    • 国内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、国内源站必须备案。

如果您觉得这篇文章有帮助,请点个赞吧~

分享文章

相关文章

更多文章 →
前端部署2024-07-29
搭建自动化 Web 页面性能检测系统 —— 部署篇
作为一个前端想去做全栈的项目时,可能第一个思路是 node + vue/react。一开始可能会新建多个工程目录去实现,假设分别为 web 和 server,也许还有管理后台的代码 admin,那么就有了三个工程的代码。此时为了方便管理就需要在远程仓库新建一个 group 统一管理代码,一般这种方式称之为 MultiRepo。   这显然是不够简洁的,对于开发者而言也不便于开发和部署。这类多模块的项目我们可以引入 Monore...
学习
前端部署2023-09-18
写给前端同学的Nginx配置指南
nginx.conf配置 找到Nginx的安装目录下的 文件,该文件负责Nginx的基础功能配置。 配置文件概述 Nginx的主配置文件( )按以下结构组织: | 配置块 | 功能描述 | | | | | 全局块 | 与Nginx运行相关的全局设置 | | events块 | 与网络连接有关的设置 | | http块 | 代理、缓存、日志、虚拟主机等的配置 | | server块 | 虚拟主机的参数设置(一个http块可包含多个serv...
学习
http-网络2026-10-15
OAuth 2.0是什么,以及如何正确接入
一、先从一个需求理解 OAuth 2.0 假设你开发了一个相册整理工具,用户希望它读取某个云盘里的照片。 把云盘密码交给工具,会带来几个问题:工具拿到的权限太大,密码可能泄漏,用户也难以只撤销这个工具的访问。 OAuth 2.0 提供一套 委托授权机制 :用户在云盘自己的页面确认授权,工具取得一个有权限范围和有效期的访问令牌,再用它调用云盘 API。用户的云盘密码不交给工具。 可以把它理解为:给工具一张“限定用途的通行证”。但令牌泄漏同...
学习
前端2026-10-15
前端动画全景指南
一、前端动画到底是什么 前端动画,就是让画面随时间、用户输入或页面状态连续变化。变化的对象可以是按钮的位置、弹窗的透明度、SVG 的线条、Canvas 里的粒子,也可以是三维场景中的镜头。 先把三个问题分开: | 问题 | 常见答案 | | | | | 画什么? | DOM/CSS、SVG、Canvas 2D、GPU 渲染的场景、预制动画素材 | | 怎样变化? | CSS 过渡/关键帧、Web Animations API、逐帧计算、...
学习
flutter2026-10-14
Flutter Android 正式签名实战:生成密钥、配置构建与验证 APK
Flutter Android 正式签名实战:生成密钥、配置构建与验证 APK Android 正式签名不需要购买证书。开发者可以自己生成密钥,用它给 APK 签名;密钥的用途是建立稳定的应用身份。签名有效并不等于应用已经通过商店审核,也不等于应用功能已完成真机验收。 本文面向 Flutter Android 项目,介绍从开发签名切换到独立正式签名的完整流程。应用名称、目录、包名和证书信息均使用通用示例,不包含真实项目密码、私钥、签名指...
学习
flutter2026-10-14
Flutter 新版本发布实战:完整安装包与 Shorebird 热更新
一、先判断该发完整包还是补丁 | 这次改动 | 发布方式 | | | | | Dart 文案、Flutter 页面布局、业务逻辑修复 | 通常可以发布补丁 | | 纯 Dart 依赖变化 | 可以尝试补丁构建,仍需验证兼容性 | | Kotlin、Java、Swift、Objective C 或原生构建配置变化 | 发布完整包 | | 插件的原生实现变化、新增原生插件、权限变化 | 发布完整包 | | 新增或修改打包图片、字体、应用图标...
学习

评论

请登录后发表评论

去登录
加载评论中...

目录