NGINX Full Version

使用 NGINX 作为对象存储网关

您是否曾经不小心发错了链接,它不是链接到您的 CDN 中的文件,而是链接到了像是 Amazon S3 这样的对象存储中的文件,而且这个链接还被大量传播使用?您是否被随之而来的飙升的云服务成本吓了一跳,或者您的云提供商甚至切断了链接?如果答案是“是”,那么本文正适合您。本文将介绍如何将 NGINX 作为缓存网关前置于 S3 私有存储桶,从而在您的私有存储桶和公共互联网之间建立一层保护。这种做法有两个优点:NGINX 会缓存对您的对象存储的请求,同时还能防止对象存储中的内容暴露给公网。

关于 Amazon S3 和兼容的存储产品

虽然 Amazon S3 是亚马逊云科技(AWS)的专有产品,但在事实层面,它已然成为对象存储系统的标准接口,许多厂商都提供了与之兼容的存储产品,例如 BackblazeDigital OceanGoogle StorageMinioNetAppNutanixTencent CloudVMwareWasabi 等。尽管 S3 API 被大范围支持,但 S3 API 的具体实现通常不太适合非存储操作,比如不适合支持大量的公共互联网流量。于是人们就产生了这样一个共同的需求:在 S3 API 的前面加设一层,以将存储接口桥接到另一个应用或特定用户接口。NGINX 可以充当此桥梁,并通过它的模块生态系统和可配置性创造额外的价值。

本文将通过探索一个托管在 GitHub 上功能完整的 Docker 实现(我们也提供了一个独立的 Ubuntu 安装实例),展示如何将 NGINX 开源版和 NGINX Plus 配置为一个与 S3 兼容的对象存储的只读网关。虽然本文只介绍如何将 NGINX 设置为与 S3 兼容的服务的网关,但您可以将这种方法延伸应用到任何 AWS API 请求的签署

用例

您可能会纳闷,“我的对象存储已经在大规模为文件提供服务了,何必在前面又多加一层呢?

答案很简单:S3 等对象存储只擅长一件事情 —— 存储和检索对象。而 NGINX 是一个高度可配置的反向代理,能够在作为基础对象存储网关的前提下提供更多功能。因此,它可以很好地支持多种用例,其中包括以下这些典型用例。

高速缓存

对象存储系统是为存储大量数据而生,故并没有为重复检索相同对象(例如文件或二进制数据)的情况进行优化。一般认为,最好的做法是在对象存储前面设置一个缓存层,以防止不必要的读取操作。使用 NGINX 作为缓存网关可以减少对象传递的延迟,防止中断,并降低使用成本。

安全控制

虽然 S3 有自己的身份验证和基于策略的访问系统,但不一定能满足您特定的身份验证需求。NGINX 支持多种不同的安全控制因此作为网关的它可以提供符合这些需求的身份验证和访问控制。您甚至可以使用安全链路模块创建带签名的链接!

访问内部应用

基于 AWS 签名的身份验证并不好实现,许多应用和平台都没有支持与 S3 轻松通信的客户端库。通过将 NGINX 用作访问 S3 的内部服务的网关,这些应用无需生成 AWS 签名便可轻松访问 S3 资源。

压缩和内容优化

您可能希望压缩对象存储中的数据以节省存储成本,但仍然能够为不支持压缩的客户端提供内容。在这种情况下,您可以配置 NGINX 使其在数据发送之前对其进行实时解压缩处理

又或者,您可能会在对象存储中存储未压缩的内容,然后希望通过在传输之前压缩数据来缩短传输时间。在这种情况下,您可以配置内置的 Gzip 模块或 Brotli 动态模块,以缩短到终端用户的传输时间。

NGINX 还支持其他类型的实时内容修改,例如 Image-Filter 动态模块可以转换 GIF、JPEG 和 PNG 图像,PageSpeed 等工具能够将 Web 性能的最佳实践自动应用到页面和相关多媒体资源,从而缩短页面加载时间。(在撰写本文时,Pagespeed 网站表示 Pagespeed“正处于 Apache 软件基金会孵化阶段”。实际上,谷歌也开发了同样成熟的代码,请参阅我们博客上的《使用 NGINX Plus 的 Google PageSpeed 动态模块优化您的网站》文章。)

安全性

