ELB 将 443/80 重定向到 nginx docker 容器上的单个端口

ELB redirecting 443/80 to single port on nginx docker container

我们有一个 public AWS ELB,它正在像这样重定向流量:

HTTP    80  HTTP    9001
TCP     443 TCP     9001

目标实例是 运行 docker 带有 nginx 容器的 AWS ECS 实例。

Docker转发9001->8080,nginx监听8080。 这是 nginx 配置的片段:

server {
    ssl on;
    ssl_certificate /etc/nginx/mydomain.crt;
    ssl_certificate_key /etc/nginx/mydomain.key;

    listen 8080;
    server_name %{ROUTER_CLEARCARE_SERVER_NAME};

    access_log  /var/log/nginx/access.log  logstash_json;


    if ($http_x_forwarded_proto != 'https') {
        return 301 https://$host$request_uri;
    }

    set $target_web "web.mydomain.com:80";
    location / {
        proxy_read_timeout 180;
        proxy_connect_timeout 2;
        proxy_send_timeout 180;
        keepalive_timeout  180;
        resolver 10.10.0.2 valid=30s;
        proxy_set_header Host $host;
        proxy_pass http://$target_web;
        proxy_set_header X-Unique-ID $request_id;
    }
}

我需要在 nginx 容器上执行 SSL 终止,因为我们有多个域的多个证书,并且我们正在使用具有不同超时的基于路径的路由(ELB 仅支持单个证书,而 ALB 不支持基于路径的路由具有不同的超时和证书)。

关键是:nginx 只能监听一个端口(我们正在使用一个名为 Empire 的工具将 nginx 容器部署到 AWS ECS,他们目前只支持这种配置)。

nginx 可以在单个端口上支持 http 和 https 吗?

现在,使用该配置,我在尝试点击 http://example.com:

时遇到此错误
The plain HTTP request was sent to HTTPS port

当我尝试点击 https://example.com 时出现此错误 我收到此错误:

mydomain.com redirected you too many times.

我发现了一个声明,在 this serverfault page (check out 2nd answer from Komu). I repeat it below, so you can find it more easily. Can you try it? If you are not bound to NginX, you might als be interested in this node.js plugin 上 NginX 应该可以监听 HTTP 和 HTTPS,这也允许在同一端口上监听 HTTP 和 HTTPS。


quoted from here:

According to wikipedia article on status codes, Nginx has a custom error code when http traffic is sent to https port (error code 497)

And according to nginx docs on error_page, you can define a URI that will be shown for a specific error. Thus we can create a uri that clients will be sent to when error code 497 is raised.

#lets assume your IP address is 89.89.89.89 and also that you want nginx to listen on port 7000 and your app is running on port 3000

server {
    listen 7000 ssl;

    ssl_certificate /path/to/ssl_certificate.cer;
    ssl_certificate_key /path/to/ssl_certificate_key.key;
    ssl_client_certificate /path/to/ssl_client_certificate.cer;

    error_page 497 301 =307 https://89.89.89.89:7000$request_uri;

    location / {
        proxy_pass http://89.89.89.89:3000/;

        proxy_pass_header Server;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-Protocol $scheme;
    }
}

However if a client makes a request via any other method except a GET, that request will be turned into a GET. Thus to preserve the request method that the client came in via; we use error processing redirects as shown in nginx docs on error_page

And thats why we use the 301 =307 redirect.

Using the nginx.conf file shown here, we are able to have http and https listen in on the same port