由于OSS通过DNS解析提供的IP地址是动态变化的,在需要配置防火墙白名单或进行特定系统集成时,可能会因IP不定导致访问受限或失败。为解决该问题,可在已绑定固定公网IP的ECS实例上部署Nginx反向代理,通过将访问请求转发至OSS,实现通过固定IP地址访问OSS资源。
工作原理
该方案的核心是将一台或多台具有固定公网IP的ECS实例作为流量入口,利用Nginx作为反向代理服务器,将公网访问请求转发至OSS。具体工作流程如下:
客户端通过ECS实例的固定公网IP(EIP)发起对OSS资源的访问请求。
部署在ECS实例上的Nginx服务接收并处理该请求。
Nginx根据预设配置,将请求转发至目标OSS Bucket。
OSS处理请求并返回响应数据给Nginx。
Nginx将响应数据通过公网返回给客户端,完成整个代理过程。
配置ECS反向代理
步骤一:创建ECS实例
ECS实例将作为反向代理软件Nginx的运行环境。
按照下方配置要求创建ECS实例,其余配置项可保持默认设置。
付费类型:选择按量付费。
地域:选择待代理的OSS Bucket所在地域,以便使用内网域名访问,节约流量成本。
网络及可用区:选择默认的专有网络和可用区。
实例:单击全部规格,搜索并选择
ecs.e-c1m2.large
。说明如果实例规格已售罄,请选择其它实例规格。
镜像:选择公共镜像的Alibaba Cloud Linux(Alibaba Cloud Linux 3.2104 LTS 64位)。
系统盘:设置ESSD Entry的容量为 40 GiB。
公网IP:勾选分配公网 IPv4 地址。
带宽计费模式:选择按使用流量,以节约成本。
带宽峰值:选择5 Mbps或以上。
安全组:选择新建安全组,并在开通IPv4端口/协议中勾选HTTP (TCP:80),开放Nginx监听端口。
登录凭证:选择自定义密码,登录名选择root,登录密码请自行设置并妥善保存。
步骤二:安装和配置Nginx反向代理
ECS实例创建完成后,需要在实例上安装Nginx并配置反向代理规则。
安装Nginx服务。
yum install -y nginx
创建并编辑配置文件。为便于管理,建议在
/etc/nginx/conf.d/
目录下创建独立的配置文件,例如oss_proxy.conf
。vi /etc/nginx/conf.d/oss_proxy.conf
将以下生产级配置模板复制到配置文件中,并根据注释说明修改Bucket内网域名和ECS实例公网IP。
# 定义OSS后端,并启用长连接复用,提高性能 upstream oss_backend { # 【必须修改】替换为Bucket内网域名 server your-bucket.oss-cn-hangzhou-internal.aliyuncs.com:80; # 建议的keepalive连接数,可根据并发量调整 keepalive 64; } # 定义生产环境的日志格式,包含上游响应时间等关键信息 log_format production '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for" ' 'rt=$request_time uct="$upstream_connect_time" uht="$upstream_header_time" urt="$upstream_response_time"'; server { listen 80; # 【必须修改】替换为ECS公网IP或解析到该IP的域名 server_name your_ecs_public_ip_or_domain; # 访问日志路径和格式 access_log /var/log/nginx/oss_proxy.access.log production; error_log /var/log/nginx/oss_proxy.error.log; # 动态DNS解析,确保Nginx能感知OSS后端IP变化 resolver 100.100.2.136 100.100.2.138 valid=60s; # 健康检查端点,用于负载均衡或监控系统 location /health { access_log off; return 200 "healthy"; } location / { # 代理到上游定义的OSS后端 proxy_pass http://oss_backend; # 关键配置:确保HTTP/1.1协议和长连接生效 proxy_http_version 1.1; proxy_set_header Connection ""; # 关键配置:将Host头设置为OSS的Bucket内网域名,确保签名验证通过 # 【必须修改】替换为Bucket内网域名 proxy_set_header Host "your-bucket.oss-cn-hangzhou-internal.aliyuncs.com"; # 转发客户端真实IP proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Real-IP $remote_addr; # 设置代理超时时间 proxy_connect_timeout 10s; proxy_send_timeout 30s; proxy_read_timeout 30s; # 允许上传的最大文件大小,0表示不限制。根据业务需求设置 client_max_body_size 1024m; } }
确认配置内容无误后,保存并退出编辑器。
检查Nginx配置文件语法正确性。
nginx -t
如果显示
syntax is ok
和test is successful
,表示配置语法正确。启动Nginx服务使配置生效。
systemctl start nginx
验证反向代理效果
请根据Bucket的读写权限设置选择相应的验证方式。
公共读和公共读写Bucket
在浏览器中通过URL:http://ecs_public_ip/object_path
访问OSS中的对象文件,其中ecs_public_ip
为ECS实例的公网IP(可在ECS控制台获取),object_path
为文件在Bucket内的访问路径。例如,文件dest.jpg
存放在Bucket的exampledir
目录下,则object_path
为exampledir/dest.jpg
。访问效果如下图所示:
私有Bucket
如果需要访问的Bucket读写权限为私有,则需要在访问文件的URL中包含签名信息。以下操作演示如何通过控制台获取文件的签名URL,关于签名的详细信息和生成方式请参见签名版本4(推荐)。
前往Bucket列表,单击目标Bucket。
单击需要访问的目标文件右侧操作列的详情。
单击复制文件URL,将URL中的https替换为http,并将URL中的Bucket域名替换为ECS实例的公网IP。
在浏览器中访问修改后的URL。
应用于生产环境
在生产环境中使用此方案时,请遵循以下最佳实践,以确保服务的稳定性、安全性和成本效益。
最佳实践
高可用架构:务必采用"负载均衡 + 多可用区ECS实例组"的生产架构设计,避免单点故障风险。
启用HTTPS:生产环境中应强制启用HTTPS访问以确保数据传输安全。需要为Nginx配置SSL证书并设置HTTP到HTTPS的自动跳转,具体配置方法如下所示。
说明为确保HTTPS服务能够正常访问,ECS实例所属的安全组必须开放443端口。具体配置方法,请参见添加/修改/删除安全组规则。
# ... upstream 和 log_format 配置保持不变 ... # HTTP server块:强制跳转到HTTPS server { listen 80; # 【必须修改】替换为ECS公网IP或解析到该IP的域名 server_name your_ecs_public_ip_or_domain; # 将所有HTTP请求通过301重定向到HTTPS return 301 https://$host$request_uri; } # HTTPS server块:处理实际的代理业务 server { # 在443端口上监听SSL连接 listen 443 ssl http2; # 【必须修改】替换为ECS公网IP或解析到该IP的域名 server_name your_ecs_public_ip_or_domain; # --- SSL证书配置 --- # 【必须修改】替换为你的SSL证书和私钥文件的路径 ssl_certificate /path/to/your/fullchain.pem; ssl_certificate_key /path/to/your/private.key; # --- SSL安全增强配置 --- ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers 'TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384'; ssl_prefer_server_ciphers on; ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; # 访问日志路径和格式 access_log /var/log/nginx/oss_proxy.access.log production; error_log /var/log/nginx/oss_proxy.error.log; # 动态DNS解析 (与原配置相同) resolver 100.100.2.136 100.100.2.138 valid=60s; # 健康检查端点 (与原配置相同) location /health { access_log off; return 200 "healthy"; } location / { # ... 所有的 proxy_* 配置与原配置完全相同 ... proxy_pass http://oss_backend; proxy_http_version 1.1; proxy_set_header Connection ""; # 【必须修改】替换为Bucket内网域名 proxy_set_header Host "your-bucket.oss-cn-hangzhou-internal.aliyuncs.com"; proxy_set_header X-Forwarded-For $proxy_add_x_forw_for; proxy_set_header X-Real-IP $remote_addr; # 增加X-Forwarded-Proto头,让后端知道客户端是通过HTTPS访问的 proxy_set_header X-Forwarded-Proto $scheme; proxy_connect_timeout 10s; proxy_send_timeout 30s; proxy_read_timeout 30s; client_max_body_size 1024m; } }
配置代理缓冲区:对于大文件下载或上传场景,开启并合理配置代理缓冲区,可以优化服务器内存使用,并避免因客户端网络速度慢而长时间占用与后端OSS的连接,从而提升整体服务性能。可在location块中添加如下配置:
location / { # ... 其他proxy_*配置 ... # 开启代理缓冲,并设置缓冲区的数量和大小 proxy_buffering on; proxy_buffers 8 128k; proxy_buffer_size 128k; proxy_busy_buffers_size 256k; }
使用EIP:为代理集群的入口(SLB或ECS)绑定弹性公网IP(EIP),确保入口IP地址的稳定性。
使用域名访问:建议配置域名解析到代理服务器IP,通过域名而非IP地址提供服务,便于后续运维管理和扩展。
容错策略
健康检查:配置负载均衡器对Nginx的
/health
端点进行定期健康检查,自动隔离故障实例。超时设置:合理配置Nginx的
proxy_connect_timeout
、proxy_read_timeout
等超时参数,避免因后端OSS响应延迟导致大量连接堆积。重试机制:如果客户端应用支持,建议在应用层增加对5xx错误的重试逻辑。
风险防范
安全加固:在ECS安全组和网络ACL中,仅对必要的IP地址和端口开放访问权限。考虑在代理前端部署Web应用防火墙(WAF)以抵御常见Web攻击。
监控与告警:监控Nginx的访问日志和错误日志,以及关键性能指标(如请求延迟、错误率、ECS的CPU/内存/网络使用率),并设置相应的告警阈值。
变更与回滚:对Nginx配置的任何变更都应经过充分测试验证。保留历史版本的配置文件,以便在出现问题时快速回滚。
常见问题
如何通过浏览器预览Bucket中的图片或网页文件?
由于OSS的安全机制,通过默认域名在浏览器中访问OSS的图片或网页文件时,文件会被强制下载而非直接预览。如果需要在浏览器中直接预览Bucket中的图片或网页文件,需要为Bucket绑定自定义域名,并在Nginx配置中使用已绑定的自定义域名。关于如何绑定自定义域名,请参见通过自定义域名访问OSS。
访问私有Bucket中的文件返回403 Forbidden错误,如何排查?
403错误通常与签名验证或权限配置相关。请按以下步骤进行排查:
检查Nginx配置:确保
proxy_set_header Host
指令设置的值与访问的Bucket内网Endpoint完全一致。这是V4签名验证成功的关键要素。检查签名生成:确认在生成签名URL时,计算签名所用的
Host
头与Nginx配置中的Host
头保持一致。检查Bucket权限:检查Bucket Policy或RAM策略是否允许相应的操作权限。
检查ECS角色授权:如果应用通过ECS实例RAM角色访问OSS,请确保该角色已被授予访问目标Bucket的相应权限。
上传大文件失败,返回413 Request Entity Too Large错误,怎么办?
这是因为上传的文件大小超过了Nginx的默认限制。请在Nginx配置文件的server
或location
块中,调整client_max_body_size
的值。例如,设置client_max_body_size 2048m;
允许上传最大2GB的文件。修改后需重载Nginx配置使其生效。
访问偶尔失败,Nginx日志中出现502 Bad Gateway错误,是什么原因?
502错误表示Nginx无法从后端(OSS)获取有效响应。可能的原因包括:
DNS解析问题:检查Nginx配置中是否包含
resolver
指令。如果缺少该配置,Nginx可能仍在使用缓存的旧IP地址访问OSS。网络连通性:检查ECS实例的安全组出方向规则以及网络ACL设置,确保允许访问目标地域OSS Endpoint的80端口。
Endpoint配置错误:检查
proxy_pass
和proxy_set_header Host
中配置的OSS Endpoint是否拼写正确且有效。
如何通过一个Nginx实例代理多个不同的Bucket?
可以使用Nginx的map
指令,根据请求的Host
头动态选择要代理的后端Bucket。
# /etc/nginx/conf.d/multi_oss_proxy.conf
# 动态映射Host到OSS内网Endpoint
map $http_host $oss_backend_host {
# 【必须修改】将 a.example.com 映射到 bucket-a 的内网Endpoint
"a.example.com" "bucket-a.oss-cn-hangzhou-internal.aliyuncs.com";
# 【必须修改】将 b.example.com 映射到 bucket-b 的内网Endpoint
"b.example.com" "bucket-b.oss-cn-shenzhen-internal.aliyuncs.com";
# 默认值,可不设置或指向一个默认Bucket
default "";
}
server {
listen 80;
# 监听多个域名
server_name a.example.com b.example.com;
# ... 其他配置如日志、resolver等 ...
location / {
# 如果映射结果为空,则返回404
if ($oss_backend_host = "") {
return 404;
}
# 动态设置proxy_pass和Host头
proxy_pass http://$oss_backend_host;
proxy_set_header Host $oss_backend_host;
# ... 其他proxy_*配置 ...
}
}