NGINX 允许您在 S3 API 前面构建另一个安全层,从而可以对发出过多下载请求的用户进行速率限制、限制存储桶内可以访问的对象路径等。您还可以使用 F5 NGINX App Protect WAFNGINX ModSecurity WAF 等集成式 Web 应用防火墙 (WAF) 保护 S3 API。

应用网关

从站点提供内容时,对所有资源使用同一域名来满足安全、品牌、一致性和可移植性的要求十分常见。因此,从同一主机同时提供静态和动态内容也是常有的需求。当被用作 S3 API 网关时,NGINX 不仅可以从对象存储中提供静态文件,而且还可以针对来自应用服务器的动态内容请求提供代理和负载均衡功能。

特性和限制

本文探讨的 NGINX S3 网关实现具有以下特性和限制:

  • 支持 AWS 签名版本 2版本 4
  • 仅支持 GETHEAD 请求
  • 支持 NGINX 开源版和 NGINX Plus
  • 支持单个存储桶
  • 缓存时长:1 小时
  • 未配置 SSL/TLS
  • 默认情况下未安装 WAF
  • 默认情况下未启用压缩(例如 GZIP 或 Brotli)
  • 代理缓冲设置为默认值(您可以根据您的工作负载和对象大小修改这些设置)

在 Docker 中配置和运行 NGINX 网关

NGINX 开源版和 NGINX Plus 均可用作 S3 的网关或与 S3 兼容的对象存储的网关。

如需使用 NGINX 开源版,请先从 Docker Hub 下载 NGINX 官方镜像,并从 GitHub 上获取我们提供的 Dockerfile,然后创建 NGINX 配置文件

使用 NGINX Plus 作为 S3 API 网关则具有一些额外吸引人的优势:

  • 使用 NGINX Plus API 以进行动态上游 DNS 解析 —— 无论何时,只要 S3 API 域更改对应的 IP 地址,NGINX 就会自动重新配置以使用新的地址。这个功能很重要,因为 Amazon S3 和其他与 S3 兼容的 API 有时会为了更好地扩展系统而添加或删除负载均衡器。如果 DNS 更改后未重新加载上游的 NGINX 配置,那么一旦所有对应 IP 地址记录不再有效,就会导致服务中断。
  • 使用键值存储减少时间和资源消耗 —— 当生成 AWS 版本 4 的认证签名时,部分加密签名(签署密钥)有效且可缓存长达 24 小时。通过将这一部分签名存储在键值存储中,计算身份验证请求所需的总体时间和 CPU 资源就会有所减少。这对具有大量请求的用例来说是一项非常实用的性能增强特性。有关相关用例的配置示例,请参阅《为 SSL 存储配置 NGINX Plus 键值存储》一文。

我们不提供 NGINX Plus 的 Docker 镜像,因为镜像需包含您的 NGINX Plus 使用凭证。请使用我们提供的 Dockerfile(其中包含下载 NGINX Plus 二进制文件的相关设置),按照下一节的说明构建 NGINX Plus Docker 镜像。

构建 NGINX Plus 网关 Docker 镜像

如需构建 NGINX Plus Docker 镜像,请执行以下步骤:

  1. 从我们的 GitHub 仓库中克隆 NGINX S3 网关项目

    git clone https://github.com/nginxinc/nginx-s3-gateway.git
  2. 进入目录 nginx-s3-gateway

    cd nginx-s3-gateway
  3. 将 NGINX Plus 证书和密钥(nginx-repo.crtnginx-repo.key)复制到 plus/etc/ssl/nginx 子路径。关于证书和密钥,NGINX Plus 客户请前往 F5 客户门户下载,NGINX Plus 免费试用版用户可从试用包中找到。

  4. 构建容器镜像。我们建议使用 Docker BuildKit,因为它能让您将 NGINX Plus 的使用许可文件传递到 Docker 以构建上下文,同时避免数据暴露的风险以及 Docker 构建层之间的数据持久化问题。

    • 如使用 BuildKit 构建,请运行以下命令:

      DOCKER_BUILDKIT=1 docker build -f Dockerfile.buildkit.plus -t nginx-plus-s3-gateway --secret id=nginx-crt,src=plus/etc/ssl/nginx/nginx-repo.crt --secret id=nginx-key,src=plus/etc/ssl/nginx/nginx-repo.key --squash .
    • 如不使用 BuildKit 构建,请运行以下命令:

      docker build -f Dockerfile.plus -t nginx-plus-s3-gateway .
  5. 继续创建 NGINX 配置文件

