├── HTTP缓存与header模块.md ├── OpenSSL.md ├── README.md ├── https基本操作.md ├── limit连接限流.md ├── proxy代理.md ├── 命令行与热部署操作.md ├── 基本命令.md ├── 日志管理.md └── 连接处理方法IO.md /HTTP缓存与header模块.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | * [HTTP缓存](#HTTP缓存) 3 | * [缓存控制](#缓存控制) 4 | * [缓存校验](#缓存校验) 5 | * [200状态码](#200状态码) 6 | * [304状态码](#304状态码) 7 | * [200fromDiskCache](#200fromDiskCache) 8 | * [具体缓存流程](#具体缓存流程) 9 | * [header模块](#header模块) 10 | * [expires](#expires) 11 | * [add_header](#add_header) 12 | * [Yii2框架HTTP缓存源码](#Yii2框架HTTP缓存源码) 13 | 14 | # HTTP缓存 15 | ## 缓存控制 16 | HTTP缓存分为缓存控制和缓存校验,缓存控制有Cache-Control和Pragma 17 | 18 | Pragma是旧产物,已经逐步抛弃,有些网站为了向下兼容还保留了这两个字段。如果一个报文中同时出现Pragma和Cache-Control时,以Pragma为准。同时出现Cache-Control和Expires时,以Cache-Control为准。即优先级从高到低是 Pragma -> Cache-Control -> Expires 19 | 20 | 如果在请求header有如下参数 21 | ``` 22 | Cache-Control: public,max-age=86400 23 | Pragma: no-cache 24 | ``` 25 | 则Pragma的优先级更高 26 | 27 | Cache-Control一般值为 28 | - no-cache,表示不管有没有缓存都去拿真实数据,不会发生304,就是强制刷新 29 | - max-age=0,表示不管响应怎么设置,在重新获取数据前需要去校验ETag或者Last-Modified,校验通过就是304,就是在页面正常刷新 30 | - max-age=自己设置的值,服务器响应客户端,表示要求客户端缓存多长时间 31 | 32 | ## 缓存校验 33 | 缓存校验有Last-Modified和ETag 34 | 35 | 如果请求Cache-Control值为max-age=0,表示客户端要去服务端做资源校验,校验通过会发生304,使用本地缓存的资源,校验不通过的话,服务端将数据返回给客户端 36 | 37 | 服务端在响应时候会有响应头Last-Modified,这是一个格林威治时间,表示资源最后的修改时间 38 | ``` 39 | Last-Modified: Thu, 01 Aug 2019 07:24:42 GMT 40 | ``` 41 | 客户端在刷新页面时候,会发一个请求头If-Modified-Since,表示收到的上一次服务端给的Last-Modified 42 | ``` 43 | If-Modified-Since: Thu, 01 Aug 2019 07:24:42 GMT 44 | ``` 45 | 当服务端会对比自己的Last-Modifed和客户端的If-Modified-Since,如果 46 | 47 | If-Modified-Since >= Last-Modifed 48 | 49 | 那么服务端会直接响应304,响应body体长度为0,以下为一个304响应的nginx-access日志 50 | ``` 51 | 192.168.124.1 - - [31/Jul/2019:13:43:46 +0800] "GET /a.css HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, l 52 | ike Gecko) Chrome/73.0.3683.86 Safari/537.36" 53 | ``` 54 | 但是Last-Modifed无法解决资源在一秒内连续修改的问题,一秒内连续修改后,客户端只会更新一次 55 | 56 | 更好的解决方法是ETag,服务器会响应一个根据资源算出来的字符,如 57 | ``` 58 | ETag: "5d4293ba-19aa" 59 | ``` 60 | 第二次客户端请求时候会携带If-None-Match请求头 61 | ``` 62 | If-None-Match: "5d4293ba-19aa" 63 | ``` 64 | 如果 65 | 66 | If-None-Match == ETag 67 | 68 | 表示资源没有修改,服务端响应304 69 | 70 | 如果同时有ETag和Last-Modify,则ETag的优先级会更高 71 | 72 | 但是ETag也有问题,如果服务端是多节点集群,那么有可能A节点算出来的ETag和B节点的ETag可能不同,造成无法正常304响应,在nginx中可以关闭ETag 73 | ``` 74 | etag off; 75 | ``` 76 | ## 200状态码 77 | 200状态码会发生于浏览器第一次加载页面、强制刷新、304校验失败、资源缓存过期、浏览器禁用缓存情况 78 | 79 | 如果是浏览器第一次加载,那么请求头不会有Cache-Control、If-None-Match、If-Modified-Since 80 | 81 | 服务端正常响应200,正常将数据传给客户端 82 | 83 | 如果是强制刷新,那么浏览器会强制加请求头 84 | ``` 85 | Cache-Control: no-cache 86 | Pragma: no-cache 87 | ``` 88 | 表示需要服务端响应真实数据,不用做校验 89 | 90 | 如果浏览器禁用了缓存Disable Cache,那么也会强制加请求头no-cache 91 | ## 304状态码 92 | 304状态码会发生于刷新页面情况 93 | 94 | 刷新情况浏览器会强制加请求头 95 | ``` 96 | Cache-Control: max-age=0 97 | ``` 98 | 99 | 表示需要浏览器校验,校验成功就是304,校验失败就是200 100 | ## 200fromDiskCache 101 | 发生过程 102 | - 浏览器输入url 103 | - 再开一个新窗口,输入url,发生200from disk cache 104 | 105 | 由于访问静态资源,服务端通常都会响应Cache-Control:max-age,表示需要客户端缓存这个静态资源多长时间,如 106 | ``` 107 | Cache-Control: max-age=36536000 108 | ``` 109 | 同一个浏览器新窗口再次访问会发生from disk cache 110 | 111 | from disk cache情况服务端不会收到请求 112 | ## 具体缓存流程 113 | - 浏览器第一次加载url,不会有请求头Cache-Control、If-None-Match、If-Modified-Since,服务端响应200,响应头为 114 | ``` 115 | Cache-Control:max-age=86400 //告诉客户端缓存86400秒 116 | Last-Modify:Wed,31 Jul 2019 04:05:42 GMT //资源最后修改时间 117 | ETage: "asdadsa" //资源的ETag 118 | ``` 119 | - 刷新页面(服务端资源未修改),请求头如下,发生304 120 | ``` 121 | If-Modified-Since:Wed,31 Jul 2019 04:05:42 GMT //客户端保存的资源最后修改时间 122 | ETag: "asdadsa" 123 | ``` 124 | - 刷新页面(服务端资源修改),发生200 125 | - 强制刷新,请求头,发生200 126 | ``` 127 | Cache-Control:no-cache 128 | ``` 129 | - 新打开一个页面,缓存86400秒内,发生200 from disk cache 130 | - 新打开一个页面,缓存86400秒外,发生200 131 | 132 | # header模块 133 | ## expires 134 | ``` 135 | Syntax: expires [modified] time; 136 | expires epoch | max | off; 137 | Default: 138 | expires off; 139 | Context: http, server, location, if in location 140 | ``` 141 | 响应码为200, 201, 206, 301, 302, 303, 307, 308情况下会发这个响应头 142 | 参数可以是正数或者负数,如果为负,则发送的头为 143 | ``` 144 | Cache-Control:no-cache 145 | ``` 146 | 可以配置max,这样响应的就是,可以认为是永久缓存 147 | ``` 148 | Expires:Thu,31 Dec 2037 23:55:55 GMT 149 | Cache-Control:max-age=315360000 150 | ``` 151 | off参数可以禁用添加或者修改expire和Cache-Control响应 152 | 153 | # add_header 154 | ``` 155 | Syntax: add_header name value [always]; 156 | Default: — 157 | Context: http, server, location, if in location 158 | ``` 159 | 响应码为200、201、204、206、301、302、303、304、307、308则添加指定的响应头 160 | 如果当前级别没有add_header,则从上一个级别继承,仅仅当前级别没有的话 161 | 如果定义了always,则不管响应码为多少都添加header 162 | 163 | -------------------------------------------------------------------------------- /OpenSSL.md: -------------------------------------------------------------------------------- 1 | **(未完成)** 2 | 3 | 联系作者 4 | - weixin: 363260961 5 | - QQ: 363260961 6 | 7 | **编写不易,转载请注明出处https://github.com/Zhucola/advanced-nginx** 8 | 9 | 使用版本 10 | - CentOS Linux release 7.5.1804 (Core) 11 | - nginx/1.12.2版本 12 | - curl 7.61.0 (x86_64-pc-linux-gnu) libcurl/7.61.0 OpenSSL/1.0.2k zlib/1.2.7 13 | - OpenSSL 1.0.2p 14 Aug 2018 14 | ## 目录 15 | * [随机数](#随机数) 16 | * [秘钥RSA](#秘钥RSA) 17 | * [查看RSA秘钥公私钥、结构](#查看RSA秘钥公私钥、结构) 18 | * [查看RSA秘钥是否被篡改](#查看RSA秘钥是否被篡改) 19 | * [秘钥DSA](#秘钥DSA) 20 | * [查看DSA秘钥公私钥、结构](#查看DSA秘钥公私钥、结构) 21 | # 随机数 22 | openssl rand ... 23 | - \-out file 指定随机数输出文件 24 | - \-rand file 指定随机数种子文件 25 | - \-base64 编码为base64 26 | - \-hex 编码为hex 27 | - num 随机数长度 28 | ```openssl 29 | openssl rand 30 30 | openssl rand -rand /root/.rnd 30 31 | ``` 32 | 输出结果为二级制 33 | ```openssl 34 | openssl rand -hex 30 35 | openssl rand -base64 30 36 | ``` 37 | 输出结果为不二级制 38 | 39 | # 秘钥RSA 40 | openssl genrsa用于生成RSA私钥,**不会生成公钥,因为公钥提取自私钥** 41 | 42 | openssl genrsa 43 | - \-out filename 将指定的秘钥保存至filenme文件,若未指定则为标准输出 44 | - numbites 秘钥长度,该项必须为命令行最后一项 45 | - \-des等 加密私钥的算法 46 | - \-passout args 加密私钥文件的密码 47 | 48 | 密码是可选项,但是强烈推荐使用密码。密码可以安全的存储、传输和备份受保护的秘钥。但是可能每次重启web服务器都需要重新输入密码。如果需要更加安全,建议投资硬件 49 | ```openssl 50 | openssl genrsa –aes128 –out a.key 2048 51 | openssl genrsa -des3 -out a.key -passout pass:1234 2048 52 | ``` 53 | # 查看RSA秘钥公私钥、结构 54 | ```openssl 55 | openssl genrsa -des3 -out a.key -passout pass:1234 2048 56 | openssl rsa -text -in a.key # 查看结构 57 | openssl rsa -in a.key -pubout -out a_pub.key -passin pass:1234 #查看公钥 58 | openssl rsa -in a.key -out a_priv.key #查看未加密的私钥 59 | ``` 60 | # 查看RSA秘钥是否被篡改 61 | ```openssl 62 | openssl genrsa -des3 -out a.key -passout pass:1234 2048 63 | openssl rsa -in a.key -check -passin pass:1234 64 | ``` 65 | # 秘钥DSA 66 | DSA秘钥生成分为两步,1.生成DSA参数2.秘钥创建 67 | ```openssl 68 | openssl dsaparam -genkey 2048 | openssl dsa -out d.key -aes128 69 | ``` 70 | # 查看DSA秘钥公私钥、结构 71 | ```openssl 72 | openssl dsaparam -genkey 2048 | openssl dsa -out d.key -aes128 73 | openssl dsa -text -in d.key # 查看结构 74 | openssl dsa -in d.key -pubout -out d_pub.key #查看公钥 75 | openssl dsa -in d.key -out d_prive.key #查看私钥 76 | 77 | ``` 78 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 未完成 2 | 3 | ## 目录 4 | * [基本命令.md](https://github.com/Zhucola/advanced-nginx/blob/master/%E5%9F%BA%E6%9C%AC%E5%91%BD%E4%BB%A4.md) 5 | * [OpenSSL.md](https://github.com/Zhucola/advanced-nginx/blob/master/OpenSSL.md) 6 | * [https操作.md](https://github.com/Zhucola/advanced-nginx/blob/master/https%E5%9F%BA%E6%9C%AC%E6%93%8D%E4%BD%9C.md) 7 | * [连接处理方法IO.md](https://github.com/Zhucola/advanced-nginx/blob/master/连接处理方法IO.md) 8 | * [日志管理.md](https://github.com/Zhucola/advanced-nginx/blob/master/日志管理.md) 9 | * [命令行与热部署操作.md](https://github.com/Zhucola/advanced-nginx/blob/master/命令行与热部署操作.md) 10 | * [limit连接限流.md](https://github.com/Zhucola/advanced-nginx/blob/master/limit%E8%BF%9E%E6%8E%A5%E9%99%90%E6%B5%81.md) 11 | -------------------------------------------------------------------------------- /https基本操作.md: -------------------------------------------------------------------------------- 1 | **查看OpenSSL的基本操作请移步至 OpenSSL.md** 2 | 3 | ngx_http_ssl_module模块使nginx能够支持https 4 | 5 | 该模块**不默认编译**,使用该模块需要--with-http_ssl_module 6 | 7 | 该模块需要OpenSSL库 8 | 9 | 为了减少服务器负载,建议配置 10 | ```nginx 11 | worker_processes auto; 12 | http { 13 | server { 14 | listen 443 ssl; 15 | keepalive_timeout 70; 16 | 17 | ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 18 | ssl_ciphers AES128-SHA:AES256-SHA:RC4-SHA:DES-CBC3-SHA:RC4-MD5; 19 | ssl_certificate /usr/local/nginx/conf/cert.pem; 20 | ssl_certificate_key /usr/local/nginx/conf/cert.key; 21 | ssl_session_cache shared:SSL:10m; 22 | ssl_session_timeout 10m; 23 | } 24 | ``` 25 | 26 | ## 目录 27 | * [ssl](#ssl) 28 | * [ssl_buffer_size](#ssl_buffer_size) 29 | * [ssl_protocols](#ssl_protocols) 30 | * [ssl_certificate ](#ssl_certificate) 31 | * [ssl_certificate_key](#ssl_certificate_key) 32 | * [ssl_password_file](#ssl_password_file) 33 | * [ssl_verify_client](#ssl_verify_client) 34 | * [ssl_client_certificate](#ssl_client_certificate) 35 | * [ssl_session_cache](#ssl_session_cache) 36 | * [ssl_session_timeout](#ssl_session_timeout) 37 | 38 | # ssl 39 | ```nginx 40 | Syntax: ssl on | off; 41 | Default: ssl off; 42 | Context: http, server 43 | ``` 44 | 该指令在1.15.0以上版本被淘汰,应该使用listen 443 ssl;这种配置来代替 45 | 46 | # ssl_buffer_size 47 | ``` 48 | Syntax: ssl_buffer_size size; 49 | Default: ssl_buffer_size 16k; 50 | Context: http, server 51 | ``` 52 | 定义发送数据buffer区域的大小 53 | 54 | 如果发送的数据较大,则使用默认的16k就好 55 | 56 | 如果发送的数据小,则使用4k 57 | 58 | # ssl_protocols 59 | ```nginx 60 | Syntax: ssl_protocols [SSLv2] [SSLv3] [TLSv1] [TLSv1.1] [TLSv1.2] [TLSv1.3]; 61 | Default: ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 62 | Context: http, server 63 | ``` 64 | 指定支持的协议版本 65 | 66 | 如果客户端使用的协议版本大于服务端支持的,则报错SSL23_GET_SERVER_HELLO:unsupported protocol 67 | 68 | 69 | **TLSv1.1 TLSv1.2 仅仅在OpenSSL1.0.1以上版本才支持** 70 | 71 | **TLSv1.3仅仅在OpenSSL1.1.1版本才支持** 72 | 73 | # ssl_certificate 74 | ```nginx 75 | Syntax: ssl_certificate file; 76 | Default: — 77 | Context: http, server 78 | ``` 79 | 给指定的主机提供PEM格式的证书 80 | 81 | 如果还需要提供中间证书,那么应该按照顺序先指定主证书,然后提供中间证书 82 | 83 | 从版本1.11.0开始,该指令可以指定多个不同类型的证书,如RSA和ECDSA 84 | ```nginx 85 | server { 86 | listen 443 ssl; 87 | server_name example.com; 88 | 89 | ssl_certificate example.com.rsa.crt; 90 | ssl_certificate_key example.com.rsa.key; 91 | 92 | ssl_certificate example.com.ecdsa.crt; 93 | ssl_certificate_key example.com.ecdsa.key; 94 | ... 95 | } 96 | ``` 97 | # ssl_certificate_key 98 | ``` 99 | Syntax: ssl_certificate_key file; 100 | Default: — 101 | Context: http, server 102 | ``` 103 | 提供一个配置与ssl_certificate证书的秘钥 104 | 105 | 配置了秘钥后,每次重启都需要重新输入秘钥密码,除非使用指令ssl_password_file指定密码 106 | 107 | # ssl_password_file 108 | ``` 109 | Syntax: ssl_password_file file; 110 | Default: — 111 | Context: http, server 112 | ``` 113 | 在1.7.3版本中出现 114 | 115 | 提供一个与指定ssl_certificate_key秘钥文件的密码 116 | 117 | **如果不指定该指令,并且秘钥有密码,reload即使输入了正确的密码,reload也不会生效** 118 | 119 | 其中可以提供多个密码,每一行一个,在使用密码的时候轮流尝试密码 120 | ```nginx 121 | server { 122 | listen 443 ssl; 123 | server_name example.com; 124 | 125 | ssl_certificate example.com.rsa.crt; 126 | ssl_certificate_key example.com.rsa.key; 127 | ssl_password_file /tmp/openssl/pass; 128 | ... 129 | } 130 | ``` 131 | # ssl_verify_client 132 | 133 | ``` 134 | Syntax: ssl_verify_client on | off | optional | optional_no_ca; 135 | Default: ssl_verify_client off; 136 | Context: http, server 137 | ``` 138 | 是否校验客户端证书,校验结果会保存在变量$ssl_client_verify中 139 | 140 | 参数optional会请求客户端证书,客户端提供了证书的时候校验,不提供不校验 141 | 142 | 参数optional_no_ca会请求客户端证书,但是客户端证书不需要被CA证书信任 143 | 144 | 该指令与ssl_client_certificate 配套使用,需要指定ssl_client_certificate 参数 145 | 146 | # ssl_client_certificate 147 | ``` 148 | Syntax: ssl_client_certificate file; 149 | Default: — 150 | Context: http, server 151 | ``` 152 | 指定一个受信与CA的证书,这个证书用来做客户端证书校验 153 | 154 | 指定的证书在请求的时候**会**响应给给客户端 155 | 156 | ```nginx 157 | server { 158 | listen 443 ssl; 159 | keepalive_timeout 70; 160 | ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 161 | ssl_ciphers AES128-SHA:AES256-SHA:RC4-SHA:DES-CBC3-SHA:RC4-MD5; 162 | ssl_certificate /tmp/openssl/nginx.crt; 163 | ssl_certificate_key /tmp/openssl/a.key; 164 | ssl_password_file /tmp/openssl/pass; 165 | ssl_verify_client on; 166 | ssl_client_certificate /etc/pki/CA/cacert.pem; 167 | location / { 168 | return 200 123; 169 | } 170 | } 171 | ``` 172 | 173 | # ssl_trusted_certificate 174 | ``` 175 | Syntax: ssl_trusted_certificate file; 176 | Default: — 177 | Context: http, server 178 | ``` 179 | 指定一个受信与CA的证书,这个证书用来做客户端证书校验 180 | 181 | 指定的证书在请求的时候**不会**响应给给客户端 182 | 183 | ## ssl_session_cache 184 | ``` 185 | Syntax: ssl_session_cache off | none | [builtin[:size]] [shared:name:size]; 186 | Default: ssl_session_cache none; 187 | Context: http, server 188 | ``` 189 | 定义如何存储session 190 | 191 | 参数none 192 | 193 | nginx告诉客户端可以重用session,但是nginx不会存储session,实际上没有使用session 194 | 195 | 参数off 196 | 197 | nginx告诉客户端不可以重用session 198 | 199 | 参数builtin 200 | 201 | 在OpenSSL中构建的缓存;由一个工作进程实现功能。缓存大小在会话中指定。如果没有给出大小,则等于20480个会话。使用内置缓存可能导致内存碎片化。 202 | 203 | 参数shared 204 | 205 | 在所有工作进程之间共享的高速缓存。缓存大小以字节指定;一兆字节可以存储大约4000个会话。每个共享缓存应该具有任意的名称。同一名称的缓存可以在多个虚拟服务器中使用 206 | ``` 207 | ssl_session_cache builtin:1000 shared:SSL:10m; 208 | ``` 209 | builtin和shared可以同时指定,但是使用shared会更加高效 210 | 211 | ## ssl_session_timeout 212 | ``` 213 | Syntax: ssl_session_timeout time; 214 | Default: ssl_session_timeout 5m; 215 | Context: http, server 216 | ``` 217 | 提供一个给客户端重用session的时间 218 | -------------------------------------------------------------------------------- /limit连接限流.md: -------------------------------------------------------------------------------- 1 | 对于一些服务器流量异常、负载过大,甚至是大流量的恶意攻击访问等,进行并发数的限制;该模块可以根据定义的键来限制每个键值的连接数,只有那些正在被处理的请求(这些请求的头信息已被完全读入)所在的连接才会被计数。 2 | ## 目录 3 | * [limit_conn_zone](#limit_conn_zone) 4 | * [limit_conn](#limit_conn) 5 | * [limit_conn_status](#limit_conn_status) 6 | * [limit_conn_log_level](#limit_conn_log_level) 7 | * [并发限制于error_page的结合使用](#并发限制于error_page的结合使用) 8 | 9 | ## limit_conn_zone 10 | ``` 11 | Syntax: limit_conn_zone key zone=name:size; 12 | Default: — 13 | Context: http 14 | ``` 15 | 设置一个共享区间,用于存储各种各样的key的连接状态 16 | 17 | 该命令和limit_zone命令一起配合使用 18 | 19 | size的大小最小为32k(32K),否则会报错 20 | ``` 21 | nginx: [emerg] zone "zone=test:30k" is too small in /usr/local/nginx/conf/nginx.conf:8 22 | ``` 23 | 24 | 参数key可以是文本、变量和他们的组合 25 | ``` 26 | http{ 27 | limit_conn_zone $remote_addr zone=test:10m; 28 | limit_conn_status 503; 29 | server { 30 | listen 80; 31 | root /tmp; 32 | location / { 33 | fastcgi_pass http://127.0.0.1:9000; 34 | include fastcgi.conf; 35 | limit_conn test 5; 36 | } 37 | } 38 | } 39 | ``` 40 | 以上配置的意思就是定一个名字是test,大小为10m的共享区间,该共享区间用以记录将请求的头信息已被完全读入的请求,记录的键为$remote_addr 41 | 42 | 比如并发情况下: 43 | 1.请求$remote_addr为127.0.0.1,则test区间127.0.0.1的键自增请求数为1 44 | 2.请求$remote_addr为127.0.0.1,则test区间127.0.0.1的键自增请求数为2 45 | 3.请求$remote_addr为127.0.0.1,则test区间127.0.0.1的键自增请求数为3 46 | 4.请求$remote_addr为192.168.1.1,则test区间192.168.1.1的键自增请求数为1 47 | 48 | 当$remote_addr并发请求数达到命令limit_conn test 5;所指定的大小5时,第5个并发返回503 Service Temporarily Unavailable 49 | 50 | 可以创建5个xshell窗口,在/tmp目录下创建文件a.php,a.php中sleep(50);,也就是阻塞50秒 51 | 52 | 5个窗口的$remote_addr为127.0.0.1,模拟5个并发操作,在第6个并发创建的时候,会返回503 53 | 54 | ``` 55 | http{ 56 | limit_conn_zone $uri zone=test:10m; 57 | limit_conn_status 503; 58 | server { 59 | listen 80; 60 | root /tmp; 61 | location / { 62 | fastcgi_pass http://127.0.0.1:9000; 63 | include fastcgi.conf; 64 | limit_conn test 5; 65 | } 66 | } 67 | } 68 | ``` 69 | 也可以同时限制$uri的并发数量为5 70 | 比如: 71 | 1.请求$uri为/a,则test区间/a的键自增请求数为1 72 | 2.请求$uri为/a,则test区间/a的键自增请求数为2 73 | 3.请求$uri为/a,则test区间/a的键自增请求数为3 74 | 4.请求$uri为/b,则test区间/b的键自增请求数为1 75 | 76 | ``` 77 | http{ 78 | limit_conn_zone $HTTP_AAA zone=test:10m; 79 | limit_conn_status 503; 80 | server { 81 | listen 80; 82 | root /tmp; 83 | location / { 84 | fastcgi_pass http://127.0.0.1:9000; 85 | include fastcgi.conf; 86 | limit_conn test 5; 87 | } 88 | } 89 | } 90 | ``` 91 | 也可以指定在请求中带head头为AAA的并发数量 92 | 93 | ``` 94 | curl 'http://127.0.0.1/a.php' -H 'AAA: 123' 95 | ``` 96 | 97 | 也就是说,如果heade头AAA值为123,那么最多接受5个并发;如果有请求没有heade头AAA,那么没有并发限制 98 | 99 | **注意** 100 | 如果用IP作为键限制,则应该使用$binary_remote_addr替代$remote_addr,因为$remote_addr参数长度在7至15个字节,而$binary_remote_addr长度在IPV4下总是为4字节,在IPV6下总是为16字节 101 | 102 | 如果区域存储已用完,服务器将将错误返回给所有其他请求 103 | 104 | ## limit_conn 105 | ``` 106 | Syntax: limit_conn zone number; 107 | Default: — 108 | Context: http, server, location 109 | ``` 110 | 比较难描述,直接看例子 111 | ``` 112 | http{ 113 | limit_conn_zone $HTTP_AAA zone=test:10m; 114 | limit_conn_status 503; 115 | server { 116 | listen 80; 117 | root /tmp; 118 | location / { 119 | fastcgi_pass http://127.0.0.1:9000; 120 | include fastcgi.conf; 121 | limit_conn test 5; 122 | } 123 | } 124 | } 125 | ``` 126 | 以上就是定义了一个并发限制,名字是test,共享内存大小为10m,限制的键是$HTTP_AAA(也就是header头的AAA) 127 | ``` 128 | curl 'http://127.0.0.1/a.php' -H 'AAA: 123' 129 | ``` 130 | 当并发数量$HTTP_AAA达到6时候,第6个请求会保存,返回响应码506 131 | 132 | 也可以在一个location里面配置多个limit_conn 133 | ``` 134 | http{ 135 | limit_conn_zone $HTTP_AAA zone=test_1:10m; 136 | limit_conn_zone $uri zone=test_2:10m; 137 | limit_conn_status 503; 138 | server { 139 | listen 80; 140 | root /tmp; 141 | location / { 142 | fastcgi_pass http://127.0.0.1:9000; 143 | include fastcgi.conf; 144 | limit_conn test_1 5; 145 | limit_conn test_2 10; 146 | } 147 | } 148 | } 149 | ``` 150 | 151 | limit_conn如果当前级别没有指明,则从前一个级别继承 152 | ``` 153 | http{ 154 | limit_conn_zone $HTTP_AAA zone=test:10m; 155 | limit_conn_status 503; 156 | server { 157 | listen 80; 158 | root /tmp; 159 | limit_conn test 5; 160 | location / { 161 | fastcgi_pass http://127.0.0.1:9000; 162 | include fastcgi.conf; 163 | } 164 | } 165 | } 166 | ``` 167 | 168 | 则被location /的匹配的请求,会使用limit_conn test 5; 169 | ## limit_conn_status 170 | ``` 171 | Syntax: limit_conn_status code; 172 | Default: limit_conn_status 503; 173 | Context: http, server, location 174 | ``` 175 | 设置状态代码以响应拒绝的请求返回 176 | 177 | 注意这个code值应该在400和599之间 178 | 179 | 503的响应码具体信息为 180 | ``` 181 | 182 | 503 Service Temporarily Unavailable 183 | 184 |

503 Service Temporarily Unavailable

185 |
nginx/1.14.1
186 | 187 | 188 | ``` 189 | ## limit_conn_log_level 190 | ``` 191 | Syntax: limit_conn_log_level info | notice | warn | error; 192 | Default: limit_conn_log_level error; 193 | Context: http, server, location 194 | ``` 195 | 设置在并发超限情况下,在error_log中的日志级别 196 | 197 | 默认情况下为error级别报错,日志描述为 198 | ``` 199 | 2018/11/12 23:05:51 [error] 21012#0: *12 limiting connections by zone "test_2", client: 127.0.0.1, server: localhost, request: "GET /a.php HTTP/1.1", host: "127.0.0.1" 200 | ``` 201 | 202 | ## 并发限制于error_page的结合使用 203 | 204 | 使用ngx_http_limit_conn_module模块来做并发限频,默认情况下会返回http code503 205 | ``` 206 | 207 | 503 Service Temporarily Unavailable 208 | 209 |

503 Service Temporarily Unavailable

210 |
nginx/1.14.1
211 | 212 | 213 | ``` 214 | 这种非程序员能看懂的提示语不是我们想要的,所以我们应该结合error_page(https://github.com/Zhucola/advanced-nginx/blob/master/ngx_http_core_module.md#error_page) 命令来与并发限频一起使用 215 | 216 | ``` 217 | http { 218 | include mime.types; 219 | limit_conn_zone $uri$HTTP_id zone=test:32k; 220 | server { 221 | listen 80; 222 | server_name localhost; 223 | error_page 599 = /response; 224 | location / { 225 | limit_conn_status 599; 226 | limit_conn test 10; 227 | root /tmp; 228 | fastcgi_pass 127.0.0.1:9000; 229 | include fastcgi.conf; 230 | } 231 | location /response { 232 | default_type application/json; 233 | return 200 '{"code":1,"message":"请求超限"}'; 234 | } 235 | } 236 | } 237 | ``` 238 | 以上配置中,如果请求$uri$HTTP_id并发达到了11,则limit_conn_status会返回599响应码,又因为我们有error_page指令,所以被转到location /response,最后返回 239 | ``` 240 | < HTTP/1.1 200 OK 241 | < Server: nginx/1.14.1 242 | < Date: Mon, 12 Nov 2018 14:56:30 GMT 243 | < Content-Type: application/json 244 | < Content-Length: 35 245 | < Connection: keep-alive 246 | < 247 | * Connection #0 to host 127.0.0.1 left intact 248 | {"code":1,"message":"请求超限"} 249 | ``` 250 | -------------------------------------------------------------------------------- /proxy代理.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | * [proxy_connect_timeout](#proxy_connect_timeout) 3 | * [proxy_method](#proxy_method) 4 | * [proxy_http_version](#proxy_http_version) 5 | * [proxy_pass_request_body](#proxy_pass_request_body) 6 | * [proxy_pass](#proxy_pass) 7 | * [proxy_set_header](#proxy_set_header) 8 | * [underscores_in_headers](#underscores_in_headers) 9 | * [获取代理模式下的真实用户ip](#获取代理模式下的真实用户ip) 10 | 11 | # proxy_connect_timeout 12 | ``` 13 | Syntax: proxy_connect_timeout time; 14 | Default: 15 | proxy_connect_timeout 60s; 16 | Context: http, server, location 17 | ``` 18 | 设置于代理服务器的连接超时时间,这个时间不能超过75秒 19 | # proxy_method 20 | ``` 21 | Syntax: proxy_method method; 22 | Default: — 23 | Context: http, server, location 24 | 25 | ``` 26 | 指定代理方法而不是使用客户端请求的方法 27 | 28 | 如果client c -> proxy server s1 -> server s2 29 | 30 | 使用get方式请求client,那么s2收到的请求方式是get 31 | 32 | 如果在proxy server s1指定 33 | ``` 34 | proxy_method POST; 35 | ``` 36 | 那么收到的请求方式就是POST 37 | 38 | # proxy_http_version 39 | ``` 40 | Syntax: proxy_http_version 1.0 | 1.1; 41 | Default: 42 | proxy_http_version 1.0; 43 | Context: http, server, location 44 | ``` 45 | 1.1版本推荐在keep alive下使用 46 | 47 | 需要在每一个被使用到的proxy都设置 48 | # proxy_pass_request_body 49 | ``` 50 | Syntax: proxy_pass_request_body on | off; 51 | Default: 52 | proxy_pass_request_body on; 53 | Context: http, server, location 54 | ``` 55 | 决定是否传送原始body给代理服务器 56 | 57 | 单独将proxy_pass_request_body off还是会将body传给server端,需要 58 | ``` 59 | location /x-accel-redirect-here/ { 60 | proxy_method GET; 61 | proxy_pass_request_body off; 62 | proxy_set_header Content-Length ""; 63 | proxy_pass ... 64 | } 65 | ``` 66 | # proxy_pass 67 | ``` 68 | Syntax: proxy_pass URL; 69 | Default: — 70 | Context: location, if in location, limit_except 71 | ``` 72 | 设置一个代理协议和地址 73 | 74 | 协议可以是http或者https,地址可以带端口和uri 75 | ``` 76 | server { 77 | listen 80; 78 | location / { 79 | proxy_pass http://127.0.0.1:81; 80 | } 81 | } 82 | server { 83 | listen 81; 84 | location / { 85 | return 200 $request_uri; 86 | } 87 | } 88 | ``` 89 | 请求80端口uri为/abc,将会proxy_pass到81端口,输出/abc 90 | 91 | ``` 92 | server { 93 | listen 80; 94 | location /abc { 95 | proxy_pass http://127.0.0.1:81/xy; 96 | } 97 | } 98 | server { 99 | listen 81; 100 | location / { 101 | return 200 $request_uri; 102 | } 103 | } 104 | ``` 105 | 请求80端口uri为/abcd,将会proxy_pass到81端口,输出/xyd,就是实际请求的uri(/abcd),与location的/abc做差集,结果为d,将d拼上proxy_pass的uri(/xy),最后代理过去的uri为/abcd 106 | ``` 107 | server { 108 | listen 80; 109 | location /abc { 110 | proxy_pass http://127.0.0.1:81; 111 | } 112 | } 113 | server { 114 | listen 81; 115 | location / { 116 | return 200 $request_uri; 117 | } 118 | } 119 | ``` 120 | 请求80端口uri为/abcd,将会proxy_pass到81端口,输出/abcd,因为proxy_pass没有默认的uri,所以不做差集处理 121 | 122 | ``` 123 | server { 124 | listen 80; 125 | location /abc { 126 | proxy_pass http://127.0.0.1:81/; 127 | } 128 | } 129 | server { 130 | listen 81; 131 | location / { 132 | return 200 $request_uri; 133 | } 134 | } 135 | ``` 136 | 请求80端口uri为/abcd,将会proxy_pass到81端口,输出/,因为proxy_pass有默认的uri为/,所以做差集处理 137 | 138 | ``` 139 | server { 140 | listen 80; 141 | location /xxx { 142 | rewrite ^/xxx /yyy break; 143 | proxy_pass http://127.0.0.1:81; 144 | } 145 | } 146 | server { 147 | listen 81; 148 | location / { 149 | return 200 $request_uri; 150 | } 151 | } 152 | ``` 153 | 请求80端口uri为/xxx,将会proxy_pass到81端口,因为有rewrite并且是break,所以改变了uri,输出/yyy 154 | 155 | ``` 156 | server { 157 | listen 80; 158 | location /a { 159 | proxy_pass http://127.0.0.1:81/oooooo; 160 | } 161 | } 162 | server { 163 | listen 81; 164 | location / { 165 | return 200 $request_uri; 166 | } 167 | } 168 | ``` 169 | 请求80端口uri为/abc,将会proxy_pass到81端口,uri做差集,最后输出结果为/oooooobc 170 | 171 | # proxy_set_header 172 | ``` 173 | Syntax: proxy_set_header field value; 174 | Default: 175 | proxy_set_header Host $proxy_host; 176 | proxy_set_header Connection close; 177 | Context: http, server, location 178 | ``` 179 | 允许重新定义或者追加header头到proxy服务器,可以包含文本、变量和他们的组合 180 | 指令会继承于上一个级别,如果当前级别没有proxy_set_header被定义 181 | ``` 182 | server { 183 | listen 80; 184 | proxy_set_header AA aa; 185 | location / { 186 | proxy_pass http://127.0.0.1:81; 187 | } 188 | } 189 | server { 190 | listen 81; 191 | location / { 192 | return 200 $HTTP_AA; 193 | } 194 | } 195 | ``` 196 | 请求80端口uri为/,会输出aa,因为80的location /里面没有定义proxy_set_header,所以会继承上一个级别的proxy_set_header 197 | ``` 198 | server { 199 | listen 80; 200 | proxy_set_header AA aa; 201 | location / { 202 | proxy_set_header BB bb; 203 | proxy_pass http://127.0.0.1:81; 204 | } 205 | } 206 | server { 207 | listen 81; 208 | location / { 209 | return 200 $HTTP_AA; 210 | } 211 | } 212 | ``` 213 | 请求80端口uri为/,会输出空 214 | ``` 215 | server { 216 | listen 80; 217 | location / { 218 | proxy_set_header BB bb; 219 | proxy_pass http://127.0.0.1:81; 220 | } 221 | } 222 | server { 223 | listen 81; 224 | location / { 225 | proxy_set_header BB xx; 226 | proxy_pass http://127.0.0.1:82; 227 | } 228 | } 229 | server { 230 | listen 82; 231 | location / { 232 | return 200 $HTTP_BB; 233 | } 234 | } 235 | ``` 236 | 请求80端口uri为/,会输出xx,相当于81端口对head头BB做了重写 237 | ``` 238 | server { 239 | listen 80; 240 | location / { 241 | proxy_set_header AA aa; 242 | proxy_pass http://127.0.0.1:81; 243 | } 244 | } 245 | server { 246 | listen 81; 247 | location / { 248 | proxy_set_header BB bb; 249 | proxy_pass http://127.0.0.1:82; 250 | } 251 | } 252 | server { 253 | listen 82; 254 | location / { 255 | return 200 $HTTP_AA; 256 | } 257 | } 258 | ``` 259 | 请求80端口uri为/,可以获取到第一次proxy添加的header头,所以输出aa 260 | # underscores_in_headers 261 | ``` 262 | Syntax: underscores_in_headers on | off; 263 | Default: 264 | underscores_in_headers off; 265 | Context: http, server 266 | ``` 267 | 自定义的header头变量是否可以带下划线 268 | ``` 269 | server { 270 | listen 81; 271 | underscores_in_headers off; 272 | location / { 273 | proxy_set_header aa $http_a_b; 274 | proxy_pass http://127.0.0.1:82; 275 | } 276 | } 277 | server { 278 | listen 82; 279 | location / { 280 | return 200 $HTTP_AA; 281 | } 282 | } 283 | ``` 284 | ``` 285 | curl 'http://127.0.0.1:81' -H 'a_b: 123' 286 | ``` 287 | 请求将获取不到aa的header头,需要将underscores_in_headers改为on这样才能获取到$http_a_b 288 | ``` 289 | server { 290 | listen 81; 291 | underscores_in_headers on; 292 | location / { 293 | proxy_set_header aa $http_a_b; 294 | proxy_pass http://127.0.0.1:82; 295 | } 296 | } 297 | server { 298 | listen 82; 299 | location / { 300 | return 200 $HTTP_AA; 301 | } 302 | } 303 | ``` 304 | ``` 305 | curl 'http://127.0.0.1:81' -H 'a_b: 123' 306 | ``` 307 | 输出123 308 | 309 | ``` 310 | server { 311 | listen 81; 312 | underscores_in_headers on; 313 | location / { 314 | return 200 $HTTP_AA_A; 315 | } 316 | } 317 | ``` 318 | ``` 319 | curl 'http://127.0.0.1' -H 'AA_A: 123' 320 | ``` 321 | 输出123 322 | ``` 323 | server { 324 | listen 81; 325 | underscores_in_headers off; 326 | location / { 327 | return 200 $HTTP_AA_A; 328 | } 329 | } 330 | ``` 331 | ``` 332 | curl 'http://127.0.0.1' -H 'AA-A: 123' 333 | ``` 334 | 输出123 335 | # 获取代理模式下的真实用户ip 336 | - Client C -> Server S S获取的remote_addr为C的ip 337 | - Client C1 -> proxy Server S1 -> proxy Server S2 -> Server S3 S3获取的remote_addr为S2的 338 | 339 | 在proxy_pass情况下,应该添加 340 | ``` 341 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 342 | ``` 343 | 这样Server S3获取的HTTP_X_FORWARDED_FOR为Client C1,Server S1 S3获取的remote_addr为S2的,真实的客户端ip为HTTP_X_FORWARDED_FOR最左端的 344 | 345 | 也可以在proxy Server S1中添加 346 | ``` 347 | proxy_set_header X-Real-IP $remote_addr; 348 | ``` 349 | 350 | 这样在Server S3中获取到的HTTP_X_REAL_IP就是client的ip 351 | 352 | Client C1 -> proxy Server S1 -> proxy Server S2 -> Server S3需要在每一个proxy里面都写proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;,如果proxy Server S2中没写,则Server S3获取到的就是client c1,remote_addr为s1的 353 | -------------------------------------------------------------------------------- /命令行与热部署操作.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | * [启动](#启动) 3 | * [停止](#停止) 4 | nginx -s stop 5 | * [优雅停止](#优雅停止) 6 | nginx -s quit 7 | * [平滑重启](#平滑重启) 8 | nginx -s reload 9 | * [指定配置文件操作](#指定配置文件操作) 10 | nginx -c /tmp/nginx.conf 11 | * [重新开始记录日志](#重新开始记录日志) 12 | nginx -s reopen 13 | * [检测语法错误](#检测语法错误) 14 | nginx -t 15 | * [查看版本信息和编译配置](#查看版本信息和编译配置) 16 | nginx -v 17 | * [热部署](#热部署) 18 | 19 | 默认编译后,nginx的可执行二进制文件在/usr/local/nginx/sbin目录下,可执行文件为nginx 20 | 21 | 我们需要执行 22 | ``` 23 | cp /usr/local/nginx/sbin/nginx /usr/bin 24 | ``` 25 | 26 | 这样才可以在全局中直接找到nginx的二进制文件 27 | 28 | # 启动 29 | 30 | 直接执行nginx 31 | 32 | 如果服务器已经有nginx在执行,再次执行nginx会报错 33 | ``` 34 | nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use) 35 | ``` 36 | # 停止 37 | ``` 38 | nginx -s stop 39 | ``` 40 | # 优雅停止 41 | ``` 42 | nginx -s quit 43 | ``` 44 | 45 | 优雅停止与停止的区别就是: 46 | 47 | -停止会直接停掉正在连接着的tcp请求,nginx会发送一个RST包,强行断开连接 48 | 49 | -优雅停止会让正在连接的tcp请求处理完,然后再进行停止;但是再连接过来的请求会失败 50 | 51 | # 平滑重启 52 | ``` 53 | nginx -s reload 54 | ``` 55 | 56 | # 指定配置文件操作 57 | nginx默认使用的配置文件在conf/nginx.conf中,如果我们需要使用其他路径的配置文件,进行指定配置文件操作 58 | ``` 59 | nginx -c /tmp/nginx.conf 60 | ``` 61 | 62 | # 重新开始记录日志 63 | ``` 64 | nginx -s reopen 65 | ``` 66 | 其实这个命令就是 67 | ``` 68 | kill -USR1 nginx.pid # nginx.pid为nginx的master进程ID 69 | ``` 70 | 71 | 有时需求为将nginx的access和error日志按小时切割 72 | 73 | 如果access和error日志位置在/tmp目录下 74 | 75 | ``` 76 | 1. mv /tmp/nginx_access.log mv /tmp/nginx_access.log.2018.11.07.11 77 | 2. mv /tmp/nginx_error.log mv /tmp/nginx_error.log.2018.11.07.11 78 | 3.nginx -s reopen 79 | ``` 80 | 执行后,将会在/tmp目录下面再次创建/tmp/nginx_access.log和/tmp/nginx_error.log日志文件 81 | 82 | ## 检测语法错误 83 | ``` 84 | nginx -t 85 | nginx -T 86 | ``` 87 | 这两个命令都可以检测配置文件是否有语法错误 88 | 89 | 一般为先检测语法错误,然后在启动或者重启nginx 90 | 91 | t与T的区别就是,T会显示详细的错误信息 92 | 93 | ## 查看版本信息和编译配置 94 | ``` 95 | nginx -v 96 | nginx -V 97 | ``` 98 | -v可以显示nginx的版本信息 99 | 100 | -V不光可以显示版本信息,还可以显示编译时候的配置、使用的编译gcc版本、OpenSSL信息 101 | ``` 102 | [root@localhost conf]# nginx -V 103 | nginx version: nginx/1.12.2 104 | built by gcc 4.8.5 20150623 (Red Hat 4.8.5-28) (GCC) 105 | built with OpenSSL 1.0.2k-fips 26 Jan 2017 106 | TLS SNI support enabled 107 | configure arguments: --with-http_ssl_module --with-select_module --with-debug 108 | ``` 109 | 110 | ## 热部署 111 | 如果需要升级nginx或者更改编译配置,不需要kill掉nginx的master进程,这样会断开正在连接中的tcp请求,造成短时间内服务器不可用 112 | 113 | 热部署就是在nginx运行期间升级nginx或者更改编译配置,使请求平滑过渡到新的nginx上 114 | 115 | 1.首先我们编译一个nginx,并且运行这个nginx 116 | ``` 117 | cd nginx-1.12.2 118 | ./configure --prefix=/usr/local/nginx && make && make install 119 | /usr/local/nginx/sbin/nginx 120 | ``` 121 | 2.为了模拟热部署操作,我们更改编译配置,再编译一个新的nginx,注意编译后的predix目录为/usr/local/new_nginx 122 | ``` 123 | cd nginx-1.12.2 124 | ./configure --prefix=/usr/local/new_nginx --with-debug && make && make install 125 | ``` 126 | 3.先查看nginx的进程状态,这个运行的nginx是我们第一次编译的nginx,master进程运行PID为28587 127 | ``` 128 | [root@localhost sbin]# ps -ef | grep nginx 129 | root 28587 1 0 14:45 ? 00:00:00 nginx: master process /usr/local/nginx/sbin/nginx 130 | nobody 28588 28587 0 14:45 ? 00:00:00 nginx: worker process 131 | ``` 132 | 4.进行可执行nginx文件(/usr/local/nginx/sbin/nginx)操作 133 | ``` 134 | mv /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx.old 135 | cp /usr/local/new_nginx/sbin/nginx /usr/local/nginx/sbin 136 | ``` 137 | 138 | 5.给正在运行的nginx发送USR2信号 139 | ``` 140 | kill -USR2 28587 141 | ``` 142 | 143 | 6.查看nginx的进程状态,可见有两个master进程了,28587是老的nginx的master进程PID,30186是新的nginx的master进程PID,这时新的连接会进入到新的nginx 144 | ``` 145 | [root@localhost sbin]# ps aux | grep nginx 146 | root 28587 0.0 0.0 20536 796 ? Ss 14:45 0:00 nginx: master process /usr/local/nginx/sbin/nginx 147 | nobody 28588 0.0 0.1 20980 1056 ? S 14:45 0:00 nginx: worker process 148 | root 30186 0.0 0.1 20592 1580 ? S 14:58 0:00 nginx: master process /usr/local/nginx/sbin/nginx 149 | nobody 30187 0.0 0.1 21036 1072 ? S 14:58 0:00 nginx: worker process 150 | ``` 151 | 7.给老的nginx发送WINCH信号 152 | ``` 153 | kill -WINCH 28587 154 | ``` 155 | 8.查看nginx进程信息,老nginx的worker进程已经不存在,老nginx的master还存在的目的是为了热部署回滚用 156 | ``` 157 | [root@localhost sbin]# ps aux | grep nginx 158 | root 28587 0.0 0.0 20536 796 ? Ss 14:45 0:00 nginx: master process /usr/local/nginx/sbin/nginx 159 | root 30186 0.0 0.1 20728 1708 ? S 14:58 0:00 nginx: master process /usr/local/nginx/sbin/nginx 160 | nobody 30196 0.0 0.1 21152 1700 ? S 15:00 0:00 nginx: worker process 161 | ``` 162 | 163 | **注意** 164 | **注意** 165 | **注意** 166 | 167 | 热部署有几个需要非常注意的几点: 168 | 169 | -在进程kill -USR2 操作后,所有的请求都会被新的nginx处理,即使将新的nginx的可执行文件移动到老版本的sbin目录下,但是新的nginx的各种配置还是使用新nginx的目录的nginx.conf,如以上的热部署操作,新请求使用的nginx.conf为/usr/local/new_nginx/conf/nginx.conf;所以在kill -USR2操作前,需要使用老版本的nginx.conf覆盖掉新版本的nginx.conf,如果nginx.conf里面还有include操作,也要复制include的文件到新版本中 170 | 171 | -操作kill -USR2需要找到可执行文件的位置,在查看nginx进程信息的时候会发现"nginx: master process /usr/local/nginx/sbin/nginx",也就是说需要在"/usr/local/nginx/sbin"进行可执行文件的剪切和复制操作,如果启动的时候将nginx可执行文件放到/usr/bin目录下,并且直接使用/usr/bin/nginx来启动,则需要执行 172 | ``` 173 | mv /usr/bin/nginx /usr/bin/nginx.old 174 | cp /usr/local/new_nginx/sbin/nginx /usr/bin/nginx 175 | ``` 176 | -------------------------------------------------------------------------------- /基本命令.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | * [nginx如何处理一个请求](#nginx如何处理一个请求) 3 | * [ngx_http_core_module](#ngx_http_core_module) 4 | * [http](#http) 5 | * [default_type](#default_type) 6 | * [types](#types) 7 | * [root](#root) 8 | * [alias](#alias) 9 | * [error_page](#error_page) 10 | * [try_files](#try_files) 11 | * [merge_slashes](#merge_slashes) 12 | * [location](#location) 13 | * [server_tokens](#server_tokens) 14 | * [client_max_body_size](#client_max_body_size) 15 | * [client_header_timeout](#client_header_timeout) 16 | * [etag](#etag) 17 | * [return](#return) 18 | * [connection_pool_size](#connection_pool_size) 19 | * [interal](#interal) 20 | # nginx如何处理一个请求 21 | 22 | nginx首先选定由那一个虚拟主机来处理请求 23 | ```nginx 24 | server { 25 | listen 80; 26 | server_name a.com b.com; 27 | location / { 28 | return 200 "server_name is a.com b.com"; 29 | } 30 | } 31 | server { 32 | listen 80; 33 | server_name c.com d.com; 34 | location / { 35 | return 500 "server_name is c.com d.com"; 36 | } 37 | } 38 | ``` 39 | 在这个配置中,nginx**仅仅**检查请求的host头以决定该请求由那个虚拟主机来处理,如果host头没有匹配任意一个虚拟主机,或者请求中根本没有包含host头,那nginx会将请求分发到定义在此端口上的默认虚拟主机,第一个被列出的虚拟主机就是nginx的默认虚拟主机。也可以显式的某个虚拟主机为默认虚拟主机(default_server从0.8.21开始使用,在以前版本使用default代替) 40 | ```curl 41 | curl 'http://127.0.0.1' -H 'host: a.com' 42 | ``` 43 | 以上请求的host被指定为a.com,所以匹配到server_name a.com b.com,返回http_code 200,消息体server_name is a.com b.com 44 | ```curl 45 | curl 'http://127.0.0.1' -H 'host: c.com' 46 | ``` 47 | 以上请求的host被指定为c.com,所以匹配到server_name c.com d.com,返回http_code 500,消息体server_name is c.com d.com 48 | ```curl 49 | curl 'http://127.0.0.1' -H 'host: xxx.com' 50 | ``` 51 | 以上请求的host被指定为xxx.com,没有server_name与其匹配,所以nginx会将请求分发到定义在此端口上的默认虚拟主机(第一个被列出的),返回http_code 200,消息体server_name is a.com b.com 52 | 53 | 如果将nginx配置改为 54 | ```nginx 55 | server { 56 | listen 80; 57 | server_name a.com b.com; 58 | location / { 59 | return 200 "server_name is a.com b.com"; 60 | } 61 | } 62 | server { 63 | listen 80 default_server; 64 | server_name c.com d.com; 65 | location / { 66 | return 500 "server_name is c.com d.com"; 67 | } 68 | } 69 | ``` 70 | ```curl 71 | curl 'http://127.0.0.1' -H 'host: xxx.com' 72 | ``` 73 | 以上请求的host被指定为xxx.com,没有server_name与其匹配,所以nginx会将请求分发到定义在此端口上的默认虚拟主机(default_server定义的),返回http_code 500,消息体server_name is c.com d.com 74 | ```nginx 75 | server { 76 | listen 80; 77 | server_name ""; 78 | return 444; 79 | } 80 | server { 81 | listen 80; 82 | server_name c.com d.com; 83 | location / { 84 | return 500 "server_name is c.com d.com"; 85 | } 86 | } 87 | ``` 88 | 设置主机名为空字符串以匹配未定义Host头的请求,而且返回了一个nginx特有的,非http标准码444,可以用来关闭连接 89 | ```curl 90 | curl 'http://127.0.0.1' -H 'host: xxx.com' 91 | ``` 92 | 返回curl: (52) Empty reply from server 93 | 94 | 不是一定要返回444,可以根据自身的业务需求来处理逻辑,比如我要返回"没有host头与之匹配" 95 | ```nginx 96 | server { 97 | listen 80; 98 | server_name ""; 99 | return 200 "没有host头与之匹配"; 100 | } 101 | server { 102 | listen 80; 103 | server_name c.com d.com; 104 | location / { 105 | return 500 "server_name is c.com d.com"; 106 | } 107 | } 108 | ``` 109 | 从0.8.48版本开始,server_name "" 以成为主机名的默认设置,所以可以省略server_name "" 110 | ```nginx 111 | server { 112 | listen 192.168.1.111:80; 113 | server_name a.com; 114 | ... 115 | } 116 | server { 117 | listen 192.168.1.112:80; 118 | server_name b.com; 119 | ... 120 | } 121 | ``` 122 | 上面的配置中,nginx首先检查请求的IP地址和端口是否匹配某个server块中的listen指令配置。接着nginx继续测试请求host头是否匹配这个server块中的某个server_name值,如果没有匹配则将这个请求交给默认主机。 123 | 124 | **默认服务器是监听端口的属性,所以不同的监听端口可以设置不同的默认服务器** 125 | 126 | # ngx_http_core_module 127 | ## http 128 | ``` 129 | Syntax: http { ... } 130 | Default: — 131 | Context: main 132 | ``` 133 | 为服务器提供配置文件上下文 134 | 135 | 如一个简单的配置示例 136 | ``` 137 | http{ 138 | include mime.types; 139 | server { 140 | listen 80; 141 | root /tmp; 142 | location / { 143 | return 200 "test"; 144 | } 145 | } 146 | } 147 | ``` 148 | ## default_type 149 | ``` 150 | Syntax: default_type mime-type; 151 | Default: default_type text/plain; 152 | Context: http, server, location 153 | ``` 154 | 该指令应该和types指令配合学习 155 | 156 | 定义**默认**响应类型(Content-Type),**默认**的意思就是文件的扩展名不在nginx定义的MIME映射表里 157 | 158 | 例外:如请求一个*.php文件,php扩展名不在MIME映射表,不会走default_type,因为php主动响应了Content-Type 159 | 160 | ```nginx 161 | root /tmp; 162 | index a.html; 163 | default_type text/plain; 164 | location / { 165 | return 200 123; 166 | } 167 | ``` 168 | ``` 169 | curl -v 'http://127.0.0.1' 170 | ``` 171 | 以上会输出服务器响应结果,可见响应Content-Type: text/plain 172 | ```nginx 173 | root /tmp; 174 | index a.html; 175 | default_type a/b; 176 | location / { 177 | return 200 123; 178 | } 179 | ``` 180 | ``` 181 | curl -v 'http://127.0.0.1' 182 | ``` 183 | 以上会输出服务器响应结果,可见响应Content-Type: a/b 184 | ```nginx 185 | root /tmp; 186 | index a.html; 187 | default_type a/b; 188 | location / { 189 | # 这里什么都不写 190 | } 191 | ``` 192 | ``` 193 | curl -v 'http://127.0.0.1' 194 | ``` 195 | 执行命令echo "file is a.html" > /tmp/a.html,请求后响应Content-Type: text/html,不会执行default_type命令,因为会查看a.html,文件后缀html与imme.types里面的text/html html htm shtml;相匹配 196 | 197 | ## types 198 | ``` 199 | Syntax: types { ... } 200 | Default: types { 201 | text/html html; 202 | image/gif gif; 203 | image/jpeg jpg; 204 | } 205 | Context: http, server, location 206 | ``` 207 | 设置文件扩展名和响应的MIME类型的映射表,可以将多个扩展名映射到同一种类型 208 | 209 | nginx都会有一行include mime.types;的,可以去mime.types里面查看映射信息,里面包含了足够多的类型 210 | 211 | 如果不想使用mime.types,而为所有请求都响应唯一的Content-Type,可以使用如下配置 212 | ```nginx 213 | location / { 214 | types {} 215 | default_type application/json; 216 | } 217 | ``` 218 | 219 | ## root 220 | ``` 221 | Syntax: root path; 222 | Default: 223 | root html; 224 | Context: http, server, location, if in location 225 | ``` 226 | 仅仅是将uri拼到root值的后面 227 | 228 | path值可以是变量,但是不能是$document_root和$realpath_root;因为$document_root和$realpath_root是根据root或者alias来定义的 229 | 230 | 如果nginx的编译路径是/usr/local/nginx,则默认的寻找的文件目录位置是/usr/local/nginx/html(因为root默认值是html) 231 | ```nginx 232 | root /tmp; 233 | location /a { 234 | return 200 $request_filename; 235 | } 236 | ``` 237 | ```curl 238 | curl 'http://127.0.0.1/a/b' 239 | ``` 240 | 会输出/tmp/a/b 241 | 242 | 如果想要输出根目录 243 | ```nginx 244 | root /tmp; 245 | location /a { 246 | return 200 $document_root; 247 | } 248 | ``` 249 | 会输出/tmp 250 | 251 | 如果想要输出请求文件的真实目录 252 | ```nginx 253 | root /tmp; 254 | location /a { 255 | return 200 $request_filename; 256 | } 257 | ``` 258 | 259 | ## alias 260 | ``` 261 | Syntax: alias path; 262 | Default: — 263 | Context: location 264 | ``` 265 | path值可以是变量,但是不能是$document_root和$realpath_root;因为$document_root和$realpath_root是根据root或者alias来定义的 266 | 267 | 指定一个指定路径的替换路径 268 | 269 | alias和rewrite不能同时出现 270 | ```nginx 271 | location /a { 272 | alias /tmp; 273 | return 200 $request_filename; 274 | } 275 | ``` 276 | ```curl 277 | curl 'http://127.0.0.1/a/b' 278 | ``` 279 | 会输出/tmp/b 280 | ```nginx 281 | merge_slashes on; 282 | location /a/ { 283 | alias /tmp; 284 | return 200 $request_filename; 285 | } 286 | ``` 287 | ```curl 288 | curl 'http://127.0.0.1/a/b' 289 | ``` 290 | 会输出/tmpb 291 | ```nginx 292 | location / { 293 | alias /tmp; 294 | return 200 $request_filename; 295 | } 296 | ``` 297 | ```curl 298 | curl 'http://127.0.0.1/a/b' 299 | ``` 300 | 会输出/tmp/a/b 301 | ```nginx 302 | root /tmp 303 | location /a { 304 | alias /tmp; 305 | return 200 $request_filename; 306 | } 307 | location /x { 308 | return 200 $request_filename; 309 | } 310 | ``` 311 | ```curl 312 | curl 'http://127.0.0.1/x/y' 313 | ``` 314 | 会输出/tmp/x/y 315 | 316 | ```curl 317 | curl 'http://127.0.0.1/a/b 318 | ``` 319 | 会输出/tmp/b 320 | ## error_page 321 | ``` 322 | Syntax: error_page code ... [=[response]] uri; 323 | Default: — 324 | Context: http, server, location, if in location 325 | ``` 326 | 为错误定义显示的URI或者状态码 327 | 如果是fastcgi的服务器,则需要设置fastcgi的配置fastcgi_intercept_errors on; 328 | ```nginx 329 | root /tmp; 330 | error_page 404 /b; 331 | location / { 332 | return 404 /ii; 333 | } 334 | location /b { 335 | return 404 123; 336 | } 337 | ``` 338 | 请求uri为/,会被location /匹配,返回404到error_page,error_page将uri变成/b重新查找location,找到location /b返回123,不会造成死循环 339 | ```nginx 340 | root /tmp; 341 | location /a { 342 | error_page 404 /b; 343 | } 344 | location /b { 345 | return 200 123; 346 | } 347 | ``` 348 | 如果请求uri为/a,出现404,则uri变为/b,重新查找location,返回123;对于http_code,即使return 200,最后的结果也是404 349 | ```nginx 350 | root /tmp; 351 | location /a { 352 | error_page 404 /b; 353 | } 354 | ``` 355 | 如果请求uri为/a,出现404,则uri变为/b,查找/tmp/b,返回/tmp/b的文件内容;对于http_code,即使return 200,最后的结果也是404 356 | 357 | ```nginx 358 | location / { 359 | error_page 500 502 503 504 /50x.html; 360 | } 361 | ``` 362 | 对于http_code500 502 503 504,使用error_page 363 | 364 | ```nginx 365 | location /a { 366 | error_page 404 =200 /200.html; 367 | } 368 | ``` 369 | 370 | 如果发生404,则error_page执行后的响应码是200,**注意404后面有一个空格** 371 | 372 | ```nginx 373 | location /a { 374 | error_page 404 = /200.php; 375 | } 376 | ``` 377 | 如果URI将被发送到一个被代理的服务器处理,或者发送到一个FastCGI服务器处理,这些后端服务器又返回了不同的响应码,那么这些响应码可以由根据被处理后的结果展现,以上配置的最终响应码取决于/200.php,**注意等号两面都有空格** 378 | ```nginx 379 | error_page 404 =200 /b; 380 | location /a { 381 | return 404 123; 382 | } 383 | location /b { 384 | #找不到页面 385 | } 386 | ``` 387 | 请求uri为/a,会被error_page请求到location /b,即使404 =200最后也会返回404,因为页面找不到 388 | 389 | ```nginx 390 | location /a { 391 | error_page 404 http://127.0.0.1:81/a; 392 | } 393 | location /b { 394 | error_page 404 =200 http://127.0.0.1:81/b; 395 | } 396 | ``` 397 | 也可以进行重定向 398 | ```nginx 399 | location /a { 400 | error_page 404 @back; 401 | } 402 | location @back { 403 | return 200 $uri; 404 | } 405 | ``` 406 | 如果不希望error_page改变uri,可以将错误转到一个命名路径,比如uri /a发生404,则跳转到location @back,最后返回/a,uri不会改变 407 | 408 | **如果不存在location @back,则会发生500 Internal Server Error** 409 | 410 | ## try_files 411 | ``` 412 | Syntax: try_files file ... uri; 413 | try_files file ... =code; 414 | Default: — 415 | Context: server, location 416 | ``` 417 | 按照指定顺序检查文件是否存在,并且使用第一个找到的文件来处理请求。文件路径是根据root和alias指令,将file参数拼接而成 418 | 419 | 如果找不到,则按最后一个参数指定的uri进行内部跳转 420 | ``` 421 | server{ 422 | root /tmp; 423 | index index.html; 424 | location / { 425 | try_files "/a" "/b"; 426 | } 427 | } 428 | ``` 429 | ``` 430 | curl 'http://127.0.0.1' 431 | ``` 432 | 创建echo "123" > a,uri为"/",try_files会找/tmp/a,这个文件,返回文件内容123 433 | 434 | 如果/tmp/a文件不存在,则会将请求uri变成/b,重新查找location,以上配置会返回http_code500,因为进入查找死循环 435 | 436 | 不能将"/a"改为"a",这样会查找/tmpa文件,也不能将"/b"改为"b",这样会将uri变成"b",正确的uri应该是"/b" 437 | 438 | try_files指令的优先级是大于index指令的 439 | ``` 440 | server{ 441 | root /tmp; 442 | index index.html; 443 | location / { 444 | try_files "/a" "/b"; 445 | } 446 | location /b{ 447 | return 200 "location b"; 448 | } 449 | } 450 | ``` 451 | 如果存在/tmp/index.html,请求uri为"/",不会查找/tmp/index.html,会直接找/tmp/a,找不到在继续找location /b 452 | ``` 453 | server{ 454 | root /tmp; 455 | index index.html; 456 | location / { 457 | try_files "/a" "/b" "/c" "/d"; 458 | } 459 | } 460 | ``` 461 | 以上配置,会查找/tmp/a、/tmp/b、/tmp/c文件,如果有一个找到则停止查找;如果都找不到则uri变成/d 462 | 463 | ``` 464 | server{ 465 | root /tmp; 466 | index index.html; 467 | location / { 468 | try_files "/a" "/d" =404; 469 | } 470 | } 471 | ``` 472 | 以上配置,会查找/tmp/a文件,如果都找不到则uri变成/d,并且响应码为http_code 404 473 | 474 | ## merge_slashes 475 | ``` 476 | Syntax: merge_slashes on | off; 477 | Default: merge_slashes on; 478 | Context: http, server 479 | ``` 480 | 开启或者关闭将请求中URI相邻的两个或者更多斜线合并成一个的功能 481 | 压缩URI对于前缀匹配和正则匹配的正确性是很重要的,没有开启这个功能时,请求//script/one.php不能被location /scripts/匹配 482 | 如果URI中包含base64编码内容,必须将斜线压缩调整成off,因为base64编码本身会使用"/"字符,然而出于安全方面的考虑,最好还是不要关闭压缩 483 | ```nginx 484 | merge_slashes on; 485 | location / { 486 | return 200 $uri; 487 | } 488 | ``` 489 | ```curl 490 | curl 'http://127.0.0.1/a//b' 491 | ``` 492 | 会输出/a/b 493 | 494 | ## location 495 | ``` 496 | Syntax: location [ = | ~ | ~* | ^~ ] uri { ... } location @name { ... } 497 | Default: — 498 | Context: server, location 499 | ``` 500 | 根据请求的URI来设置配置 501 | * \~ 执行一个正则匹配,区分大小写,**匹配成功则停止,和顺序有关** 502 | * \~ \* 执行一个正则匹配,不区分大小写,**匹配成功则停止,和顺序有关** 503 | * ^~ 前缀匹配,区分大小写,**匹配成功则停止** 504 | * = 精准匹配,区分大小写,**匹配成功则停止** 505 | * /abc 常规字符串匹配,**如果有多个能匹配的话,使用匹配最长的那个,和顺序无关** 506 | * @ 定义一个命名的location,使用在内部定向时,如error_page 507 | 508 | 优先级:(从高到低) 509 | * = 510 | * ^~ 511 | * \~ \* \~ 512 | * /abc 513 | 514 | ```nginx 515 | location = /ab { 516 | return 200 "= /ab" 517 | } 518 | location /a { 519 | return 200 "/a" 520 | } 521 | location /ab { 522 | return 200 "/ab" 523 | } 524 | ``` 525 | ```curl 526 | curl 'http://127.0.0.1/a' 527 | ``` 528 | 返回http_code 200,消息体/a 529 | ```nginx 530 | location /a { 531 | return 200 "/a" 532 | } 533 | location /ab { 534 | return 200 "/ab" 535 | } 536 | ``` 537 | ```curl 538 | curl 'http://127.0.0.1/ab' 539 | ``` 540 | 返回http_code 200,消息体/ab 541 | ```nginx 542 | location /a { 543 | return 200 "/a" 544 | } 545 | location /ab { 546 | return 200 "/ab" 547 | } 548 | ``` 549 | ```curl 550 | curl 'http://127.0.0.1/ab' 551 | ``` 552 | 返回http_code 200,消息体/ab 553 | ```nginx 554 | location = /ab { 555 | return 200 "= /ab" 556 | } 557 | location ^~ /ab { 558 | return 200 "^~ /ab" 559 | } 560 | ``` 561 | ```curl 562 | curl 'http://127.0.0.1/ab' 563 | ``` 564 | 返回http_code 200,消息体= /ab 565 | ```nginx 566 | location ~ /ab { 567 | return 200 "~ /ab" 568 | } 569 | location ~* /ab { 570 | return 200 "~* /ab" 571 | } 572 | ``` 573 | ```curl 574 | curl 'http://127.0.0.1/aB' 575 | ``` 576 | 返回http_code 200,消息体~\* ab 577 | 578 | **=与^~不支持正则** 579 | ```nginx 580 | location = /abc$ { # $不是正则的结束标志 581 | return 200 $uri; 582 | } 583 | ``` 584 | 可以使用前缀字符串或者正则表达式定义路径。使用正则表达式需要在路径开始添加"\~\*"前缀 (不区分大小写),或者"\~"前缀(区分大小写)。为了根据请求URI查找路径,nginx先检查前缀字符串定义的路径 (前缀路径),在这些路径中找到能最精确匹配请求URI的路径。然后nginx按在配置文件中的出现顺序检查正则表达式路径, 匹配上某个路径后即停止匹配并使用该路径的配置,否则使用最大前缀匹配的路径的配置 585 | 586 | **~与*~匹配成功则不继续匹配,并且和location的顺序有关** 587 | ```nginx 588 | location ~ /a { 589 | return 200 aaa; 590 | } 591 | location ~ /ab { 592 | return 200 bbb; 593 | } 594 | ``` 595 | 请求uri为/abc则返回aaa 596 | 597 | ```nginx 598 | location ~ /ab { 599 | return 200 111; 600 | } 601 | location ~ /a { 602 | return 200 222; 603 | } 604 | ``` 605 | 请求uri为/abc则返回111 606 | **注意** 607 | 608 | **^~ /a与/a不能同时写,会报错** 609 | ```nginx 610 | location = /a { 611 | return 200 $uri; 612 | } 613 | location ^~ /a { 614 | return 200 $uri; 615 | } 616 | ``` 617 | ```nginx 618 | nginx: [emerg] duplicate location "/a" 619 | ``` 620 | 621 | **^~与普通匹配都能匹配的情况,按照匹配的长度来** 622 | ```nginx 623 | location /ab { 624 | return 200 111; 625 | } 626 | location ^~ /a { 627 | return 200 222; 628 | } 629 | ``` 630 | 请求uri为/abc,会返回111,请求uri为akl,会返回222 631 | ```nginx 632 | location /a { 633 | return 200 111; 634 | } 635 | location ^~ /ab { 636 | return 200 222; 637 | } 638 | ``` 639 | 请求uri为/abc,会返回222,请求uri为a,会返回111 640 | 641 | 642 | 路径匹配在URI**规范化**以后进行,所谓规范化,就是先将URI中形如"%XX"的编码字符进行编码,再解析URI中的相对路径"."和".."部分,另外还可能会压缩相邻的两个或多个斜线成为一个斜线(需要merge_slashes on;) 643 | ```nginx 644 | location /abc+ { 645 | return 200 $uri; 646 | } 647 | ``` 648 | ```curl 649 | curl 'http://127.0.0.1/abc%2B' 650 | ``` 651 | 因为请求URI会规范化,所以将/abc%2B解析成/abc+,返回http_code 200,消息体/abc+ 652 | ```nginx 653 | location /a { 654 | return 200 $uri; 655 | } 656 | ``` 657 | ```curl 658 | curl 'http://127.0.0.1/b/../a' 659 | ``` 660 | 因为请求URI会规范化,所以将/b/../a解析成/a,返回http_code 200,消息体/a 661 | 路径可以嵌套 662 | ```nginx 663 | location /{ 664 | location /a { 665 | return 200 "a"; 666 | } 667 | location /b { 668 | return 200 "b"; 669 | } 670 | } 671 | ``` 672 | ```curl 673 | curl 'http://127.0.0.1/a' 674 | ``` 675 | 返回http_code 200,消息体/a 676 | 677 | 如果请求"\/"出现频繁,定义"location \= \/"可以提高这些请求的处理速度, 因为查找过程在第一次比较以后即结束 678 | ```nginx 679 | server { 680 | listen 80; 681 | location /a/ { 682 | proxy_pass http://127.0.0.1:81/b; 683 | } 684 | } 685 | server { 686 | listen 81; 687 | location / { 688 | return 200 $uri; 689 | } 690 | } 691 | ``` 692 | ```curl 693 | curl 'http://127.0.0.1/a' 694 | ``` 695 | 返回http_code 301 696 | ```nginx 697 | server { 698 | listen 80; 699 | location /a { 700 | proxy_pass http://127.0.0.1:81/b; 701 | } 702 | } 703 | server { 704 | listen 81; 705 | location / { 706 | return 200 $uri; 707 | } 708 | } 709 | ``` 710 | ```curl 711 | curl 'http://127.0.0.1/a' 712 | ``` 713 | 返回http_code 200,响应体/b 714 | 715 | ```nginx 716 | root /tmp; 717 | index index.css; 718 | server { 719 | listen 80; 720 | location / { 721 | 722 | } 723 | location /index.css { 724 | return 200 123; 725 | } 726 | } 727 | ``` 728 | 请求uri为/,则uri变为/index.css,查找location /index.css,即使有/tmp/index.css,最后也会返回return 200 123 729 | 730 | ## server_tokens 731 | ``` 732 | Syntax: server_tokens on | off | build | string; 733 | Default: server_tokens on; 734 | Context: http, server, location 735 | ``` 736 | 开启或者关闭在响应头中输出nginx版本号 737 | ``` 738 | HTTP/1.1 200 OK 739 | Server: nginx/1.14.0 740 | ``` 741 | 参数build,如果编译时候configure -–build=8,则 742 | ``` 743 | HTTP/1.1 200 OK 744 | Server: nginx/1.14.0 (8) 745 | ``` 746 | 参数off会不显示具体nginx版本 747 | ``` 748 | HTTP/1.1 200 OK 749 | Server: nginx 750 | ``` 751 | 参数string在商业版本中使用 752 | 753 | ## client_max_body_size 754 | ``` 755 | Syntax: client_max_body_size size; 756 | Default: client_max_body_size 1m; 757 | Context: http, server, location 758 | ``` 759 | 760 | 设置允许客户端请求正文的最大长度,请求长度由Content-Length请求头指定。如果超过设定值,将返回413(Request Entity Too Large)。浏览器不能正确显示这个错误。size为0可以使nginx不检查客户端请求正文长度 761 | 762 | 当实际传的正文大于nginx限制,但是重写Content-Length,不会报错 763 | 764 | ``` 765 | curl 'http://127.0.0.1' -H 'Content-Length: 1234 766 | ``` 767 | 默认值1m的可接受最大Content-Length为1048576 768 | 769 | ## client_header_timeout 770 | ``` 771 | Syntax: client_header_timeout time; 772 | Default: client_header_timeout 60s; 773 | Context: http, server 774 | ``` 775 | 定义读取客户端请求头部的超时。如果客户端在这段时间内没有传送完整的头部到nginx, nginx将返回错误408 (Request Time-out)到客户端 776 | 777 | ## etag 778 | ``` 779 | Syntax: etag on | off; 780 | Default: etag on; 781 | Context: http, server, location 782 | ``` 783 | 开启或者关闭静态文件自动计算etag响应头 784 | 785 | 只是在静态文件中有效 786 | 787 | 默认情况下,请求静态文件会响应etag头,如ETag: "5bc887e1-2" 788 | 789 | ## return 790 | ``` 791 | Syntax: return code [text]; 792 | return code URL; 793 | return URL; 794 | Default: — 795 | Context: server, location, if 796 | 797 | ``` 798 | 停止处理并返回指定code给客户端 799 | 800 | 该指令在debug的时候非常有用,比如nginx请求一个404的页面,如果想要知道nginx到底请求了什么路径,可以 801 | ``` 802 | server { 803 | listen 80; 804 | location / { 805 | return 200 $request_filename; 806 | } 807 | } 808 | ``` 809 | 在fastcgi下,也可以 810 | ``` 811 | server { 812 | listen 80; 813 | location / { 814 | fastcgi_pass http://127.0.0.1:9000; 815 | include fastcgi.conf; 816 | return 200 $document_root$fastcgi_script_name; 817 | } 818 | } 819 | ``` 820 | 可以返回各种nginx内部定义好的,和自己定义的变量 821 | ``` 822 | server { 823 | listen 80; 824 | set $name 123; 825 | location / { 826 | return 200 $name; 827 | } 828 | } 829 | ``` 830 | 返回非标准状态码444可以直接关闭连接而不返回响应头 831 | ``` 832 | server { 833 | listen 80; 834 | location / { 835 | return 444; 836 | } 837 | } 838 | ``` 839 | 请求127.0.0.1:80,请求过程为 840 | ``` 841 | * Rebuilt URL to: http://127.0.0.1/ 842 | * Trying 127.0.0.1... 843 | * TCP_NODELAY set 844 | * Connected to 127.0.0.1 (127.0.0.1) port 80 (#0) 845 | > GET / HTTP/1.1 846 | > Host: 127.0.0.1 847 | > User-Agent: curl/7.61.0 848 | > Accept: */* 849 | > 850 | * Empty reply from server 851 | * Connection #0 to host 127.0.0.1 left intact 852 | curl: (52) Empty reply from server 853 | ``` 854 | ``` 855 | server { 856 | listen 80; 857 | location / { 858 | return 444 "abc"; 859 | } 860 | } 861 | ``` 862 | 请求127.0.0.1:80,请求过程为 863 | ``` 864 | * Rebuilt URL to: http://127.0.0.1/ 865 | * Trying 127.0.0.1... 866 | * TCP_NODELAY set 867 | * Connected to 127.0.0.1 (127.0.0.1) port 80 (#0) 868 | > GET / HTTP/1.1 869 | > Host: 127.0.0.1 870 | > User-Agent: curl/7.61.0 871 | > Accept: */* 872 | > 873 | < HTTP/1.1 444 874 | < Server: nginx/1.12.2 875 | < Date: Tue, 06 Nov 2018 13:04:21 GMT 876 | < Content-Type: text/plain 877 | < Content-Length: 3 878 | < Connection: keep-alive 879 | < 880 | * Connection #0 to host 127.0.0.1 left intact 881 | abc 882 | ``` 883 | 884 | 可以在指令中指定重定向的URL(0.8.42版本之后),状态码为301、302、303和307,或者指定响应体文本 885 | 886 | return http:\/\/uri 响应码为302 887 | 888 | 0.7.51版本以前只能返回204、400、402-406、408、410、411、413、416和500-504 889 | 890 | 直到1.1.16和1.0.13版本,307才被认为是一种重定向 891 | 892 | 1.13.0可以返回308 893 | ``` 894 | server { 895 | listen 80; 896 | location / { 897 | return http://127.0.0.1:81; 898 | } 899 | } 900 | ``` 901 | 请求127.0.0.1:80,会返回响应码302,如果请求支持重定向(如 curl -L ),则重定向到127.0.0.1:81 902 | 903 | **注意** 904 | 905 | 对于return重定向,要么写成return http:\/\/url这种形式,要么写成return 302 http:\/\/url这种形式(或者将302换成301、307) 906 | 907 | 如果return 200 http:\/\/url,则不会重定向,响应码是200,响应body体是"http:\/\/url" 908 | 909 | ## connection_pool_size 910 | ``` 911 | Syntax: connection_pool_size size; 912 | Default: connection_pool_size 256|512; 913 | Context: http, server 914 | ``` 915 | 允许微调为每个连接分配的内存,这个指令对nginx的性能影响非常小,一般不应该使用 916 | 917 | 默认值256在32位系统,512在64位系统 918 | 919 | ## interal 920 | 921 | ``` 922 | Syntax: internal; 923 | Default: - 924 | Context: location 925 | ``` 926 | 指定一个路径是否只能用于内部访问,如果是外部访问,客户端将收到404 927 | ``` 928 | server { 929 | listen 80; 930 | location / { 931 | internal; 932 | return 200 "test"; 933 | } 934 | } 935 | ``` 936 | 请求127.0.0.1:80,返回的响应码为404而不是200 937 | 938 | 内部访问是 939 | - error_page、index、random_index、和try_files指令引起的重定向 940 | - 由后端服务器返回的X-Accel-Redirect响应头引起的重定向 941 | - 由ngx_http_ssi_module和ngx_http_addition_module模块的include virtual指令产生的子请求 942 | - 用rewrite指令对请求进行修改 943 | 944 | nginx限制每个请求只能最多进行10次内部重定向,以防配置错误引起请求处理出现问题,如果已经达到10次,nginx将返回500,同时日志中有rewrite or internal redirection cycle 945 | -------------------------------------------------------------------------------- /日志管理.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | * [error_log](#error_log) 3 | * [log_format](#log_format) 4 | * [access_log](#access_log) 5 | * [log_not_found](#log_not_found) 6 | 7 | # error_log 8 | ``` 9 | Syntax: error_log file [level]; 10 | Default: error_log logs/error.log error; 11 | Context: main, http, mail, stream, server, location 12 | ``` 13 | 日志级别严重性从轻到重顺序:debug、info、notice、warn、error、crit、alert、emerg 14 | 15 | 如果file设置为stderr,nginx将会将日志输出到标准错误输出 16 | 17 | 设置某个日志级别将会使指定级别和更高级别的日志都被记录下来,如指定error会使nginx记录所有的error、crit、alert、emerg级别消息 18 | 19 | debug日志级别需要configure --with-debug 20 | 21 | 特殊file值stderr可以将error_log输出到标准错误输出中,不过需要nignx的守护进程设置为off(damemon off;) 22 | 23 | # log_format 24 | ``` 25 | Syntax: log_format name [escape=default|json|none] string ...; 26 | Default: log_format combined "..."; 27 | Context: http 28 | ``` 29 | 定义日志的格式,access_log默认使用的日志格式名字叫combined,可以定一个名字叫test的日志格式,然后让access_log使用test的日志格式 30 | 31 | nginx有一个默认的日志combined 32 | ``` 33 | log_format combined '$remote_addr - $remote_user [$time_local] ' 34 | '"$request" $status $body_bytes_sent ' 35 | '"$http_referer" "$http_user_agent"'; 36 | ``` 37 | 38 | # access_log 39 | ``` 40 | Syntax: access_log path [format [buffer=size] [gzip[=level]] [flush=time] [if=condition]]; 41 | access_log off; 42 | Default: access_log logs/access.log combined; 43 | Context: http, server, location, if in location, limit_except 44 | ``` 45 | ``` 46 | server{ 47 | access_log /tmp/nginx.access combined buffer=64k gzip=9 flush=1m; 48 | } 49 | ``` 50 | 参数: 51 | - path:指定记录日志的位置 52 | - format:指定记录日志内容的格式,由log_format指定,默认的format名字为combined 53 | - buffer:指定缓存buffer大小,buffer的大小不能超过磁盘原子性写入大小 54 | - gzip:指定缓存压缩,如果gzip参数被使用,则buffer数据会先被压缩,然后再写入文件。gzip参数可以指定为1-9,1为最快,9最慢但是压缩比最大。默认情况下,gizp为1 55 | - flush:指定缓存到期时间,flush=1m为1分钟(如果达到1分钟,不管buffer满没满都将缓存写进日志文件) 56 | - 57 | 58 | 为访问日志设置路径、格式和缓冲区大小。在同一个配置层级里可以指定多个日志,特定值off会取消当前配置层级里面的所有access_log。如果没有指定日志格式则会使用预定义的combined 59 | 60 | 请求在处理结束时,会按请求路径的配置记录访问日志,如果请求处理期间产生了内部跳转,请求结束时的路径可能不同于原始的请求路径 61 | 62 | - 如果请求location a;在location a里面发生内部跳转到location b;在location b里面重新定义access_log或者error_log等,则location a里面的不会生效 63 | 64 | - 如果在location a里面proxy pass到location b,则a和b的都会记录,并且a的http_code是b给返回的 65 | ``` 66 | server{ 67 | location /a { 68 | access_log /tmp/a; 69 | rewrite ^/(.*)$ /b last; #请求这里会改变uri为/b,并且发生重新请求到location /b 70 | } 71 | location /b { 72 | access_log /tmp/b; 73 | } 74 | } 75 | ``` 76 | 以上只有access_log /tmp/b会生效 77 | 78 | ``` 79 | server{ 80 | location /a { 81 | access_log /tmp/a; 82 | proxy_pass http://127.0.0.1/b; #发生请求到location /b 83 | } 84 | location /b { 85 | access_log /tmp/b; 86 | } 87 | } 88 | ``` 89 | 以上access_log /tmp/b和access_log /tmp/a都会生效 90 | 91 | 92 | 如果指定gzip**或者**buffer参数,则写操作会被缓存 93 | 94 | 如果写操作缓存被使用,以下会发生实际写入文件的操作 95 | - 下一个日志没有被缓存 96 | - 如果到了flush指定的时间 97 | - 达到指定的buffer大小 98 | - 工作进程关闭或者打开(kill掉工作进程) 99 | 100 | 101 | 如果指定了缓存或者gzip,还指定了flush=1m,则在缓存不超缓存大小的情况下,会在1分钟后写入日志 102 | 103 | 如果日志数据被压缩,查看日志文件需要使用zcat filename 104 | 105 | 为了支持gzip功能,系统必须有zlib library模块 106 | 107 | 如果access_log的路径值使用变量,则不能使用buffer、gzip、flush,否则会报错 108 | 109 | 如果将nginx日志删掉,启动nginx和reload会新建这个日志文件;如果在运行期间删除nginx文件,则新请求不会创建nginx日志文件;日志路径包含变量的话,会在运行期间创建文件 110 | 111 | 如果运行期间日志被删除,则可以使用kill -USR1 nginx进程号 来创建nginx日志,-USR1对日志切割同样管用 112 | 113 | 在日志切割中,如果剪切access_log到access_log.old文件,然后给nginx的master进程发送-USR1信号,如果日志缓存启用,则日志缓存不管有没有到期或者达到buffer指定的大小,都缓存会写进access_log.old文件中 114 | 115 | **注意**,如果更改access_log的format,则要使用log_format定义,然后再使用 116 | 117 | ``` 118 | server{ 119 | log_format test '$remote_addr $status'; 120 | access_log /tmp/nginx_access.log test; 121 | } 122 | ``` 123 | **压缩的access日志解压** 124 | 可以使用gunzip来解压 125 | 126 | 1.cp nginx_access.log access.log.gz 127 | 128 | 2.gunzip access.log.gz 129 | 130 | 如果日志里面有gzip的内容,也有开启gzip前的明文内容,则无法解压 131 | 132 | # log_not_found 133 | ``` 134 | Syntax: log_not_found on | off; 135 | Default: 136 | log_not_found on; 137 | Context: http, server, location 138 | ``` 139 | 如果为on,当静态资源发生404的时候,会在error_log日志中记录error级别的错误信息 140 | ``` 141 | 2019/05/28 16:42:17 [error] 2941#0: *9 open() "/tmp/aa.php" failed (2: No such file or directory), client: 127.0.0.1, server: , request: "GET /aa.php HTTP/1.1", host: "127.0.0.1" 142 | 143 | ``` 144 | 即使为off,在请求fastcgi情况下发生404,也会记录错误信息 145 | ``` 146 | 2019/05/28 16:41:24 [error] 2923#0: *5 FastCGI sent in stderr: "Primary script unknown" while reading response header from upstream, client: 127.0.0.1, server: , request: "GET /aa.php HTTP/1.1", upstream: "fastcgi://127.0.0.1:9000", host: "127.0.0.1" 147 | ``` 148 | -------------------------------------------------------------------------------- /连接处理方法IO.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | * [概述](#概述) 3 | * [几种可选方法介绍](#几种可选方法介绍) 4 | * [use](#use) 5 | * [如何查看当前nginx的IO方法](#如何查看当前nginx的IO方法) 6 | 7 | # 概述 8 | nginx支持多种连接处理IO方法,特定IO方法的可用性取决于所使用的平台。如果平台支持多种IO方法,nginx会自动选择最有效的IO方法。但是,如果需要的话,也可以通过指令use指定具体的IO方法 9 | 10 | 如果不指定use,则选择系统和nginx可以支持的最优IO模型 11 | 12 | configure编译选项中可以选择--without-poll_module、--with-poll_module、--without-select_module、--with-select_module使其强制使用或者禁止使用某IO模型 13 | 14 | 如果使用--without-select_module,则不可以使用use select指令了,报错提示:invalid event type "select" 15 | 16 | 如果使用--with-select_module,则可以使用use epoll指令,最后nginx使用的是epoll的IO模型 17 | 18 | # 几种可选方法介绍 19 | **select** 20 | 21 | 标准方法。如果平台没有更有效的方法的话,则这个方法会自动被选择和构建 22 | 23 | **poll** 24 | 25 | 标准方法。如果平台没有更有效的方法的话,则这个方法会自动被选择和构建 26 | 27 | **kqueue** 28 | 29 | 优先选择的有效方法(在FreeBSD 4.1+,OpenBSD 2.9+,NetBSD 2.0和macOS平台上) 30 | 31 | **epoll** 32 | 33 | 优先选择的有效方法(在Linux 2.6+平台上) 34 | 35 | **/dev/poll** 36 | 37 | 优先选择的有效方法(在Solaris 7 11/99+,HP/UX 11.22+ (eventport),IRIX 6.5.15+,和Tru64 UNIX 5.1A+平台上) 38 | 39 | **eventport** 40 | 41 | 建议使用/dev/poll替代,该IO模型用于Solaris 10+ 42 | 43 | # use 44 | ``` 45 | Syntax: use method; 46 | Default: — 47 | Context: events 48 | ``` 49 | ``` 50 | events{ 51 | use select; 52 | #use epoll; 53 | } 54 | ``` 55 | 通常不会指定,因为nginx会默认选择最优的方案 56 | 57 | # 如何查看当前nginx的IO方法 58 | 59 | ``` 60 | server{ 61 | ... 62 | error_log /tmp/nginx_error.log debug; #注意,debug级别需要configure --with-debug 63 | ... 64 | } 65 | ``` 66 | 可以指定error_log为debug级别,然后会有debug信息 67 | ``` 68 | 2018/10/23 23:27:40 [debug] 90859#0: epoll add event: fd:7 op:1 ev:00002001 69 | ``` 70 | --------------------------------------------------------------------------------