nginx实现一个对外端口同时支持http和https协议访问

前言

  • 最近有一个需求,需要让一个非80端口的http服务支持https访问;但是业务牵扯太多没法将http直接改为https,因此需要一个端口同时支持http和https

方案一. 使用nginx的stream、 stream_ssl_preread模块

参考资料

1.准备工作

  • nginx版本1.11.5及以上
  • 由于stream和stream_ssl_preread模块非默认引入,需要在编译安装nginx时引入;编译时添加配置参数 --with-stream --with-stream_ssl_preread_module
  • 这里给一个笔者编译tengine时的配置,仅供参考
./configure --add-module=./modules/ngx_http_upstream_vnswrr_module --add-module=./modules/ngx_http_proxy_connect_module --without-http_rewrite_module --with-openssl=/root/openssl-1.0.1j --with-pcre  --without-http_gzip_module --with-stream --with-stream_ssl_preread_module --with-stream_ssl_module --with-stream_sni

2.配置stream

stream {
  upstream http_gateway {
    # 20036端口是一个开启http的端口
    server  127.0.0.1:20036;
  }
  upstream https_gateway {
    # 20037端口是一个开启https的端口
    server  127.0.0.1:20037;
  }
  # 根据不同的协议走不同的upstream
  map $ssl_preread_protocol $upstream{
    default http_gateway;
    "TLSv1.0" https_gateway;
    "TLSv1.1" https_gateway;
    "TLSv1.2" https_gateway;
    "TLSv1.3" https_gateway;
  }
  server {
    listen 12345;
    ssl_preread on;
    proxy_pass $upstream;
  }
}

3.简单的nginx.conf示例供参考

user  root;
worker_processes  2;
worker_rlimit_nofile  100000;
stream {
  upstream http_gateway {
    server  127.0.0.1:20036;
  }
  upstream https_gateway {
    server  127.0.0.1:20037;
  }
  map $ssl_preread_protocol $upstream{
    default http_gateway;
    "TLSv1.0" https_gateway;
    "TLSv1.1" https_gateway;
    "TLSv1.2" https_gateway;
    "TLSv1.3" https_gateway;
  }

  server {
    listen 12345;
    ssl_preread on;
    proxy_pass $upstream;
  }
}

http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
     upstream gateway_service{
          server  127.0.0.1:8080  weight=1;
          server  127.0.0.1:8081  weight=2;
     }

    server {
        listen       20036;
        listen       20037 ssl;
        server_name  xxx.com;
        ssl_certificate      xxx.pem;
        ssl_certificate_key  xxx.key;
        location / {
            proxy_pass http://gateway_service;
        }
    }

}

上面配置即可实现端口12345同时支持http和https协议访问。

但是上面配置存在一个弊端就是服务端无法获取到客户端请求的真实ip地址,因为使用stream之后,上面配置无法获取到客户端的真实ip。

于是对上面配置进行进一步修改,

user  root;
worker_processes  2;
worker_rlimit_nofile  100000;
stream {
  upstream http_gateway {
    server  127.0.0.1:20036;
  }
  upstream https_gateway {
    server  127.0.0.1:20037;
  }
  map $ssl_preread_protocol $upstream{
    default http_gateway;
    "TLSv1.0" https_gateway;
    "TLSv1.1" https_gateway;
    "TLSv1.2" https_gateway;
    "TLSv1.3" https_gateway;
  }

  server {
    listen 12345;
    ssl_preread on;
    proxy_pass $upstream;
	proxy_protocol on; #开启protocol
  }
}

http {
	real_ip_recursive on;
    real_ip_header proxy_protocol; #基于stream层传来protocol数据进行后续修改
    set_real_ip_from 127.0.0.0/24; #从real_ip_header中删除这个ip段的ip,也可直接写具体ip;


    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
     upstream gateway_service{
          server  127.0.0.1:8080  weight=1;
          server  127.0.0.1:8081  weight=2;
     }

    server {
        listen       20036;
        listen       20037 ssl;
        server_name  xxx.com;
        ssl_certificate      xxx.pem;
        ssl_certificate_key  xxx.key;
        location / {
            proxy_pass http://gateway_service;
        }
    }
}

上面配置即可实现将客户端ip透传

 

参考文章:

nginx实现一个对外端口同时支持http和https协议访问 - 知乎 (zhihu.com)

nginx开启stream模块获取真实ip | 忐忑の博客 (twbhub.top)

posted @ 2024-02-04 11:55  wang_longan  阅读(3237)  评论(0编辑  收藏  举报