nginx.org的Configuring HTTPS servers页面翻译

本文介绍如何配置HTTPS服务,包括设置SSL参数、优化HTTPS服务器性能、处理证书链问题等。此外还探讨了如何在同一IP地址上运行多个HTTPS服务器的技术方案。

国庆期间,抽时间翻译。英文水平太差,翻译太费劲了。。。


英文文档对应页面:Configuring HTTPS servers

配置https服务

为了配置https服务,必须开启 "server"块的 "listen" 指令的 "ssl" 参数,并且需要指定 "server_certificate" 和 "private_key" 文件位置:

server {
    listen              443 ssl;
    server_name         www.example.com;
    ssl_certificate     www.example.com.crt;
    ssl_certificate_key www.example.com.key;
    ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers         HIGH:!aNULL:!MD5;
}

服务器证书是一个公共的实体。会发送给每个连接到这台服务器的客户端。密钥是一个安全的(私有到)实体,并且应该被存储到一个访问受限的文件中,但必须保证针nginx的主进程是可读的。密钥也可以被存储到同证书相同的文件中(一个文件中,同时包含了证书和密钥),例如:
ssl_certificate     www.example.com.cert;
ssl_certificate_key www.example.com.cert;

当文件中同时包含了证书和密钥,这个文件的访问权限也应该被限制(因为密钥的访问权限需要被限制)。虽然证书和密钥存储在同一个文件中,但是连接时只有证书内容会被发送给客户端。
"ssl_protocols" 和 "sll_ciphers" 指令,可用来限制连接的SSL/TLS版本和ciphers。默认情况下,nginx使用 "ssl_protocols TLSv1 TLSv1.1 TLSv1.2" 和 "ssl_ciphers HIGH:!aNULL:!MD5",所以通常情况下,不需要准确配置它们。注意:这些指令的值被改变过好几次了。


HTTPS服务器优化

