weixueyuan-Nginx Web服务4

https://www.weixueyuan.net/nginx/web/

Nginx静态资源服务器搭建

HTML 是一种标记语言,提供 HTML 文件读取是静态服务器最基本的功能,静态服务器的配置样例如下:
server {
    listen 8080;
    root /opt/nginx-web/www;                # 存放静态文件的文件目录
    location / {
        index index.html;
    }
    location /js {
        alias /opt/nginx-web/static/js/;    # 存放JavaScript文件的文件目录
        index index.html;
    }
}
在以上配置中,每个 server 指令域等同于一个虚拟服务器,每个 location 指令域等同于一个虚拟目录。

Nginx文件下载服务器搭建

在对外分享文件时,利用 Nginx 搭建一个简单的下载文件管理服务器,文件分享就会变得非常方便。利用 Nginx 的诸多内置指令可实现自动生成下载文件列表页、限制下载带宽等功能。配置样例如下:
server {
    listen 8080;
    server_name  localhost;
    charset utf-8;
    root    /opt/nginx-web/files;             # 文件存放目录

    # 下载
    location / {
        autoindex on;                         # 启用自动首页功能
        autoindex_format html;                # 首页格式为HTML
        autoindex_exact_size off;             # 文件大小自动换算
        autoindex_localtime on;               # 按照服务器时间显示文件时间

        default_type application/octet-stream;# 将当前目录中所有文件的默认MIME类型设置为
                                              # application/octet-stream

        if ($request_filename ~* ^.*?\.(txt|doc|pdf|rar|gz|zip|docx|exe|xlsx|ppt|pptx)$){
            # 当文件格式为上述格式时,将头字段属性Content-Disposition的值设置为"attachment"
            add_header Content-Disposition: 'attachment;'; 
        }
        sendfile on;                          # 开启零复制文件传输功能
        sendfile_max_chunk 1m;                # 每个sendfile调用的最大传输量为1MB
        tcp_nopush on;                        # 启用最小传输限制功能

        aio on;                               # 启用异步传输
        directio 5m;                          # 当文件大于5MB时以直接读取磁盘的方式读取文件
        directio_alignment 4096;              # 与磁盘的文件系统对齐
        output_buffers 4 32k;                 # 文件输出的缓冲区大小为128KB

        limit_rate 1m;                        # 限制下载速度为1MB
        limit_rate_after 2m;                  # 当客户端下载速度达到2MB时进入限速模式
        max_ranges 4096;                      # 客户端执行范围读取的最大值是4096B
        send_timeout 20s;                     # 客户端引发传输超时时间为20s
        postpone_output 2048;                 # 当缓冲区的数据达到2048B时再向客户端发送
        chunked_transfer_encoding on;         # 启用分块传输标识
    }
}

Nginx伪动态SSI服务器

Nginx 可以通过 SSI 命令将多个超文本文件组合成一个页面文件发送给客户端。SSI(Server Side Include)是一种基于服务端的超文本文件处理技术。由于 SSI 仍是通过其他动态脚本语言获取动态数据的,所以此处将其归类为伪动态服务功能。

SSI 服务器可通过 SSI 命令实现诸多动态脚本语言的 HTML 模板功能,配合其他动态脚本服务的 API,完全可以实现前后端分离的 Web 应用。

1、配置指令

Nginx 是通过 ngx_http_ssi_module 模块实现 SSI 命令处理的,SSI 配置指令如下表所示。

指令名称 指令值格式 默认值指令说明
ssi on 或 off off 启用 SSI 命令功能
ssi_last_modified on 或 off off  允许保留原始响应头中的属性字段 Last-Modified,默认配置下该字段会被移除
ssi_min_file_chunk size 1k 设置存储在磁盘上的响应数据的最小值,超过该值的文件使用 sendfile 功能发送
ssi_silent_errors on 或 off off 当指令值为 on 时,SSI 处理出现错误后不输出 errmsg 的内容
ssi_types mime-type...  text/html 设置 SSI 处理的 MIME 类型
ssi_value_length length 256   SSI 中变量值的最大长度

上述指令均可编写在 http、server、location 指令域中,ssi 指令还可编写在 if 指令域中。

2、SSI 命令

SSI 命令格式如下:

<!--# command parameter1=value1 parameter2=value2 ... -->

Nginx 支持如下 SSI 命令。

1) block

通过 block 命令可以定义一个超文本内容,该内容可以被 include 命令参数 stub 引用。超文本内容中可以包含其他 SSI 命令。

2) include

通过 include 命令可以引入一个文件或请求响应的结果数据。参数有 file(引入一个文件)、virtual(引入一个内部请求响应数据)、stub(引入一个 block 内容为默认数据)、wait(是否等待 virtual 参数发起请求处理完毕再处理 SSI 命令)、set(将 virtual 参数的响应内容输出到指定的变量)。

SSI 文件配置样例如下:

<!--# block name="one" -->&nbsp;<!--# endblock -->      # block one的内容为空
<!--# include file="footer.html" stub="one" -->        
    # 引用文件footer.html的内容,若footer.html文件不存在或SSI命令出错,输出block one的内容
<!--# include virtual="/remote/body.php?argument=value" wait="yes" stub="one"
      set="body" -->
    # 引用内部请求的响应数据,等待请求完毕再处理SSI指令,若出错则输出block one的内容,成功则
    # 把返回结果赋值给变量body

Nginx中样例配置如下:

location /remote/ {
    subrequest_output_buffer_size 128k; # 子请求的输出缓冲区大小是128KB
    ...
}

include 不支持“../”这样的相对路径;另外 include 参数 set 的响应数据大小通过指令 subrequest_output_buffer_size 设置。

3) config

通过 config 命令可以设置 SSI 处理过程中使用的参数 errmsg(SSI 处理出错时输出的字符串)和 timefmt(输出时间的格式,默认为“%A,%d-%b-%Y %H:%M:%S %Z”)。

<!--# config errmsg="oh!出错了" timefmt="%A, %d-%b-%Y %H:%M:%S %Z" -->

4) set

通过 set 命令设置变量。参数有 var(变量名)和 value(变量值)。

5) echo

通过 echo 命令输出变量的值。参数有 encoding(HTML 编码方式,默认为 entity)、default(变量不存在时定义的默认输出,默认为 none)。

<!--# set var="This_TEST" value="with a SSI test value" -->
<!--# echo var="This_TEST" -->

6) if

通过 if 命令可进行条件控制,且 if 命令支持正则判断。

<!--# if expr="$name != /text/" -->
    <!--# echo var="name" -->
<!--# endif -->
<!--# if expr="$name = /(.+)@(?P<domain>.+)/" -->
    <!--# echo var="domain" -->
<!--# else -->
    <!--# echo var="1" -->
<!--# endif -->

3、配置样例

根据 Nginx SSI 模块提供的功能可以搭建一个类似 HTML 框架的前端模板网站。模板目录规划如下:

├── _footer.html 
├── _header.html
├── _head.html
├── index.html
├── _sidebar.html
├── static
│     └── main.css
└── table.html

文件 _footer.html 内容如下:
  1. <div id="footer">
  2. <!--# config timefmt="%Y" -->&copy;<!--# echo var="date_local" --> Nginx
  3. SSI sample - All Rights Reserved.
  4. </div>
文件 _header.html 内容如下:
  1. <div id="logo">
  2. <img src="http://nginx.org/nginx.png" style="width: 100px;" alt="nginx">
  3. </div>
  4. <div id="header">
  5. <ul class="nav nav-pills">
  6. <li class="active"><a href="index.html">首页</a></li>
  7. <li><a href="table.html">表格测试</a></li>
  8. <li><a href="#">测试2</a></li>
  9. </ul>
  10. </div>
文件 _head.html 内容如下:
  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  2. <html>
  3. <head>
  4. <meta content="text/html; charset=UTF-8" http-equiv="Content-Type">
  5. <link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css">
  6. <script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
  7. <script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
  8. <link rel="stylesheet" href="/static/main.css?v=12">
  9. </head>
文件 index.html 内容如下:
  1. <!--# block name="one" --><!--# endblock -->
  2. <!--# include file="_head.html" stub="one" -->
  3. <body>
  4. <div>
  5. <!--# include file="_header.html" stub="one" -->
  6. <!--# include file="_sidebar.html" stub="one" -->
  7. </div>
  8. <div id="section">
  9. <h1>Hello World</h1>
  10. </div>
  11. <!--# include file="_footer.html" stub="one" -->
  12. </body>
  13. </html>
文件 _sidebar.html 内容如下:
  1. <div id="sidebar">
  2. <ul class="nav navbar-nav">
  3. <li class="active"><a href="http://www.baidu.com" target="blank">百度</a></li>
  4. <li class="active"><a href="#">测试</a></li>
  5. </ul>
  6. </div>
首页页面效果如下图所示。

SSI框架首页
图:SSI框架首页

文件 table.html 内容如下:
  1. <!--# block name="one" --><!--# endblock -->
  2. <!--# include file="_head.html" stub="one" -->
  3. <body>
  4. <div>
  5. <!--# include file="_header.html" stub="one" -->
  6. <!--# include file="_sidebar.html" stub="one" -->
  7. </div>
  8. <div id="section">
  9. <table class="table">
  10. <caption>表格示例</caption>
  11. <thead>
  12. <tr>
  13. <th>省份</th>
  14. <th>省会</th>
  15. </tr>
  16. </thead>
  17. <tbody>
  18. <tr>
  19. <td>上海</td>
  20. <td>上海</td>
  21. </tr>
  22. <tr>
  23. <td>广东</td>
  24. <td>广州</td>
  25. </tr>
  26. </tbody>
  27. </table>
  28. </div>
  29. <!--# include file="_footer.html" stub="one" -->
  30. </body>
  31. </html>
表格页页面效果如下图所示。

SSI 框架表格页
图:SSI 框架表格页

Nginx 配置内容如下:
server {
    listen 8081;
    server_name localhost;
    charset utf-8;
    root /opt/nginx-web/nginx-ssi;
    sendfile on;
    ssi on;                         # 启用SSI命令解析支持
    ssi_min_file_chunk 1k;          # 存储在磁盘上的响应数据的最小值为1KB
    ssi_value_length 1024;          # SSI中变量值的最大长度为1024字节
    ssi_silent_errors off;          # 输出errmsg的内容

    location / {
         index index.html;
    }
}

