Nginx服务之核心要点


纸上得来终觉浅,绝知此事要躬行。

Nginx服务之核心要点


Nginx服务之核心要点


1. 命令行选项

  • [1] 命令帮助
$ nginx -h
nginx version: nginx/1.14.0 (Ubuntu)
Usage: nginx [-?hvVtTq] [-s signal] [-c filename] [-p prefix] [-g directives]

Options:
  -?,-h         : this help
  -v            : show version and exit
  -V            : show version and configure options then exit
  -t            : test configuration and exit
  -T            : test configuration, dump it and exit
  -q            : suppress non-error messages during configuration testing
  -s signal     : send signal to a master process: stop, quit, reopen, reload
  -p prefix     : set prefix path (default: /usr/share/nginx/)
  -c filename   : set configuration file (default: /etc/nginx/nginx.conf)
  -g directives : set global directives out of configuration file
  • [2] 命令帮助
Nginx 命令行选项 子选项 选项说明
nginx -c file - 指定配置文件代替默认的配置文件加载;默认/etc/nginx/nginx.conf
nginx -g directives - 设置全局配置指令
nginx -p prefix - 指定安装路径;默认安装在/usr/share/nginx/
nginx -q - 测试中不显示错误信息
nginx -s signal - master进程发送信号量
stop 立即停止
quit 优雅停止
reload 重载配置文件
reopen 重新打开日志文件
nginx -t - 测试配置文件的语法规范
nginx -h - 显示帮助信息
  • [3] 演示说明
# 指定配置文件
$ sudo nginx -c /data/ci/nginx.conf -s reload

# 使用-g参数设置启动全局变量
$ sudo nginx -g "pid /var/run/nginx.pid; worker_processes `sysctl -n hw.ncpu`"
  • [4] 信号量
$ kill -l
 1) SIGHUP   2) SIGINT   3) SIGQUIT  4) SIGILL   5) SIGTRAP
 6) SIGABRT  7) SIGBUS   8) SIGFPE   9) SIGKILL 10) SIGUSR1
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
16) SIGSTKFLT   17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
21) SIGTTIN 22) SIGTTOU 23) SIGURG  24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM   27) SIGPROF 28) SIGWINCH    29) SIGIO   30) SIGPWR
31) SIGSYS  34) SIGRTMIN    35) SIGRTMIN+1  36) SIGRTMIN+2  37) SIGRTMIN+3
38) SIGRTMIN+4  39) SIGRTMIN+5  40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+8
43) SIGRTMIN+9  44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9  56) SIGRTMAX-8  57) SIGRTMAX-7
58) SIGRTMAX-6  59) SIGRTMAX-5  60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2

2. 设置哈希表

为了快速处理静态的数据集合,诸如虚拟主机名、map 指令的值、MIME 类型和请求头的字段名,Nginx 使用了哈希表。

Nginx 启动和更新配置的过程中,它会尽可能为哈希表选择最小的容量,同时使每个哈希桶的长度不超过设置的配置参数。这些桶用于保存键和对应的哈希值。整个哈希表的容量以哈希桶的数量来定义。

Nginx 不断调整哈希表直到哈希表容量超过配置的最大值。大部分哈希表都有对应的指令,允许修改这些配置参数。比如,针对虚拟主机名的哈希表,有 server_names_hash_max_sizeserver_names_hash_bucket_size 两条指令。

哈希桶大小的参数会对齐到处理器缓存线长度的整数倍。这将加速哈希表中的键查找,因为在现代的处理器上,这可以减少内存访问的次数。

如果哈希桶大小等于处理器的缓存线长度,那么在最坏情况下,键查找时的内存访问次数是两次。第一次是计算哈希桶的地址,第二次是在哈希桶内进行键查找。因此,如果 Nginx 提示需要增大哈希表容量或者哈希桶大小时,应优先增大前者。


3. 调试日志

要开启调试日志,必须在编译 Nginx 时打开调试功能。

./configure --with-debug ...

然后在配置文件中进行设置才能使用,设置 error_log 的日志级别为 debug。注意,重新定义错误日志时,如过没有指定 debug 级别,调试日志会被屏蔽。

error_log /path/to/log debug;

