如何让 AWS ELB 将实际主机名而不是 ELB 的主机名转发到目标组?

Posted

技术标签:

【中文标题】如何让 AWS ELB 将实际主机名而不是 ELB 的主机名转发到目标组?【英文标题】:How to have an AWS ELB forward the actual host name to the target group instead of the ELB's host name? 【发布时间】:2021-11-22 17:38:55 【问题描述】:

我们有一个 Ruby/Rails 网站,我们正在从 Heroku 迁移到 AWS。原始开发人员不可用。我现在正在尝试完成迁移。我的背景是 Windows / .NET 世界。这个 Linux / Ruby/Rails 环境对我来说很陌生......

这是我设置的当前环境:

53 号公路

Record Name Record Type Alias Alias Route Traffic To
foo.example.com A yes cloudfront: xyz.cloudfront.net

云端

Domain Name Alternate Domain Names Origin Domain Origin Protocol Behavior Protocol
xyz.cloudfront.net foo.example.com foo.us-west-2.elb.amazonaws.com HTTP only Redirect HTTP to HTTPS

CloudFront 分布:

使用 AWS 颁发的 SSL 证书 处理 http 到 https 的重定向 通过http(不是https)将请求转发到ELB

负载均衡器

DNS Name Listener Rule Forward To
foo.us-west-2.elb.amazonaws.com HTTP 80: default action Target Group: foo-ec2

Target Group: foo-ec2 包含一个运行 nginx/1.18.0 + Phusion Passenger 6.0.10 的 Ubuntu ec2 实例,用于为 Ruby/Rails 站点提供服务。

nginx 配置

server 
    listen 80 default_server;
    listen [::]:80 default_server;

    # SSL Config - we should NEVER receive 443/https traffic; 
    # CloudFront manages https traffic => AWS ELB => http to this server
    #listen 443 ssl default_server;
    #listen [::]:443 ssl default_server;

    server_name foo.example.com
                foo.us-west-2.elb.amazonaws.com;

    # Tell Nginx and Passenger where the app's 'public' directory is
    root /var/www/foo_example/public;

    # Turn on Passenger
    passenger_enabled on;
    passenger_app_env production;
    passenger_ruby /home/ubuntu/.rbenv/versions/2.6.8/bin/ruby;

问题

rails 应用程序启动时没有错误,并通过 https 提供服务。但是,当用户尝试登录/验证时,Devise gem 会使用 http 和 ELB 的 DNS 名称发回重定向。

示例

登录请求

Request URL: https://foo.example.com/users/sign_in
Request Method: POST
Status Code: 302 

登录响应

location: http://foo.us-west-2.elb.amazonaws.com/users
server: nginx/1.18.0 + Phusion Passenger(R) 6.0.10
status: 302 Found

请注意,请求是通过 https 和我们的域:

https://foo.example.com

但现在我们已经结束了 http 和 ELB 的域:

http://foo.us-west-2.elb.amazonaws.com

我的假设

devise gem 从 ELB 中查看主机,然后从 ELB 主机生成 URL,从而产生两个问题:

我们现在使用 http,因为 ELB 通过 http 与 ec2 实例通信 我们现在使用的是 ELB 的主机名 foo.us-west-2.elb.amazonaws.com,而不是我们的名称 foo.example.com

我查看了devise 文档,看看我们是否可以在创建回帖时传入要使用的 http 协议和域,但我的 ruby​​ 知识有限。另外,我认为这将是“坏”的道路; “好的”路径是让 AWS ELB 转发实际的域名,而不是它自己的。

我已经查看了几个具有类似问题的 SO 和相关堆栈站点,但我要么以无限循环重定向结束,要么各种配置更改导致 devise gem 的相同行为造成错误网址回发。

这两个问题似乎是最接近的,但我不太能够在答案和我对这个生态系统的有限知识之间建立“联系”。

AWS Cloudfront + Load Balancer, url changes from main domain to load balancer subdomain cloudfront domain replaced by application load balancer dns name when redirecting from http to https

问题

如何让 AWS ELB 将我们的域 foo.example.com 转发到 ec2 目标组而不是 ELB 的域?

【问题讨论】:

【参考方案1】:

在对 AWS 设置进行更多实验后,解决方案实际上相当简单。我在问题中发布的其他答案在实际设置中含糊不清,所以这是具体的解决方案。

在 CloudFront 中,您需要创建一个新的origin request policy不是一个cache policy

打开 CloudFront 转到政策(左导航) 点击“源请求”标签 点击“创建源请求策略”按钮 随意命名策略,即“我的源请求策略” 在“源请求设置”> 标头下:选择“包括以下标头” 在“添加标题”下:选中“主机”选项 点击“创建”按钮

政策将如下所示:

创建新的源请求策略后:

返回 CloudFront 分发版 点击您的发行版的 ID 以便进行编辑 点击“行为”标签 选择您的行为并进行编辑 向下滚动到“缓存键和源请求” 确保选中“缓存策略和源请求策略(推荐)” 在“源请求策略 - 可选”下,选择您的新策略,即“我的源请求策略” 保存更改

行为将如下所示(我现在不使用缓存来验证 ec2 实例是否正在获取所有请求):

就是这样。现在,主机标头已正确传递到 ELB 和 ec2 实例。不需要对 ELB 进行任何其他操作。

我通过修改 nginx 日志记录选项以在日志文件中包含 $host 变量验证了所有请求中都使用了主机标头(并对 OOB 格式进行了更多自定义):

# prefixed log with '[my-log]', but it's not needed; remove.
log_format my-log '[my-log] $http_x_forwarded_for - $remote_user [$time_local] '
                  '"$request_method $scheme://$host$request_uri $server_protocol" '
                  '$status $body_bytes_sent "$http_referer" "$http_user_agent" $request_time';

server 
    listen 80 default_server;
    listen [::]:80 default_server;

    # SSL Config - we should NEVER receive 443/https traffic; 
    # CloudFront manages https traffic => AWS ELB => http to this server
    #listen 443 ssl default_server;
    #listen [::]:443 ssl default_server;

    server_name foo.example.com
                foo.us-west-2.elb.amazonaws.com;

    # create the our log file
    access_log /var/log/nginx/my-log.access.log my-log;

    # Tell Nginx and Passenger where the app's 'public' directory is
    root /var/www/foo_example/public;

    # Turn on Passenger
    passenger_enabled on;
    passenger_app_env production;
    passenger_ruby /home/ubuntu/.rbenv/versions/2.6.8/bin/ruby;

这肯定会对我和其他人的未来有所帮助。

【讨论】:

嘿,我遇到了类似的问题并尝试了您的解决方案,但这也无济于事。你能给些建议么。详细问题在这里 [***.com/questions/69937819/…

以上是关于如何让 AWS ELB 将实际主机名而不是 ELB 的主机名转发到目标组?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Istio 中设置 AWS ALB 而不是 ELB?

在 AWS ELB 上运行 Docker 容器,连接到主机节点应用程序

AWS 云产品 CloudFront + ELB + EC2 + S3 构建虚拟主机动静分离站点

如何将 AWS ELB 状态更改为 InService?

通过 ELB 访问 AWS EC2 实例

如何在自动缩放组中添加 aws new elb