Nginx HTTPS服务器搭建

互联网应用为我们提供了丰富的信息内容,在给我们带来方便的同时也影响着我们的生活方式。随着人们对网络的依赖不断增强,安全问题变得愈发重要,各种加密技术应运而生。SSL 协议是 20 世纪 90 年代由 Netscape 公司提出的,后由 ITEL 接管并进行标准化,更名为 TLS 协议,TLS 1.0 就是 SSL 3.1 版本。

HTTPS(HyperText Transfer Protocol Secure,超文本传输安全协议)是在 HTTP 的基础上增加了 SSL 协议,为数据传输提供了身份验证和加密功能。使用 HTTPS 协议可验证用户客户端和服务器的身份,确保数据可以在正确的用户客户端和服务器间传输。

因为 HTTPS 协议的数据传输是加密的,所以在传输过程中可以有效防止数据被窃取和修改,从而保障网络信息的安全。Nginx 的 HTTPS 协议服务是通过 ngx_http_ssl_module 模块实现的,在配置编译参数时需要添加 --with-http_ssl_module 参数启用该功能。

1、配置指令

Nginx HTTPS 配置指令如下表所示。

指令名称指令值格式默认值指令说明
ssl on 或 off off 启用 SSL 支持,建议使用 listen 的 ssl 参数开启
ssl_protocols [SSLv2][SSLv3]
[TLSvl][TLSv1.1]
[TLSv1.2][TLSv1.3]
TLSv1
TLSv1.1
TLSv1.2
设置使用的 SSL 协议
ssl_buffer_size size 16k 设置用于发送数据的缓存大小
ssl_certificate file -- PEM 格式的网站证书文件,可自建或由 CA 机构颁发
ssl_certificate_key file -- PEM 格式的网站证书私钥文件,可自建或由 CA 机构颁发
ssl_password_file file -- 存放网站证书私钥密码的文件,一个密码一行,有多个密码时,Nginx 会依次尝试
ssl_ciphers ciphers HIGH:
!aNULL:
!MD5
设置 HTTPS 建立连接时用于协商使用的加密算法组合,也称密码套件,指令值内容为 openssl 的密码套件名称,多个套件名称间用“:”分隔
ssl_prefer_server_ciphers on 或 off off 是否启用在 SSLv3 和 TLSv1 协议的 HTTPS 连接时优先使用服务端设置的密码套件
ssl_dhparam file -- DH 密钥交换的 Diffie-Hellman 参数文件
ssl_ecdh_curve curve auto 配置 SSL 加密时使用椭圆曲线DH密钥交换的曲线参数,多个参数间使用“:”分隔。ecdh 是 Elliptic-Curve 和 Diffie-Hellman 的缩写,指令值为 auto 时,配置的曲线参数是 prime256v1
ssl_early_data on 或 off off 是否启用 TLS 1.3 0-RTT 支持
ssl_session_cache off 或 none 或
[builtin[:size]]
[shared:name:size]
none HTTPS 会话缓存设置,指令值参数见后面的介绍
ssl_session_tickets on 或 off on 是否启用会话凭证(Session Ticket)机制实现 HTTPS 会话缓存,当指令值为 off 时,使用会话编号(Session ID)机制
ssl_session_ticket_key file -- 指定会话凭证密钥文件,用于在多台 Nginx 间实现会话凭证共享,否则 Nginx 会随机生成一个会话凭证密钥
ssl_session_timeout time 5m 设置客户端可用会话缓存的超时时间
ssl_verify_client on 或 off 或 optional 或 optional_no_ca off 设置是否启用客户端证书验证功能。当指令值为 on 时启用验证;当指令值为 optional 时,如果接收到客户端证书则启用验证;当指令值为 optional_no_ca 时,若接收到客户端证书则启用客户端证书验证,但不进行证书链校验。将验证结果存储在 $ssl_client_verity 变量中
ssl_verify_depth number 1 设置客户端证书链验证深度
ssl_crl file -- 用于验证客户端证书有效性的证书吊销列表文件
ssl_client_certificate file -- 指定一个 PEM 格式的 CA 证书(根或中间证书)文件,该证书用作在线证书协议(OCSP)响应的证书验证或客户端证书验证,该证书列表会发送给客户端
ssl_trusted_certificate file -- 指定一个 PEM 格式的 CA 证书(根或中间证书)文件,该证书用作在线证书协议响应的证书验证或客户端证书验证,该证书列表不会发送给客户端
ssl_stapling on 或 off off 是否启用在线证书协议结果缓存
ssl_stapling_file file -- 在线证书协议结果缓存文件
ssl_stapling_responder url -- 设置获取在线证书协议结果的 URL,优先级低于 ssl_stapling_file,仅支持 HTTP 协议,默认端口为 80
ssl_stapling_verify on 或 off off 设置是否启用在线证书协议结果缓存证书验证

1) 上述指令都可编写在 http、server 指令域中。

2) ssl_ciphers 指令值的内容是 OpenSSL 参数 ciphers 的内容,可通过如下命令查看。

openssl ciphers                 # 列出OpenSSL支持的密码套件
openssl ciphers -v 'ALL:eNULL'  # 列出指定密码套件详情

3) 密码套件格式及说明可参见 OpenSSL 相关文档。

4) ssl_session_cache 指令值参数如下。
  • off:禁用 HTTPS 会话缓存;
  • none:启用伪会话缓存支持,Nginx 告知客户端可进行会话重用,但服务端并未存储会话参数;
  • builtin:使用内置 OpenSSL 缓存机制,无法在 Nginx 的多个工作进程中共享缓存内容;
  • shared:使用 Nginx 的共享缓存机制,会在 Nginx 的多个工作进程中共享缓存内容,1MB 内存可以存储 4000 个会话。

2、HTTPS 基本配置

HTTPS 协议数据的传输是基于 SSL 层加密的数据,其简单模型是服务端获得客户请求后,将用私钥加密的协商数据发送给客户端。客户端先使用服务端提供的公钥解密协商数据并读取真实的内容,再用公钥加密返回协商数据并发送给服务端,完成彼此间的密钥协商。密钥协商完毕后,服务端和客户端通过协商后的密钥进行通信数据的加解密传输。私钥只存放在服务端,公钥则由所有的客户端持有。

在实际使用过程中,为提高公钥的使用安全性、防止公钥被替换,使用第三方 CA 机构的证书实现对服务器身份的认证和网站公钥的安全传递。HTTPS 先通过非对称加密方式交换密钥,建立连接后再通过协商后的密钥与加密算法进行对称加密数据传输,如下图所示。

HTTPS 时序图
图:HTTPS 时序图

1) 服务端按照自身的域名等身份信息创建网站证书私钥和网站证书申请文件,网站管理员将证书申请文件提交给 CA 机构并获得网站证书,网站证书和网站证书私钥被部署到服务端。

2) 客户端发送包含协议版本号、客户端随机数(Client Random)、支持加密套件列表的请求给服务端。

3) 服务端获得客户端 HTTPS 请求后,将包含网站信息及网站证书公钥的证书、服务端随机数(Server Random)及随机选择的客户端支持加密套件返回给客户端,若需要验证客户端身份,也会在此时发送相关信息给客户端。

4) 客户端通过操作系统中的 CA 公钥解密证书获取网站证书公钥并进行网站证书的合法性、有效期和是否被吊销的验证。

5) 客户端用网站证书公钥将新生成的客户端随机数加密后发送给服务端,同时使用 3 个随机数生成会话密钥。

6) 服务端使用网站证书私钥解密客户端数据获取客户端随机数(Pre-master),使用 3 个随机数生成会话密钥。

7) 服务端与客户端使用一致的会话密钥和加密算法完成传输数据的加解密交互。

HTTPS 网站证书是由 CA 机构颁发的,网站管理员只需按照相关流程向 CA 机构提交请求文件即可,操作步骤如下。

1) 生成请求文件

生成请求文件的脚本如下:

## 创建无密码网站证书私钥文件的请求文件
openssl req -out /etc/nginx/conf/ssl/www_nginxbar_org.csr -new -sha256 -newkey rsa:2048 -nodes -keyout /etc/nginx/conf/ssl/www_nginxbar_org.key -subj "/C=CN/ST=Shanghai/L=Shanghai/O=nginxbar/OU=admin/CN=nginxbar.com/emailAddress=admin@nginxbar.com"

## 创建有密码私钥文件的请求文件
openssl genrsa -aes256 -passout pass:111111 -out /etc/nginx/conf/ssl/www_nginxbar_org.key 2048

openssl req -out /etc/nginx/conf/ssl/www_nginxbar_org.csr -new -sha256 -nodes -passin pass:111111 -key /etc/nginx/conf/ssl/www_nginxbar_org.key -subj "/C=CN/ST=Shanghai/L=Shanghai/O=nginxbar/OU=admin/CN=nginxbar.com/emailAddress=admin@nginxbar.com"

## 保存私钥密码
echo "111111" >>/etc/nginx/conf/ssl/www_nginxbar_org.pass

网站证书私钥文件是否需要密码由用户自行选择,只需选择一种方式执行即可。

2) 获取证书文件

将 www_nginxbar_org.csr 文件提交给 CA 机构后,即可获得 Nginx 支持的 PEM 格式证书文件。

CA 机构为方便进行证书管理,通常会以证书链的方式进行网站证书的颁发与验证,证书链通常由网站证书、中间证书与根证书组成。证书链的验证是由网站证书开始、自下而上进行信任验证传递的。根证书通常存放在客户端,吊销根证书的过程非常困难;中间证书只是增加了一个中间验证环节,可以减少 CA 机构对根证书的管理维护工作,吊销也相对简单。除了向 CA 机构申请证书外,也可以自签证书在内部使用,自签证书操作如下:

## 创建独立站点使用的自签证书
openssl req -new -x509 -nodes -out /etc/nginx/conf/ssl/www_nginxbar_org.pem -keyout /etc/nginx/conf/ssl/www_nginxbar_org.key -days 3650 -subj "/C=CN/ST=Shanghai/L=Shanghai/O=nginxbar/OU=admin/CN=nginxbar.com/emailAddress=admin@nginxbar.com"