可以通过debug_connection,设置只针对选定的客户端地址开启调试日志。

error_log  /path/to/log;

events {
    debug_connection   192.168.1.1;
    debug_connection   192.168.10.0/24;
}

当然,还可以设置日志的轮转缓冲区大小。

error_log memory:32m debug;

4. syslog 日志

Nginx 支持将 访问日志(access) 和 错误日志(error) 使用 syslog 记录。

syslog 日志参数 参数说明
server=address 定义 syslog 的服务器地址;可以使用域名、IP 地址+端口号和 UNIX 套接字;如果端口号没有指定,默认工作在UDP514端口上;如果使用域名会反解析为 IP 地址,使用第一个反解析 IP 地址
facility=string 定义 syslog 设备信息;kernmailftpnewsauthlocal0-7,默认工作在local7
severity=string 定义日志级别,默认为info级别;通过error_log指定
tag=string 设置 syslog 的标签信息;默认为Nginx
nohostname 禁用主机名字段添加到 syslog 消息头
# 举例说明
error_log syslog:server=192.168.1.1 debug;

access_log syslog:server=unix:/var/log/nginx.sock,nohostname;

access_log syslog:server=[2001:db8::1]:12345,facility=local7,tag=nginx,severity=info combined;

5. 处理用户请求

  • [1] 基于名字的虚拟主机

在这个配置中,Nginx仅仅检查请求的Host头以决定该请求应由哪个虚拟主机来处理。如果Host头没有匹配任意一个虚拟主机,或者请求中根本没有包含Host头,那Nginx会将请求分发到定义在此端口上的默认虚拟主机。

注释:default_server参数从0.8.21版开始可用,在之前的版本中,应该使用default参数代替。

server {
    listen      80 default_server;
    server_name example.org www.example.org;
    ...
}

server {
    listen      80;
    server_name example.net www.example.net;
    ...
}

server {
    listen      80;
    server_name example.com www.example.com;
    ...
}
  • [2] 防止处理未定义主机名的请求

如果不允许请求中缺少 Host 头,可以定义如下主机,丢弃这些请求。

在这里,我们设置主机名为空字符串以匹配未定义 Host 头的请求,而且返回了一个 Nginx 特有的非 HTTP 标准的返回码 444,它可以用来关闭连接。

server {
    listen       80;
    server_name  "";
    return       444;
}
  • [3] 基于域名和 IP 混合的虚拟主机

这个配置中,Nginx 首先测试请求的 IP 地址和端口是否匹配某个 server 配置块中的 listen 指令配置。接着 Nginx 继续测试请求的 Host 头是否匹配这个 server 块中的某个 server_name 的值。如果主机名没有找到,Nginx将把这个请求交给默认虚拟主机处理。

默认服务器是监听端口的属性,所以不同的监听端口可以设置不同的默认服务器。

server {
    listen      192.168.1.1:80;
    server_name example.org www.example.org;
    ...
}

server {
    listen      192.168.1.1:80 default_server;
    server_name example.net www.example.net;
    ...
}

server {
    listen      192.168.1.2:80 default_server;
    server_name example.com www.example.com;
    ...
}
  • [4] 简单 PHP 站点配置

首先,Nginx 使用前缀匹配找出最准确的 location,这一步 Nginx 会忽略 location 在配置文件出现的顺序。

上面的配置中,唯一的前缀匹配 location"/",而且因为它可以匹配任意的请求,所以被作为最后一个选择。接着,Nginx 继续按照配置中的顺序依次匹配正则表达式的 location,匹配到第一个正则表达式后停止搜索。匹配到的 location 将被使用。如果没有匹配到正则表达式的 location,则使用刚刚找到的最准确的前缀匹配的 location

server {
    listen      80;
    server_name example.org www.example.org;
    root        /data/www;

    location / {
        index   index.html index.php;
    }

    location ~* \.(gif|jpg|png)$ {
        expires 30d;
    }

    location ~ \.php$ {
        fastcgi_pass  localhost:9000;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include       fastcgi_params;
    }
}
  • 请注意所有 location 匹配测试只使用请求的 URI 部分,而不使用参数部分,这是因为写参数的方法很多。除此以外,任何人在请求串中都可以随意添加字符串。
