此答案假设您已在负载均衡器安全组中启用 https,将 SSL 证书添加到负载均衡器,将 443 添加到负载均衡器转发的端口,并将您的域名指向具有 Route 53 的 Elastic Beanstalk 环境(或等效的 DNS 服务)。
您需要做的就是将以下内容添加到项目目录中的一个.config
文件中.ebextensions
:
files:
"/etc/httpd/conf.d/ssl_rewrite.conf":
mode: "000644"
owner: root
group: root
content: |
RewriteEngine On
<If "-n '%{HTTP:X-Forwarded-Proto}' && %{HTTP:X-Forwarded-Proto} != 'https'">
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R,L]
</If>
解释
这在 Elastic Beanstalk 之外是相当直接的。通常会添加一个 Apache 重写规则,如下所示:
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
或者,如果在负载均衡器后面,就像我们在这种情况下一样:
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R,L]
但是,这些配置仅在一个<VirtualHost>
块内起作用。将 更改RewriteCond
为<If>
块允许它在块之外正常工作<VirtualHost>
,允许我们放入独立的 Apache 配置文件。请注意,CentOS 上的标准 Apache 设置(包括 ElasticBeanstalk 上的设置)包括所有/etc/httpd/conf.d/*.conf
匹配的文件,它与我们存储此文件的文件路径匹配。
如果您不在负载均衡器后面,则条件的-n '%{HTTP:X-Forwarded-Proto}'
一部分会阻止它重定向,从而允许您在具有负载均衡器和 https 的生产环境与单实例且没有 https 的暂存环境之间共享配置。如果您在所有环境中都使用负载均衡器和 https,则这不是必需的,但拥有它并没有什么坏处。
我见过的糟糕的解决方案
我已经看到了很多针对这个问题的糟糕解决方案,值得通过它们来了解为什么需要这个解决方案。
使用 Cloudfront: 有人建议在 Elastic Beanstalk 前面使用非缓存 Cloudfront 设置来执行 HTTP 到 HTTPS 的重定向。这增加了一个不完全合适的全新服务(从而增加了复杂性)(Cloudfront 是一个 CDN;它不是在固有动态内容上强制使用 HTTPS 的正确工具)。Apache config 是这个问题的正常解决方案,而 Elastic Beanstalk 使用 Apache,所以我们应该这样做。
SSH 进入服务器并...:这与 Elastic Beanstalk 的观点完全相反,并且存在很多问题。通过自动缩放创建的任何新实例都不会具有修改后的配置。任何克隆的环境都没有配置。任何数量的合理环境更改都将清除配置。这真是个坏主意。
使用新文件覆盖 Apache 配置:这进入了正确的解决方案领域,但如果 Elastic Beanstalk 更改服务器设置的各个方面(他们很可能会这样做),那么您将面临维护噩梦。另请参阅下一项中的问题。
动态编辑 Apache 配置文件以添加几行:这是一个不错的主意。这样做的问题是,如果 Elastic Beanstalk 更改其默认 Apache 配置文件的名称,它将无法正常工作,并且该文件可能会在您最不期望的时候被覆盖:https ://forums.aws.amazon.com/thread .jspa?threadID=163369