## 创建独立站点使用有密码的网站证书私钥文件的自签证书
openssl genrsa -aes256 -passout pass:111111 -out /etc/nginx/conf/ssl/www_nginxbar_org.key 2048

openssl req -new -x509 -nodes -out /etc/nginx/conf/ssl/www_nginxbar_org.pem -passin pass:111111 -key /etc/nginx/conf/ssl/www_nginxbar_org.key -days 3650 -subj "/C=CN/ST=Shanghai/L=Shanghai/O=nginxbar/OU=admin/CN=nginxbar.com/emailAddress=admin@nginxbar.com"

## 保存私钥密码
echo "111111" >>/etc/nginx/conf/ssl/www_nginxbar_org.pass

## 创建自签客户端证书
openssl req -new -x509 -nodes -out /etc/nginx/conf/ssl/client.pem -keyout /etc/nginx/conf/ssl/client.key -days 3650 -subj "/C=CN/ST=Shanghai/L=Shanghai/O=nginxbar/OU=admin/CN=nginxbar.com/emailAddress=admin@nginxbar.com"

## 转换客户端证书为可被浏览器导入的pkcs12格式
openssl pkcs12 -export -clcerts -in /etc/nginx/conf/ssl/client.pem -inkey /etc/nginx/conf/ssl/client.key -out /etc/nginx/conf/ssl/client.p12

获得网站证书后,可以按照如下方式配置 HTTPS 站点。
server {
    listen 443 ssl;                                 # 启用HTTPS支持
    server_name www.nginxbar.org;
    charset utf-8;
    root /opt/nginx-web;
    index index.html index.htm;

    ssl_certificate ssl/www_nginxbar_org.pem;       # HTTPS网站证书
    ssl_certificate_key ssl/www_nginxbar_org.key;   # HTTPS网站证书私钥
    ssl_password_file ssl/www_nginxbar_org.pass;    # HTTPS网站证书私钥密码文件
}

3、HTTPS 密钥交换算法

在 HTTPS 建立连接进行密钥交换阶段,可以通过多种密钥交换算法实现密钥交换。基于 RSA 的密钥交换过程是客户端把第 3 个随机数发送给服务端,但在 HTTPS 建立连接阶段的传输仍是明文的,会存在安全问题。

DH(Diffie-Hellman)密钥交换算法可保证通信双方在明文传输的环境下安全地交换密钥。基于 DH 的密钥交换过程是在服务端产生服务端随机数后,将 DH 参数和密钥交换服务端公钥加密后传递给客户端,客户端根据 DH 参数和密钥交换服务端公钥计算出第 3 个随机数,并把自己产生的密钥更换为客户端公钥发送给服务端,服务端依据密钥交换客户端公钥计算出第 3 个随机数并完成后续的操作。

椭圆曲线的 DH(ECDH)密钥交换算法与 DH 交换算法相似,但使用了不同的数学模型。在使用椭圆曲线的 DH 密钥交换时,服务器会为密钥交换指定一条预先定义好参数的曲线,Nginx 的 ECDH 密钥交换默认配置的是 prime256v1 曲线算法。配置样例如下:
server {
    listen 443 ssl;
    server_name www.nginxbar.org;
    charset utf-8;
    root /opt/nginx-web;
    index index.html index.htm;

    ssl_certificate ssl/www_nginxbar_org.pem;
    ssl_certificate_key ssl/www_nginxbar_org.key;
    ssl_password_file ssl/www_nginxbar_org.pass;
    ssl_dhparam ssl/dhparam.pem;                    # DH参数文件
    ssl_ecdh_curve auto;                            # ECDH椭圆曲线算法为prime256v1
}
DH 参数文件可通过如下命令生成。

openssl dhparam -out /etc/nginx/conf/ssl/dhparam.pem 2048

基于 DH 的密钥交换算法也称前向加密(Forward Secrecy)或完全前向加密(Perfect Forward Secrecy),其应用场景是即便日后服务器的 SSL 私钥被第三方获得,后者也无法推算出会话密钥。

4、HTTPS 会话缓存

HTTPS 建立连接时传递证书及协商会话密钥会占用一定资源,为加快 HTTPS 建立连接的速度,提升性能,TLS 协议使用了会话缓存机制。会话缓存机制可以使已经断开连接的 HTTPS 会话重用之前的协商会话密钥继续 HTTPS 数据传输。会话缓存机制有两种实现方式:会话编号(Session ID)和会话凭证(Session Ticket)。

1) 会话编号

服务端在与客户端进行数据传输时,会为每次会话生成一个会话编号,并存储该会话编号与会话协商数据。HTTPS 会话中断需要重新连接时,客户端将最后一次会话的会话编号发送给服务端,服务端检查存储中该编号是否存在,如果存在就与客户端使用原有的会话密钥进行数据传输。配置样例如下:
server {
    listen 443 ssl;
    server_name www.nginxbar.org;
    charset utf-8;
    root /opt/nginx-web;
    index index.html index.htm;

    ssl_certificate ssl/www_nginxbar_org.pem;
    ssl_certificate_key ssl/www_nginxbar_org.key;
    ssl_password_file ssl/www_nginxbar_org.pass;

    ssl_session_cache shared:SSL:10m;               # HTTPS会话缓存存储大小为10MB
    ssl_session_tickets off;                        # 以会话编号机制实现会话缓存
    ssl_session_timeout 10m;                        # 会话缓存超时时间为10分钟
}
这里作以下两点说明。
  • 服务端会存储会话编号和会话协商数据,相对会消耗服务器资源;
  • 当 Nginx 服务器为多台时,无法实现会话共享。

2) 会话凭证

会话凭证类似于 cookie,它将协商的通信数据加密之后发送给客户端保存,服务端只保存密钥。HTTPS 建立连接后,服务端发送一个会话凭证给客户端,当需要重新连接时,客户端发送会话凭证与服务端恢复会话连接。配置样例如下:
server {
    listen 443 ssl;
    server_name www.nginxbar.org;
    charset utf-8;
    root /opt/nginx-web;
    index index.html index.htm;

    ssl_certificate ssl/www_nginxbar_org.pem;
    ssl_certificate_key ssl/www_nginxbar_org.key;
    ssl_password_file ssl/www_nginxbar_org.pass;

    ssl_session_cache shared:SSL:10m;               # HTTPS会话缓存存储大小为10MB
    ssl_session_tickets off;                        # 以会话凭证机制实现会话缓存
    ssl_session_timeout 10m;                        # 会话缓存超时时间为10分钟
    ssl_session_ticket_key ssl/session_ticket.key;  # 会话凭证密钥文件
}
ssl_session_ticket_key 可以实现多台 Nginx 间共用会话缓存,解决了会话缓存共享问题,可通过如下命令生成:

openssl rand 80 > /etc/nginx/conf/ssl/session_ticket.key

5、HTTPS 双向认证配置

通常网站的 HTTPS 访问,都是客户端通过证书验证所访问服务器的身份,而服务器对来访的客户端并不做身份验证,也称单向认证。在一些场景中,也会增加客户端身份验证以提高数据传输的安全性,这就是双向认证。配置样例如下:
server {
    listen 443 ssl;
    server_name www.nginxbar.org;
    charset utf-8;
    root /opt/nginx-web;
    index index.html index.htm;

    ssl_certificate ssl/www_nginxbar_org.pem;
    ssl_certificate_key ssl/www_nginxbar_org.key;
    ssl_password_file ssl/www_nginxbar_org.pass;

    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    ssl_session_ticket_key ssl/session_ticket.key;

    ssl_verify_client on;                          # 启用客户端证书认证
    ssl_client_certificate ssl/ca.pem;             # 客户端证书信任链的CA中间证书或根证书
}

6、HTTPS 吊销证书配置

HTTPS 的证书会因安全原因在正常有效期到期前进行证书变更,为了方便客户端或浏览器及时判断当前使用的网站证书是否已被吊销,通常会采用以下两种方式实现:证书吊销列表(CRL)和在线证书协议(OCSP)。

1) 证书吊销列表

证书吊销列表是由 CA 机构维护的列表,列表中包含已被吊销的证书序列号和时间,通常在 CA 机构证书中都会包含 CRL 下载地址。证书吊销列表 Nginx 配置如下:
server {
    listen 443 ssl;
    server_name www.nginxbar.org;
    charset utf-8;
    root /opt/nginx-web;
    index index.html index.htm;

    ssl_certificate ssl/www_nginxbar_org.pem;
    ssl_certificate_key ssl/www_nginxbar_org.key;
    ssl_password_file ssl/www_nginxbar_org.pass;

    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    ssl_session_ticket_key ssl/session_ticket.key;

    ssl_crl ssl/ca.crl;                          # 证书吊销列表文件
}
证书吊销列表可通过查看网站证书字段“CRL分发点”的字段值下载获得。

2) 在线证书协议

在线证书协议是一个吊销证书在线查询协议,虽然可以实现实时查询,但同时也会因在 HTTPS 建立连接时查询 OCSP 接口引发性能问题。为解决 OCSP 查询造成的性能影响,引入了 OCSP Stapling 机制,即由 HTTPS 服务器查询 OCSP 接口或本地 OCSP 缓存,并通过证书状态消息返回给客户端。

在线证书协议缓存 Nginx 配置如下:
resolver 114.114.114.114 valid=300s;             # DNS服务器地址
resolver_timeout 1s;                             # DNS解析超时时间为1s

server {
    listen 443 ssl;
    server_name www.nginxbar.org;
    charset utf-8;
    root /opt/nginx-web;
    index index.html index.htm;

    ssl_certificate ssl/www_nginxbar_org.pem;
    ssl_certificate_key ssl/www_nginxbar_org.key;
    ssl_password_file ssl/www_nginxbar_org.pass;

    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    ssl_session_ticket_key ssl/session_ticket.key;

    ssl_stapling on;                                 # 启用OCSP缓存
    ssl_stapling_file ssl/ocsp.pem;                  # OCSP结果缓存文件
    ssl_stapling_responder http://ocsp.example.com/; # 设置获取OCSP结果的URL
    ssl_stapling_verify on;                          # 设置OCSP结果缓存证书验证
    ssl_trusted_certificate ssl/ca.pem;              # 网站证书信任证书链的中间证书文件
}
注意,OCSP 结果缓存文件和获取 OCSP 结果的 URL 同时设置时,OCSP 结果缓存文件的优先级最高。