/index.php?user=john&page=1
/index.php?page=1&user=john
/index.php?page=1&something+else&user=john

6. 处理 TCP/UDP 会话

Nginx 处理客户端的 TCP/UDP 会话(session)的连续的几个阶段

  • Post-accept
    • 接受客户端连接的一个阶段
    • ngx_stream_realip_module模块会在这个阶段调用到
  • Pre-access
    • 访问的初步检查
    • ngx_stream_limit_conn_module模块会在这个阶段调用到
  • Access
    • 客户端访问到实际的数据处理过程
    • ngx_stream_access_module模块会在这个阶段调用到
  • SSL
    • TLS/SSL过程
    • ngx_stream_ssl_module模块会在这个阶段调用到
  • Preread
    • 阅读原始字节的数据到预读缓冲区允许模块
    • 如果ngx_stream_ssl_preread_module分析数据前处理
  • Content
    • 数据的时间封装阶段
    • 通常为代理的upstream服务器或者提供指定返回值给客户端
  • Log
    • 最后阶段,客户端会话记录处理的结果到日志中
    • ngx_stream_log_module模块会在这个阶段调用到

7. 虚拟主机名

虚拟主机名使用server_name指令定义,用于决定由某台虚拟主机来处理请求。虚拟主机名可以使用确切的名字、通配符和正则表达式来定义。Nginx 以名字查找虚拟主机时,如果名字可以匹配多于一个主机名定义,比如同时匹配了通配符的名字和正则表达式的名字,那么 Nginx 按照下面的优先级别进行查找,并选中第一个匹配的虚拟主机。

  1. 确切的名字
  2. 最长的以星号起始的通配符名字:*.example.org
  3. 最长的以星号结束的通配符名字:mail.*
  4. 第一个匹配的正则表达式名字,按在配置文件中出现的顺序
server {
    listen       80;
    server_name  example.org  www.example.org;
    ...
}

server {
    listen       80;
    server_name  *.example.org;
    ...
}

server {
    listen       80;
    server_name  mail.*;
    ...
}

server {
    listen       80;
    server_name  ~^(?<user>.+)\.example\.net$;
    ...
}
  • 通配符名字

通配符名字只可以在名字的起始处或结尾处包含一个星号,并且星号与其他字符之间用点分隔。所以,www.*.example.orgw*.example.org都是非法的,但可用在正则表达式上。

星号可以匹配名字的多个节,*.example.org不仅匹配www.example.org,也匹配www.sub.example.org。有一种形如.example.org的特殊通配符,它可以既匹配确切的名字example.org,又可以匹配一般的通配符名字*.example.org

  • 正则表达式名字

Nginx使用的正则表达式兼容PCRE,虚拟主机名必须以波浪线~起始。

server_name  ~^www\d+\.example\.net$;
server_name  "~^(?<name>\w\d{1,3}+)\.example\.net$";

而且还支持正则表达式捕获,如?<name>/?'name'(兼容 Perl 5.10 语法)、?P<name>(兼容 Python 语法)。

# perl
server {
    server_name   ~^(www\.)?(?<domain>.+)$;

    location / {
        root   /sites/$domain;
    }
}
  • 性能优化

确切名字通配符名字存储在哈希表中,哈希表和监听端口关联。Nginx首先搜索确切名字的哈希表,如果没有找到,搜索以星号起始的通配符名字的哈希表,如果还是没有找到,继续搜索以星号结束的通配符名字的哈希表。

因为名字是按照域名的节来搜索的,所以搜索通配符名字的哈希表比搜索确切名字的哈希表慢。正则表达式是一个一个串行的测试,所以是最慢的,而且不可扩展。

鉴于以上原因,请尽可能使用确切的名字。

# 效率更高
server {
    listen       80;
    server_name  example.org  www.example.org  *.example.org;
    ...
}

# 方法简单
server {
    listen       80;
    server_name  .example.org;
    ...
}
  • 如果定义了大量名字,或者定义了非常长的名字,那可能需要在http配置块中使用server_names_hash_max_sizeserver_names_hash_bucket_size指令进行调整。
# nginx显示下面错误信息
could not build the server_names_hash,
you should increase server_names_hash_bucket_size: 32