ssl操作消耗额外的cpu资源。在多处理器系统中,运行的工作进程(worker_processes)数不应该低于可用的cpu核心的数量。最密集的cpu操作是:ssl的握手操作。有2种方式去减少每个客户端的这些操作数量:第一种方式是:启用 'keepalive' 长连接,在一个连接中可发送多个请求;第二种方式是:重新使用ssl的session参数,避免并发连接和后续连接原本需要的的ssl握手操作。session存储在一个ssl的session缓存中,被工作进程(workers)和"ssl_session_cache"指令所设置的值所共享。1m缓存可包含大约4000条session。默认的缓存过期时间是5分钟。使用 "ssl_session_timeout"指令可延长缓存的过期时间。下面是使用了10m共享session缓存空间来优化一个多核系统的配置实例:
worker_processes auto;
http {
    ssl_session_cache   shared:SSL:10m;
    ssl_session_timeout 10m;


    server {
        listen              443 ssl;
        server_name         www.example.com;
        keepalive_timeout   70;


        ssl_certificate     www.example.com.crt;
        ssl_certificate_key www.example.com.key;
        ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers         HIGH:!aNULL:!MD5;
        ...


ssl证书链

一些浏览器抱怨,其他浏览器接受知名证书机构未发布的签名证书(某些浏览器支持一些未发布的证书,而有些浏览器并不支持)。出现这种情况是因为:发布机构使用了一个中间证书签署了服务器证书。这个证书并不是基于知名、信任的证书机构发布的证书,而是由一个特殊浏览器发布。在这种情况下,该机构提供了一个同已签名的服务器证书相关联的捆绑证书链(服务器证书同捆绑证书链在同一个文件中)。在合并的文件中,服务器证书必需出现在所有证书链之前:
$ cat www.example.com.crt bundle.crt > www.example.com.chained.crt      // 服务器证书在最前面(bundle.crt-是证书链文件)
最终的结果文件,应该被使用到 "ssl_certificate" 指令:
server {
    listen              443 ssl;
    server_name         www.example.com;
    ssl_certificate     www.example.com.chained.crt;
    ssl_certificate_key www.example.com.key;
    ...
}

如果服务器证书和捆绑的证书,以错误的方式关联在一起,nginx启动失败,并且显示如下错误信息:
SSL_CTX_use_PrivateKey_file(" ... /www.example.com.key") failed
   (SSL: error:0B080074:x509 certificate routines:
    X509_check_private_key:key values mismatch)

因为nginx首先会尝试绑定证书中的第一个的私钥,替代之前的服务器证书私钥。
浏览器通常存储它们接收到的,以及信任机构签名过的中间证书,因此积极使用的浏览器可能已经有所需的中间证书,所以可能不会抱怨(complain about)一个发送过来的没有chained绑定证书(因为浏览器可能已经存储过,该证书的chained绑定证书)。为了确保服务器发送完整的证书链,可能需要使用 "openssl" 命令行工具,例如:
$ openssl s_client -connect www.godaddy.com:443
...
Certificate chain
 0 s:/C=US/ST=Arizona/L=Scottsdale/1.3.6.1.4.1.311.60.2.1.3=US
     /1.3.6.1.4.1.311.60.2.1.2=AZ/O=GoDaddy.com, Inc
     /OU=MIS Department/CN=www.GoDaddy.com
     /serialNumber=0796928-7/2.5.4.15=V1.0, Clause 5.(b)
   i:/C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc.
     /OU=http://certificates.godaddy.com/repository
     /CN=Go Daddy Secure Certification Authority
     /serialNumber=07969287
 1 s:/C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc.
     /OU=http://certificates.godaddy.com/repository
     /CN=Go Daddy Secure Certification Authority
     /serialNumber=07969287
   i:/C=US/O=The Go Daddy Group, Inc.
     /OU=Go Daddy Class 2 Certification Authority
 2 s:/C=US/O=The Go Daddy Group, Inc.
     /OU=Go Daddy Class 2 Certification Authority
   i:/L=ValiCert Validation Network/O=ValiCert, Inc.
     /OU=ValiCert Class 2 Policy Validation Authority
     /CN=http://www.valicert.com//emailAddress=info@valicert.com
...

在这个例子中, 'www.GoDaddy.com'服务器证书 "#0" 的主题("S")被发行人("/")签名。而发行人("/")自己又是证书 "#1"的主题,被发行人签名,该发行人自身又是 证书 "#2" 的主题,被知名发行人 "ValiCert,inc" 签名。发行人 "ValiCert,inc" 的证书存储在浏览器的内置证书基地(that lay in the house that Jack built - 不知道是啥意思)
------
太难翻译,太难懂了,总之可以理解为一个首位相关联的证书链。。。
------
如果已经添加了一个证书捆绑,仅仅会显示服务器证书 "#0"

单个HTTP/HTTPS服务器

配置同时处理HTTP和HTTPS请求的单个服务器也是可能的:
server {
    listen              80;
    listen              443 ssl;
    server_name         www.example.com;
    ssl_certificate     www.example.com.crt;
    ssl_certificate_key www.example.com.key;
    ...
}

在0.7.14版本之前,SSL无法对单个监听sockets选择性地启用,就像上面展示的那样(现在是可以对单个sockets启用的)。SSL仅仅可以对使用了 "ssl" 指令的整个服务器("server"块)启用,使得配置单个HTTP/HTTPS服务器是不可能的。"listen"指令的 "ssl"参数的引入,就是为了解决这个问题。因此,在现代的这些版本中,不鼓励使用 "ssl" 指令。

基于名称的HTTPS服务器

一个普遍的问题是:一个IP地址,配置2个或更多的HTTPS服务器。
server {
    listen          443 ssl;
    server_name     www.example.com;
    ssl_certificate www.example.com.crt;
    ...
}
server {
    listen          443 ssl;
    server_name     www.example.org;
    ssl_certificate www.example.org.crt;
    ...
}

使用这个配置,浏览器接收默认服务器的证书,即:www.example.com,而忽略请求的服务器名称。这是由 "ssl" 协议自身行为导致的。在浏览器发送HTTP请求之前,已经建立了 "ssl" 连接,这样浏览器不知道请求服务器的名字。因此,它仅仅提供默认服务器的证书。
解决这一问题的最古老、最健壮的方法是:为每个HTTPS服务器分配一个单独的IP地址。
server {
    listen          192.168.1.1:443 ssl;
    server_name     www.example.com;
    ssl_certificate www.example.com.crt;
    ...
}
server {
    listen          192.168.1.2:443 ssl;
    server_name     www.example.org;
    ssl_certificate www.example.org.crt;
    ...
}

多个server使用一个ssl证书

有其他方式,允许在几个HTTPS服务器之间分享一个单独的IP地址。然而,所有方法都有它们的缺点。一种方式是:使用一个证书,并且在 "SubjectAltName" 证书字段中使用多个服务器名称,例如:"www.example.com" 和 "www.example.org"。然而,"SubjectAltName" 字段长度有限制(只能添加有限个服务器名称)。
另一种方式是:使用一个证书和一个通配符表示的服务器名称,例如:"*.example.org"。一个通配符证书,会保证指定域名的所有子域名的安全,但仅仅是一级域名。这个证书匹配到 "www.example.org",但是不会匹配到 "example.org" 和 "www.sub.example.org"。
上面的这两种方法也可以结合使用。一个证书的 "SubjectAltName" 字段,可以包含准确的服务器名称和通配符表示的服务器名称,例如:"example.org" 和 "*.example.org"。
更好的方式是:多个服务器名称,然后在配置文件的 "http" 块中,指定 "证书文件" 和 "证书文件的密钥文件",让所有服务器都可以继承它们都配置(配置在"server"块的上层上下文中,使每个"server"块都可以共享该配置):
ssl_certificate     common.crt;
ssl_certificate_key common.key;
server {
    listen          443 ssl;
    server_name     www.example.com;
    ...
}
server {
    listen          443 ssl;
    server_name     www.example.org;
    ...
}

服务器名称说明

在一个单独的IP地址上,运行多个HTTPS服务器的更通用的解决方案是:TLS 服务器名称说明扩展(TLS Server Name Indication extension - SNI, RFC 6066,链接地址:http://en.wikipedia.org/wiki/Server_Name_Indication),允许浏览器在SSL握手期间传递请求服务器的名称,因此,ssl握手连接时,服务器将知道它应该使用哪个证书。然而,"SNI" 受浏览器支持的限制。目前,支持SNI的浏览器版本有:
Opera 8.0;
MSIE 7.0 (but only on Windows Vista or higher);
Firefox 2.0 and other browsers using Mozilla Platform rv:1.8.1;
Safari 3.2.1 (Windows version supports SNI on Vista or higher);
and Chrome (Windows version supports SNI on Vista or higher, too).

注意:SNI中,仅可以传递域名,然而如果一个请求包含一个IP地址,一些浏览器可能错误的传递一个IP地址作为服务器名字。这是不应该依赖SNI的一个理由。(One should not rely on this - 翻译出来应该是这个意思)
为了在nginx中使用SNI,OpenSSL库和nginx二进制文件(nginx程序)都必须支持SNI,nginx中已经内置SNI的支持(不支持,可能得我们安装其他补丁或扩展?),运行时会动态链接到OpenSSL库。OpenSSL在0.9.8f版本后,开始支持SNI,安装时只需要指定配置选项 "--enable-tlsext"。OpenSSL在0.9.8f版本后,该选项是默认启用的。如果nginx内置了SNI支持,当运行'nginx -V',将显示如下信息:
$ nginx -V
...
TLS SNI support enabled
...

如果内置了SNI的nginx被动态链接到不支持SNI的OpenSSL库中,nginx将显示如下的警告:
nginx was built with SNI support, however, now it is linked
dynamically to an OpenSSL library which has no tlsext support,
therefore SNI is not available

兼容性

关于版本方面的一些支持,就不翻译了,自己查看原文档

### Nginx reload failed after configuring Flask upstream proxy leading to 502 error Nginx 返回 502 错误(Bad Gateway)通常表明反向代理配置无法正确地与后端服务通信,而 `nginx: [emerg]` 错误提示通常意味着配置文件中存在语法错误或路径配置不正确,导致 Nginx 无法成功重载配置。以下是可能导致此问题的原因及解决方法: #### 1. 配置文件语法错误 Nginx 配置文件中存在语法错误会导致 `nginx -t` 检查失败,并阻止 `nginx -s reload` 执行。例如,`server` 块未闭合、缺少分号、变量引用格式错误等。 **解决方法**:使用以下命令检查配置文件语法是否正确: ```bash nginx -t ``` 如果提示错误信息,例如: ``` nginx: [emerg] unknown directive "proxy_pass" in /etc/nginx/conf.d/myflask_apps.conf:10 ``` 说明配置文件中存在语法错误,需检查配置文件中的拼写、分号、大括号闭合情况等。例如,确保 `proxy_pass` 指令使用正确格式,且以分号结尾[^1]。 #### 2. 变量引用格式错误 在 Nginx 配置中,变量引用应使用 `$` 符号,而非转义形式。例如,配置中使用了 `\$host` 而非 `$host`,会导致变量无法解析,进而引发 502 错误。 **解决方法**:修改配置文件中的变量引用方式,确保使用正确的变量格式。例如: ```nginx location / { proxy_pass http://flask_servers; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } ``` 上述配置中,变量 `$host`、`$remote_addr` 和 `$proxy_add_x_forwarded_for` 应直接使用,而非使用反斜杠转义[^1]。 #### 3. 后端 Flask 应用未运行或端口未监听 如果 Flask 应用未运行或未监听指定端口(如 5000 和 5001),Nginx 无法将请求转发到后端服务,从而导致 502 错误。 **解决方法**:确保 Flask 应用已启动并监听正确的端口。例如,使用以下命令启动 Flask 应用: ```bash flask run --host=0.0.0.0 --port=5000 flask run --host=0.0.0.0 --port=5001 ``` 使用 `netstat` 或 `ss` 命令检查端口监听情况: ```bash ss -tuln | grep 5000 ``` #### 4. Nginx 无法访问后端服务 Nginx 与后端服务之间的通信可能受到防火墙或 SELinux 限制,导致连接被拒绝。 **解决方法**:检查系统防火墙规则,确保允许 Nginx 访问后端服务端口。例如,使用 `firewall-cmd` 添加端口开放规则: ```bash firewall-cmd --permanent --add-port=5000/tcp firewall-cmd --permanent --add-port=5001/tcp firewall-cmd --reload ``` #### 5. Nginx 配置文件路径错误 Nginx 默认加载 `/etc/nginx/nginx.conf` 文件,若未正确包含 `/etc/nginx/conf.d/` 目录下的配置文件,可能导致配置未生效。 **解决方法**:确保主配置文件中包含以下 `include` 指令,以加载 `conf.d` 目录下的配置文件: ```nginx http { ... include /etc/nginx/conf.d/*.conf; ... } ``` #### 6. Nginx 服务未启动或崩溃 如果 Nginx 服务未启动或在运行过程中崩溃,会导致配置无法加载,从而引发 502 错误。 **解决方法**:检查 Nginx 服务状态,确保其正常运行: ```bash systemctl status nginx ``` 若服务未运行,使用以下命令启动: ```bash systemctl start nginx ``` #### 7. 日志分析定位问题 通过分析 Nginx 的错误日志可以获取详细的错误信息,帮助定位问题根源。 **解决方法**:查看 Nginx 错误日志,通常位于 `/var/log/nginx/error.log`,使用以下命令查看最新日志: ```bash tail -f /var/log/nginx/error.log ``` ### 示例配置 以下是一个典型的 Nginx 配置示例,用于反向代理多个 Flask 应用: ```nginx upstream flask_servers { server 127.0.0.1:5000; server 127.0.0.1:5001; } server { listen 80; server_name 172.21.1.66; location / { proxy_pass http://flask_servers; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } location /server_info { proxy_pass http://flask_servers; } } ``` ### 相关问题
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值