OCSP 响应结果可通过如下命令获得。

openssl ocsp -issuer /etc/nginx/conf/ssl/ca.pem -cert
/etc/nginx/conf/ssl/www_nginxbar_org.pem -no_nonce -text -url
http://ocsp.example.com -text -respout /etc/nginx/conf/ssl/ocsp.pem

7、HTTPS 配置样例

HTTPS 通过加密通道保护客户端与服务端之间的数据传输,极大地降低了数据被窃取、篡改的风险,增强了网站对数据安全的保护能力,已成为当前网站建设的必选配置。根据Nginx提供的配置指令,HTTPS 配置样例如下:
resolver 114.114.114.114 valid=300s;               # DNS服务器地址
resolver_timeout 5s;                               # DNS解析超时时间为5s

server {
    listen 443 ssl;
    server_name www.nginxbar.org;
    charset utf-8;
    root /opt/nginx-web;
    index index.html index.htm;

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;   # DNS服务器地址
    ssl_ciphers EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
    ssl_prefer_server_ciphers on;                  # 启用服务端密码组件优先
    ssl_dhparam  ssl/dhparam.pem;                  # 设置DH密钥交换算法参数
    ssl_ecdh_curve secp384r1;                      # DH密钥交换椭圆曲线算法为secp384r1

    ssl_certificate ssl/www_nginxbar_org.pem;      # 网站证书文件
    ssl_certificate_key ssl/www_nginxbar_org.key;  # 网站证书密钥文件
    ssl_password_file ssl/www_nginxbar_org.pass;   # 网站证书密钥密码文件

    ssl_session_cache shared:SSL:10m;              # 会话缓存存储大小为10MB
    ssl_session_timeout  10m;                      # 会话缓存超时时间为10分钟
    ssl_session_tickets on;                        # 设置会话凭证为会话缓存机制
    ssl_session_ticket_key  ssl/session_ticket.key;# 设置会话凭证密钥文件

    ssl_stapling on;                               # 启用OCSP缓存
    ssl_stapling_file ssl/ocsp.pem;                # OCSP结果缓存文件
    ssl_stapling_verify on;                        # 设置OCSP结果缓存证书验证
    ssl_trusted_certificate  ssl/ca.pem;           # 网站证书信任证书链的中间证书文件
   
    # 启用HSTS
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";

    add_header X-Frame-Options DENY;               # 禁止被嵌入框架
    add_header X-XSS-Protection "1; mode=block";   # XSS跨站防护
    add_header X-Content-Type-Options nosniff;     # 防止在浏览器中的MIME类型混淆攻击
}

server {
    listen      80;
    server_name www.nginxbar.org;
    rewrite ^(.*)$  https://$host$1? permanent;    # 强制HTTP访问跳转为HTTPS访问
}
可以通过网站 ssllabs.com 对 HTTPS 的配置进行安全性检测,并按照测试结果有针对性地进行优化。
 

Nginx FastCGI模块配置简述

Nginx 的 FastCGI 模块默认编译在 Nginx 的二进制文件中,无须单独编译。该模块配置指令如下表所示。

指令名称指令值格式默认值指令说明
fastcgi_bind address
[transparent]
或 off
-- 设置从指定的本地 IP 地址及端口号与 FastCGI 服务器建立连接,指令值可以是变量。当指令值参数为 transparent 时,允许将客户端的真实 IP 透传给 FastCGI 服务器,并以客户端真实 IP 为访问 FastCGI 服务器的源 IP,当指令值为 off 时,取消上一层指令域同名指令的配置
fastegi_buffering on 或 off on 设置是否启用响应数据缓冲区
fastcgi_buffers number size 8 4k 或 8k 设置单个连接从 FastCGI 服务器接收响应数据缓冲区的数量及单个缓冲区的大小,至少是两个
fastcgi_buffer_size size 4k 或 8k 设置用于读取 FastCGI 服务器响应数据第一部分的缓冲区大小,默认值根据操作系统平台的不同为 4KB 或 8KB
fastcgi_busy_buffers_size size 8k 或 16k 限制在响应数据未完全读取完毕时忙于向客户端发送响应的缓冲区的大小,以使其余的缓冲区用于读取响应数据。该值必须大于单个缓冲区或 fastcgi_buffer_size 的大小,小于总缓冲区大小减掉一个缓冲区的大小
fastcgi_limit_rate rate 0 限制从 FastCGI 服务器读取响应的每个请求的速率,单位是字节/秒,指令值为 0 表示不限制。该指令只在 fastcgi_buffer_ing 启用时有效
fastcgi_max_temp_file_size size 1024m 当响应数据超出响应数据缓冲区的大小时,超出部分的数据将存储于临时文件中。该指令用于设置临时文件的最大值。该指令值必须大于单个缓冲区或 fastcgi_buffer_size 的大小
fastegi_temp_file_write_size size 8k 或 16k 限制一次写入临时文件的数据大小。默认配置下,其大小通过 fastcgi-buffer-size 和 fastcgi-buffers 指令配置进行限制,最大值是 fastcgi_max_temp_file_size 指令的值,最小值必须大于单个缓冲区或 fastcgi_buffer_size 的大小
fastcgi_temp_path path[level1
[level2[level3]]]
fastcgi_temp 设置临时文件存储目录
fastcgi_request_buffering on 或 off on 设置是否在将请求转发给 FastCGI 服务器之前先从客户端读取整个请求体。当禁用该功能时,如果已经发送请求主体,则无法将请求传递到下一个服务器
fastcgi_store on、off 或 string off 设置是否将 FastCGI 的响应数据在本地持久存储。当指令值为 on 时,存储路径为 root 或 alias 的设置。该指令可以为不经常变更的 FastCGI 响应文件创建本地镜像。响应数据先存储到临时文件中,再进行复制或重命名存储
fastcgi_store_access users:permissions... user:rw 设置创建持久存储路径的文件夹权限
fastcgi_cache zone 或 off off 设置一个共享内存 zone 用作缓存
fastegi_cache_path path 参数 -- 设置缓存文件存储路径及参数。缓存数据以 URL 的 MD5 值命名并存储在缓存目录中。
fastcgi_cache_bypass string... -- 设置不使用缓存响应数据的条件,指令值中至少有一个值不为空或 0 时,当前请求不使用缓存中的响应数据
fastcgi_cache_key string -- 设置缓存的关键字
fastegi_cache_lock on 或 off off 是否启用缓存锁指令。向 FastCGI 发送请求时,每次只允许一个请求按照 fastcgi_cache_key 指令设置的标识增添新的缓存数据,其他相同的请求将等待缓存中出现响应数据或该缓存锁被释放,等待时间由 fastcgi_cache_lock_timeout 指令设置
fastcgi_cache_lock_age time 5s 如果一个请求在该指令设定的时间内没有完成响应数据缓存的添加,则再向 FastCGI 发送一次请求
fastcgi_cache_lock_timeout time 5s 缓存锁超时时间。超过该时间的请求将直接从 FastCGI 读取响应
fastcgi_cache_max_range_offset number -- 用于设置范围请求(byte-range)请求时的最大偏移量。超出该偏移量的请求将直接从 FastCGI 读取响应
fastcgi_cache_methods GET、HEAD 或 POST ... GET HEAD 指定可被缓存的请求方法列表
fastcgi_cache_min_uses number 1 响应数据超过设置请求次数后将被缓存
fastcgi_no_cache string... -- 指定字符串的值不为空或不等于 0,则不对当前请求的响应数据进行缓存
fastcgi_cache_purge string... -- 定义清除缓存请求条件,若指定的字符串不为空或 0,则将 fastcgi_cache_key 设置的标识的缓存清除。清除成功则返回状态码 204,商业版有效
fastcgi_cache_revalidate on 或 off off 设置在 HTTP 头中有字段属性 If-Modified-Since 和 If-None-Match 时是否启用重新验证
fastcgi_cache_use_stale error、timeout、
invalid_header、
updating、http_500、
http_503、http_403、
http_404、http_429、
off...
off 当出现指定的条件时,使用已经过期的缓存响应数据
fastcgi_cache_background_update on 或 off off 当允许使用过期的响应数据时,设置是否启用后台子请求更新过期缓存,同时向客户端返回过期的缓存响应数据
fastcgi_cache_valid [code...]time -- 根据响应码设置缓存时间
fastcgi_catch_stderr string -- 错误响应标识。若 FastCGI 响应中包含指定的字符串,则被判断为返回了无效响应
fastcgi_index name -- 设置默认 index 文件
fastcgi_pass address -- 设置 FastCGI 服务器的 IP 地址或套接字,也可以是域名或 upstream 定义的服务器组
fastcgi_pass_request_body on 或 off on 设置是否将客户端请求体传递给 FastCGI 服务器
fastcgi_pass_request_headers on 或 off on 设置是否将客户端请求头传递给 FastCGI 服务器
fastcgi_force_ranges on 或 off off 无论 FastCGI 的 HTTP 响应头中是否有字段 Accept-Ranges,都启用 byte-range 请求支持
fastcgi_hide_header field -- 指定 FastCGI 响应数据中不向客户端传递的 HTTP 头字段名称
fastcgi_pass_header field -- 默认配置下,Nginx 不会将头字段属性 Status 和 X-Accel-... 传递给客户端,可通过该指令开放传递
fastcgi_ignore_headers field... -- 设置禁止 Nginx 处理从 FastCGI 获取响应的头字段
fastcgi_connect_timeout time 60s Nginx 与 FastCGI 服务器建立连接的超时时间,通常不超过 75s
fastcgi_keep_conn on 或 off off 默认配置下,FastCGI 发送完响应数据后会立刻关闭连接,当该指令的指令值为 on 时,将启用保持连接
fastcgi_ignore_client_abort on 或 off off 设置当客户端关闭连接时,是否关闭与 FastCGI 服务器的连接
fastcgi_read_timeout time 60s 在连续两个从 FastCGI 服务器接收数据的读操作之间的间隔时间超过设定的时间时,将关闭连接
fastcgi_send_timeout time 60s 在连续两个发送到 FastCGI 服务器的写操作之间的间隔时间超过设定的时间时,将关闭连接
fastcgi_send_lowat size 0 设置 FreeBSD 系统中使用 kqueue 驱动时,socket 接口 SO_SNDLOWAT 选项的大小。在 Linux、Solaris 及 Windows 台该指令无效
fastcgi_socket_keepalive on 或 off off 设置是否对 FastCGI 的连接启用 so-keepalive socket 选项
fastcgi_intercept_errors on 或 off off 在 FastCGI 响应数据中响应码大于或等于 300 时,设置是直接传递给客户端还是重定向给 Nginx,以便 error_page 指令进行处理
fastcgi_next_upstream error、timeout、
invalid、header、
http_500、http_503、
http_403、http_404、
http_429、non_idempotent、off...
error timeout 当出现指定的条件时,将未返回响应的客户端请求传递给 upstream 中的下一个服务器
fastcgi_next_upstream_timeout time 0 设置将符合条件的请求传递给 upstream 中下一个服务器的超时时间。当指令值为 0 时,关闭该限制
fastcgi_next_upstream_tries number 0 设置将符合条件的请求传递给 upstream 中下一个服务器的尝试次数。当指令值为 0 时,关闭该限制
fastcgi_split_path_info regex -- 定义一个正则表达式,可以将 URI 正则匹配赋值到 $fastcgi_script_name 及 $fastcgi_path_info 两个变量中,可用于获取 index.php/arg1/111/arg2/222 格式的请求参数
fastegi_param parameter value[if_not_empty] -- 设置发送请求到 FastCGI 时传递的请求参数。指令值为 if_not_empty 时,表示当传递的参数值不为空时才进行传递

