前言

之前的一篇文章《自建CA并生成自签名SSL证书》中讲到为什么要自建CA和自签名SSL证书,是因为买证书得花钱,对于内部或小规模项目,使用自建SSL证书可能更为方便,不需要支付费用,而且不涉及复杂的验证过程。正式对外的服务一般都是要买公共证书颁发机构(CA)签发的SSL证书的,但是在对外发布前可以先使用自建证书打通流程

配置SSL证书

创建SSL证书的流程参考上文中提到的文章吧,本文只讲怎样把自建SSL证书配置到nginx,实际上非常简单。

假设我们的自建证书是 /root/ca/server.crt,服务器私钥是 /root/ca/server.key,nginx配置文件我以《记录一下第一次安装和配置Nginx》 这篇文章的配置文件为例,初始配置为:

upstream go_entrance {
    server localhost:4101;
    server localhost:4102;
}

server {
    listen       4100;
    server_name  localhost;

    location / {

        proxy_pass http://go_entrance;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

4100端口监听http协议转发到本机的4101端口和4102端口,如果把SSL证书配置到这个端口上,就相当于这个端口支持了https,配置修改如下:

upstream go_entrance {
    server localhost:4101;
    server localhost:4102;
}

server {
    listen 4100 ssl;
    server_name  localhost;

    ssl_certificate /root/ca/server.crt;
    ssl_certificate_key /root/ca/server.key;

    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on; 

    location / { 
        proxy_pass http://go_entrance;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }   
}

只需要将4100端口后面加上 ssl,再配置几个ssl相关的参数就可以了,含义如下:

  • ssl_certificate: 指定 SSL 证书文件路径 /root/ca/server.crt

  • ssl_certificate_key: 指定私钥文件路径 /root/ca/server.key

  • ssl_session_cache: 配置用于存储 SSL 会话的缓存。shared:SSL:10m 表示使用共享的内存区域,最大占用内存为 10MB

  • ssl_session_timeout: 配置 SSL 会话的超时时间,这里设置为 10 分钟

  • ssl_protocols: 指定支持的 SSL/TLS 协议版本,这里包括 TLSv1、TLSv1.1 和 TLSv1.2

  • ssl_ciphers: 指定支持的加密套件,这里配置为 HIGH:!aNULL:!MD5,表示使用高强度的加密套件,不支持空加密和 MD5

SSL证书放在 Nginx 而不放在应用服务器上的好处

正如上面的配置一样,4100端口收到https请求后转发到4101和4102上的是http协议,说明使用这种方式一些仅支持http协议的应用服务也可以通过nginx配置证书来达到支持https的目的,具体好处如下:

  • 集中管理: 使用反向代理服务器管理 SSL 证书可以实现集中式管理。这意味着你可以在一个地方管理证书,而不需要在每个应用服务器上都安装和维护证书。这样能够简化证书的更新和维护流程。

  • 简化配置: 通过在反向代理服务器上配置 SSL,你可以简化应用服务器的配置。应用服务器可以专注于处理应用程序逻辑,而无需关心 SSL 配置。这样有助于提高系统的可维护性和简化配置过程。

  • 负载均衡和扩展: 如果你使用负载均衡,SSL终止(SSL Termination)在负载均衡器上执行可以减轻应用服务器的负担。负载均衡器负责处理SSL握手,将非加密的请求转发给后端应用服务器。这样,后端服务器就可以专注于处理业务逻辑,而无需处理加密和解密操作。

  • 性能优化: SSL 握手和加解密操作可能是计算密集型的任务,将这些任务从应用服务器中移除,可以在 SSL 握手和加解密方面提高性能。

  • 统一的安全策略: 通过在反向代理服务器上管理 SSL,可以实施统一的安全策略,确保所有传入和传出的流量都经过相同的安全设置。

Nginx只能转发http协议吗

不,Nginx 不仅仅能够转发 HTTP 协议,还支持其他多种协议的代理转发。主要的协议包括:

  • HTTPS协议: 通过在配置中启用 SSL/TLS,Nginx 可以用作安全的 HTTPS 服务器和反向代理,处理加密的 HTTP 流量。

    listen 443 ssl;
    ssl_certificate /path/to/certificate.crt;
    ssl_certificate_key /path/to/private-key.key;
    
    location / {
        proxy_pass https://backend_server;
    }
    
  • TCP协议: 从1.9版本开始 Nginx 可以用于代理 TCP 流量,例如数据库连接、消息队列等。

    stream {
        server {
            listen 3306;
            proxy_pass backend_server:3306;
        }
    }
    
  • UDP协议: 从Nginx 1.9.13版本开始,开始支持 UDP 代理。这使得它可以用于代理 UDP 流量,如 DNS 请求等。

    stream {
        server {
            listen 53 udp;
            proxy_pass backend_dns_server:53;
        }
    }
    
  • WebSocket协议: WebSocket 是一种在单个 TCP 连接上提供全双工通信的协议,常用于实时应用程序,如在线游戏、聊天应用等。

    map $http_upgrade $connection_upgrade {
        default upgrade;
        ''      close;
    }
    
    server {
        listen 80;
    
        server_name your_domain.com;
    
        location /websocket {
            proxy_pass http://backend_server;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection $connection_upgrade;
        }
    }
    

Nginx转发TCP协议会收到端口限制吗

是的,TCP是一种面向连接的全双工通信的协议,当转发TCP消息时,Nginx不仅是一个服务器接受客户端的连接,再它连接应用服务器时还表现成一个客户端,每个连接需要消耗一个端口,以理论值65535个端口来计算,nginx最多转发65535个连接,但是可以通过 proxy_bind 来突破限制,或者配置多个IP或虚拟IP也可以。

这种方式还没测过,感兴趣可以参考官方说明的看一下 https://nginx.org/r/proxy_bind

Nginx本身能将Websocket数据转化成TCP数据吗

只使用Nginx是做不到的,但是搭配Websockify就可以做到WSS(WebSocket Secure)到 TCP 的转发

  1. 安装 Nginx:
    确保你的系统上已经安装了 Nginx。你可以使用系统包管理器或从 Nginx 官方网站下载并安装

  2. 安装 Websockify:
    安装 Websockify,可以使用 pip 执行以下命令:

    pip install websockify
    
  3. 创建 Websockify 启动脚本:
    创建一个用于启动 Websockify 的脚本,例如 start_websockify.sh。脚本内容可能如下所示:

    #!/bin/bash
    websockify --web /path/to/webroot 1234 localhost:5678
    

    这里 1234 是用于 WebSocket 连接的端口,localhost:5678 是实际 TCP 服务的地址

  4. 配置 Nginx:
    修改 Nginx 配置文件,将 WSS 请求转发到 Websockify 启动脚本。示例配置如下:

    server {
        listen 443 ssl;
        server_name your_domain.com;
    
        ssl_certificate /root/ca/server.crt;
        ssl_certificate_key /root/ca/server.key;
    
        location / {
            proxy_pass http://localhost:1234;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
            proxy_set_header Host $host;
        }
    }
    

    这里的 listen 443 表示监听 HTTPS 请求,proxy_pass http://localhost:1234 将请求代理到 Websockify 启动脚本

  5. 启动服务:
    启动 Websockify 服务:

    chmod +x start_websockify.sh
    ./start_websockify.sh
    

    启动 Nginx 服务:

    systemctl start nginx
    
  6. 测试:
    使用支持 WebSocket 的客户端连接到 WSS 地址,例如 wss://your_domain.com,并验证是否成功将 WebSocket 请求转发到 TCP 服务

总结

  • nginx配置自建SSL证书,只需要修改nginx配置文件,在端口后配置添加 ssl 并指定证书和私钥路径即可
  • nginx上配置SSL证书可以将证书统一管理,减轻应用服务器加密解密的负担,专注于业务逻辑开发
  • nginx不仅支持http协议转发,还支持https、tcp、udp、websocket等协议的转发
  • nginx转发tcp协议时会收到端口号个数限制,理论上限6万,通过proxy_bind可以突破上限
  • nginx搭配websockify可以做到WSS 到 TCP 的转发


12-09 05:26