通过ECS反向代理访问OSS

更新时间:
一键部署
我的部署

为满足防火墙白名单配置或特定系统集成对固定IP的访问需求,针对OSS通过DNS解析提供动态IP地址的问题,可在绑定了固定公网IPECS实例上部署Nginx反向代理,将访问请求转发至OSS,从而实现以固定IP地址访问OSS资源。

工作原理

该方案的核心是将一台或多台具有固定公网IPECS实例作为流量入口,利用Nginx作为反向代理服务器,将公网访问请求转发至OSS。具体工作流程如下:

  1. 客户端通过ECS实例的固定公网IP(EIP)发起对OSS资源的访问请求。

  2. 部署在ECS实例上的Nginx服务接收并处理该请求。

  3. Nginx根据预设配置,将请求转发至目标OSS Bucket。

  4. OSS处理请求并返回响应数据给Nginx。

  5. Nginx将响应数据通过公网返回给客户端,完成整个代理过程。

image

配置ECS反向代理

步骤一:创建ECS实例

ECS实例将作为反向代理软件Nginx的运行环境。

  1. 登录ECS控制台,单击创建实例

  2. 按照下方配置要求创建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或以上。

    • 安全组:选择已有安全组

    • 登录凭证:选择自定义密码,登录名选择root登录密码请自行设置并妥善保存。

步骤二:安装和配置Nginx反向代理

ECS实例创建完成后,需要在实例上安装Nginx并配置反向代理规则。

  1. 安装Nginx服务。

    yum install -y nginx
  2. 创建并编辑配置文件。为便于管理,建议在/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头设置为OSSBucket内网域名,确保签名验证通过
            # 【必须修改】替换为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;
        }
    }

    确认配置内容无误后,保存并退出编辑器。

  3. 检查Nginx配置文件语法正确性。

    nginx -t

    如果显示syntax is oktest is successful,表示配置语法正确。

  4. 启动Nginx服务使配置生效。

    systemctl start nginx

步骤三:配置安全组访问规则

由于ECS安全组默认拒绝对80端口的外部访问,需要添加入方向规则允许HTTP流量通过80端口访问Nginx服务。

  1. 前往ECS控制台,在目标实例中单击网络与安全组 > 添加入方向规则

  2. 配置安全组规则:选择授权策略允许协议类型Web HTTP 流量访问,在访问目的(本实例)中输入Nginx监听端口(默认80端口)并添加,如下图所示。

    image

  3. 单击确定,完成安全组访问规则配置。

验证反向代理效果

请根据Bucket的读写权限设置选择相应的验证方式。

公共读和公共读写Bucket

在浏览器中通过URL:http://ecs_public_ip/object_path访问OSS中的对象文件,其中ecs_public_ipECS实例的公网IP(可在ECS控制台获取),object_path为文件在Bucket内的访问路径。例如,文件dest.jpg存放在Bucketexampledir目录下,则object_pathexampledir/dest.jpg。访问效果如下图所示:

image

私有Bucket

如果需要访问的Bucket读写权限为私有,则需要在访问文件的URL中包含签名信息。以下操作演示如何通过控制台获取文件的签名URL,关于签名的详细信息和生成方式请参见签名版本4(推荐)

  1. 前往Bucket列表,单击目标Bucket。

  2. 单击需要访问的目标文件右侧操作列的详情

  3. 单击复制文件URL,将URL中的https替换为http,并将URL中的Bucket域名替换为ECS实例的公网IP。

  4. 在浏览器中访问修改后的URL。

image

应用于生产环境

在生产环境中使用此方案时,请遵循以下最佳实践,以确保服务的稳定性、安全性和成本效益。

最佳实践

  • 高可用架构:务必采用"负载均衡 + 多可用区ECS实例组"的生产架构设计,避免单点故障风险。

  • 启用HTTPS:生产环境中应强制启用HTTPS访问以确保数据传输安全。需要为Nginx配置SSL证书并设置HTTPHTTPS的自动跳转,具体配置方法如下所示。

    # ... 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:为代理集群的入口(SLBECS)绑定弹性公网IP(EIP),确保入口IP地址的稳定性。

  • 使用域名访问:建议配置域名解析到代理服务器IP,通过域名而非IP地址提供服务,便于后续运维管理和扩展。

容错策略

  • 健康检查:配置负载均衡器对Nginx/health端点进行定期健康检查,自动隔离故障实例。

  • 超时设置:合理配置Nginxproxy_connect_timeoutproxy_read_timeout等超时参数,避免因后端OSS响应延迟导致大量连接堆积。

  • 重试机制:如果客户端应用支持,建议在应用层增加对5xx错误的重试逻辑。

风险防范

  • 安全加固:在ECS安全组和网络ACL中,仅对必要的IP地址和端口开放访问权限。考虑在代理前端部署Web应用防火墙(WAF)以抵御常见Web攻击。

  • 监控与告警:监控Nginx的访问日志和错误日志,以及关键性能指标(如请求延迟、错误率、ECSCPU/内存/网络使用率),并设置相应的告警阈值。

  • 变更与回滚:对Nginx配置的任何变更都应经过充分测试验证。保留历史版本的配置文件,以便在出现问题时快速回滚。

常见问题

如何通过浏览器预览Bucket中的图片或网页文件?

由于OSS的安全机制,通过默认域名在浏览器中访问OSS的图片或网页文件时,文件会被强制下载而非直接预览。如果需要在浏览器中直接预览Bucket中的图片或网页文件,需要为Bucket绑定自定义域名,并在Nginx配置中使用已绑定的自定义域名。关于如何绑定自定义域名,请参见绑定自定义域名至Bucket默认域名

访问私有Bucket中的文件返回403 Forbidden错误,如何排查?

403错误通常与签名验证或权限配置相关。请按以下步骤进行排查:

  1. 检查Nginx配置:确保proxy_set_header Host指令设置的值与访问的Bucket内网Endpoint完全一致。这是V4签名验证成功的关键要素。

  2. 检查签名生成:确认在生成签名URL时,计算签名所用的Host头与Nginx配置中的Host头保持一致。

  3. 检查Bucket权限:检查Bucket PolicyRAM策略是否允许相应的操作权限。

  4. 检查ECS角色授权:如果应用通过ECS实例RAM角色访问OSS,请确保该角色已被授予访问目标Bucket的相应权限。

上传大文件失败,返回413 Request Entity Too Large错误,怎么办?

这是因为上传的文件大小超过了Nginx的默认限制。请在Nginx配置文件的serverlocation块中,调整client_max_body_size的值。例如,设置client_max_body_size 2048m;允许上传最大2GB的文件。修改后需重载Nginx配置使其生效。

访问偶尔失败,Nginx日志中出现502 Bad Gateway错误,是什么原因?

502错误表示Nginx无法从后端(OSS)获取有效响应。可能的原因包括:

  1. DNS解析问题:检查Nginx配置中是否包含resolver指令。如果缺少该配置,Nginx可能仍在使用缓存的旧IP地址访问OSS。

  2. 网络连通性:检查ECS实例的安全组出方向规则以及网络ACL设置,确保允许访问目标地域OSS Endpoint80端口。

  3. Endpoint配置错误:检查proxy_passproxy_set_header Host中配置的OSS Endpoint是否拼写正确且有效。

如何通过一个Nginx实例代理多个不同的Bucket?

可以使用Nginxmap指令,根据请求的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_*配置 ...
    }
}