对于上表,有以下几点说明。
  • 除 fastcgi_cache_path 指令外,FastCGI 模块指令均可编写在 http、server、location 指令域中。
  • fastcgi_cache_purge 指令仅商业版 Nginx 才支持。开源版可通过第三方模块或自己写脚本实现。
  • fastcgi_cache_path 指令只能编写在 http 指令域中。
  • fastcgi_cache 与 fastcgi_store 指令不能在同一指令域中同时使用。
  • non_idempotent 是指 POST、LOCK、PATCH 请求方法的处理。

fastcgi_cache_path 指令值参数如下表所示。

参数名参数格式默认值参数说明
levels levels -- 设置缓存目录的层级及命名方式
use_temp_path on 或 off on 当指令值为 on 时,使用 fastcgi_temp_path 设置作为临时文件目录;当指令值为 off 时,使用缓存目录作为临时文件目录
keys_zone name:size -- 设置存储 cache_key 的共享内存 zone 及其大小,1MB 内存可以存储 8000 个 key
inactive time 10 分钟 设定时间内未被访问的缓存将被删除
max_size size -- 缓存数据的最大值,超出设定的最大值时,将执行一次迭代更新,并删除最近使用最少的缓存数据
manager_files number 100 当执行一次迭代更新时,删除文件的最大数
manager_sleep time 50ms 连续两次迭代更新间的最短时间间隔
manager_threshold time 200ms 执行一次迭代更新时的最大执行时间
loader_files number 100 每次迭代加载时,加载缓存目录中缓存数据的最大文件数
loader_sleep time 50ms 连续两次迭代加载间的最短时间间隔
loader_threshold time 200ms 每次迭代加载时的最大执行时间
purger on 或 off off 是否启用缓存清除功能。仅商业版有效
purger_files number 10 每次迭代清除时,清除缓存目录中缓存数据的最大文件数。仅商业版有效
purger_sleep time 50ms 连续两次迭代清除间的最短时间间隔。仅商业版有效
purger_threshold time 50ms 每次迭代清除时的最大执行时间。仅商业版有效

Nginx基于FastCGI实现负载均衡

Nginx 支持后端多个 FastCGI 服务器的负载均衡,负载均衡有两种方式:一种是通过域名解析多个 FastCGI 服务器,该方式通过所有域名地址轮询(round-robin)的方式实现负载;另一种是通过配置 Nginx 的 upstream 模块实现负载。

本节通过后一种方式实现负载均衡场景的搭建。Nginx 的 FastCGI 模块支持对后端 PHP 解析数据的缓存,对于动态数据的缓存可以在实际应用场景中提升动态网站的访问速度。

安装 PHP-FPM 后,如果把 PHP 代码部署在与 Nginx 不同的服务器上,需要修改 PHP-FPM 服务器中的 /etc/php-fpm.d/www.conf 配置。

    # PHP-FPM绑定本机所有IP
sed -i "s/^listen =.*/listen = 0.0.0.0:9000/g" /etc/php-fpm.d/www.conf    
    # 允许任何主机访问PHP-FPM服务
sed -i "s/^listen.allowed_clients/;listen.allowed_clients/g" /etc/php-fpm.d/www.conf

Nginx 配置样例如下:
upstream fscgi_server {
    ip_hash;                               # session会话保持
    server 192.168.2.145:9000;             # PHP-FPM服务器IP
    server 192.168.2.159:9000;             # PHP-FPM服务器IP
}

fastcgi_cache_path /usr/local/nginx/nginx-cache1
                            levels=1:2
                            keys_zone=fscgi_hdd1:100m
                            max_size=10g
                            use_temp_path=off
                            inactive=60m;    # 设置缓存存储路径1,缓存的共享内存名称和大小
                                             # 100MB,无效缓存的判断时间为1小时

fastcgi_cache_path /usr/local/nginx/nginx-cache2
                            levels=1:2
                            keys_zone=fscgi_hdd2:100m
                            max_size=10g
                            use_temp_path=off
                            inactive=60m;   # 设置缓存存储路径2,缓存的共享内存名称和大小
                                            # 100MB,无效缓存的判断时间为1小时

split_clients $request_uri $fscgi_cache {
              50%           "fscgi_hdd1";  # 50%请求的缓存存储在第一个磁盘上
              50%           "fscgi_hdd2";  # 50%请求的缓存存储在第二个磁盘上
}

server {
    listen 8080;
    root /opt/nginx-web/phpweb;
    index index.php;
    include        fscgi.conf;             # 引入默认配置文件
   
    location ~ \.(gif|jpg|png|htm|html|css|js|flv|ico|swf)(.*) {  # 静态资源文件过期时间
                                                                  # 为12小时
        expires      12h;
    }

    set $no_cache 0;
    if ($query_string != "") {              # URI无参数的数据不进行缓存
        set $no_cache 1;
    }

    location ~ \.php(.*)$ {
        root /opt/nginx-web/phpweb;

        fastcgi_cache $fscgi_cache;        # 启用fastcgi_cache_path设置的$fscgi_cache
                                           # 的共享内存区域做缓存
        fastcgi_cache_key ${request_method}://$host$request_uri; # 设置缓存的关键字
        fastcgi_cache_lock on;             # 启用缓存锁
        fastcgi_cache_lock_age 5s;         # 启用缓存锁时,添加缓存请求的处理时间为5s
        fastcgi_cache_lock_timeout 5s;     # 等待缓存锁超时时间为5s
        fastcgi_cache_methods GET HEAD;    # 默认对GET及HEAD方法的请求进行缓存
        fastcgi_cache_min_uses 1;          # 响应数据被请求一次就将被缓存

        fastcgi_no_cache $no_cache;        # $no_cache时对当前请求不进行缓存
        fastcgi_cache_bypass $no_cache;    # $no_cache时对当前请求不进行缓存

        fastcgi_cache_use_stale error timeout invalid_header
                                updating http_500 http_503
                                http_403 http_404 http_429;        # 当出现指定的条件时,使用
                                                                   # 已经过期的缓存响应数据
        fastcgi_cache_background_update on; # 允许使用过期的响应数据时,启用后台子请求用于
                                            # 更新过期缓存,并将过期的缓存响应数据返回给客户端

        fastcgi_cache_revalidate on;       # 当缓存过期时,向后端服务器发起包含If-
                                           # Modified-Since和If-None-Match HTTP消息
                                           # 头字段的服务端校验
        fastcgi_cache_valid 200 301 302 10h; # 200 301 302状态码的响应缓存10小时
        fastcgi_cache_valid any 1m;        # 其他状态码的响应缓存1分钟

        add_header X-Cache-Status $upstream_cache_status;   # 查看缓存命中状态

        fastcgi_pass   fscgi_server;
        fastcgi_index  index.php;
        fastcgi_split_path_info       ^(.+\.php)(.*)$;      # 获取$fastcgi_path_info变量值
        fastcgi_param PATH_INFO       $fastcgi_path_info;   # 赋值给参数PATH_INFO
        include        fastcgi.conf;                        # 引入默认参数文件
    }

    error_page 404 /404.html;
    error_page 500 502 503 504 /50x.html;
}

Nginx CGI、FastCGI、SCGI、WSGI网关接口简介

我们将服务端程序分为了 web 服务器和应用程序服务器两个部分。web 服务器是用于处理 HTML 文件,让客户可以通过浏览器进行访问。主流的有 Apache、IIS、Nginx、Lghttpd 等。而应用服务器处理业务逻辑,比如使用 python 的 django,flask 写成的程序。

通常来自客户端浏览器的请求被 web 服务器截获,如果是静态请求,则如 nginx 会自己做处理,如果是动态请求,则会抛给后端应用服务器来处理。于是如何在 web 服务器与应用服务器之间进行通信成了主要问题,这就引出了以下四种处理的接口:CGI、FastCGI、SCGI、WSGI。

1、CGI(Common Gateway Interface,通用网关接口)

CGI 是一种通用网关接口规范,该规范详细描述了 Web 服务器和请求处理程序(脚本解析器)在获取及返回数据过程中传输数据的标准,如 HTTP 协议的参数名称等。大多数 Web 程序以脚本形式接收并处理请求,然后返回响应数据,如脚本程序 PHP、JSP、Python 等。

2、FastCGI(Fast Common Gateway Interface,快速通用网关接口)