# 解决方法
http {
    server_names_hash_bucket_size  64;
    ...
}
# nginx显示下面错误信息
could not build the server_names_hash,
you should increase either server_names_hash_max_size: 512
or server_names_hash_bucket_size: 32

# 解决方法
http {
    server_names_hash_max_size: 512
    server_names_hash_bucket_size  64;
    ...
}

8. HTTP 负载均衡

负载均衡是一个常用的跨多个应用程序实例的技术,能够优化资源利用率、减少延迟、最大化吞吐量以及容错机制。

可以使用Nginx作为非常有效的HTTP负载均衡器将流量分发给几个应用程序服务器和提高性能,Nginxweb应用程序的可伸缩性和可靠性。

  • 负载均衡方法

    • round-robin轮转;对应用服务器的请求以轮转方式负载均衡
    • least-connected最少连接;下一个请求分配给服务器的活跃连接数最少的
    • ip-hash会话持久性;基于客户端 IP 地址选择之前对应的服务器提供服务
  • 负载均衡配置

    • 负载均衡的默认方法就是round-robin
    • 反向代理包括HTTPHTTPSFastCGIuwsgiSCGImemcached
# 定义为轮转的负载均衡
http {
    upstream myapp1 {
        server srv1.example.com;
        server srv2.example.com;
        server srv3.example.com;
    }

    server {
        listen 80;
        location / {
            proxy_pass http://myapp1;
        }
    }
}
# 定义为最少连接的负载均衡
upstream myapp1 {
    least_conn;
    server srv1.example.com;
    server srv2.example.com;
    server srv3.example.com;
}
# 定义为会话持久性的负载均衡
upstream myapp1 {
    ip_hash;
    server srv1.example.com;
    server srv2.example.com;
    server srv3.example.com;
}
# 定义为加权的负载均衡的负载均衡
upstream myapp1 {
    server srv1.example.com weight=3;
    server srv2.example.com;
    server srv3.example.com;
}
  • 健康监测

Nginx的反向代理实现了服务器的健康监测(in-band or passive)机制。如果特定服务器因为错误导致无法响应,Nginx将其标记为failed,之后尽量避免后续入站的请求再去请求该服务器。

max_fails指令用于设定在失败超时时间之内,与服务器连接的失败次数。默认max_fails指令的值为1,当值为0的时候,将不会此服务器做健康监测。

fail_timeout指令用于定义多长时间将服务器标记为failed状态。之后,Nginx会定时去监测该failed状态的服务器,如果监测成功了,将其标记为live状态。

upstream dynamic {
    zone upstream_dynamic 64k;

    server backend1.example.com      weight=5;
    server backend2.example.com:8080 fail_timeout=5s slow_start=30s;
    server 192.0.2.1                 max_fails=3;
    server backend3.example.com      resolve;
    server backend4.example.com      service=http resolve;

    server backup1.example.com:8080  backup;
    server backup2.example.com:8080  backup;
}

server {
    location / {
        proxy_pass http://dynamic;
        health_check;
    }
}

9. 配置 HTTPS 服务器

  • 基本配置

配置HTTPS主机,必须在server配置块中打开SSL协议,还需要指定服务器端证书和密钥文件的位置。

server {
    listen              443;
    server_name         www.example.com;
    ssl                 on;
    ssl_certificate     www.example.com.crt;  # 公钥位置
    ssl_certificate_key www.example.com.key;  # 私钥位置
    ssl_protocols       SSLv3 TLSv1 TLSv1.1 TLSv1.2;  # 支持协议
    ssl_ciphers         HIGH:!aNULL:!MD5;  # 加密方式
    ...
}

服务器证书是公开的,会被传送到每一个连接到服务器的客户端。而私钥不是公开的,需要存放在访问受限的文件中,当然Nginx主进程必须有读取密钥的权限。

# 私钥和证书可以存放在同一个文件中
# 这种情况下,证书文件同样得设置访问限制
# 虽然证书和密钥存放在同一个文件,但证书会发送给客户端,密钥不会发送
ssl_certificate     www.example.com.cert;
ssl_certificate_key www.example.com.cert;

