V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
NGINX
NGINX Trac
3rd Party Modules
Security Advisories
CHANGES
OpenResty
ngx_lua
Tengine
在线学习资源
NGINX 开发从入门到精通
NGINX Modules
ngx_echo
jinliming2
V2EX  ›  NGINX

关于 Nginx 配置 HTTP 跳转非 443 端口 HTTPS 的问题

  •  
  •   jinliming2 ·
    jinliming2 · 2020-03-02 02:00:37 +08:00 · 11764 次点击
    这是一个创建于 1760 天前的主题,其中的信息可能已经有所发展或是发生改变。

    如果正常的,80 端口 HTTP 跳转 HTTPS,那么直接在 server listen 80 下写 return 301 https://$host$request_uri; 就行

    但是,现在的情况是,80/443 都有服务了,然后在 8443 端口上开了一个需要客户端证书认证的 TLS 双向认证服务,通过 https://example.com:8443 可以成功访问,浏览器会提示选择客户端证书,这都没问题。

    但是在首次访问的时候,如果没有显式指定 https 协议,将会自动默认使用 http 协议来访问 8443 端口,导致 nginx 报错:400 Bad Request: The plain HTTP request was sent to HTTPS port。

    所以,有没有什么办法可以让 http://example.com:8443 自动跳转到 https://example.com:8443

    尝试过这样配置,但不行:

    server {
        listen 8443 default_server;
    
        return 301 https://$host$request_uri;
    }
    server {
        listen 8443 ssl http2;
        server_name xxxxx.com;
    
        ssl_verify_client on;
        
        ............
    }
    
    第 1 条附言  ·  2020-03-02 12:20:54 +08:00
    已解决:
    不需要两个 server 块,只需要捕获 497 错误就行了:
    ```
    server {
    listen 8443 ssl http2;
    server_name xxxxx.com;

    error_page 497 301 =307 https://$host:$server_port$request_uri;

    ssl_verify_client on;

    ............
    }
    ```
    代码参考了 4 楼第二个链接里的,用了 307 状态码。
    16 条回复    2024-04-21 04:17:15 +08:00
    xiri
        1
    xiri  
       2020-03-02 02:08:24 +08:00 via Android   ❤️ 1
    我只试过重定向到非 443 的 https 端口,没有实践过 http 和 https 绑定到同一个端口,如果你那个配置没有出现报错的话,把 return 301 那里改成
    return 301 https://$host:8443$request_uri;
    应该就可以了
    chengxy
        2
    chengxy  
       2020-03-02 02:16:26 +08:00
    default_server 应该是 example.com
    uqf0663
        3
    uqf0663  
       2020-03-02 02:17:57 +08:00
    没遇到过这种,但是猜测应该写个 if 判断协议来实现跳转
    seki
        5
    seki  
       2020-03-02 02:51:16 +08:00   ❤️ 1
    看了一下,基本方案是这个端口只配置 https,加一个对 nginx 497 错误的处理来改变协议,写成

    error_page 497 https://$host$request_uri;

    没实际试过,不知道非标准端口需不需要加上端口号

    参考 https://stackoverflow.com/questions/14144514/can-i-redirect-non-ssl-traffic-that-comes-in-on-an-ssl-port-with-nginx
    iflyime
        6
    iflyime  
       2020-03-02 03:04:34 +08:00 via Android
    楼上的

    error_page 497 https://$host$request_uri;

    以前试过好像是可以把非 443 端口的直接跳转到 HTTPS 的。
    iflyime
        7
    iflyime  
       2020-03-02 03:37:32 +08:00 via Android   ❤️ 1
    不用监听 80 端口,直接监听 8443 端口,然后这样配置

    server {
    listen 8443 ssl http2;
    server_name xxxxx.com;
    error_page 497 https://$host:8443$request_uri;
    ............
    }

    @iflyime
    mgrddsj
        8
    mgrddsj  
       2020-03-02 03:43:55 +08:00
    @iflyime #7
    正解,我的服务器就是这样配置的。原理是把 The plain HTTP request was sent to HTTPS port 的错误页跳转到加了 https:// 的页面。5 楼的方案漏了端口号,7 楼这个应该完美符合楼主场景。
    zvc888
        9
    zvc888  
       2020-03-02 11:05:36 +08:00
    8443 rewrite 就可以了
    jinliming2
        10
    jinliming2  
    OP
       2020-03-02 12:14:03 +08:00
    @xiri 这个试过了,貌似是这一个非 ssl 的 server 就完全没有生效,不发生任何跳转。
    @chengxy emmmm,这只是个样例代码……
    @zhengjian 后两个链接里的可以,谢谢啦~
    @seki 497 错误代码可以的,需要加上端口号,谢谢啦~
    @iflyime 你的这个代码可以正常跳转,谢谢~
    Anonono
        11
    Anonono  
       307 天前
    `error_page 497 301 =307`中的 301 有什么作用吗,不是很理解为什么要在这加 301
    jinliming2
        12
    jinliming2  
    OP
       306 天前
    @Anonono #11 不太记得当时怎么想的了,貌似是看了那个 stack overflow 的回答就直接复制过来了。。。
    看了下那个回答的修改记录,最开始是没有 301 =307 这一段的,测试了下这样默认就是 302 。
    然后底下有个人说加上 301 =307 防止请求方法发生改变( 301 和 302 的标准规定请求方法不变,但是部分浏览器实现会在重定向后变成 GET )。
    但是实际上测试了下,只写 =307 或者 =308 就行。
    前面的 301 只在 upstream 服务返回了 301 状态码的情况下生效,用于改写为 307 (按理应该改写成 308🤔)保留请求方法。
    jinliming2
        13
    jinliming2  
    OP
       306 天前
    @Anonono #11 #12 我注意到 nginx 文档中有一句 The code 308 was not treated as a redirect until version 1.13.0. 也就是说,308 状态码是 nginx 1.13.0 才支持的,查了下 nginx 的更新记录,1.13.0 是 2017 年 4 月 25 发布的。而那个评论的时间是 2015 年 2 月 4 日。
    所以评论者当时的 nginx 版本只支持 307 ( 2012 年 2 月 29 日的 1.1.16 和 2012 年 3 月 5 日的 1.0.13 )。评论者的原话是 That way the request method isn't auto converted to a GET as is default 。所以 301 估计就是那个人自己加的,用于避免请求方法被改成 GET 用的,与原题无关,但推荐一块加上?
    现在版本的 nginx 支持 308 了,所以应该用 308 更合适?
    kevinwu04266
        14
    kevinwu04266  
       249 天前
    @iflyime 为什么我改到别的非 443 的端口,访问网站需要在网站后面加“:端口号”才能正常进入呢
    kevinwu04266
        15
    kevinwu04266  
       249 天前
    @xiri 为什么我改到别的非 443 的端口,访问网站需要在网站后面加“:端口号”才能正常进入呢
    jinliming2
        16
    jinliming2  
    OP
       249 天前 via iPhone
    @kevinwu04266 标准 https 端口就是 443 ,http 就是 80 ,你用其他端口就是非标准。
    浏览器怎么知道你用的哪个端口,你总不能让浏览器去猜吧?肯定是得要你自己明确指定啊!
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3667 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 21ms · UTC 10:36 · PVG 18:36 · LAX 02:36 · JFK 05:36
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.