FastCGI 是 CGI 的增强版本,其将请求处理程序独立于 Web 服务器之外,并通过减少系统为创建进程而产生的系统开销,使 Web 服务器可以处理更多的 Web 请求。FastCGI 与 CGI 的区别在于,FastCGI 不像 CGI 那样对 Web 服务器的每个请求均建立一个进程进行请求处理,而是由 FastCGI 服务进程接收 Web 服务器的请求后,由自己的进程自行创建线程完成请求处理。

3、SCGI(Simple Common Gateway Interface,简单通用网关接口)

SCGI 是 CGI 的替代版本,它与 FastCGI 类似,同样是将请求处理程序独立于 Web 服务器之外,但更容易实现,性能比 FastCGI 要弱一些。

4、WSGI(Web Server Gateway Interface,Web 服务网关接口)

WSGI 是为 Python 语言中定义的 Web 服务器与 Python 应用程序或框架间的通用通信接口,可以使 Python 应用程序或框架与支持这一协议的不同Web服务器进行通信。常见的 Python Web 框架都实现了该协议的封装。

Nginx uWSGI模块配置简述

uWSGI 是 Python 实现 WSGI、uWSGI(uWSGI 独有的协议)、HTTP 等协议功能的 Web 服务器,Nginx 通过 ngx_http_uwsgi_module 模块实现与 uWSGI 服务器的数据交换并完成 Python 网站的请求处理。该模块默认编译在 Nginx 二进制文件中,无须单独编译。该模块的配置指令如下表所示。

指令名称指令值格式默认值指令说明
uwsgi_bind address [transparent] 或 off -- 设置从指定的本地 IP 地址及端口号与 uWSGI 服务器建立连接,指令值可以是变量。当指令值为 transparent 时,允许将客户端的真实 IP 透传给 uWSGI 服务器,并以客户端真实IP为访问 uWSGI 服务器的源 IP;当指令值为 off 时,则取消上一层指令域同名指令的配置
uwsgi_buffering on 或 off on 设置是否启用响应数据缓冲区
uwsgi_buffers number size 8 4k 或 8k 设置单个连接从 uWSGI 服务器接收响应数据缓冲区的数量及单个缓冲区的大小。至少是两个
uwsgi_buffer_size size 4k 或 8k 设置用于读取 uWSGI 服务器响应数据第一部分的缓冲区大小,默认值根据操作系统平台的不同为 4KB 或 8KB
uwsgi_busy_buffers_size size 8k 或 16k 限制在响应数据未完全读取完毕时忙于向客户端发送响应的缓冲区的大小,以使其余的缓冲区用于读取响应数据。该值必须大于单个缓冲区或 uwsgi_buffer_size 的大小,小于总缓冲区大小减掉一个缓冲区的大小
uwsgi_limit_rate rate 0 限制从 uWSGI 服务器读取响应的每个请求的速率,单位是字节/秒,指令值为 0 表示不限制。该指令只在 uwsgi_buffering 启用时有效
uwsgi_max_temp_file_size size 1024m 当响应数据超出响应数据缓冲区的大小时,超出部分的数据将存储于临时文件中。该指令设置临时文件的最大值。该值必须大于单个缓冲区或 uwsgi_buffer_size 的大小
uwsgi_temp_file_write_size size 8k 或 16k 限制一次写入临时文件的数据大小。默认配置下,大小通过 uwsgi-buffer-size 和 uwsgi-buffers 配置指令进行限制,最大值是 uwsgi_max_temp_filesize 指令的值,最小值必须大于单个缓冲区或 uwsgi_buffer_size 的大小
uwsgi_temp_path path[level1 [level2 [level3]]] uwsgi_temp 设置临时文件存储目录
uwsgi_request_buffering on 或 off on 设置是否在将请求转发给 uWSGI 服务器之前先从客户端读取整个请求体。若禁用该功能,如果已经发送请求主体,则无法将请求传递到下一个服务器。对于基于 HTTP/1.1 协议的分块传输请求,会强制读取完整请求体
uwsgi_store on 或 off 或 string off 设置是否将 uWSGI 服务器的响应数据在本地持久存储。当指令值为 on 时,存储路径为 root 或 alias 的设置。该指令可以为不经常变更的 uWSGI 服务器响应文件创建本地镜像。响应数据先存储到临时文件中再进行复制或重命名存储
uwsgi_store_access users:permissions... user:rw 设置创建持久存储路径的文件夹权限
uwsgi_cache zone 或 off off 设置一个共享内存 zone 用作缓存
uwsgi_cache_path path 参数 -- 设置缓存文件存储路径及参数。缓存数据以 URI 的 MD5 值命名并存储在缓存目录中
uwsgi_cache_bypass string... -- 设置不使用缓存响应数据的条件,指令值中至少一个值不为空或 0 时,则当前请求不使用缓存中的响应数据
uwsgi_cache_key string -- 设置缓存的关键字
uwsgi_cache_lock on 或 off off 是否启用缓存锁指令。向 uWSGI 服务器发送请求时,每次只允许一个请求按照 uwsgi_cache_key 指令设置的标识增添新的缓存数据,其他相同的请求将等待缓存中出现响应数据或该缓存锁被释放,等待时间通过 uwsgi_cache_lock_timeout 指令设置
uwsgi_cache_lock_age time 5s 如果一个请求在该指令设定的时间内没有完成响应数据缓存的添加,则向 uWSGI 服务器再发送一次请求
uwsgi_cache_lock_timeout time 5s 缓存锁超时时间。超过该时间的请求将直接从 uWSGI 服务器读取响应
uwsgi_cache_max_range_offset number -- 用于设置范围请求请求时的最大偏移量。超出该偏移量的请求将直接从 uWSGI 服务器读取响应
uwsgi_cache_methods GET、HEAD 或 POST... GET HEAD 指定可被缓存的请求方法列表
uwsgi_cache_min_uses number 1 响应数据超过设置请求次数后将被缓存
uwsgi_no_cache string... -- 指定字符串的值不为空或不等于 0,则不对当前请求的响应数据进行缓存
uwsgi_cache_purge string -- 定义清除缓存请求条件,若指定的字符串不为空或 0,则对 uwsgi_cache_key 设置的标识的缓存进行清除。清除成功则返回状态码 204。仅商业版有效
uwsgi_cache_revalidate on 或 off off 设置在 HTTP 头中有字段属性 If-Modified-Since 和 If-None-Match 时是否启用重新验证
uwsgi_cache_ use_stale error、timeout、 
invalid_header、
updating、http_500、
http_503、http_403、
http_404、http_429、
off ...
off 当出现指定的条件时,使用已经过期的缓存响应数据
uwsgi_cache_background_update on 或 off off 允许使用过期的响应数据时,设置是否启用后台子请求更新过期缓存,同时向客户端返回过期的缓存响应数据
uwsgi_cache_valid [code …] time -- 根据响应码设置缓存时间
uwsgi_pass address -- 设置 uWSGI 服务器的协议、IP 地址或套接字,也可以是域名或 upstream 定义的服务器组。支持的协议有 HTTP、uWSGI、suwsgi(基于 SSL 的 uWSGI)
uwsgi_pass_request_body on 或 off on 设置是否将客户端请求体传递给 uWSGI 服务器
uwsgi_pass_request_headers on 或 off on 设置是否将客户端请求头传递给 uWSGI 服务器
uwsgi_force_ranges on 或 off off 无论 uWSGI 服务器的 HTTP 响应头中是否有字段 Accept-Ranges,都启用 byte-range 请求支持
uwsgi_hide_header field -- 指定 uWSGI 服务器响应数据中不向客户端传递的 HTTP 头字段名称
uwsgi_pass_header field -- 默认配置下,Nginx 不会将头字段属性 Status 和 X-Accel-... 传递给客户端,可通过该指令开放传递
uwsgi_ignore_headers field … -- 设置禁止 Nginx 处理从 uWSGI 服务器获取响应的头字段
uwsgi_modifier1 number 0 设置 uWSGI 数据包头中 modifier1 字段的值
uwsgi_modifier2 number 0 设置 uWSGI 数据包头中 modified2 字段的值
uwsgi_connect_timeout time 60s Nginx 与 uWSGI 服务器建立连接的超时时间,通常不超过 75s
uwsgi_ignore_client_abort on 或 off off 当客户端关闭连接时,是否关闭与 uWSGI 服务器的连接
uwsgi_read_timeout time 60s 在连续两个从 uWSGI 服务器接收数据的读操作之间的间隔时间超过设定的时间时,将关闭连接
uwsgi_send_timeout time 60s 在连续两个发送到 uWSGI 服务器的写操作之间的间隔时间超过设定的时间时,将关闭连接
uwsgi_socket_keepalive on 或 off off 设置是否对 uWSGI 服务器的连接启用 so-kccpalive socket 选项
uwsgi_intercept_errors on 或 off off 在 uWSGI 服务器响应数据中响应码大于或等于 300 时,设置是直接传递给客户端还是重定向给 Nginx,以便 error_page 指令进行处理
uwsgi_next_ upstream error、timeout、
invalid_header、
http_500、http_503、
http_403、http_404、
http_429、
non_idempotent、
off ...
error timeout 当出现指定条件时,将未返回响应的客户端请求传递给 upstream 中的下一个服务器
uwsgi_next_upstream_timeout time 0 设置将符合条件的请求传递给 upstream 中的下一个服务器的超时时间。指令值为 0 时关闭该限制
uwsgi_next_upstream_tries number 0 设置将符合条件的请求传递给 upstream 中的下一个服务器的尝试次数。指令值为 0 时关闭该限制
uwsgi_param parameter value
[if_not_empty]
-- 设置发送请求到 uWSGI 服务器时传递的请求参数。指令值为 if_not_empty 时,表示传递的参数值不为空时才进行传递
uwsgi_ssl_certificate file -- 指定用于安全 uWSGI 服务器 SSL 身份认证的 PEM 格式服务器证书文件
uwsgi_ssl_certificate_key file -- 指定用于安全 uWSGI 服务器 SSL 身份认证的 PEM 格式服务器证书密钥文件
uwsgi_ssl_password_file file -- 指定一个包含服务器证书密钥密码的文件。文件中每行一个密码,Nginx 将遍历整个文件并尝试有效的密码
uwsgi_ssl_ciphers ciphers DEFAULT 指定用于安全 uWSGI 服务器 SSL 请求的 OpenSSL 格式密码套件
uwsgi_ssl_crl file -- 指定用于验证安全 uWSGI 服务器 SSL 证书的 PEM 格式吊销证书文件
uwsgi_ssl_trusted_certificate file -- 指定用于验证安全 uWSGI 服务器 SSL 证书的 PEM 格式 CA 证书文件
uwsgi_ssl_name name uwsgi_pass 指 令指定的主机 允许指定并覆盖安全uWSGI服务器SSL证书验证的 主机名,将通过SNI向建立连接的SSL安全uWSGI服 务器进行传递
uwsgi_ssl_protocols [SSLv2] [SSLv3]
[TLSv1] [TLSv1.1]
[TLSv1.2]
[TLSv1.3]
TLSv1
TLSv1.1
TLSv1.2
指定安全 uWSGI 服务器 SSL 协议的版本
uwsgi_ssl_server_name on 或 off off 启用通过 SNI 或 RFC 6066 向建立连接的 SSL 安全 uWSGI 服务器传递主机名
uwsgi_ssl_session_reuse on 或 off off 启用 SSL 会话重用功能
uwsgi_ssl_verify on 或 off off 启用安全 uWSGI 服务器的证书验证功能
uwsgi_ssl_verify_depth number 1 设置安全 uWSGI 服务器的证书链的验证深度