1.0.5版本开始,Nginx默认使用ssl_protocols SSLv3 TLSv1ssl_ciphers HIGH:!aNULL:!MD5。从1.1.131.0.12版本开始,Nginx默认使用ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2

CBC模式的加密算法容易受到一些攻击,尤其是BEAST攻击,可以通过下面配置调整为优先使用RC4-SHA加密算法。

ssl_ciphers RC4:HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
  • HTTPS 服务器优化

SSL操作需要消耗CPU资源,所以在多处理器的系统,需要启动多个工作进程,而且数量需要不少于可用CPU的个数。

最消耗CPU资源的SSL操作是SSL 握手,有两种方法可以将每个客户端的握手操作数量降到最低。第一种是保持客户端长连接,在一个SSL连接发送多个请求。第二种是在并发的连接或者后续的连接中重用SSL会话参数,这样可以避免SSL握手的操作。

会话缓存用于保存SSL会话,这些缓存在工作进程间共享,可以使用ssl_session_cache指令进行配置。1M内存缓存可以存放大约4000个会话,默认的缓存超时是5分钟,可以使用ssl_session_timeout加大它。

# 针对4核系统的配置优化的例子,使用10M的共享会话缓存
worker_processes  4;

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

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

        ssl                 on;
        ssl_certificate     www.example.com.crt;
        ssl_certificate_key www.example.com.key;
        ssl_protocols       SSLv3 TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers         HIGH:!aNULL:!MD5;
        ...
    }
}
  • SSL 证书链

有些浏览器不接受那些众所周知的证书认证机构签署的证书,而另外一些浏览器却接受它们。这是由于证书签发使用了一些中间认证机构,这些中间机构被众所周知的证书认证机构授权代为签发证书,但是它们自己却不被广泛认知,所以有些客户端不予识别。

针对这种情况,证书认证机构提供一个证书链的包裹,用来声明众所周知的认证机构和自己的关系,需要将这个证书链包裹与服务器证书合并成一个文件。

# 在这个文件里,服务器证书需要出现在认证方证书链的前面
$ cat www.example.com.crt bundle.crt > www.example.com.chained.crt

# 这个文件需要使用ssl_certificate指令来引用
server {
    listen              443;
    server_name         www.example.com;
    ssl                 on;
    ssl_certificate     www.example.com.chained.crt;
    ssl_certificate_key www.example.com.key;
    ...
}

如果服务器证书和认证方证书链合并时顺序弄错了,Nginx就不能正常启动,而且会显示下面的错误信息。因为Nginx首先需要用私钥去解密服务器证书,而遇到的却是认证方的证书。

SSL_CTX_use_PrivateKey_file(" ... /www.example.com.key") failed
   (SSL: error:0B080074:x509 certificate routines:
    X509_check_private_key:key values mismatch)

浏览器通常会将那些被受信的认证机构认证的中间认证机构保存下来,那么这些浏览器以后在遇到使用这些中间认证机构但不包含证书链的情况时,因为已经保存了这些中间认证机构的信息,所以不会报错。可以使用 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=[email protected]
...
  • 合并 HTTP/HTTPS 主机

如果HTTPHTTPS虚拟主机的功能是一致的,可以配置一个虚拟主机,既处理HTTP请求,又处理HTTPS请求。配置的方法是删除ssl on的指令,并在*:443端口添加参数ssl

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.8.21版本以前,只有添加了default参数的监听端口才能添加ssl参数
listen  443  default ssl;
  • 基于名字的 HTTPS 主机

如果在同一个 IP 上配置多个HTTPS主机,会出现一个很普遍的问题。

server {
    listen          443;
    server_name     www.example.com;
    ssl             on;
    ssl_certificate www.example.com.crt;
    ...
}

server {
    listen          443;
    server_name     www.example.org;
    ssl             on;
    ssl_certificate www.example.org.crt;
    ...
}

使用上面的配置,不论浏览器请求哪个主机,都只会收到默认主机www.example.com的证书。这是由SSL协议本身的行为引起的——先建立SSL连接,再发送HTTP请求,所以Nginx建立SSL连接时不知道所请求主机的名字,因此它只会返回默认主机的证书。