创建 NGINX 配置文件

如要启动和运行 NGINX 网关(NGINX 开源版或 NGINX Plus),首先需要创建一个配置文件,其中包含连接 NGINX 和 S3 API 上游的设置。相关配置文件示例请参见我们的 GitHub 仓库。我们来看看一些面向不同的 S3 API 后端的配置示例。

Amazon S3

以下是使用 Amazon S3 作为后端时的配置。由于 AWS 正逐渐弃用 AWS 签名版本 2,故在此我们使用的是版本 4。

S3_BUCKET_NAME=my-bucket-name
S3_ACCESS_KEY_ID=PUBLICACCESSKEY4TEXT
S3_SECRET_KEY=ProtectThisPrivateKeyBecauseItIsASecret!
S3_SERVER=s3-us-west-2.amazonaws.com 
S3_SERVER_PORT=443 
S3_SERVER_PROTO=https 
S3_REGION=us-west-2
AWS_SIGS_VERSION=4
ALLOW_DIRECTORY_LIST=true

Wasabi

以下是将 Wasabi 作为与 S3 兼容的后端的配置。此处我们使用的是 AWS 签名版本 2,因为 Wasabi 一直支持该身份验证方法,并且性能通常更好。

S3_BUCKET_NAME=my-bucket-name
S3_ACCESS_KEY_ID=PUBLICACCESSKEY4TEXT
S3_SECRET_KEY=ProtectThisPrivateKeyBecauseItIsASecret!
S3_SERVER=s3.us-west-1.wasabisys.com
S3_SERVER_PORT=443
S3_SERVER_PROTO=https
S3_REGION=us-west-1
AWS_SIGS_VERSION=2
ALLOW_DIRECTORY_LIST=true

启动网关

将配置保存到文件(此处为当前目录下的 s3-settings.env)后,就可以使用 Docker 启动网关了。

  • 如需在前台启动 NGINX 开源版网关,请运行:

    docker run -it --env-file ./s3-settings.env -p8080:80 nginxinc/nginx-s3-gateway
  • 如需在前台启动 NGINX Plus 网关,请运行:

    docker run -it --env-file ./s3-settings.env -p8080:80 nginx-plus-s3-gateway

在确认镜像运行正常后,您可以把它推送到企业的私有 Docker 仓库,以供更大规模地使用。但是:

切勿将 NGINX Plus 镜像上传到像是 Docker Hub 这样的公共仓库,否则就违反了许可协议要求。

NGINX 启动后,您可以通过 http://localhost:8080 访问网关。

自定义网关

在熟悉了以默认配置运行 NGINX S3 网关的方法后,您可以尝试根据自己的特定需求扩展其配置。基础 NGINX Docker 镜像被配置为自动加载在 /etc/nginx/conf.d 目录中发现的任何 *.conf 文件,这让用户能够相对轻松地添加其他功能的配置。

例如,您可以将 Gzip 压缩 模块的配置存储在本地目录的 etc/nginx/conf.d/gzip_compression.conf。在我们的 GitHub 仓库中有一个运行良好的例子,展示了如何自定义 NGINX S3 网关从而搭配使用 Gzip 压缩模块。

如需添加其他功能的配置,请执行以下操作:

  1. 为您想支持的功能创建一个配置文件,例如在本地目录 etc/nginx/conf.d/ 中创建 gzip_compression.conf 文件。

  2. 将以下几行代码添加到 Dockerfile 中,以便自动从本地目录 etc/nginx/conf.d 中加载扩展名为 .conf 的任何文件。

    FROM nginxinc/nginx-s3-gateway
    COPY etc/nginx/conf.d /etc/nginx/conf.d

结语

本文介绍了如何将 NGINX 作为缓存网关,置于 Amazon S3 私有存储桶或其他与之兼容的对象存储之前。这不仅可以减少对象存储的流量,而且还在对象存储与公共互联网之间添加了一层保护,能够防止内容意外暴露到公网。

如欲使用 NGINX 开源版,请从 Docker Hub 下载 NGINX 官方镜像,并从 GitHub 上获取我们提供的 Dockerfile

如欲升级到 NGINX Plus,请立即下载 30 天免费试用版,或联系我们讨论您的用例