关于上表,有以下几点需要说明:
  • 除 uwsgi_cache_path 指令外,uWSGI 模块指令均可编写在 http、server、location 指令域中;
  • uwsgi_cache_path 指令只能编写在 http 指令域中;
  • uwsgi_cache 与 uwsgi_store 指令不可在同一指令域中同时使用;
  • non_idempotent 是指 POST、LOCK、PATCH 请求方法的处理。

uwsgi_cache_path 指令值参数如下表所示。

参数名参数格式默认值参数说明
levels levels -- 设置缓存目录的层级及命名方式
use_temp_path on 或 off on 当指令值为 on 时,使用 uwsgi_temp_path 设置作为临时文件目录;当指令值为 off 时,使用缓存目录作为临时文件目录
keys_zone name:size -- 设置存储 cache_key 的共享内存 zone 及其大小,1MB 内存可以存储 8000 个 key
inactive time 10m 设定时间内未被访问的缓存将被删除
max_size size -- 缓存数据的最大值,超出设定的最大值时将执行一次迭代更新,并删除最近使用最少的缓存数据
manager_files number 100 执行一次迭代更新时删除文件的最大数
manager_sleep time 50ms 连续两次迭代更新间的最短时间间隔
manager_threshold time 200ms 执行一次迭代更新时的最大执行时间
loader_files number 100 每次迭代加载时,加载缓存目录中缓存数据的最大文件数
loader_sleep time 50ms 连续两次迭代加载间的最短时间间隔
loader_threshold time 200ms 每次迭代加载时的最大执行时间
purger on 或 off off 是否启用缓存清除功能。仅商业版有效
purger_files number 10 每次迭代清除时,清除缓存目录中缓存数据的最大文件数。仅商业版有效
purger_sleep time 50ms 连续两次迭代清除间的最短时间间隔。仅商业版有效
purger_threshold time 50ms 每次迭代清除时的最大执行时间。仅商业版有效

Nginx Python(Django)项目部署

CentOS 7 系统默认安装 Python 2.7 版本,本节搭建的是基于 Python3 的 Django 网站,所以需要升级到 Python3 版本。

1、安装 Python 及 Django

配置样例如下:
yum install -y epel-release              # 安装EPEL扩展源
yum install -y python36 python36-pip python36-devel \
                sqlite-devel supervisor  # 安装Python3.6及其工具组件
ln -s /usr/bin/pip3 /usr/bin/pip         # 设置pip3为默认pip
pip install --upgrade pip                # 升级pip版本
echo "alias python='/usr/bin/python3.6'" >/etc/profile.d/python.sh
                                                # 添加Python 3.6为系统执行的默认Python
echo "alias pip='/usr/local/bin/pip'" >>/etc/profile.d/python.sh
                                                # 添加pip为系统执行的默认pip
source /etc/profile                      # 使系统配置生效
pip install django==2.0 uwsgi -i https://pypi.tuna.tsinghua.edu.cn/simple
                                                # 安装Django和uWSGI

2、创建测试 Django 项目 demonginx 及项目应用 Nginx

配置样例如下:
cd /opt/nginx-web/pythonweb
django-admin.py startproject demonginx
cd demonginx
sed -i "s/ALLOWED_HOSTS = \[.*/ALLOWED_HOSTS = \['\*', \]/g" demonginx/settings.py

# 创建项目应用Nginx及测试页面
django-admin.py startapp nginx

cat >>nginx/views.py<<EOF
from django.http import HttpResponse
def index(request):
    return HttpResponse("<h1>Hello Nginx for Django!</h1>")
EOF

sed -i "/\]/i\    path('',nginx_views.index,name=\"index\")," demonginx/urls.py

3、创建默认 admin 管理后台账号

配置样例如下:

python manage.py migrate
python manage.py createsuperuser --username admin --email admin@example.com

启动测试Django项目测试Python网站的有效性,测试成功后关闭该进程。

python manage.py runserver 0.0.0.0:9080

4、配置 uWSGI 服务器

配置样例如下:
cat>/opt/nginx-web/pythonweb/demonginx/nginx_uwsgi.ini<<EOF
[uwsgi]
socket = :9080
chdir        = /opt/nginx-web/pythonweb/demonginx  # 设置Python文件目录
module       = demonginx.wsgi                   # demonginx项目的wsgi.py位置
master       = true                             # 主进程模式
processes    = 2                                # 开启两个工作进程
vacuum       = true                             # 退出时自动删除UNIX socket和PID文件
max-requests = 1000                             # 每个工作进程设置请求数为1000
limit-as     = 512                              # 每个uWSGI工作进程的虚拟内存为512MB
buffer-size  = 32768                            # uWSGI接收数据包的缓存区大小为32KB
pidfile = /var/run/uwsgi9080.pid                # 进程pid文件
daemonize = /opt/nginx-web/pythonweb/demonginx/uwsgi9080.log   
    # 使进程在后台运行,并输出日志到uwsgi9080.log
EOF

5、配置 uWSGI 服务器守护进程 supervisord

配置样例如下:
## 启用supervisord Web管理
sed -i "s/^;\[inet_http/\[inet_http/g" /etc/supervisord.conf
sed -i "s/^;port/port/g" /etc/supervisord.conf

## 设置supervisord
cat>/etc/supervisord.d/demonginx.ini<<EOF
# 配置进程运行命令
[program:demonginx]
command=/usr/local/bin/uwsgi --ini /opt/nginx-web/pythonweb/demonginx/nginx_uwsgi.ini
directory=/opt/nginx-web/pythonweb/demonginx  # 进程运行目录
startsecs=5                           # 启动5秒后没有异常则退出表示进程正常启动,默认为1秒
autostart=true                        # 在supervisord启动的时候也自动启动
autorestart=true                      # 程序退出后自动重启
EOF

# 启动demonginx的uWSGI服务
systemctl restart supervisord

6、Nginx 配置

Nginx 配置样例如下:
## Python网站配置
server {
    listen         8083; 
    server_name    localhost
    charset UTF-8;

    client_max_body_size 75M;

    location / {
        include uwsgi_params;         # 引入uWSGI默认参数配置
        uwsgi_pass 127.0.0.1:9080;    # uWSGI服务端口
        uwsgi_read_timeout 2;
    }
}

## supervisord Web管理配置
server {
    listen         9083;
    server_name    localhost
    charset UTF-8;

    location / {
        allow 192.168.2.0/24;
        deny all;
        proxy_pass 127.0.0.1:9001;    # supervisord服务端口
    }
}

7、启动 Nginx 服务

配置样例如下:
# 测试Nginx配置
nginx -t

# 重启Nginx服务
systemctl restart nginx

Nginx伪流媒体服务器搭建

Nginx 支持伪流媒体播放功能,其可以和客户端的 Flash 播放器结合,对以 .flv、.f4f、.mp4、.m4v、.m4a 为扩展名的文件实现流媒体的播放功能。若启用伪流媒体的支持功能,需要按媒体文件格式在配置编译时增加 --with-http_f4f_module、--with-http_flv_module 和 --with-http_mp4_module 这 3 个参数。

1、模块配置指令

伪流媒体模块配置指令如下表所示。

指令名称指令值格式默认值指令说明
f4f -- -- 启用 F4F 文件支持
f4f_buffer_size size 512k 设置读取 .f4x 索引文件的缓冲区大小
flv -- -- 启用 FLV 文件支持
mp4 -- -- 启用 MP4 文件支持
mp4_buffer_size size 512k 设置处理 MP4 文件的缓冲区大小
mp4_max_buffer_size size 512k Metadata 数据处理过程中的最大缓冲区大小
mp4_limit_rate on 或 off 或 facto off 限制客户单媒体流请求的最大速率。仅在 Nginx 商业版本中提供
mp4_limit_rate_after time 60s 客户单媒体流请求的速率达到指定值时开始限速。仅在 Nginx 商业版本中提供

F4F 格式仅在 Nginx 商业版本中提供。

2、伪流媒体配置样例

伪流媒体配置样例是利用 Nginx 的自动索引功能生成 XML 格式的目录列表,通过 XSLT 生成前端页面,使用 jQuery 插件 video.js 的 Flash 播放器播放 FLV 及 MP4 格式的流媒体文件。页面效果如下图所示。

Nginx 配置样例如下:
server {
    listen 8081;
    server_name localhost;
    charset utf-8;
    root /opt/nginx-web/files;
    default_type text/xml;

    location / {
       autoindex on;                                    # 启用自动页面功能
       autoindex_localtime on;                          # 使用Nginx服务器时间
       autoindex_format xml;                            # 自动页面输出格式为XML
       xslt_stylesheet conf/conf.d/example/test.xslt;   # 引入XSLT模板文件
    }

    location ~ \.flv$ {
        flv;                                            # FLV文件启用伪流媒体支持
    }
    location ~ \.mp4$ {
        mp4;                                            # MP4文件启用伪流媒体支持
        mp4_buffer_size       1m;                       # MP4文件的缓冲区大小为1MB
        mp4_max_buffer_size   5m;                       # MP4文件最大缓冲区大小为5MB
    }
}