最古老的也是最稳定的解决方法就是每个HTTPS主机使用不同的 IP 地址。

server {
    listen          192.168.1.1:443;
    server_name     www.example.com;
    ssl             on;
    ssl_certificate www.example.com.crt;
    ...
}

server {
    listen          192.168.1.2:443;
    server_name     www.example.org;
    ssl             on;
    ssl_certificate www.example.org.crt;
    ...
}
  • 带有多个主机名的 SSL 证书

也有其他一些方法可以实现多个HTTPS主机共享一个IP地址,但都有不足。其中一种方法是使用在SubjectAltName字段中存放多个名字的证书,比如www.example.comwww.example.org。但是,SubjectAltName字段的长度有限制。

另一种方式是使用主机名中含有通配符的证书,比如*.example.org。这个证书匹配www.example.org,但是不匹配example.orgwww.sub.example.org。这两种方法可以结合在一起——使用在SubjectAltName字段中存放的多个名字的证书,这些名字既可以是确切的名字,也可以是通配符,比如example.org*.example.org

最好将带有多个名字的证书和它的密钥文件配置在http配置块中,这样可以只保存一份内容拷贝,所有主机的配置都从中继承。

ssl_certificate      common.crt;
ssl_certificate_key  common.key;

server {
    listen          443;
    server_name     www.example.com;
    ssl             on;
    ...
}

server {
    listen          443;
    server_name     www.example.org;
    ssl             on;
    ...
}
  • 主机名指示

在一个IP上运行多个HTTPS主机的更通用的方案是TLS 主机名指示扩展(SNI)。它允许浏览器和服务器进行SSL握手时,将请求的主机名传递给服务器,因此服务器可以知道使用哪一个证书来服务这个连接。但SNI只得到有限的浏览器的支持。

通过SNI只能传递域名,但当请求中包含可读的IP地址时,某些浏览器将服务器的IP地址作为服务器的名字进行了传送。这是一个错误,大家不应该依赖于这个。

为了在Nginx中使用SNI,那么无论是在编译nginx时使用的OpenSSL类库,还是在运行nginx时使用的OpenSSL运行库,都必须支持SNI。从0.9.8f版本开始,OpenSSL通过--enable-tlsext配置选项加入SNI支持,从0.9.8j版本开始,此选项成为默认选项。

# 使用-V选项运行时会显示如下信息
$ nginx -V
...
TLS SNI support enabled
...

10. 转换 rewrite 规则

  • 重定向到主站

共享站点的管理员,习惯于只在Apache下使用.htaccess文件配置所有信息,通常会将下面规则。

RewriteCond  %{HTTP_HOST}  example.org
RewriteRule  (.*)          http://www.example.org$1

翻译成这样,这种做法是错的,复杂而且低效。

server {
    listen       80;
    server_name  www.example.org  example.org;
    if ($http_host = example.org) {
        rewrite  (.*)  http://www.example.org$1;
    }
    ...
}

正确的方式是为example.org定义一个单独的服务器。

server {
    listen       80;
    server_name  example.org;
    return       301 http://www.example.org$request_uri;
}

server {
    listen       80;
    server_name  www.example.org;
    ...
}
  • 转化混合规则

典型的混合规则如下:

DocumentRoot /var/www/myapp.com/current/public

RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f
RewriteCond %{SCRIPT_FILENAME} !maintenance.html
RewriteRule ^.*$ %{DOCUMENT_ROOT}/system/maintenance.html [L]

RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^(.*)$ $1 [QSA,L]

RewriteCond %{REQUEST_FILENAME}/index.html -f
RewriteRule ^(.*)$ $1/index.html [QSA,L]

RewriteCond %{REQUEST_FILENAME}.html -f
RewriteRule ^(.*)$ $1/index.html [QSA,L]

RewriteRule ^/(.*)$ balancer://mongrel_cluster%{REQUEST_URI} [P,QSA,L]

转换成Nginx配置应该是这样:

location / {
    root       /var/www/myapp.com/current/public;

    try_files  /system/maintenance.html
               $uri  $uri/index.html $uri.html
               @mongrel;
}

location @mongrel {
    proxy_pass  http://mongrel;
}

文章作者: Escape
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Escape !
  目录