欢迎光临
我们一直在努力
RackNerd Billboard Banner

nginx配置在一个端口下,同时支持http与https两种协议

Linux服务器运维

Nginx 不支持同一个端口 同时提供 HTTP 和 HTTPS 服务,原因如下:

  • HTTPHTTPS 使用的是不同的协议,HTTPS 需要 TLS 握手,而 HTTP 不需要。
  • Nginx 无法在同一个端口上自动区分 HTTP 和 HTTPS

解决方案

虽然 Nginx 本身不支持 HTTP 和 HTTPS 共享同一端口,但你可以使用 SSL 预读(SSL Preread) 技术,通过 Nginx 的 stream 模块在 同一端口 上区分 HTTP 和 HTTPS 流量。

配置方式:使用 stream 模块监听 443 端口并区分 HTTP/HTTPS

# 在 http 之外的全局配置中
stream {
    map $ssl_preread_protocol $name {
        "" http_backend;  # 没有 TLS 的是 HTTP
        default https_backend;  # 有 TLS 的是 HTTPS
    }

    upstream http_backend {
        server 127.0.0.1:8080;  # HTTP 服务器
    }

    upstream https_backend {
        server 127.0.0.1:8443;  # HTTPS 服务器
    }

    server {
        listen 443;
        proxy_pass $name;
        ssl_preread on;
    }
}

http {
    server {
        listen 8080;
        server_name yourdomain.com;

        location / {
            root /usr/share/nginx/html;
            index index.html;
        }
    }

    server {
        listen 8443 ssl;
        server_name yourdomain.com;

        ssl_certificate /path/to/cert.pem;
        ssl_certificate_key /path/to/key.pem;

        location / {
            root /usr/share/nginx/html;
            index index.html;
        }
    }
}

工作原理

  1. stream 监听 443 端口

    • 使用 ssl_preread 读取数据流,判断是否是 HTTPS(即是否有 TLS 握手)。
    • 如果是 HTTP,转发到 http_backend127.0.0.1:8080)。
    • 如果是 HTTPS,转发到 https_backend127.0.0.1:8443)。
  2. http {} 配置 HTTP 和 HTTPS

    • server 监听 8080 端口处理 HTTP。
    • server 监听 8443 端口处理 HTTPS。

最终效果

  • 访问 http://yourdomain.com:443:会自动转发到 8080 端口的 HTTP 服务器。
  • 访问 https://yourdomain.com:443:会自动转发到 8443 端口的 HTTPS 服务器。

这样,你就能在 一个端口(443) 上同时支持 HTTP 和 HTTPS 访问!


同一端口(443)支持 HTTP 和 HTTPS 访问的 Nginx 实现原理

Nginx 通过 stream 模块ssl_preread 技术,在 443 端口 自动区分 HTTP 和 HTTPS,并将请求转发到不同的后台端口(8080 和 8443)。


主要技术点

1. stream 模块

  • 作用:处理 TCP 层(四层) 代理,而不是 HTTP(七层)。
  • 由于 Nginx 默认是 HTTP 服务器,只能解析 HTTP 请求,但 stream 允许它直接代理 TCP 流量(即 HTTP 和 HTTPS)。

2. ssl_preread on;

  • 作用:在 不终止 TLS 连接 的情况下,读取客户端的 TLS 握手信息,从而判断是否为 HTTPS。
  • 具体来说,它读取客户端发送的 ClientHello 数据包:
    • 如果是 HTTPS 包含 TLS 版本、加密算法、SNI(服务器名称指示)
    • 如果是 HTTP 直接是明文的 GET/POST 请求

3. map 变量映射

map $ssl_preread_protocol $proxy_backend {
    "" http_backend;   # 没有 TLS 的是 HTTP
    default https_backend;  # 有 TLS 的是 HTTPS
}
  • $ssl_preread_protocol 变量:
    • 为空(””) 说明是 HTTP(明文)
    • 非空 说明是 HTTPS(加密)
  • 作用
    • HTTP 请求 代理到 8080 端口
    • HTTPS 请求 代理到 8443 端口

4. stream 服务器配置

server {
    listen 443;
    proxy_pass $proxy_backend;
    ssl_preread on;
}
  • 监听 443 端口
  • 自动区分 HTTP 和 HTTPS
  • 基于 $proxy_backend 变量,将请求转发到 8080(HTTP)或 8443(HTTPS)

访问流程

情况 1:客户端访问 HTTP

curl -v http://zhgdqh.ezczb.com:443
  1. 客户端发送 HTTP 请求(明文)
  2. Nginx ssl_preread 检测到是 HTTP
  3. Nginx map 规则匹配$ssl_preread_protocol 为空 → 选择 http_backend
  4. 代理到 127.0.0.1:8080(HTTP 服务器)
  5. 服务器返回 HTTP 响应

情况 2:客户端访问 HTTPS

curl -v https://zhgdqh.ezczb.com:443
  1. 客户端发送 TLS ClientHello 握手包
  2. Nginx ssl_preread 读取 TLS 协议
  3. Nginx map 规则匹配:发现是 HTTPS → 选择 https_backend
  4. 代理到 127.0.0.1:8443(HTTPS 服务器)
  5. 服务器继续握手并建立 HTTPS 连接

为什么要这样做?

  1. 默认情况下,Nginx 不能在同一端口同时处理 HTTP 和 HTTPS

    • 传统方案:用 listen 80 处理 HTTP,listen 443 ssl 处理 HTTPS。
    • 但如果只能用 443 端口,就需要 ssl_preread 来区分流量。
  2. 适用于负载均衡或网关

    • stream 代理 TCP 流量,可以在反向代理前端统一监听 443,然后转发到不同的服务(HTTP / HTTPS)。

方案优缺点

优点 缺点
允许 HTTP 和 HTTPS 共用 443 端口 stream 只能代理 TCP 层,无法解析 HTTP 请求路径
ssl_preread 无需解密 TLS,效率高 不能同时做 HTTP → HTTPS 自动重定向
兼容性好,适用于负载均衡 需要额外的 http {} 服务器监听 8080 / 8443

总结

通过 stream + ssl_preread,Nginx 无需额外端口 就能在 443 端口同时支持 HTTP 和 HTTPS
适用于负载均衡、网关、同一 IP 端口共用的场景
高效,无需解密 HTTPS,直接转发 TCP 流量。
缺点:无法做 HTTP → HTTPS 自动跳转,但可以用前端 JS 或 meta refresh 解决。

这个方案特别适合 企业级 Nginx 反向代理、云服务器、Kubernetes Ingress 网关

赞(0) 打赏
未经允许不得转载:全球主机测评 » nginx配置在一个端口下,同时支持http与https两种协议
RackNerd Leaderboard Banner 新春特惠 服务器运维包年大优惠查看活动

觉得文章有用就打赏一下文章作者

非常感谢你的打赏,我们将继续提供更多优质内容,让我们一起创建更加美好的网络世界!

支付宝扫一扫

微信扫一扫