Nginx HTTP2模块配置简述

HTTP/2 是 HTTP 协议的 2.0 版本,该协议通过多路复用、请求优化、HTTP 头压缩等功能提升网络传输速度、优化用户体验。HTTP/2 使用二进制分帧层将传输的数据分割为更小的数据和帧,并对它们进行二进制格式编码处理,以实现在不改变 HTTP 现有语义等标准的基础上提升传输性能,从而降低响应延迟、提高请求吞吐的能力。HTTP/2 通过多路复用技术使客户端可以并行发送多个请求,以提高带宽的利用率。

HTTP/2 是基于 SPDY 协议设计的,是 SPDY 的演进版本,但其不强制使用 HTTPS 协议,仍可支持 HTTP 明文传输。Nginx 是通过 ngx_http_v2_module 实现 HTTP/2 协议支持的,编译配置时可通过增加参数 --with-http_v2_module 启用 HTTP2 模块。

HTTP2 模块配置指令如下。

指令名称指令值格式默认值指令说明
http2_body_preread_size size 64k 设置每个请求可用缓冲区的大小,可用于保存请求体数据
http2_chunk_size size 8k 设置响应体被分割成块的大小,该指令值设置得太小时将消耗服务器资源,太大时将因队列头部阻塞(Head-of-line Blocking,HOL)影响优先级
http2_idle_timeout time 3m 设置关闭连接后非活动连接超时时间
http2_max_concurrent_pushes number 10 设置连接中并发推送请求的最大数
http2_max_concurrent_streams number 128 设置连接中并发 HTTP/2 流的最大数
http2_max_field_size size 4k 设置 HPACK 压缩请求头字段的最大大小,如果应用了 Huffman 编码,解压缩后的名称和值字符串的实际大小可能会更大
http2_max_header_size size 16k 设置 HPACK 解压缩后整个请求头列表的最大大小
http2_max_requests number 1000 设置一个连接多路复用最大请求数
http2_push uri 或 off off 设置服务端主动推送的资源 URI,指令值 uri 是推送资源的网站绝对路径
http2_push_preload on 或 off off 设置当响应头中有 Link 字段时,是否自动向客户端推送 Link 字段中设置的网站资源
http2_recv_buffer_size size 256k 设置 Nginx 每个工作进程接收缓冲区的大小
http2_recv_timeout time 30s 设置等待客户端发送更多数据的超时时间,超过设定时间之后关闭连接

关于上面的表格,有以下几点需要说明。
  • http2_recv_buffer_size 指令可编写在 http 指令域中;
  • http2_chunk_size、http2_push、http2_push_preload 指令可编写在 http、server、location 指令域中;
  • 其余的指令可编写在 http、server 指令域中。

HTTP2 服务器推送可以实现将多个资源文件(CSS、JS、图片等)同时发送到客户端,如下页面中包含 style.css 和 nginx.png 两个资源文件。
  1. <!DOCTYPE html>
  2. <html>
  3. <meta charset="utf-8">
  4. <title>Nginx HTTPv2 Test</title>
  5. <head>
  6. <link rel="stylesheet" href="style.css">
  7. </head>
  8. <body>
  9. <h1>Nginx HTTPv2 Test</h1>
  10. <img src="nignx.png">
  11. </body>
  12. </html>
在没有服务器推送的情况下,客户端通过 3 个 GET 方法获取该页面的所有资源。在启用服务器推送后客户端只需通过一个 GET 方法,就可以获取到该页面的所有资源。配置样例如下:
server {
    listen 443 ssl http2 default_server;

    ssl_certificate ssl/www_nginxbar_org.pem;       # 网站证书文件
    ssl_certificate_key ssl/www_nginxbar_org.key;   # 网站证书密钥文件
    ssl_password_file ssl/www_nginxbar_org.pass;    # 网站证书密钥密码文件
    root /opt/nginx-web;
    location / {
        http2_push /style.css                       # 服务端推送
        http2_push /nginx.png                       # 服务端推送
    }
}

Nginx WebDAV模块配置简述

WebDAV(Web-based Distributed Authoring and Versioning)是基于 HTTP/1.1 的增强协议。该协议使用户可以直接对 Web 服务器进行文件读写,并支持对文件的版本控制和写文件的加锁及解锁等操作。

Nginx 通过 ngx_http_dav_module 模块实现对 WebDAV 协议的支持,使用户通过 WebDAV 模块的配置指令实现文件的管理操作,该模块支持 WebDAV 协议的 PUT、DELETE、MKCOL、COPY 和 MOVE 请求方法,在配置编译参数时,需要添加 --with-http_dav_module 参数启用该功能。

ngx_http_dav_module 模块的配置指令如下表所示。

指令名称指令值格式默认值指令说明
create_full_put_path on 或 off off 启用创建目录支持,默认情况下,Put 方法只能在已存在的目录里创建文件
dav_access users:permissions... user:rw 设置创建的文件及目录的访问权限,如果定义了 group 或 all 权限,user 设置可省略
dav_methods off 或 [PUT][DELETE][MKCOL][COPY][MOVE] off 指定支持的 WebDAV 方法
min_delete_depth number 0 允许删除文件及目录的最小层级,小于该层级的文件及目录不允许删除

上述指令都可编写在 http、server、location 指令域中。

Nginx 的自有模块对 WebDAV 协议的支持并不完整,可以通过第三方模块 nginx-dav-ext-module 增加文件特性查找和对写文件的加锁与解锁支持。nginx-dav-ext-module 模块的配置指令如下表所示。

指令名称指令值格式默认值指令说明
dav_ext_methods [PROPFIND][OPTIONS][LOCK][UNLOCK] -- 指定支持的 WebDAV 方法
dav_ext_lock_zone zone=NAME:SIZE[timeout=TIMEOUT] -- 定义存储文件锁的共享内存区域及锁超时时间,默认锁超时时间是 1 分钟
dav_ext_lock zone=NAME -- 启用 WebDav 的锁操作支持

关于上表,有以下几点需要说明。
  • dav_ext_lock_zone 指令只能编写在 http 指令域中;
  • dav_methods 和 dav_ext_lock 指令可编写在 http、server、location 指令域中;
  • WebDAV 协议方法及方法说明如下表所示。

方法名称文件权限方法说明
OPTIONS -- 支持 WebDAV 的检索服务方法
GET 获取文件
PUT、POST 上传文件
DELETE 删除 删除文件或集合
COPY 读、写 复制文件
MOVE 删除、写 移动文件
MKCOL 创建由一个或多个文件 URI 组成的新集合
PROPFIND 获取一个或多个文件的特性(创建日期、文件作者等),实现文件的查找与管理
LOCK、UNLOCK 添加、删除文件锁,实现写操作保护

进行 WebDAV 协议的 MOVE/COPY 操作时,会通过 HTTP 请求头属性字段 Destination 指定目标路径,如果客户端请求头中没有字段 Destination,Nginx 会直接报错。为增加服务端兼容性,可以通过第三方模块 headers-more-nginx-module 的 more_set_input_headers 指令在 MOVE/COPY 操作的 HTTP 请求头中强制添加 Destination 字段。

WebDAV 协议服务配置过程如下所示。

1) 模块编译

模块编译配置样例如下:

# 编译模块
$ ./configure --with-http_dav_module --add-module=../nginx-dav-ext-module --add-module=../headers-more-nginx-module

2) 设置文件夹权限

文件夹权限配置样例如下:

chown -R nobody:nobody /opt/nginx-web/davfile
chmod -R 700 /opt/nginx-web/davfile

3) 设置登录账号及密码

登录账号及密码配置样例如下:

echo "admin:$(openssl passwd 123456)" >/etc/nginx/conf/.davpasswd

4) Nginx 配置

Nginx 配置样例如下:
dav_ext_lock_zone zone=davlock:10m;                   # DAV文件锁内存共享区

server {
    listen 443 ssl http2;                             # 启用HTTPS及HTTP/2提升传输性能
    server_name  dav.nginxbar.org;
    access_log  logs/webdav.access.log  main;
    root    /opt/nginx-web/davfile;
   
    ssl_certificate ssl/www_nginxbar_org.pem;         # 网站证书文件
    ssl_certificate_key ssl/www_nginxbar_org.key;     # 网站证书密钥文件
    ssl_password_file ssl/www_nginxbar_org.pass;      # 网站证书密钥密码文件
    ssl_session_cache shared:SSL:10m;                 # 会话缓存存储大小为10MB
    ssl_session_timeout  20m;                         # 会话缓存超时时间为20分钟

    client_max_body_size 20G;                         # 最大允许上传的文件大小

    location / {
        autoindex on;
        autoindex_localtime on;

        set $dest $http_destination;
        if (-d $request_filename) {                   # 对目录请求、对URI自动添加“/”
            rewrite ^(.*[^/])$ $1/;
            set $dest $dest/;
        }

        if ($request_method ~ (MOVE|COPY)) { # 对MOVE|COPY方法强制添加Destination请求头
            more_set_input_headers 'Destination: $dest';
        }

        if ($request_method ~ MKCOL) {
            rewrite ^(.*[^/])$ $1/ break;
        }

        dav_methods PUT DELETE MKCOL COPY MOVE;      # DAV支持的请求方法
        dav_ext_methods PROPFIND OPTIONS LOCK UNLOCK;# DAV扩展支持的请求方法
        dav_ext_lock zone=davlock;                   # DAV扩展锁绑定的内存区域
        create_full_put_path  on;                    # 启用创建目录支持
        dav_access user:rw group:r all:r;            # 设置创建的文件及目录的访问权限

        auth_basic "Authorized Users WebDAV";
        auth_basic_user_file /etc/nginx/conf/.davpasswd;
    }
}

 

posted @ 2022-04-26 13:36  hanease  阅读(165)  评论(0编辑  收藏  举报