【问题标题】:How to have an AWS ELB forward the actual host name to the target group instead of the ELB's host name?如何让 AWS ELB 将实际主机名而不是 ELB 的主机名转发到目标组?
【发布时间】: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 ELB 将我们的域 foo.example.com 转发到 ec2 目标组而不是 ELB 的域?

【问题讨论】:

    标签: ruby-on-rails nginx devise amazon-cloudfront amazon-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;
    }
    

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

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-09-28
    • 2018-07-03
    • 1970-01-01
    • 1970-01-01
    • 2012-04-24
    • 1970-01-01
    • 2014-05-14
    • 2017-04-23
    相关资源
    最近更新 更多