200字
Nginx让请求自动转发到 OSS 的内网地址
2026-03-05
2026-03-05

在 Nginx 中实现请求自动转发到 OSS 内网地址,本质上是利用 Nginx 作为**反向代理(Reverse Proxy)。**这样即使你的应用服务器(ECS)和 OSS 在同一内网,用户通过公网访问 ECS 时,Nginx 能悄悄地从内网把 OSS 资源取回来。

核心配置规则

server {
    listen 80;
    server_name www.ayakakuya.cn;

    # 匹配所有以 /static/ 开头的请求
    location /static/ {
        # 1. 定义 OSS 的内网 Endpoint (注意:必须是同地域内网地址)
        # 这里的地址从 OSS 控制台获取,例如:bucket-name.oss-cn-hangzhou-internal.aliyuncs.com
        proxy_pass http://your-bucket-name.oss-cn-hangzhou-internal.aliyuncs.com/;

        # 2. 设置回源 Host,OSS 依靠这个 Header 识别你访问的是哪个 Bucket
        proxy_set_header Host your-bucket-name.oss-cn-hangzhou-internal.aliyuncs.com;

        # 3. 隐藏 OSS 返回的一些敏感 Header(可选)
        proxy_hide_header x-oss-request-id;
        proxy_hide_header x-oss-object-type;

        # 4. 缓存设置(让 Nginx 也存一份,减少内网带宽压力)
        expires 7d;
    }
}

Internal Endpoint(内网域名):一定要确认你的 ECS 和 OSS 处于同一个地域(比如都在杭州)。如果地域不同,内网是不通的,必须改用公网域名。

斜杠 / 的奥秘:如果proxy_pass 结尾有/ (如上面的例子),访问www.xxx.com/static/a.jpg 时,Nginx 会去掉/static/ ,去 OSS 请求a.jpg 。

如果结尾没有 /,则会带上 去 OSS 寻找路径/static/

可能遇到的问题

在生产环境中,如果你使用 Nginx 后面直接跟一个域名(比如 OSS 的域名),Nginx 的行为可能会让你踩坑。proxy_pass

当你写下proxy_pass http://your-bucket.oss-cn-hangzhou-internal.aliyuncs.com;时,Nginx 的默认逻辑如下:

  • 启动时解析:Nginx 仅在启动(或者 reload)时,通过作系统的 DNS 配置查询一次该域名的 IP。
  • 永久缓存:一旦拿到 IP,Nginx 会将其保存在内存中,直到下次重启。
  • 风险:云厂商(如阿里云)的 OSS 域名 IP 可能会因为机房维护、扩容或高防切换而发生变化。如果 IP 变了,Nginx 还在往旧 IP 发请求,你的网站就会报 502 Bad Gateway

解决办法

给 Nginx 装上“实时导航”resolver

通过配置resolver指令,你可以强迫 Nginx 按照你设定的时间频率,重新去询问 DNS 服务器最新的 IP 地址。

示例:

http {
    # 1. 定义 DNS 服务器地址(8.8.8.8 是 Google 的,内网建议用阿里云内网 DNS)
    # valid=30s 表示每 30 秒强制重新解析一次
    resolver 100.100.2.136 100.100.2.138 valid=30s;

    server {
        listen 80;
        
        # 2. 关键技巧:使用变量定义域名
        # 如果不写在变量里,有些 Nginx 版本依然会只解析一次
        set $oss_domain "your-bucket.oss-cn-hangzhou-internal.aliyuncs.com";

        location /static/ {
            # 3. 引用变量
            proxy_pass http://$oss_domain/;
            
            proxy_set_header Host $oss_domain;
        }
    }
}

如果你在阿里云 ECS 上,建议使用阿里云的内网 DNS(通常是100.100.2.136和100.100.2.138),这样解析速度最快且最稳定。

valid=30s: 告诉 Nginx:“哪怕 DNS 记录说这个 IP 一年不变(TTL 很大),你也得每 30 秒给我重查一次”。

