在 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了还是不通可以检查:
-
服务器能不能通 DNS:在命令行 看看。
ping 8.8.8.8 -
防火墙/安全组:是否放行了 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 其实非常简单:
- 在阿里云 CDN 控制台添加域名:
- 加速域名填:。
cdn.ayakakuya.cn - 源站信息:选择 “OSS 域名”。
- 加速域名填:。
- 开启“OSS 私有 Bucket 回源授权”(如果你的 OSS 是私有的):
- 这样 CDN 就可以代表你去 OSS 拿图,但普通人拿不到 OSS 的直接地址,保证了安全。
- 代码替换:
- 将你网页 HTML 里的图片地址从换成 。
/img/logo.png``https://cdn.ayakakuya.cn/img/logo.png
- 将你网页 HTML 里的图片地址从换成 。
什么时候用内网?什么时候用 CDN?
| 场景 | 调用方式 | 理由 |
|---|---|---|
| 给用户看图/视频 | CDN 边缘加速 | 追求用户加载速度,节省服务器带宽。 |
| 后端代码处理图片 | OSS 内网调用 | 比如 Java 程序要给上传的图加水印,或者进行压缩。内网免费且极速。 |
| 小规模内网测试 | Nginx 内网回源 | 方便调试,不产生 CDN 费用。 |
CDN 预热问题
为什么需要预热?
解决“缓存击穿”风险 在常规状态下,CDN 遵循“被动缓存”策略:只有当第一个用户来要东西时,CDN 才会去 OSS 拿。
但如果发生以下情况,你的源站会瞬间崩溃:
- 大促开启:零点准时发布新海报或新商品图,几万个用户同时刷新页面。
- 游戏/APP 更新:发布一个 500MB 的更新包,用户同时点击下载。
- 后果:所有请求瞬间“击穿” CDN,全部堆到你的源站 Nginx 或 OSS 上,导致带宽占满、请求超时。
预热的工作流程
- 你在 CDN 控制台输入需要预热的 URL。
- CDN 调度中心指挥全国各地的核心节点,主动去 OSS(通过你配置好的内网/骨干网链路)下载该资源。
- 当活动正式开始,用户第一个请求过来时,CDN 节点里已经有货了,回源率为 0。
如何运作
- 控制台作:进入阿里云/腾讯云 CDN 控制台 -> 刷新预热 -> 切换到 “预热” 选项卡 -> 输入 URL。
- API 自动化:在大厂,通常会将预热集成到 CI/CD 流水线中。比如前端代码一发布,自动调用 CDN 接口,预热最新的 JS/CSS 文件。
预热 和 刷新的区别
| 动作 | 目的 | 发生时机 | 结果 |
|---|---|---|---|
| 刷新(刷新/清除) | 删掉旧东西 | 发现线上资源有 Bug 或需要更替时 | 节点缓存变空,下次访问必回源 |
| 预热 (Prefetch) | 提前存新东西 | 大流量活动开启前、新版本发布后 | 节点缓存变满,下次访问必命中 |