ipv6=off: 有时候 DNS 会返回 IPv6 地址,如果你的内网环境不支持 IPv6,建议加上这个参数: 以避免解析等待超时。resolver 8.8.8.8 valid=30s ipv6=off;

为什么要配合”变量”使用

  • 直接写域名proxy_pass http://domain.com; —— Nginx 倾向于在启动时静态解析。
  • 写成变量proxy_pass http://$variable; —— Nginx 每次请求都会去检查这个变量。配合resolver ,它就能实现真正的动态更新 IP。

如果配置resolver了还是不通可以检查:

  1. 服务器能不能通 DNS:在命令行 看看。ping 8.8.8.8

  2. 防火墙/安全组:是否放行了 UDP 53 端口(DNS 请求走的是 UDP)。

如果你想看具体的“用户真实 IP”而不是“CDN 的 IP”

放在Server块的location里面

# 将用户真实的 IP 放在 X-Real-IP 头里发给后端
proxy_set_header X-Real-IP $remote_addr;

# 将整个经过的代理路径(包括用户 IP 和各级 CDN IP)都传下去
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
#传递协议,方便后端识别是 http 还是 https
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host; #建议也带上 Host 头部,防止后端应用跳转错误
proxy_pass http://backend_server;

如何利用 CDN 进行边缘加速?

既然你已经把资源迁移到了 OSS,配置 CDN 其实非常简单:

  1. 在阿里云 CDN 控制台添加域名
    • 加速域名填:。cdn.ayakakuya.cn
    • 源站信息:选择 “OSS 域名”
  2. 开启“OSS 私有 Bucket 回源授权”(如果你的 OSS 是私有的):
    • 这样 CDN 就可以代表你去 OSS 拿图,但普通人拿不到 OSS 的直接地址,保证了安全。
  3. 代码替换
    • 将你网页 HTML 里的图片地址从换成 。/img/logo.png``https://cdn.ayakakuya.cn/img/logo.png
什么时候用内网?什么时候用 CDN?
场景调用方式理由
给用户看图/视频CDN 边缘加速追求用户加载速度,节省服务器带宽。
后端代码处理图片OSS 内网调用比如 Java 程序要给上传的图加水印,或者进行压缩。内网免费且极速。
小规模内网测试Nginx 内网回源方便调试,不产生 CDN 费用。

CDN 预热问题

为什么需要预热?

解决“缓存击穿”风险 在常规状态下,CDN 遵循“被动缓存”策略:只有当第一个用户来要东西时,CDN 才会去 OSS 拿。

但如果发生以下情况,你的源站会瞬间崩溃:

  • 大促开启:零点准时发布新海报或新商品图,几万个用户同时刷新页面。
  • 游戏/APP 更新:发布一个 500MB 的更新包,用户同时点击下载。
  • 后果:所有请求瞬间“击穿” CDN,全部堆到你的源站 Nginx 或 OSS 上,导致带宽占满、请求超时。
预热的工作流程
  1. 你在 CDN 控制台输入需要预热的 URL。
  2. CDN 调度中心指挥全国各地的核心节点,主动去 OSS(通过你配置好的内网/骨干网链路)下载该资源。
  3. 当活动正式开始,用户第一个请求过来时,CDN 节点里已经有货了,回源率为 0
如何运作
  • 控制台作:进入阿里云/腾讯云 CDN 控制台 -> 刷新预热 -> 切换到 “预热” 选项卡 -> 输入 URL。
  • API 自动化:在大厂,通常会将预热集成到 CI/CD 流水线中。比如前端代码一发布,自动调用 CDN 接口,预热最新的 JS/CSS 文件。
预热 和 刷新的区别
动作目的发生时机结果
刷新(刷新/清除)删掉旧东西发现线上资源有 Bug 或需要更替时节点缓存变空,下次访问必回源
预热 (Prefetch)提前存新东西大流量活动开启前、新版本发布后节点缓存变满,下次访问必命中

评论