Fork me on GitHub

随笔分类 - nginx

nginx笔记-location优先级

[TOC] 网上查了下location的优先级规则,但是很多资料都说的模棱两可,自己动手实地配置了下,下面总结如下。 # 1. 配置语法 1> 精确匹配 ``` location = /test { ... } ``` 2> 前缀匹配 - 普通前缀匹配 ``` location /test { ... } ``` - 优先前缀匹配 ``` location ^~ /test { ... } ``` 3> 正则匹配 - 区分大小写 ``` location ~ /test$ { ... } ``` - 不区分大小写 ``` location ~* /test$ { ... } ``` # 2. 配置实例 1> 多个前缀匹配,访问/test/a,则先记住最长的前缀匹配,并继续匹配 ``` location / { root html; index index.html index.htm; } location /test { return 601; } location /test/a { return 602; } ``` 命中的响应状态码 ``` 602 ``` 2> 前缀匹配和正则匹配,访问/test/a,则命中正则匹配 ``` location / { root html; index index.html index.htm; } location /test/a { return 601; } location ~* /test/a$ { return 602; } ``` 命中的响应状态码 ``` 602 ``` 3> 优先前缀匹配和正则匹配,访问/test/a,则命中优先前缀匹配,终止匹配 ``` location / { root html; index index.html index.htm; } location ^~ /test/a { return 601; } location ~* /test/a$ { return 602; } ``` 命中的响应状态码 ``` 601 ``` 4> 多个正则匹配命中,访问/test/a,则使用第一个命中的正则匹配,终止匹配 ``` location / { root html; index index.html index.htm; } location ~* /a$ { return 601; } location ~* /test/a$ { return 602; } ``` 命中的响应状态码 ``` 601 ``` 5> 精确匹配和正则匹配,访问/test,精确匹配优先 ``` location / { root html; index index.html index.htm; } location ~* /test { return 602; } location = /test { return 601; } ``` 命中的响应状态码 ``` 601 ``` # 3. 总结: - 搜索优先级: ``` 精确匹配 > 字符串匹配( 长 > 短 [ 注: ^~ 匹配则停止匹配 ]) > 正则匹配( 上 > 下 ) ``` - 使用优先级: ``` 精确匹配 > (^~) > 正则匹配( 上 > 下 )>字符串(长 > 短) ``` 解释: - 先搜索有没有精确匹配,如果匹配就命中,终止匹配。 - 索前缀匹配,命中则先记住(可能命中多个),继续往下搜索,如果有优先前缀匹配符号“^~”,则命中优先前缀匹配,不再去检查正则表达式;反之则继续进行正则匹配,如果命中则使用正则表达式,如果没命中则使用最长的前缀匹配。 - 前缀匹配,长的优先;多个正则匹配,在上面的优先。

nginx笔记-pagespeed使用详解

[TOC] # 1.简介 PageSpeed 是一个款Google开源(Google出品必输竞品)用来自动优化网站的神器!,作为Nginx组件,ngx_pagespeed将重写你的网页,让用户以更快的速度进行访问。重写的工作包括压缩图片、缩减CSS和JavaScript、扩展缓存时间 # 2.安装 官方安装讲解:[地址](https://www.modpagespeed.com/doc/build_ngx_pagespeed_from_source) ## 2.1脚本安装 可以选择使用自动脚本,可以到的一个对应的nginx版本,并且编译了pagespeed模块 ### 查看该脚本的如何使用 ``` $ bash <(curl -f -L -sS https://ngxpagespeed.com/install) --help Usage: build_ngx_pagespeed.sh [options] Installs ngx_pagespeed and its dependencies. Can optionally build and install nginx as well. Can be run either as: bash <(curl -f -L -sS https://ngxpagespeed.com/install) [options] Or: git clone [email protected]:pagespeed/ngx_pagespeed.git cd ngx_pagespeed/ git checkout <branch> scripts/build_ngx_pagespeed.sh [options] Options: -v, --ngx-pagespeed-version <ngx_pagespeed version> What version of ngx_pagespeed to build. Valid options include: * latest-beta * latest-stable * a version number, such as 1.11.33.4 If you don't specify a version, defaults to latest-stable unless --devel is specified, in which case it defaults to master. This option doesn't make sense if we're running within an existing ngx_pagespeed checkout. -n, --nginx-version <nginx version> What version of nginx to build. If not set, this script only prepares the ngx_pagespeed module, and expects you to handle including it when you build nginx. If you pass in 'latest' then this script scrapes the nginx download page and attempts to determine the latest version automatically. -m, --dynamic-module Build ngx_pagespeed as a dynamic module. -b, --builddir <directory> Where to build. Defaults to $HOME. -p, --no-deps-check By default, this script checks for the packages it depends on and tries to install them. If you have installed dependencies from source or are on a non-deb non-rpm system, this won't work. In that case, install the dependencies yourself and pass --no-deps-check. -s, --psol-from-source Build PSOL from source instead of downloading a pre-built binary module. -l, --devel Sets up a development environment in ngx_pagespeed/nginx, building with testing-only dependencies. Includes --psol-from-source, conflicts with --nginx-version. Uses a 'git clone' checkout for ngx_pagespeed and nginx instead of downloading a tarball. -t, --build-type When building PSOL from source, what to tell it for BUILD_TYPE. Defaults to 'Release' unless --devel is set in which case it defaults to 'Debug'. -y, --assume-yes Assume the answer to all prompts is 'yes, please continue'. Intended for automated usage, such as buildbots. -a, --additional-nginx-configure-arguments When running ./configure for nginx, you may want to specify additional arguments, such as --with-http_ssl_module. By default this script will pause and prompt you for them, but this option lets you pass them in. For example, you might do: -a '--with-http_ssl_module --with-cc-opt="-I /usr/local/include"' -d, --dryrun Don't make any changes to the system, just print what changes you would have made. -h, --help Print this message and exit. ``` ### 使用脚本自动安装 我们主要使用`--nginx-version` `--additional-nginx-configure-arguments` `--dynamic-module`这三个参数,选择nginx的版本,编译的参数,使用动态模块 ``` bash <(curl -f -L -sS https://ngxpagespeed.com/install) \ --nginx-version 1.12.1 \ --dynamic-module \ --additional-nginx-configure-arguments '--prefix=/usr/share/nginx --sbin-path=/usr/sbin/nginx --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --http-client-body-temp-path=/var/lib/nginx/tmp/client_body --http-proxy-temp-path=/var/lib/nginx/tmp/proxy --http-fastcgi-temp-path=/var/lib/nginx/tmp/fastcgi --http-uwsgi-temp-path=/var/lib/nginx/tmp/uwsgi --http-scgi-temp-path=/var/lib/nginx/tmp/scgi --modules-path=/usr/lib64/nginx/modules --pid-path=/run/nginx.pid --lock-path=/run/lock/subsys/nginx --user=nginx --group=nginx --with-file-aio --with-ipv6 --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-http_addition_module --with-http_auth_request_module --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_random_index_module --with-http_secure_link_module --with-http_degradation_module --with-http_stub_status_module --with-http_slice_module --with-mail=dynamic --with-mail_ssl_module --with-stream_ssl_module --with-threads --with-pcre --with-debug --with-cc-opt="-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -m64 -mtune=generic"' ``` 脚本运行结果 类似下面 ``` test -f '/etc/nginx/nginx.conf' \ || cp conf/nginx.conf '/etc/nginx/nginx.conf' cp conf/nginx.conf '/etc/nginx/nginx.conf.default' test -d '/run' \ || mkdir -p '/run' test -d '/var/log/nginx' \ || mkdir -p '/var/log/nginx' test -d '/usr/share/nginx/html' \ || cp -R html '/usr/share/nginx' test -d '/var/log/nginx' \ || mkdir -p '/var/log/nginx' test -d '/usr/lib64/nginx/modules' \ || mkdir -p '/usr/lib64/nginx/modules' test ! -f '/usr/lib64/nginx/modules/ngx_mail_module.so' \ || mv '/usr/lib64/nginx/modules/ngx_mail_module.so' \ '/usr/lib64/nginx/modules/ngx_mail_module.so.old' cp objs/ngx_mail_module.so '/usr/lib64/nginx/modules/ngx_mail_module.so' make[1]: Leaving directory `/root/nginx-1.12.1' Nginx installed with ngx_pagespeed support compiled-in. If this is a new installation you probably need an init script to manage starting and stopping the nginx service. See: http://wiki.nginx.org/InitScripts You'll also need to configure ngx_pagespeed if you haven't yet: https://developers.google.com/speed/pagespeed/module/configuration ``` 此时的变化是在相应的文件夹有个编译好的nginx,还有个编译好的ngx_pagespeed,进入相应文件夹,我使用的是root账户,这里是/root下,多了两个文件夹 ``` incubator-pagespeed-ngx-latest-stable nginx-1.12.1 ``` `/root/nginx-1.12.1/objs/nginx` 其实就是编译好的nginx可执行文件 `/root/nginx-1.12.1/objs/ngx_pagespeed.so` 是相应的模块 ### 替换以前的nginx (如果以前有yum安装,并且还想使用以前的启动脚本等,可以考虑替换,可以节省精力) 下面就是替换我以前使用yum安装的nginx, ``` cp /usr/sbin/nginx /usr/sbin/nginx.bak #备份 cp /opt/nginx-1.12.1/objs/nginx /usr/sbin/nginx #替换程序 cp /opt/nginx-1.12.1/objs/ngx_pagespeed.so /usr/share/nginx/modules/ #替换模块 systemctl restart nginx #重启 nginx 服务 ``` 对于使用动态模块,需要在主配置文件引入该模块才可以正常使用 ``` load_module "modules/ngx_pagespeed.so"; ``` 这里讲一下使用yum安装pagespeed的另一种情形 可能你已经使用yum安装了nginx,并且有很多依赖重新编译可能会通过不了,并且发现已经自带编译了ngx_pagespeed,但是这个模块其实并没有真正下载,并不能直接使用,这种情况下,只要按照该源的说明,安装该模块即可,进入相关源的页面,https://webtatic.com/packages/nginx1/ 查看,然后安装该模块,这样做也很方便 ``` yum install nginx1w-module-pagespeed ``` ## 2.2 手动安装 ### 先安装基本依赖 ``` sudo yum install gcc-c++ pcre-devel zlib-devel make unzip libuuid-devel ``` ### 构建pagespeed ``` cd /root wget https://github.com/pagespeed/ngx_pagespeed/archive/release-1.6.29.5-beta.zip unzip -q release-1.6.29.5-beta cd ngx_pagespeed-release-1.6.29.5-beta wget https://dl.google.com/dl/page-speed/psol/1.6.29.5.tar.gz tar xzf 1.6.29.5.tar.gz -C ngx_pagespeed-release-1.6.29.5-beta ``` ### 重新编译安装nginx 查看原Nginx配置 ``` $ nginx -V nginx version: nginx/1.12.1 built by gcc 4.8.5 20150623 (Red Hat 4.8.5-16) (GCC) built with OpenSSL 1.0.2k-fips 26 Jan 2017 TLS SNI support enabled configure arguments: --prefix=/usr/share/nginx --sbin-path=/usr/sbin/nginx --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --http-client-body-temp-path=/var/lib/nginx/tmp/client_body --http-proxy-temp-path=/var/lib/nginx/tmp/proxy --http-fastcgi-temp-path=/var/lib/nginx/tmp/fastcgi --http-uwsgi-temp-path=/var/lib/nginx/tmp/uwsgi --http-scgi-temp-path=/var/lib/nginx/tmp/scgi --modules-path=/usr/lib64/nginx/modules --pid-path=/run/nginx.pid --lock-path=/run/lock/subsys/nginx --user=nginx --group=nginx --with-file-aio --with-ipv6 --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-http_addition_module --with-http_auth_request_module --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_random_index_module --with-http_secure_link_module --with-http_degradation_module --with-http_stub_status_module --with-http_slice_module --with-mail=dynamic --with-mail_ssl_module --with-stream_ssl_module --with-threads --with-pcre --with-debug --with-cc-opt="-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -m64 -mtune=generic" ``` 下载对应的源码,知道yum 安装nginx 的版本为1.12.1,下载对应的源码 ``` wget http://nginx.org/download/nginx-1.12.1.tar.gz ``` 原配置基础上增加pagespeed模块、 ``` ./configure --prefix=/usr/share/nginx --sbin-path=/usr/sbin/nginx --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log ... --add-module=/root/incubator-pagespeed-ngx-latest-stable ``` 注意:如果你想要使用动态模块安装,则使用下面参数 ``` --add-dynamic-module=/root/incubator-pagespeed-ngx-latest-stable ``` 编译 ``` make && make install ``` 同样,如果有需要,可对执行文件进行备份替换,(根据自己实际情况) ``` cp /usr/sbin/nginx /usr/sbin/nginx.bak #备份 cp /opt/nginx-1.12.1/objs/nginx /usr/sbin/nginx #替换 # 如果是动态模块,同时需要 cp /opt/nginx-1.12.1/objs/ngx_pagespeed.so /usr/share/nginx/modules/ systemctl restart nginx #重启 nginx 服务 ``` # 3.配置 官方介绍:[文档地址](https://www.modpagespeed.com/doc/) ## 3.1 开启,待机,关闭 ### 开启 开启或关闭用 pagespeed on/off; 指令,例如: ``` load_module "modules/ngx_pagespeed.so"; http { ... } server { listen 80; pagespeed on; pagespeed FileCachePath /tmp/ngx_pagespeed_cache; ... } ``` ### 备机 pagespeed有一个备机模式,它不会改变你网站的原有配置,只有在以下两种情况下才会起作用 1、当你的请求带着关于pagespeed的参数的时候,这时候会按照参数的配置返回给你响应。 2、当请求.pagespeed类的资源的时候。 ``` pagespeed standby; ``` ### 关闭 ``` pagespeed unplugged; ``` 注意:在1.12.34.1或更早版本以前,不要使用unlugged,会导致崩溃,请使用off ## 3.2 功能配置 ### Content-Security-Policy 头部 从1.13.35.1开始,PageSpeed能够根据响应头中指定的任何内容安全策略调整其优化。在这个版本中,您需要选择加入这个特性,未来的版本可能会默认打开它。 ``` pagespeed HonorCsp on; ``` ### HTTP Vary 协议 为了达到优化的最大效果,对于资源文件(css、js,HTML 文件除外)等,PageSpeed 是不遵循 Vary HTTP 头的,如果你希望 PageSpeed 完全遵守 Vary 协议,可以使用指令 `pagespeed RespectVary on`,不过除非有特殊需求,建议不开启,默认配置往往是最佳配置。关于 Vary 大体的意思是就是 Vary 可以标示同一个 url 可以返回不同的内容,主要是给缓存中间件用的,避免只缓存单一内容。 ### Cache-Control: no-transform 协议 PageSpeed 默认遵守 Cache-Control: no-transform 协议, 表示不可被中间代理软件改写,如果想让优化效果最大化,可以这样: pagespeed DisableRewriteOnNoTransform off; 该指令,表示不遵守 Cache-Control: no-transform 协议。 ### LowercaseHtmlNames HTML是不区分大小写的,而XML和XHTML不是。Web性能最佳实践建议使用小写。一般来说,pagespeed会根据头信息自动判断是不是html页面,但是有时候xml或者xhtml会使用错误的头信息`Content-Type: text/html `,此时如果开启了转换成小写,那么当时xml和xhtml的时候可能会出现问题,所以pagespeed默认是不开启的。 ``` pagespeed LowercaseHtmlNames on; ``` ### ModifyCachingHeaders PageSpeed 默认情况下会修改 HTML 页面汇总的 Meta 缓存标记,将其统一执为 `Cache-Control: no-cache, max-age=0`,如果要保留 HTML 页面原始的缓存控制指令,可以这样: ``` pagespeed ModifyCachingHeaders off; ``` 不过官方并不建议关闭该指令,官方解释如下: ``` Note: We do not suggest you turn this option off. It breaks PageSpeed's caching assumptions and can lead to unoptimized HTML being served from a proxy caches set up in front of the server. If you do turn it off, we suggest that you do not set long caching headers to HTML or users may receive stale or unoptimized content. ``` ### 保留相对路径 默认情况下,PageSpeed 在优化时会把相对路径转成绝对路径,如果因此而产生问题,你可以使用如下指令来保留相对路径 ``` pagespeed PreserveUrlRelativity on; ``` NOTE: 官方文档上说,未来会默认保留相对路径,而且将来也会移除该指令。 ### 开启 debug 功能 ListOutstandingUrlsOnError 可以列出优化过程中所有失败的请求,debug 时很有用,失败的信息会打印到 error log 里。 ``` pagespeed ListOutstandingUrlsOnError on; ``` ### https支持 如果你使用 https 协议,则需要加上如下指令之后,某些过滤器才能生效,从1.10版本开始,默认(fetchhttps是开启的) ``` pagespeed FetchHttps enable; ``` 可以添加更多参数 ``` pagespeed FetchHttps enable,allow_self_signed,allow_unknown_certificate_authority,allow_certificate_not_yet_valid; ``` ### 开启gzip 开启gzip压缩后,后会减少网络资源传输的字节,参考示例: ``` pagespeed FetchWithGzip on; gzip on; gzip_vary on; # Turn on gzip for all content types that should benefit from it. gzip_types application/ecmascript; gzip_types application/javascript; gzip_types application/json; gzip_types application/pdf; gzip_types application/postscript; gzip_types application/x-javascript; gzip_types image/svg+xml; gzip_types text/css; gzip_types text/csv; # "gzip_types text/html" is assumed. gzip_types text/javascript; gzip_types text/plain; gzip_types text/xml; gzip_http_version 1.0; ``` ## 3.3 管理页面 PageSpeed 还提供了一个 web 的管理员界面来进行监控管理,很方便 配置如下: http下配置 ``` #PageSpeed管理页面配置 #共享内存统计 pagespeed Statistics on; #开启虚拟主机统计信息 pagespeed UsePerVhostStatistics on; pagespeed StatisticsLogging on; pagespeed StatisticsLoggingIntervalMs 60000; pagespeed StatisticsLoggingMaxFileSizeKb 1024; #消息缓冲区大小,默认为0,不保留消息 pagespeed MessageBufferSize 100000; pagespeed LogDir /var/log/pagespeed; pagespeed StatisticsPath /ngx_pagespeed_statistics; pagespeed GlobalStatisticsPath /ngx_pagespeed_global_statistics; pagespeed MessagesPath /ngx_pagespeed_message; pagespeed ConsolePath /pagespeed_console; pagespeed AdminPath /pagespeed_admin; pagespeed GlobalAdminPath /pagespeed_global_admin; ``` server下配置 ``` # admin页面 location /ngx_pagespeed_statistics { auth_basic "PageSpeed Admin Dashboard"; auth_basic_user_file /etc/nginx/page_speed/.htpasswd; } location /ngx_pagespeed_global_statistics { auth_basic "PageSpeed Admin Dashboard"; auth_basic_user_file /etc/nginx/page_speed/.htpasswd; } location /ngx_pagespeed_message { auth_basic "PageSpeed Admin Dashboard"; auth_basic_user_file /etc/nginx/page_speed/.htpasswd; } location /pagespeed_console { auth_basic "PageSpeed Admin Dashboard"; auth_basic_user_file /etc/nginx/page_speed/.htpasswd; } location ~ ^/pagespeed_admin { auth_basic "PageSpeed Admin Dashboard"; auth_basic_user_file /etc/nginx/page_speed/.htpasswd; } location ~ ^/pagespeed_global_admin { auth_basic "PageSpeed Admin Dashboard"; auth_basic_user_file /etc/nginx/page_speed/.htpasswd; } ``` 创建用户认证文件,`/etc/nginx/page_speed/.htpasswd`,使用htpasswd生成用户名和密码 ``` # 创建auth用户 htpasswd -bc .passwd archer 123456 ``` 直接访问 <域名>/pagespeed_admin 就可以打开管理员界面了。 提一下相关知识: 1、ngx_http_auth_basic_module模块 `ngx_http_auth_basic_module`模块实现让访问者,只有输入正确的用户密码才允许访问web内容。web上的一些内容不想被其他人知道,但是又想让部分人看到。默认情况下nginx已经安装了`ngx_http_auth_basic_module`模块。 2、htpasswd的用法 ``` htpasswd(选项)(参数) ``` ``` -c:创建一个加密文件; -n:不更新加密文件,只将加密后的用户名密码显示在屏幕上; -m:默认采用MD5算法对密码进行加密; -d:采用CRYPT算法对密码进行加密; -p:不对密码进行进行加密,即明文密码; -s:采用SHA算法对密码进行加密; -b:在命令行中一并输入用户名和密码而不是根据提示输入密码; -D:删除指定的用户。 ``` 页面类似下面这样,我们可以在管理页面,查看过滤器的效果,查看日志,清除缓存。。。 ![](http://markdown.archerwong.cn/2019-01-01-22-11-19_clipboard.png) ## 3.4 过滤规则 ### 过滤级别 PageSpeed提供了三个“级别”来简化配置:`PassThrough`、`CoreFilters`和`OptimizeForBandwidth`。CoreFilters集合包含PageSpeed团队认为对大多数web站点是安全的过滤器,并且是默认级别。`OptimizeForBandWidth` 更保守些,更安全。这里的安全是指对原始内容的改变是否会影响页面的展示、效果、功能等等。 这个链接有`CoreFilters`和`OptimizeForBandwidth`级别的对比,[Enabling, Disabling, And Forbidding Specific Filters](https://www.modpagespeed.com/doc/config_filters#enabling) `CoreFilters`级别包括以下过滤器 ``` add_head combine_css combine_javascript convert_meta_tags extend_cache fallback_rewrite_css_urls flatten_css_imports inline_css inline_import_to_link inline_javascript rewrite_css rewrite_images rewrite_javascript rewrite_style_attributes_with_url ``` ### 可以选择关闭或者开启某些过滤器 ``` # 禁用CoreFilters中的某些过滤器 pagespeed DisableFilters rewrite_images; # 选择性地启用额外的过滤器 pagespeed EnableFilters collapse_whitespace; #禁用过滤器用 pagespeed ForbidFilters rewrite_css,rewrite_javascript; #禁用所有关闭的过滤器: pagespeed ForbidAllDisabledFilters true; ``` 关闭意思是不自动使用,但是我们可以通过输入url参数来继续使用该过滤器,关闭则是彻底禁止,即使url参数输入也不能使用。 ### 可以通过 url 参数来动态控制过滤器 例如: ``` http://modpagespeed.com/rewrite_css.html?PageSpeed=on&PageSpeedFilters=rewrite_css ``` 开启过滤器用参数 PageSpeed=on, 过滤器列表用参数 PageSpeedFilters,多个过滤器用“,” 分割。 ### 部分配置简介 参考: https://www.ngxpagespeed.com/ ``` ####### CSS ############ # 把多个CSS文件合并成一个CSS文件,减少 HTTP 请求数量。 pagespeed EnableFilters combine_css; # combine_css配合MaxCombinedCssBytes参数使用,影响combine_css的参数 MaxBytes是组合CSS文件的最大字节大小。大于MaxBytes的CSS文件将保持完整;其他CSS文件将被组合成一个或多个文件,每个文件的大小都不超过MaxBytes。MaxBytes的当前默认值是-1(无限制) pagespeed MaxCombinedJsBytes MaxBytes; # 通过删除 CSS 文件中的@import,减少 HTTP 请求往返次数。 pagespeed EnableFilters flatten_css_imports; # 最小化 css 文件,去掉多余的空格和换行,并删除注释 pagespeed EnableFilters rewrite_css; # 重写CSS,首先加载渲染页面的CSS规则 pagespeed EnableFilters prioritize_critical_css; # 将小的 css 文件已内联方式引入,避免 http 请求。 inline_css # 将 css 内容移动到 script 之前,优先于 script 渲染。 move_css_above_scripts #将 css 文件移到头部。显示优先,让用户体验更好。 move_css_to_head ####### JS ############ # 启用JavaScript库卸载,通过自动把流行的 JavaScript 库换成免费托管的 JavaScript 库(比如由谷歌托管),减少带宽使用量 pagespeed EnableFilters canonicalize_javascript_libraries; # 把多个JavaScript文件合并成一个JavaScript文件,减少 HTTP 请求数量。 pagespeed EnableFilters combine_javascript; # combine_javascript配合MaxCombinedJsBytes参数使用,该参数是组合JavaScript文件的最大未压缩大小(以字节为单位)。大于MaxBytes的JavaScript文件将保持完整;其他JavaScript文件将组合成一个或多个文件,每个文件的大小不超过MaxBytes。MaxBytes的当前默认值是92160 (90K)。 pagespeed MaxCombinedJsBytes MaxBytes; # 启用JavaScript缩小机制 ,相当于rewrite_javascript_inline(内部脚本)和rewrite_javascript_external(外部脚本) pagespeed EnableFilters rewrite_javascript; #将小的 js 文件已内联方式引入,避免 http 请求。 inline_javascript ####### IMAGE ############ # 延时加载客户端看不见的图片 pagespeed EnableFilters lazyload_images; # 启用图片优化机制 pagespeed EnableFilters rewrite_images; #将小图片的 http 调用转成内联方式调用。 inline_images #存在多个相同的内联图片的话,通过 js 控制,只保留第一个内联的数据。这样可以删除重复数据,较小页面体积。经常和 inline_images 过滤器配合使用。 dedup_inlined_images # 自动将多张背景图片合并成一张图片。在处理一些图标图片时很有用。 sprite_images ####### 其它 ############ # 启用压缩空白过滤器 pagespeed EnableFilters collapse_whitespace; # 将多个 head 标签合并成一个。 pagespeed EnableFilters combine_heades; # 删除带默认属性的标签,缩小文档大小 pagespeed EnableFilters elide_attributes; # 通过优化网页资源的可缓存性,减少带宽使用量 pagespeed EnableFilters extend_cache; # 移除 HTML 中的注释 remove_comments # 移除 HTML 属性中的不必要的引号。 remove_quotes ``` # 4. 配置实例 /etc/nginx/page_speed/pagespeed_main.conf ``` pagespeed on; #启用PageSpeed Gzip请求资源,此项要求ng启用gzip pagespeed FetchWithGzip on; #配置筛选项默认CoreFilters pagespeed RewriteLevel CoreFilters; #是否尊重原始header,为了达到优化最大效果,官方建议不开启 pagespeed RespectVary off; # ···是否让PageSpeed优化缓存时间(接管缓存控制) pagespeed DisableRewriteOnNoTransform off; #重写HTML缓存头,官方不建议关闭,默认会统计执行为Cache-Control: no-cache, max-age=0 pagespeed ModifyCachingHeaders on; #列出未解决的错误 pagespeed ListOutstandingUrlsOnError on; # ···限制资源最大值启用优化,默认大小16M pagespeed MaxCacheableContentLength 16777216; # 单个js文件最大大小,配合combine_javascript使用,该数值过小会引起js文件不合并 pagespeed MaxCombinedJsBytes 921600; #配置共享内存元数据缓存 pagespeed CreateSharedMemoryMetadataCache "/var/cache/pagespeed/" 51200; #配置文件高速缓存 pagespeed FileCachePath /var/cache/pagespeed; pagespeed FileCacheSizeKb 102400; pagespeed FileCacheCleanIntervalMs 3600000; pagespeed FileCacheInodeLimit 500000; # 为了优化性能,可以写LRU缓存,nginx使用更少的进程,LRUCacheKbPerProcess可以适当大点 pagespeed LRUCacheKbPerProcess 8192; pagespeed LRUCacheByteLimit 16384; #缓存清除,比较方便的管理方式是,通过admin页面管理(自己可以通过配置开启) pagespeed EnableCachePurge on; pagespeed PurgeMethod PURGE; #PageSpeed管理页面配置 #共享内存统计 pagespeed Statistics on; #开启虚拟主机统计信息 pagespeed UsePerVhostStatistics on; pagespeed StatisticsLogging on; pagespeed StatisticsLoggingIntervalMs 60000; pagespeed StatisticsLoggingMaxFileSizeKb 1024; #消息缓冲区大小,默认为0,不保留消息 pagespeed MessageBufferSize 100000; pagespeed LogDir /var/log/pagespeed; pagespeed StatisticsPath /ngx_pagespeed_statistics; pagespeed GlobalStatisticsPath /ngx_pagespeed_global_statistics; pagespeed MessagesPath /ngx_pagespeed_message; pagespeed ConsolePath /pagespeed_console; pagespeed AdminPath /pagespeed_admin; pagespeed GlobalAdminPath /pagespeed_global_admin; ``` /etc/nginx/page_speed/pagespeed_server.conf ``` # 禁用CoreFilters中的某些过滤器 # pagespeed DisableFilters rewrite_images; # 选择性地启用额外的过滤器 pagespeed EnableFilters remove_comments; pagespeed EnableFilters collapse_whitespace; pagespeed EnableFilters prioritize_critical_css; # 直接获取HTTPS资源,允许自签名证书资源,1.10版本后FetchHttps是默认开启的 pagespeed FetchHttps enable,allow_self_signed; # 启用测量客户端加载和呈现页面所花费的时间 pagespeed EnableFilters add_instrumentation; #预处理DNS pagespeed EnableFilters insert_dns_prefetch; # 确保对pagespeed优化资源的请求进入pagespeed处理程序并且没有额外的头部信息 location ~ "\.pagespeed\.([a-z]\.)?[a-z]{2}\.[^.]{10}\.[^.]+" { add_header "" ""; } # admin页面 location /ngx_pagespeed_statistics { auth_basic "PageSpeed Admin Dashboard"; auth_basic_user_file /etc/nginx/page_speed/.htpasswd; } location /ngx_pagespeed_global_statistics { auth_basic "PageSpeed Admin Dashboard"; auth_basic_user_file /etc/nginx/page_speed/.htpasswd; } location /ngx_pagespeed_message { auth_basic "PageSpeed Admin Dashboard"; auth_basic_user_file /etc/nginx/page_speed/.htpasswd; } location /pagespeed_console { auth_basic "PageSpeed Admin Dashboard"; auth_basic_user_file /etc/nginx/page_speed/.htpasswd; } location ~ ^/pagespeed_admin { auth_basic "PageSpeed Admin Dashboard"; auth_basic_user_file /etc/nginx/page_speed/.htpasswd; } location ~ ^/pagespeed_global_admin { auth_basic "PageSpeed Admin Dashboard"; auth_basic_user_file /etc/nginx/page_speed/.htpasswd; } ``` 同时为了优化动态文件,加入了以下命令 ``` pagespeed LoadFromFile "https://www.archerwong.cn/public/" "/data/gopath/src/z-blog/public/"; pagespeed LoadFromFile "https://archerwong.cn/public/" "/data/gopath/src/z-blog/public/"; pagespeed LoadFromFileRuleMatch disallow .*; pagespeed LoadFromFileRuleMatch allow \.css$; pagespeed LoadFromFileRuleMatch allow \.jpe?g$; pagespeed LoadFromFileRuleMatch allow \.png$; pagespeed LoadFromFileRuleMatch allow \.gif$; pagespeed LoadFromFileRuleMatch allow \.js$; ``` # 5. 其他 可以根据[PageSpeed Insights](https://developers.google.com/speed/pagespeed/insights)的评测来定向更改自己的网站。 ![](http://markdown.archerwong.cn/2019-01-01-22-11-30_clipboard.png) 开启pagespeed的效果,比较直观的是多个css文件合并成了一个请求,多个js文件也合并成了一个请求 ![](http://markdown.archerwong.cn/2019-01-01-22-11-43_clipboard.png) # 参考 https://www.coderxing.com/nginx-pagespeed-module.html

nginx笔记-error_page

# 1. error_page语法 语法: ``` error_page code [ code... ] [ = | =answer-code ] uri | @named_location ``` 默认值: ``` no ``` 使用字段: ``` http, server, location, location 中的if字段 ``` # 2. 实例 nginx指令error_page的作用是当发生错误的时候能够显示一个预定义的uri,比如: ``` error_page 502 503 /50x.html; location = /50x.html { root /usr/share/nginx/html; } ``` 这样实际上产生了一个内部跳转(internal redirect),当访问出现502、503的时候就能返回50x.html中的内容,这里需要注意是否可以找到50x.html页面,所以加了个location保证找到你自定义的50x页面。 同时我们也可以自己定义这种情况下的返回状态吗,比如: ``` error_page 502 503 =200 /50x.html; location = /50x.html { root /usr/share/nginx/html; } ``` 这样用户访问产生502 、503的时候给用户的返回状态是200,内容是50x.html。 当error_page后面跟的不是一个静态的内容的话,比如是由proxyed server或者FastCGI/uwsgi/SCGI server处理的话,server返回的状态(200, 302, 401 或者 404)也能返回给用户。 ``` error_page 404 = /404.php; location ~ \.php$ { fastcgi_pass 127.0.0.1:9000; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } ``` 也可以设置一个named location,然后在里边做对应的处理。 ``` error_page 500 502 503 504 @jump_to_error; location @jump_to_error { proxy_pass http://backend; } ``` 同时也能够通过使客户端进行302、301等重定向的方式处理错误页面,默认状态码为302。 ``` error_page 403 http://example.com/forbidden.html; error_page 404 =301 http://example.com/notfound.html; ``` 同时error_page在一次请求中只能响应一次,对应的nginx有另外一个配置可以控制这个选项:`recursive_error_pages ` 默认为false,作用是控制error_page能否在一次请求中触发多次。 # 2. Nginx 自定义404错误页面配置中有无等号的区别 - error_page 404 /404.html 可显示自定义404页面内容,正常返回404状态码。 - error_page 404 = /404.html 可显示自定义404页面内容,但返回200状态码。 - error_page 404 /404.php 如果是动态404错误页面,包含 header 代码(例如301跳转),将无法正常执行。正常返回404代码。 - error_page 404 = /404.php 如果是动态404错误页面,包含 header 代码(例如301跳转),加等号配置可以正常执行,返回php中定义的状态码。但如果php中定义返回404状态码,404状态码可以正常返回,但无法显示自定义页面内容(出现系统默认404页面),这种情况可以考虑用410代码替代( header("HTTP/1.1 410 Gone"); 正常返回410状态码,且可正常显示自定义内容)。

nginx笔记-proxy_cache缓存详解

[TOC] # 1. 关于缓冲区指令 ## 1.1 proxy_buffer_size ``` 语法: proxy_buffer_size size; 默认值: proxy_buffer_size 4k|8k; 上下文: http, server, location ``` 1. 该缓冲用于来自上游服务器响应的开始部分,在该部分通常包含一个小小的响应头 2. 该缓冲区大小默认等于proxy_buffers指令设置的一块缓冲区的大小,没有必要也跟着设置太大。 proxy_buffer_size最好单独设置,一般设置个4k就够了,但它也可以被设置得更小。 3. 一块缓冲区的大小通常等于一个内存页的大小(4K或者8K),获取Linux 内存页(基页)大小的命令:`getconf PAGE_SIZE `,一般的输出是4096,即 4KB。 ## 1.2 proxy_buffering ``` 语法: proxy_buffering on | off; 默认值: proxy_buffering on; 上下文: http, server, location ``` 1. 该指令控制缓冲是否启用。默认情况下,它的值是“on”。如果这个设置为off,那么proxy_buffers和proxy_busy_buffers_size这两个指令将会失效。 但是无论proxy_buffering是否开启,对proxy_buffer_size配置都会起作用。 2. 当开启缓冲时,nginx尽可能快地从被代理的服务器接收响应,再将它存入proxy_buffer_size和proxy_buffers指令设置的缓冲区中。如果响应无法整个纳入内存,那么其中一部分将存入磁盘上的临时文件,某些请求的响应过大,则超过_buffers的部分将被缓冲到硬盘, 当然这将会使读取响应的速度减慢, 影响用户体验。通过proxy_max_temp_file_size和proxy_temp_file_write_size指令可以控制临时文件的写入。 3. 当关闭缓冲时,收到响应后,nginx立即将其同步传给客户端。nginx不会尝试从被代理的服务器读取整个请求,而是将proxy_buffer_size指令设定的大小作为一次读取的最大长度(所以无论是否开启,proxy_buffer_size都起作用)。每次传输内容小了,效率肯定会有影响。 4. 响应头“X-Accel-Buffering”传递“yes”或“no”可以动态地开启或关闭代理的缓冲功能。 这个能力可以通过proxy_ignore_headers指令关闭。 proxy_buffering启用时,要提防使用的代理缓冲区太大。这可能会吃掉你的内存,限制代理能够支持的最大并发连接数。 ## 1.3 proxy_buffers ``` 语法: proxy_buffers number size; 默认值: proxy_buffers 8 4k|8k; 上下文: http, server, location ``` 1. 为每个连接设置缓冲区的数量为number,每块缓冲区的大小为size。这些缓冲区用于保存从被代理的服务器读取的响应。 2. proxy_buffers的缓冲区大小一般会设置的比较大,以应付大网页。proxy_buffers当中单个缓冲区的大小是由系统的内存页面大小决定的,Linux系统中一般为4k。 proxy_buffers由缓冲区数量和缓冲区大小组成的。总的大小为number*size。 ## 1.4 proxy_busy_buffers_size ``` 语法: proxy_busy_buffers_size size; 默认值: proxy_busy_buffers_size 8k|16k; 上下文: http, server, location ``` 1. 当开启缓冲响应的功能以后,在没有读到全部响应的情况下,写缓冲到达一定大小时,nginx一定会向客户端发送响应,直到缓冲小于此值。这条指令用来设置此值。 2. 同时,剩余的缓冲区可以用于接收响应,如果需要,一部分内容将缓冲到临时文件。该大小默认是proxy_buffer_size和proxy_buffers指令设置单块缓冲大小的两倍。 ## 1.5 proxy_max_temp_file_size ``` 语法: proxy_max_temp_file_size size; 默认值: proxy_max_temp_file_size 1024m; 上下文: http, server, location ``` 1. 打开响应缓冲以后,如果整个响应不能存放在proxy_buffer_size和proxy_buffers指令设置的缓冲区内,部分响应可以存放在临时文件中。 这条指令可以设置临时文件的最大容量。而每次写入临时文件的数据量则由proxy_temp_file_write_size指令定义。 2. 写入硬盘的临时文件的大小,如果超过了这个值, Nginx将与Proxy服务器同步的传递内容, 而不再缓冲到硬盘. 设置为0时,将禁止响应写入临时文件,也就相当于直接关闭硬盘缓冲。 ## 1.6 proxy_temp_file_write_size ``` 语法: proxy_temp_file_write_size size; 默认值: proxy_temp_file_write_size 8k|16k; 上下文: http, server, location ``` 在开启缓冲后端服务器响应到临时文件的功能后,设置nginx每次写数据到临时文件的size(大小)限制。 size的默认值是proxy_buffer_size指令和proxy_buffers指令定义的每块缓冲区大小的两倍, 而临时文件最大容量由proxy_max_temp_file_size指令设置。 ## 1.7 缓冲区配置实例 通用网站的配置 ``` proxy_buffer_size 4k; #设置代理服务器(nginx)保存用户头信息的缓冲区大小 proxy_buffers 4 32k; #proxy_buffers缓冲区,网页平均在32k以下的设置 proxy_busy_buffers_size 64k; #高负荷下缓冲大小(proxy_buffers*2) proxy_temp_file_write_size 64k; #设定缓存文件夹大小,大于这个值,将从upstream服务器传 ``` docker registry的配置 这个每次传输至少都是9M以上的内容,缓冲区配置大; ``` proxy_buffering on; proxy_buffer_size 4k; proxy_buffers 8 1M; proxy_busy_buffers_size 2M; proxy_max_temp_file_size 0; ``` 关于缓冲区大小的配置,还是需要实地的分析,一般来说通用配置可以应付了。 # 2. 常用配置项 ## 2.1 proxy_cache_path ``` 语法: proxy_cache_path path [levels=levels] keys_zone=name:size [inactive=time] [max_size=size] [loader_files=number] [loader_sleep=time] [loader_threshold=time]; 默认值: — 上下文: http ``` - path 指定缓存文件目录,和 proxy_temp_path 最好设置在同一文件分区下,缓存内容是先写在 temp_path,临时文件和缓存可以放在不同的文件系统,将导致文件在这两个文件系统中进行拷贝,而不是廉价的重命名操作。因此,针对任何路径,都建议将缓存和proxy_temp_path指令设置的临时文件目录放在同一文件系统。 - level 定义了缓存的层次结构,每层可以用1(最多16中选择,0-f)或2(最多256种选择,00-ff)表示,中间用 [冒号] 分隔。“levels=1:2”表示开启1、2层级(第2层级理论有16*256个目录)。 ``` proxy_cache_path /data/nginx/cache; # 所有缓存只有一个目录 /data/nginx/cache/d7b6e5978e3f042f52e875005925e51b proxy_cache_path /data/nginx/cache levels=1:2; # 第二层级有16*256=4096个目录 /data/nginx/cache/b/51/d7b6e5978e3f042f52e875005925e51b proxy_cache_path /data/nginx/cache levels=1:1:1; #第三层级有16*16*16个目录 /data/nginx/cache/b/1/5/d7b6e5978e3f042f52e87500592 proxy_cache_path /data/nginx/cache levels=2; # 第一层级有256个目录 /data/nginx/cache/1b/d7b6e5978e3f042f52e875005925e51b ``` - keys_zone 指定一个共享内存空间zone,所有活动的键和缓存数据相关的信息都被存放在共享内存中,这样nginx可以快速判断一个request是否命中或者未命中缓存,1m可以存储8000个key,10m可以存储80000个key; - inactive inactive=30m 表示 30 分钟没有被访问的文件会被 cache manager 删除,inactive的默认值是10分钟。 需要注意的是,inactive和expired配置项的含义是不同的,expired只是缓存过期,但不会被删除,inactive是删除指定时间内未被访问的缓存文件 - max_size cache存储的最大尺寸,如果不指定,会用掉所有磁盘空间,当尺寸超过,将会基于LRU算法移除数据,以减少占用大小。nginx启动时,会创建一个“Cache manager”进程,通过“purge”方式移除数据。 - loader_files “cache loader”进程遍历文件时,每次加载的文件个数。默认为100. - loader_threshold 每次遍历消耗时间上限。默认为200毫秒。 - loader_sleep 一次遍历之后,停顿的时间间隔,默认为50毫秒。 需要注意的是: 特殊进程“cache manager”监控缓存的条目数量,如果超过max_size参数设置的最大值,使用LRU算法移除缓存数据。nginx新启动后不就,特殊进程“cache loader”就被启动。该进程将文件系统上保存的过去缓存的数据的相关信息重新加载到共享内存。加载过程分多次迭代完成,每次迭代,进程只加载不多于loader_files参数指定的文件数量(默认值为100)。此外,每次迭代过程的持续时间不能超过loader_threshold参数的值(默认200毫秒)。每次迭代之间,nginx的暂停时间由loader_sleep参数指定(默认50毫秒)。缓存文件并不是越多越好,所以 cache_key 的设计非常关键。代理或 URL 跳转常常会添加的无用请求参数,这就会出现不同的 cache_key 保存了多份相同的缓存内容,这对缓存效果影响很大。 ## 2.2 proxy_temp_path ``` 语法: proxy_temp_path path [level1 [level2 [level3]]]; 默认值: proxy_temp_path proxy_temp; 上下文: http, server, location ``` 定义从后端服务器接收的临时文件的存放路径,可以为临时文件路径定义至多三层子目录的目录树。 比如,下面配置 ``` proxy_temp_path /spool/nginx/proxy_temp 1 2; ``` 那么临时文件的路径看起来会是这样: ``` /spool/nginx/proxy_temp/7/45/00000123457 ``` ## 2.3 proxy_cache ``` 语法: proxy_cache zone | off; 默认值: proxy_cache off; 上下文: http, server, location ``` 指定用于页面缓存的共享内存。同一块共享内存可以在多个地方使用。off参数可以屏蔽从上层配置继承的缓存功能。zone名称由“proxy_cache_path”指令定义。 ## 2.4 proxy_cache_key ``` 语法: proxy_cache_key string; 默认值: proxy_cache_key $scheme$proxy_host$request_uri; 上下文: http, server, location ``` 定义如何生成缓存的键,比如 ``` proxy_cache_key "$host$request_uri $cookie_user"; ``` 这条指令的默认值类似于下面字符串 ``` proxy_cache_key $scheme$proxy_host$uri$is_args$args; ``` 缓存文件并不是越多越好,所以 cache_key 的设计非常关键。代理或 URL 跳转常常会添加的无用请求参数,这就会出现不同的 cache_key 保存了多份相同的缓存内容,这对缓存效果影响很大。通过 ngx_lua 可以对 URL 参数进行过滤,保证 cache_key 唯一。 ## 2.5 proxy_cache_valid ``` 语法: proxy_cache_valid [code ...] time; 默认值: — 上下文: http, server, location ``` 为不同的响应状态码设置不同的缓存时间。比如,下面指令 ``` proxy_cache_valid 200 302 10m; proxy_cache_valid 404 1m; ``` 设置状态码为200和302的响应的缓存时间为10分钟,状态码为404的响应的缓存时间为1分钟。 如果仅仅指定了time, ``` proxy_cache_valid 5m; ``` 那么只有状态码为200、300和302的响应会被缓存。 如果使用了any参数,那么就可以缓存任何响应: ``` proxy_cache_valid 200 302 10m; proxy_cache_valid 301 1h; proxy_cache_valid any 1m; ``` 缓存参数也可以直接在响应头中设定。这种方式的优先级高于使用这条指令设置缓存时间。 ``` “X-Accel-Expires”响应头可以以秒为单位设置响应的缓存时间,如果值为0,表示禁止缓存响应,如果值以@开始,表示自1970年1月1日以来的秒数,响应一直会被缓存到这个绝对时间点。 如果不含“X-Accel-Expires”响应头,缓存参数仍可能被“Expires”或者“Cache-Control”响应头设置。 如果响应头含有“Set-Cookie”,响应将不能被缓存。 这些头的处理过程可以使用指令proxy_ignore_headers忽略。 ``` ## 2.6 proxy_ignore_headers ``` 语法: proxy_ignore_headers field ...; 默认值: — 上下文: http, server, location ``` 指定来自后端server的响应中的某些header不会被处理,如下几个fields可以被ignore:“X-Accel-Redirect”、“X-Accel-Expires”、“X-Accel-Limit-Rate”、“X-Accel-Buffering”、“X-Accel-Charset”、“Expires”、“Cache-Control”、“Set-Cookie”、“Vary”。“不被处理”就是nginx不会尝试解析这些header并应用它们,比如nginx处理来自后端server的“Expires”,将会影响它本地的文件cache的机制 如果不被取消,这些头部的处理可能产生下面结果: ``` “X-Accel-Expires”,“Expires”,“Cache-Control”,和“Set-Cookie” 设置响应缓存的参数; “X-Accel-Redirect”执行到指定URI的内部跳转; “X-Accel-Limit-Rate”设置响应到客户端的传输速率限制; “X-Accel-Buffering”启动或者关闭响应缓冲; “X-Accel-Charset”设置响应所需的字符集。 ``` ## 2.7 proxy_hide_header ``` 语法: proxy_hide_header field; 默认值: — 上下文: http, server, location ``` nginx默认不会将“Date”、“Server”、“X-Pad”,和“X-Accel-...”响应头发送给客户端。proxy_hide_header指令则可以设置额外的响应头,这些响应头也不会发送给客户端。相反的,如果希望允许传递某些响应头给客户端,可以使用proxy_pass_header指令。 ## 2.8 proxy_pass_header ``` 语法: proxy_pass_header field; 默认值: — 上下文: http, server, location ``` 允许传送被屏蔽的后端服务器响应头到客户端。 ## 2.9 proxy_cache_min_uses ``` 语法: proxy_cache_min_uses number; 默认值: proxy_cache_min_uses 1; 上下文: http, server, location ``` 设置响应被缓存的最小请求次数。默认为1,当客户端发送相同请求达到规定次数后,nginx才对响应数据进行缓存;指定请求至少被发送了多少次以上时才缓存,可以防止低频请求被缓存 ## 2.10 proxy_cache_use_stale ``` 语法: proxy_cache_use_stale error | timeout | invalid_header | updating | http_500 | http_502 | http_503 | http_504 | http_404 | off ...; 默认值: proxy_cache_use_stale off; 上下文: http, server, location ``` 如果后端服务器出现状况,nginx是可以使用过期的响应缓存的。这条指令就是定义何种条件下允许开启此机制。这条指令的参数与proxy_next_upstream指令的参数相同。 此外,updating参数允许nginx在正在更新缓存的情况下使用过期的缓存作为响应。这样做可以使更新缓存数据时,访问源服务器的次数最少。 在植入新的缓存条目时,如果想使访问源服务器的次数最少,可以使用proxy_cache_lock指令。 ## 2.11 proxy_cache_lock ``` 语法: proxy_cache_lock on | off; 默认值: proxy_cache_lock off; 上下文: http, server, location 这个指令出现在版本 1.1.12. ``` 开启此功能时,对于相同的请求,同时只允许一个请求发往后端,并根据proxy_cache_key指令的设置在缓存中植入一个新条目。 其他请求相同条目的请求将一直等待,直到缓存中出现相应的内容,或者锁在proxy_cache_lock_timeout指令设置的超时后被释放。如果不启用proxy_cache_lock,则所有在缓存中找不到文件的请求都会直接与服务器通信。 ## 2.12 proxy_cache_bypass ``` 语法: proxy_cache_bypass string ...; 默认值: — 上下文: http, server, location ``` 定义nginx不从缓存取响应的条件。如果至少一个字符串条件非空而且非“0”,nginx就不会从缓存中去取响应: ``` proxy_cache_bypass $cookie_nocache $arg_nocache$arg_comment; proxy_cache_bypass $http_pragma $http_authorization; ``` 本指令可和与proxy_no_cache一起使用。 ## 2.13 proxy_no_cache ``` 语法: proxy_no_cache string ...; 默认值: — 上下文: http, server, location ``` 定义nginx不将响应写入缓存的条件。如果至少一个字符串条件非空而且非“0”,nginx就不将响应存入缓存: ``` proxy_no_cache $cookie_nocache $arg_nocache$arg_comment; proxy_no_cache $http_pragma $http_authorization; ``` 这条指令可以和proxy_cache_bypass指令一起使用。 # 3. 其他一些配置 ## 3.1 proxy_cache_lock_timeout ``` 语法: proxy_cache_lock_timeout time; 默认值: proxy_cache_lock_timeout 5s; 上下文: http, server, location ``` 这个指令出现在版本 1.1.12. 为proxy_cache_lock指令设置锁的超时。 ## 3.2 proxy_read_timeout ``` 语法: proxy_read_timeout time; 默认值: proxy_read_timeout 60s; 上下文: http, server, location ``` 定义从后端服务器读取响应的超时。此超时是指相邻两次读操作之间的最长时间间隔,而不是整个响应传输完成的最长时间。如果后端服务器在超时时间段内没有传输任何数据,连接将被关闭。 ## 3.3 proxy_connect_timeout ``` 语法: proxy_connect_timeout time;默认值: proxy_connect_timeout 60s; 上下文: http, server, location ``` 设置与后端服务器建立连接的超时时间。应该注意这个超时一般不可能大于75秒。 ## 3.4 proxy_send_timeout ``` 语法: proxy_send_timeout time; 默认值: proxy_send_timeout 60s; 上下文: http, server, location ``` 定义向后端服务器传输请求的超时。此超时是指相邻两次写操作之间的最长时间间隔,而不是整个请求传输完成的最长时间。如果后端服务器在超时时间段内没有接收到任何数据,连接将被关闭。 ## 3.5 proxy_http_version ``` 语法: proxy_http_version 1.0 | 1.1; 默认值: proxy_http_version 1.0; 上下文: http, server, location ``` 这个指令出现在版本 1.1.4. 设置代理使用的HTTP协议版本。默认使用的版本是1.0,而1.1版本则推荐在使用keepalive连接时一起使用。 ## 3.6 proxy_ignore_client_abort ``` 语法: proxy_ignore_client_abort on | off; 默认值: proxy_ignore_client_abort off; 上下文: http, server, location ``` 决定当客户端在响应传输完成前就关闭连接时,nginx是否应关闭后端连接。 ## 3.7 proxy_intercept_errors ``` 语法: proxy_intercept_errors on | off; 默认值: proxy_intercept_errors off; 上下文: http, server, location ``` 当后端服务器的响应状态码大于等于400时,决定是否直接将响应发送给客户端,亦或将响应转发给nginx由error_page指令来处理。 ## 3.8 proxy_next_upstream ``` 语法: proxy_next_upstream error | timeout | invalid_header | http_500 | http_502 | http_503 | http_504 | http_404 | off ...; 默认值: proxy_next_upstream error timeout; 上下文: http, server, location ``` 指定在何种情况下一个失败的请求应该被发送到下一台后端服务器: ``` error 和后端服务器建立连接时,或者向后端服务器发送请求时,或者从后端服务器接收响应头时,出现错误; timeout 和后端服务器建立连接时,或者向后端服务器发送请求时,或者从后端服务器接收响应头时,出现超时; invalid_header 后端服务器返回空响应或者非法响应头; http_500 后端服务器返回的响应状态码为500; http_502 后端服务器返回的响应状态码为502; http_503 后端服务器返回的响应状态码为503; http_504 后端服务器返回的响应状态码为504; http_404 后端服务器返回的响应状态码为404; off 停止将请求发送给下一台后端服务器。 ``` 需要理解一点的是,只有在没有向客户端发送任何数据以前,将请求转给下一台后端服务器才是可行的。也就是说,如果在传输响应到客户端时出现错误或者超时,这类错误是不可能恢复的。 ## 3.9 proxy_cookie_domain ``` 语法: proxy_cookie_domain off; proxy_cookie_domain domain replacement; 默认值: proxy_cookie_domain off; 上下文: http, server, location ``` 这个指令出现在版本 1.1.15. 设置“Set-Cookie”响应头中的domain属性的替换文本。 假设后端服务器返回的“Set-Cookie”响应头含有属性“domain=localhost”,那么指令 proxy_cookie_domain localhost example.org; 将这个属性改写为“domain=example.org”。 domain和replacement配置字符串,以及domain属性中起始的点将被忽略。 匹配过程大小写不敏感。 domain和replacement配置字符串中可以包含变量: proxy_cookie_domain www.$host $host; 这条指令同样可以使用正则表达式。这时,domain应以“~”标志开始,且可以使用命名匹配组和位置匹配组,而replacement可以引用这些匹配组: ``` proxy_cookie_domain ~\.(?P<sl_domain>[-0-9a-z]+\.[a-z]+)$ $sl_domain; ``` 可以同时定义多条proxy_cookie_domain指令: ``` proxy_cookie_domain localhost example.org; proxy_cookie_domain ~\.([a-z]+\.[a-z]+)$ $1; ``` off参数可以取消当前配置级别的所有proxy_cookie_domain指令: ``` proxy_cookie_domain off; proxy_cookie_domain localhost example.org; proxy_cookie_domain www.example.org example.org; ``` ## 3.10 proxy_cookie_path ``` 语法: proxy_cookie_path off; proxy_cookie_path path replacement; 默认值: proxy_cookie_path off; 上下文: http, server, location ``` 这个指令出现在版本 1.1.15. 设置“Set-Cookie”响应头中的path属性的替换文本。 假设后端服务器返回的“Set-Cookie”响应头含有属性“path=/two/some/uri/”,那么指令 ``` proxy_cookie_path /two/ /; ``` 将这个属性改写为“path=/some/uri/”。 path和replacement配置字符串可以包含变量: ``` proxy_cookie_path $uri /some$uri; ``` 这条指令同样可以使用正则表达式。如果使用大小写敏感的匹配,path应以“~”标志开始,如果使用大小写不敏感的匹配,path应以“~*”标志开始。path可以使用命名匹配组和位置匹配组,replacement可以引用这些匹配组: ``` proxy_cookie_path ~*^/user/([^/]+) /u/$1; ``` 可以同时定义多条proxy_cookie_path指令: ``` proxy_cookie_path /one/ /; proxy_cookie_path / /two/; ``` off参数可以取消当前配置级别的所有proxy_cookie_path指令: ``` proxy_cookie_path off; proxy_cookie_path /two/ /; proxy_cookie_path ~*^/user/([^/]+) /u/$1; ``` ## 3.11 proxy_pass ``` 语法: proxy_pass URL; 默认值: — 上下文: location, if in location, limit_except ``` 设置后端服务器的协议和地址,还可以设置可选的URI以定义本地路径和后端服务器的映射关系。 这条指令可以设置的协议是“http”或者“https”,而地址既可以使用域名或者IP地址加端口(可选)的形式来定义: ``` proxy_pass http://localhost:8000/uri/; ``` 又可以使用UNIX域套接字路径来定义。该路径接在“unix”字符串后面,两端由冒号所包围,比如: ``` proxy_pass http://unix:/tmp/backend.socket:/uri/; ``` 如果解析一个域名得到多个地址,所有的地址都会以轮转的方式被使用。当然,也可以使用服务器组来定义地址。 请求URI按下面规则传送给后端服务器: 如果proxy_pass使用了URI,当传送请求到后端服务器时,规范化以后的请求路径与配置中的路径的匹配部分将被替换为指令中定义的URI: ``` location /name/ { proxy_pass http://127.0.0.1/remote/; } ``` 如果proxy_pass没有使用URI,传送到后端服务器的请求URI一般客户端发起的原始URI,如果nginx改变了请求URI,则传送的URI是nginx改变以后完整的规范化URI: ``` location /some/path/ { proxy_pass http://127.0.0.1; } ``` 在1.1.12版以前,如果proxy_pass没有使用URI,某些情况下,nginx改变URI以后,会错误地将原始URI而不是改变以后的URI发送到后端服务器。 某些情况下,无法确定请求URI中应该被替换的部分: 使用正则表达式定义路径。 这种情况下,指令不应该使用URI。 在需要代理的路径中,使用rewrite指令改变了URI,但仍使用相同配置处理请求(break): ``` location /name/ { rewrite /name/([^/]+) /users?name=$1 break; proxy_pass http://127.0.0.1; } ``` 这种情况下,本指令设置的URI会被忽略,改变后的URI将被发送给后端服务器。 后端服务器的地址,端口和URI中都可以使用变量: ``` proxy_pass http://$host$uri; ``` 甚至像这样: ``` proxy_pass $request; ``` 这种情况下,后端服务器的地址将会在定义的服务器组中查找。如果查找不到,nginx使用resolver来查找该地址。 ## 3.12 proxy_redirect ``` 语法: proxy_redirect default; proxy_redirect off; proxy_redirect redirect replacement; 默认值: proxy_redirect default; 上下文: http, server, location ``` 设置后端服务器“Location”响应头和“Refresh”响应头的替换文本。 假设后端服务器返回的响应头是 “Location: http://localhost:8000/two/some/uri/”,那么指令 ``` proxy_redirect http://localhost:8000/two/ http://frontend/one/; ``` 将把字符串改写为 “Location: http://frontend/one/some/uri/”。 replacement字符串可以省略服务器名: ``` proxy_redirect http://localhost:8000/two/ /; ``` 此时将使用代理服务器的主域名和端口号来替换。如果端口是80,可以不加。 用default参数指定的默认替换使用了location和proxy_pass指令的参数。因此,下面两例配置等价: ``` location /one/ { proxy_pass http://upstream:port/two/; proxy_redirect default; location /one/ { proxy_pass http://upstream:port/two/; proxy_redirect http://upstream:port/two/ /one/; ``` 而且因为同样的原因,proxy_pass指令使用变量时,不允许本指令使用default参数。 replacement字符串可以包含变量: ``` proxy_redirect http://localhost:8000/ http://$host:$server_port/; ``` 而redirect字符串从1.1.11版本开始也可以包含变量: ``` proxy_redirect http://$proxy_host:8000/ /; ``` 同时,从1.1.11版本开始,指令支持正则表达式。使用正则表达式的话,如果是大小写敏感的匹配,redirect以“~”作为开始,如果是大小写不敏感的匹配,redirect以“~*”作为开始。而且redirect的正则表达式中可以包含命名匹配组和位置匹配组,而在replacement中可以引用这些匹配组的值: ``` proxy_redirect ~^(http://[^:]+):\d+(/.+)$ $1$2; proxy_redirect ~*/user/([^/]+)/(.+)$ http://$1.example.com/$2; ``` 除此以外,可以同时定义多个proxy_redirect指令: ``` proxy_redirect default; proxy_redirect http://localhost:8000/ /; proxy_redirect http://www.example.com/ /; ``` 另外,off参数可以使所有相同配置级别的proxy_redirect指令无效: ``` proxy_redirect off; proxy_redirect default; proxy_redirect http://localhost:8000/ /; proxy_redirect http://www.example.com/ /; ``` 最后,使用这条指令也可以为地址为相对地址的重定向添加域名: ``` proxy_redirect / /; ``` ## 3.13 proxy_set_header ``` 语法: proxy_set_header field value; 默认值: proxy_set_header Host $proxy_host; proxy_set_header Connection close; 上下文: http, server, location ``` 允许重新定义或者添加发往后端服务器的请求头。value可以包含文本、变量或者它们的组合。 当且仅当当前配置级别中没有定义proxy_set_header指令时,会从上面的级别继承配置。 默认情况下,只有两个请求头会被重新定义: ``` proxy_set_header Host $proxy_host; proxy_set_header Connection close; ``` 如果不想改变请求头“Host”的值,可以这样来设置: ``` proxy_set_header Host $http_host; ``` 但是,如果客户端请求头中没有携带这个头部,那么传递到后端服务器的请求也不含这个头部。 这种情况下,更好的方式是使用$host变量——它的值在请求包含“Host”请求头时为“Host”字段的值,在请求未携带“Host”请求头时为虚拟主机的主域名: ``` proxy_set_header Host $host; ``` 此外,服务器名可以和后端服务器的端口一起传送: ``` proxy_set_header Host $host:$proxy_port; ``` 如果某个请求头的值为空,那么这个请求头将不会传送给后端服务器: ``` proxy_set_header Accept-Encoding ""; 语法: proxy_ssl_session_reuse on | off; 默认值: proxy_ssl_session_reuse on; 上下文: http, server, location ``` 决定是否重用与后端服务器的SSL会话。如果日志中出现“SSL3_GET_FINISHED:digest check failed”错误,请尝试关闭会话重用。 ## 3.14 proxy_store ``` 语法: proxy_store on | off | string; 默认值: proxy_store off; 上下文: http, server, location ``` 开启将文件保存到磁盘上的功能。如果设置为on,nginx将文件保存在alias指令或root指令设置的路径中。如果设置为off,nginx将关闭文件保存的功能。此外,保存的文件名也可以使用含变量的string参数来指定: ``` proxy_store /data/www$original_uri; ``` 保存文件的修改时间根据接收到的“Last-Modified”响应头来设置。响应都是先写到临时文件,然后进行重命名来生成的。从0.8.9版本开始,临时文件和持久化存储可以放在不同的文件系统,但是需要注意这时文件执行的是在两个文件系统间拷贝操作,而不是廉价的重命名操作。因此建议保存文件的路径和proxy_temp_path指令设置的临时文件的路径在同一个文件系统中。 这条指令可以用于创建静态无更改文件的本地拷贝,比如: ``` location /images/ { root /data/www; open_file_cache_errors off; error_page 404 = /fetch$uri; } location /fetch/ { internal; proxy_pass http://backend/; proxy_store on; proxy_store_access user:rw group:rw all:r; proxy_temp_path /data/temp; alias /data/www/; } ``` 或者像这样: ``` location /images/ { root /data/www; error_page 404 = @fetch; } location @fetch { internal; proxy_pass http://backend; proxy_store on; proxy_store_access user:rw group:rw all:r; proxy_temp_path /data/temp; root /data/www; } ``` ``` 语法: proxy_store_access users:permissions ...; 默认值: proxy_store_access user:rw; 上下文: http, server, location ``` 设置新创建的文件和目录的访问权限,比如: ``` proxy_store_access user:rw group:rw all:r; ``` 如果指定了任何group或者all的访问权限,那么可以略去user的访问权限: ``` proxy_store_access group:rw all:r; ``` # 4. 其他一些问题 ## 4.1 缓存动态内容 NGINX可以缓存动态内容,但是这不应该乱用,有些情况需要考虑 首先,任何用户相关的数据不应被高速缓存。这可能导致一个用户的数据被呈现给其他用户。如果你的网站是完全静态的,这可能不是一个问题。 如果你的网站有一些动态元素,你将不得不考虑到这一点。你如何处理要看是什么应用程序或服务器处理的后端处理。对于私人的内容,你应该设置Cache-Control头为“no-cache”,“no-sotre”,或者“private”依赖于数据的性质: ## 4.2 缓存不生效问题 nginx是否缓存是由nginx缓存服务器与源服务器共同决定的, 缓存服务器需要严格遵守源服务器响应的header来决定是否缓存以及缓存的时长。 默认情况下,NGINX需要考虑从原始服务器得到的Cache-Control标头。当在响应头部中Cache-Control被配置为Private,No-Cache,No-Store或者Set-Cookie,NGINX不进行缓存。NGINX仅仅缓存GET和HEAD客户端请求。 可以尝试通过更改头信息改让反代服务器缓存 1、尝试修改源服务器代码,改变程序响应的头信息 2、nginx反代配置提供了proxy_ignore_headers配置来忽略某些头信息,我们可以忽略引起反代不缓存的头信息 ``` proxy_ignore_headers X-Accel-Expires Expires Cache-Control Set-Cookie; ``` ## 4.2 缓存过期问题 引起缓存过期的因素 - inactive:在proxy_cache_path配置项中进行配置,说明某个缓存在inactive指定的时间内如果不访问,将会从缓存中删除。 - 源服务器php页面中生成的响应头中的Expires,生成语句为: header("Expires: Fri, 07 Sep 2013 08:05:18 GMT"); - 源服务器php页面生成的max-age,生成语句为: header("Cache-Control: max-age=60"); - nginx的配置项 proxy_cache_valid:配置nginx cache中的缓存文件的缓存时间,如果配置项为:proxy_cache_valid 200 304 2m;说明对于状态为200和304的缓存文件的缓存时间是2分钟,两分钟之后再访问该缓存文件时,文件会过期,从而去源服务器重新取数据。 优先级 - 在同时设置了源服务器端Expires、源服务器端max-age和nginx cahe端的proxy_cache_valid的情况下,以源服务器端设置的Expires的值为标准进行缓存的过期处理 - 若在nginx中配置了相关配置项(proxy_ignore_headers,proxy_hide_header),取消原服务器端Expires对缓存的影响,在同时设置了源服务器端Expires、源服务器端max-age和nginx cahe端的proxy_cache_valid的情况下,以源服务器端max-age的值为标准进行缓存的过期处理 - 若同时取消源服务器端Expires和源服务器端max-age对缓存的影响,则以proxy_cache_valid设置的值为标准进行缓存的过期处理 - Inactive的值不受上述三个因素的影响,即第一次请求页面之后,每经过inactvie指定的时间,都要强制进行相应的缓存清理。因此inactive的优先级最高。 详细的测试可以参照http://www.ttlsa.com/nginx/nginx-cache-priority/ ## 4.3 缓存清除问题 nginx没有提供直接缓存清除的方法,但是我们可以使用以下方法清除 1、但是可以通过使用第三方的模块ngx_cache_purge清除指定的URL 需要加入一个新的location配置 ``` location ~ /purge(/.*) { proxy_cache_purge cache_one $host$1$is_args$args; } ``` 原网址和清除缓存的url对应关系 ``` www.firefoxbug.net/index.html ==>> www.firefoxbug.net/purge/index.html就能清除. ``` 2、直接删除指定的缓存文件 直接想办法删除proxy_cache_path配置的目录下的所有文件,如果你可以直接操作linux那么可以直接`rm -rf xxx`了,如果不方便可以考虑写个脚本去删除相应的文件目录。 ## 4.4 缓存命中率 nginx 提供了变量$upstream-cache-status 来显示缓存的命中状态,我们可以再nginx.conf配置中添加一个http响应头来显示这一状态 反代配置中加入 ``` location / { proxy_pass http://zhengde.xxx.cn; proxy_set_header Host zhengde.xxx.cn; add_header X-Cache-Status $upstream_cache_status; ... 其他配置 } ``` 在对客户端的响应中添加了一个`X-Cache-Status`HTTP响应头,这样可以在响应信息中查看X-Cache-Status状态来判定是否命中 如果想要统计命中率,那么在访问日志的格式中加入$upstream_cache_status记录即可 ``` log_format main ‘$remote_addr – $remote_user [$time_local] “$request” ‘ ‘$status $body_bytes_sent “$http_referer” ‘ ’”$http_user_agent” “$http_x_forwarded_for”‘ ’”$upstream_cache_status”‘; ``` 然后可以使用awk命令进行统计 ``` 命令:awk '{if($NF=="\"HIT\"") hit++} END {printf "%.2f%",hit/NR}' access.log 结果: 32.15% ``` 下面是$upstream_cache_status的可能值: ``` 1.MISS——响应在缓存中找不到,所以需要在服务器中取得。这个响应之后可能会被缓存起来。 2.BYPASS——响应来自原始服务器而不是缓存,因为请求匹配了一个proxy_cache_bypass(见下面我可以在缓存中打个洞吗?)。这个响应之后可能会被缓存起来。 3.EXPIRED——缓存中的某一项过期了,来自原始服务器的响应包含最新的内容。 4.STALE——内容陈旧是因为原始服务器不能正确响应。需要配置proxy_cache_use_stale。 5.UPDATING——内容过期了,因为相对于之前的请求,响应的入口(entry)已经更新,并且proxy_cache_use_stale的updating已被设置。 6.REVALIDATED——proxy_cache_revalidate命令被启用,NGINX检测得知当前的缓存内容依然有效(If-Modified-Since或者If-None-Match)。 7.HIT——响应包含来自缓存的最新有效的内容。 ``` ## 4.5 如何实现动静分离 ``` server { listen 10000; server_name localhost; #静态处理交给nginx location ~ .*\.(htm|html|gif|jpg|jpeg|png|bmp|swf|ioc|ico|rar|zip|txt|flv|mid|doc|ppt|pdf|xls|mp3|wma|css|js)$ { proxy_cache cache_one; proxy_cache_valid 200 304 302 2d; proxy_cache_valid any 1d; proxy_cache_key $host$uri$is_args$args; add_header X-Cache '$upstream_cache_status from $host'; proxy_pass http://127.0.0.1:8088; expires 30d; } #动态文件不处理 location / { proxy_pass http://127.0.0.1:8080; } } ``` # 参考网址 http://tengine.taobao.org/nginx_docs/cn/docs/http/ngx_http_proxy_module.html#proxy_ignore_headers https://blog.csdn.net/mary881225/article/details/70173907 http://www.cnblogs.com/bethal/p/5606062.html http://lmdkfs.blog.163.com/blog/static/74611324201421283237778/

nginx笔记-反向代理

[TOC] # 1. 正向代理和反向代理 ## 1.1 正向代理 正向代理(Forward Proxy)通常都被简称为代理,就是在用户无法正常访问外部资源,比方说受到GFW的影响无法访问twitter的时候,我们可以通过代理的方式,让用户绕过防火墙,先访问代理服务器,然后告诉代理服务器去访问twitter,取到信息后返回给我们,从而连接到目标网络或者服务。。 ![](http://markdown.archerwong.cn/2018-12-18-08-10-36_1.jpg) ## 1.2 反向代理 反向代理(Reverse Proxy)方式是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给internet上请求连接的客户端,此时代理服务器对外就表现为一个服务器。 ![](http://markdown.archerwong.cn/2018-12-18-08-10-39_2.jpg) ## 1.3 正向代理和反向代理的区别 (http://markdown.archerwong.cn/2018-12-18-08-10-43_3.png) ![](http://markdown.archerwong.cn/2018-12-18-08-10-45_4.png) 正向代理中,proxy和client同属一个LAN,对server透明; 反向代理中,proxy和server同属一个LAN,对client透明。 正向代理隐藏真实客户端,反向代理隐藏真实服务端 # 2. 反向代理的好处 ## 2.1 保护了真实的web服务器 web服务器对外不可见,外网只能看到反向代理服务器,而反向代理服务器上并没有真实数据,因此,保证了web服务器的资源安全,我们还可以在代理服务器层增加waf防火墙,这样可以保证发往真是服务器的请求更加安全。 ## 2.2 节约了有限的IP地址资源 企业内所有的网站共享一个在internet中注册的IP地址,这些服务器分配私有地址,采用虚拟主机的方式对外提供服务。 ## 2.3 减少WEB服务器压力,提高响应速度 反向代理就是通常所说的web服务器加速,它是一种通过在繁忙的web服务器和外部网络之间增加一个高速的web缓冲服务器来降低实际的web服务器的负载的一种技术。反向代理是针对web服务器提高加速功能,作为代理缓存,它并不是针对浏览器用户,而针对一台或多台特定的web服务器,它可以代理外部网络对内部网络的访问请求。 反向代理服务器会强制将外部网络对要代理的服务器的访问经过它,这样反向代理服务器负责接收客户端的请求,然后到源服务器上获取内容,把内容返回给用户,并把内容保存到本地,以便日后再收到同样的信息请求时,它会把本地缓存里的内容直接发给用户,以减少后端web服务器的压力,提高响应速度。因此Nginx还具有缓存功能。 ## 2.4 其他优点 (1)请求的统一控制,包括设置权限、过滤规则等; (2)区分动态和静态可缓存内容; (3)实现负载均衡,内部可以采用多台服务器来组成服务器集群,外部还是可以采用一个地址访问; (4)解决Ajax跨域问题; (5)作为真实服务器的缓冲,解决瞬间负载量大的问题; # 3. 应用场景 **反向代理的应用场景1:** 北邮的图书馆资源只能在校内访问,当一个同学暑期放假回家,想要查询图使馆资源的资料(比如知网),因为他不在校园内,所以他没有办法免费访问知网,此时如果有一个反向代理服务器(在校园内网,有权限免费访问知网),他就可以先访问反向代理服务器,然后让反向代理服务器去帮他和知网沟通。 **反向代理的应用场景2:** 反向代理实现负载均衡 ``` upstream myapp { server 192.168.0.100:8080; server 192.168.0.101:8080; server example.com:8080; } server { listen 80; location / { proxy_pass http://myapp; } } ``` 这样对外发布的还是一个ip地址,用户并不知道后面其实有3个真实的服务器,在处理请求,这样可以大大提高处理性能。 # 4. 反向代理的配置 基本配置很简单 ``` location / { proxy_pass http://zhengde.xxx.cn; proxy_set_header Host zhengde.xxx.cn; } ``` ## 4.1 proxy_pass proxy_pass 后面跟着一个 URL,用来将请求反向代理到 URL 参数指定的服务器上。例如我们上面例子中的 `proxy_pass http://zhengde.xxx.cn;`,则将匹配的请求反向代理到 http://zhengde.xxx.cn。 ## 4.2 proxy_set_header 语法: ``` proxy_set_header field value; ``` 默认值: ``` proxy_set_header Host $proxy_host; proxy_set_header Connection close; ``` 上下文: ``` http, server, location ``` 允许重新定义或者添加发往后端服务器的请求头。value可以包含文本、变量或者它们的组合。 当且仅当当前配置级别中没有定义proxy_set_header指令时,会从上面的级别继承配置。 默认情况下,只有两个请求头会被重新定义: ``` proxy_set_header Host $proxy_host; proxy_set_header Connection close; ``` 如果不想改变请求头“Host”的值,可以这样来设置: ``` proxy_set_header Host $http_host; ``` 但是,如果客户端请求头中没有携带这个头部,那么传递到后端服务器的请求也不含这个头部。 这种情况下,更好的方式是使用$host变量——它的值在请求包含“Host”请求头时为“Host”字段的值,在请求未携带“Host”请求头时为虚拟主机的主域名: ``` proxy_set_header Host $host; ``` 此外,服务器名可以和后端服务器的端口一起传送: ``` proxy_set_header Host $host:$proxy_port; ``` 如果某个请求头的值为空,那么这个请求头将不会传送给后端服务器: ``` proxy_set_header Accept-Encoding ""; ``` 默认情况下,反向代理不会转发**原始请求**中的 Host 头部,真实服务器可能会根据这个host找到相应的站点,不写的话可能找不到,如果需要转发,就需要加上这句:`proxy_set_header Host $host;` ## 4.3 proxy_cookie_domain 语法: ``` proxy_cookie_domain off; proxy_cookie_domain domain replacement; ``` 默认值: ``` proxy_cookie_domain off; ``` 上下文: ``` http, server, location ``` 这个指令出现在版本 1.1.15. 设置“Set-Cookie”响应头中的domain属性的替换文本。 假设后端服务器返回的“Set-Cookie”响应头含有属性“domain=localhost”,那么指令 ``` proxy_cookie_domain localhost example.org; ``` 将这个属性改写为“`domain=example.org`”。 domain和replacement配置字符串,以及domain属性中起始的点将被忽略。 匹配过程大小写不敏感。domain和replacement配置字符串中可以包含变量: 可以同时定义多条proxy_cookie_domain指令: ``` proxy_cookie_domain localhost example.org; proxy_cookie_domain ~\.([a-z]+\.[a-z]+)$ $1; ``` off参数可以取消当前配置级别的所有proxy_cookie_domain指令: ``` proxy_cookie_domain off; proxy_cookie_domain localhost example.org; proxy_cookie_domain www.example.org example.org; ``` ## 4.4 proxy_redirect 语法: ``` proxy_redirect [ default|off|redirect replacement ] ``` 默认值: ``` proxy_redirect default ``` 使用字段: ``` http, server, location ``` 背景:即便配置了nginx代理,当服务返回重定向报文时(http code为301或302),会将重定向的目标url地址放入http response报文的header的location字段内(该字段用于重定向)。用户浏览器收到重定向报文时,会解析出该字段并作跳转。此时新的请求报文将直接发送给真实服务地址,而非反代服务器地址。为了能让反代服务器nginx拦截此类请求,必须修改重定向报文的location信息。 假设被代理服务器返回Location字段为: `http://localhost:8000/two/some/uri/` 这个指令: ``` proxy_redirect http://localhost:8000/two/ http://frontend/one/; ``` 将Location字段重写为`http://frontend/one/some/uri/`。 如果使用“default”参数,将根据location和proxy_pass参数的设置来决定。 例如下列两个配置等效: ``` location /one/ { proxy_pass http://upstream:port/two/; proxy_redirect default; } location /one/ { proxy_pass http://upstream:port/two/; proxy_redirect http://upstream:port/two/ /one/; } ``` 在指令中可以使用一些变量: ``` proxy_redirect http://localhost:8000/ http://$host:$server_port/; ``` 参数off将在这个字段中禁止所有的proxy_redirect指令: ``` proxy_redirect off; proxy_redirect default; proxy_redirect http://localhost:8000/ /; proxy_redirect http://www.example.com/ /; ``` ## 4.5 sub_filter ngx_http_sub_module模块是一个过滤器,它修改网站响应内容中的字符串,比如你想把响应内容中的‘xxxx’全部替换成‘yyy’,这个模块已经内置在nginx中,但是默认未安装,需要安装需要加上配置参数:--with-http_sub_module 1、语法: ``` sub_filter string replacement; ``` 默认值: ``` — ``` 配置段: ``` http, server, location ``` 设置需要使用说明字符串替换说明字符串.string是要被替换的字符串,replacement是新的字符串,它里面可以带变量。 2、语法: ``` sub_filter_once on | off; ``` 默认值: ``` sub_filter_once on; ``` 配置段: ``` http, server, location ``` 字符串替换一次还是多次替换,默认替换一次,例如你要替换响应内容中的ttlsa为运维生存时间,如果有多个ttlsa出现,那么只会替换第一个,如果off,那么所有的ttlsa都会 被替换 3、语法: ``` sub_filter_types mime-type ...; ``` 默认值: ``` sub_filter_types text/html; ``` 配置段: ``` http, server, location ``` 指定需要被替换的MIME类型,默认为“text/html”,如果制定为*,那么所有的 4、示例: ``` location / { proxy_pass http://zhengde.xxx.cn; proxy_set_header Host zhengde.xxx.cn; sub_filter xxx.com yyy.com; sub_filter_once on; sub_filter_types text/html; } ``` 解释: - sub_filter 前面字符串(xxx.com)是需要替换的内容,后面字符串(yyy.com)是替换成的内容。 - sub_filter_once 意思是只查找并替换一次。on是开启此功能,off是关闭,默认值是on。 - sub_filter_types 一行意思是选定查找替换文件类型为文本型。也可以不加此行,因为默认只查找文本型文件。 # 5. 使用nginx反向代理后如何在web应用中获取用户ip 在实际应用中,我们可能需要获取用户的ip地址,比如做异地登陆的判断,或者统计ip访问次数等,通常情况下我们使用request.getRemoteAddr()就可以获取到客户端ip,但是当我们使用了nginx作为反向代理后,使用request.getRemoteAddr()获取到的就一直是nginx服务器的ip的地址。 经过反向代理后,由于在客户端和web服务器之间增加了中间层,通过`$remote_addr`变量拿到的将是反向代理服务器的ip地址,在web端使用`request.getRemoteAddr()`(本质上就是获取`$remote_addr`),取得的是nginx的地址,当然是没法获得用户的真实ip的。 但是,nginx是可以获得用户的真实ip的,也就是说nginx使用$remote_addr变量时获得的是用户的真实ip,如果我们想要在web端获得用户的真实ip,就必须在nginx这里作一个赋值操作,如下: ``` proxy_set_header X-real-ip $remote_addr; ``` 其中这个X-real-ip是一个自定义的变量名,名字可以随意取,这样做完之后,用户的真实ip就被放在X-real-ip这个变量里了,然后,在web端可以这样获取: request.getAttribute("X-real-ip") **简单描述如下:** web端直接获取$remote_addr,实际上获取的是反代服务器地址,无法得到用户真实地址 但是,nginx端存在关系 ``` $remote_addr => 真实用户地址 ``` 在nginx端,新定义一个变量,将这个值存起来,发给web端 ``` $x-real-ip = $remote_addr ``` 在web端获取$x-real-ip,实际上就可以获取到真实用户地址了 --- 既然提到了真实的用户地址,这里再探讨下`X-Forwarded-For` X-Forwarded-For 是一个 HTTP 扩展头部。HTTP/1.1(RFC 2616)协议并没有对它的定义,它最开始是由 Squid 这个缓存代理软件引入,用来表示 HTTP 请求端真实 IP。如今它已经成为事实上的标准,被各大 HTTP 代理、负载均衡等转发服务广泛使用,并被写入 RFC 7239(Forwarded HTTP Extension)标准之中。 X-Forwarded-For 请求头格式非常简单,就这样: ``` X-Forwarded-For: client, proxy1, proxy2 ``` 可以看到,XFF 的内容由「英文逗号 + 空格」隔开的多个部分组成,最开始的是离服务端最远的设备 IP,然后是每一级代理设备的 IP。 当我们 意思是增加一个$proxy_add_x_forwarded_for到X-Forwarded-For里去,注意是增加,而不是覆盖,实际过程是如下的, 假如一个 HTTP 请求到达真实服务器(real_server)之前,经过了三个代理 Proxy1、Proxy2,IP 分别为 IP1、IP2,用户真实 IP 为 IP0,在每台代理服务器nginx增加了如下配置: ``` proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; ``` 以上配置中,$proxy_add_x_forwarded_for变量包含客户端请求头中的"X-Forwarded-For",与$remote_addr两部分,他们之间用逗号分开。以下是$proxy_add_x_forwarded_for变量在不同服务器中的值变化 ``` 那么第一台代理服务器proxy1的情形:X-Forwarded-For(空) + $remote_addr(IP0) 那么第二台代理服务器proxy2的情形:X-Forwarded-For(IP0) + $remote_addr(IP1) 那么真实服务器real_server的情形:X-Forwarded-For(IP0,IP1) + $remote_addr(IP2) ``` 此时服务端获取的X-Forwarded-For的值为 IP0,IP1,IP2,其中并没有包含真实服务器的地址,这个地址可以通过Remote Address 字段获得。 # 参考资料: https://imququ.com/post/x-forwarded-for-header-in-http.html http://tengine.taobao.org/nginx_docs/cn/docs/http/ngx_http_proxy_module.html#proxy_set_header http://gong1208.iteye.com/blog/1559835

nginx笔记-负载均衡

[TOC] # 1. 负载均衡介绍 客户端向反向代理发送请求,接着反向代理根据某种负载机制转发请求至目标服务器(这些服务器都运行着相同的应用),并把获得的内容返回给客户端,期中,代理请求可能根据配置被发往不同的服务器。 ![](http://markdown.archerwong.cn/2018-12-18-08-12-54_1.png) 负载均衡的目的是为了解决单个节点压力过大,造成Web服务响应过慢,严重的情况下导致服务瘫痪,无法正常提供服务。 # 2. 负载均衡策略 ## 2.1 策略种类 - 轮循(默认) 请求以循环、轮转的方式分发到应用服务器。 - 最少连接 下一个请求被分配到拥有最少活动连接数的服务器。 - IP Hash 绑定处理请求的服务器。第一次请求时,根据该客户端的IP算出一个HASH值,将请求分配到集群中的某一台服务器上。后面该客户端的所有请求,都将通过HASH算法,找到之前处理这台客户端请求的服务器,然后将请求交给它来处理。 - fair(第三方) 按后端服务器的响应时间来分配,响应时间短的优先分配 - url_hash (第三方) 按访问的url的hash结果分配,使每个url定向到同一个后端服务器,后端为缓存服务器比较有效。 ## 2.2 策略详细介绍 ### 2.2.1 轮询 ``` http { # ... 省略其它配置 upstream myapp { server 192.168.0.100:8080; server 192.168.0.101:8080; server example.com:8080; } server { listen 80; location / { proxy_pass http://myapp; } } # ... 省略其它配置 } ``` proxy_pass http://myapp:表示将所有请求转发到myapp服务器组中配置的某一台服务器上。 upstream模块:配置反向代理服务器组,Nginx会根据配置,将请求分发给组里的某一台服务器。myapp是服务器组的名称。 upstream模块下的server指令:配置处理请求的服务器IP或域名,端口可选,不配置默认使用80端口。通过上面的配置,Nginx默认将请求依次分配给192.168.0.100,192.168.0.101,example.com来处理 ### 2.2.2 最少连接 ``` upstream myapp { least_conn; server 192.168.0.100:8080; server 192.168.0.101:8080; server example.com:8080; } ``` nginx会尽量不让负载繁忙的应用服务器上负载过多的请求,相反的,会把新的请求发送到比较不繁忙的服务器 ### 2.2.3 IP HASH 轮询和最少连接策略下,每个后续的客户端可能被分发至不同服务器,不保证相同客户端的请求总是被发送到相同的服务器。 如果有必要把客户端绑定至特定服务器,则可使用ip-hash负载均衡机制。 ip-hash机制下,客户端ip地址被用作hash key来判断客户端请求应该发送到哪个服务器,这种方法保证了来自相同客户端的请求总是发送到相同服务器(如果服务器可用的话),该调度算法可以解决session的问题,但有时会导致分配不均即无法保证负载均衡。 ``` upstream myapp { ip_hash; server 192.168.0.100:8080; server 192.168.0.101:8080; server example.com:8080; } ``` ### 2.2.4 fair(第三方) 按后端服务器的响应时间来分配请求,响应时间短的优先分配。 ``` upstream myapp { fair; server 192.168.0.100:8080; server 192.168.0.101:8080; server example.com:8080; } ``` ### 2.2.5 url_hash(第三方) 按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,后端服务器为缓存时比较有效。 例:在upstream中加入hash语句,server语句中不能写入weight等其他的参数,hash_method是使用的hash算法 ``` upstream myapp { hash $request_uri; hash_method crc32; server 192.168.0.100:8080; server 192.168.0.101:8080; server example.com:8080; } ``` ## 2.3 参数 可以配置参数来更改策略 - weight ``` upstream myapp { server 192.168.0.100:8080 weight=2; # 2/6次 server 192.168.0.101:8080 weight=3; # 3/6次 server 192.168.0.102:8080 weight=1; # 1/6次 } ``` 上例配置,表示6次请求中,100分配2次,101分配3次,102分配1次,注意权重适用于轮询策略下。 - max_fails 默认为1。某台Server允许请求失败的次数,超过最大次数后,在fail_timeout时间内,新的请求将不会分配给这台机器。如果设置为0,Nginx会将这台Server置为永久无效状态,然后将请求发给定义了proxy_next_upstream, fastcgi_next_upstream, uwsgi_next_upstream, scgi_next_upstream, and memcached_next_upstream指令来处理这次错误的请求。 - fail_timeout 默认为10秒。某台Server达到max_fails次失败请求后,在fail_timeout期间内,nginx会认为这台Server暂时不可用,不会将请求分配给它 ``` upstream myapp { server 192.168.0.100:8080 weight=2 max_fails=3 fail_timeout=15; server 192.168.0.101:8080 weight=3; server 192.168.0.102:8080 weight=1; } ``` 192.168.0.100这台机器,如果有3次请求失败,nginx在15秒内,不会将新的请求分配给它。 - backup 备份机,所有服务器挂了之后才会生效 ``` upstream myapp { server 192.168.0.100:8080 weight=2 max_fails=3 fail_timeout=15; server 192.168.0.101:8080 weight=3; server 192.168.0.102:8080 backup; } ``` 在100和101都挂了之前,102为不可用状态,不会将请求分配给它。只有当100和101都挂了,102才会被启用。 - down 标识某一台server不可用。可能能通过某些参数动态的激活它吧,要不真没啥用。 ``` upstream myapp { server 192.168.0.100:8080 weight=2 max_fails=3 fail_timeout=15; server 192.168.0.101:8080 down; server 192.168.0.102:8080 backup; } ``` 表示101这台Server为无效状态,不会将请求分配给它。 - max_conns 限制分配给某台Server处理的最大连接数量,超过这个数量,将不会分配新的连接给它。默认为0,表示不限制。注意:1.5.9之后的版本才有这个配置 ``` upstream myapp { server 192.168.0.100:8080 max_conns=1000; } ``` 表示最多给100这台Server分配1000个请求,如果这台Server正在处理1000个请求,nginx将不会分配新的请求给到它。假如有一个请求处理完了,还剩下999个请求在处理,这时nginx也会将新的请求分配给它。 - resolve 将server指令配置的域名,指定域名解析服务器。需要在http模块下配置resolver指令,指定域名解析服务 ``` http { resolver 10.0.0.1; upstream myapp { zone ...; ... server example.com resolve; } } ``` 表示example.com域名,由10.0.0.1服务器来负责解析。 # 参考资料 https://www.jianshu.com/p/4656ca690639 https://blog.csdn.net/xyang81/article/details/51702900 http://blog.sina.com.cn/s/blog_13cc013b50102wbpz.html

nginx笔记-配置详解

[TOC] # 1. nginx配置总览 一般来说nginx的配置文件位于/etc/nginx/nginx.conf,大体的结构如下 ``` ... #全局块 events { #NGINX工作模式 ... } http #http块 { ... #http全局块 server #server块 { ... #server全局块 location [PATTERN] #location块 { ... } location [PATTERN] { ... } } server { ... } ... #http全局块 } ``` 大体的职责 ``` 1、全局块:配置影响nginx全局的指令。一般有运行nginx服务器的用户组,nginx进程pid存放路径,日志存放路径,配置文件引入,允许生成worker process数等。 2、events块:配置影响nginx服务器或与用户的网络连接。有每个进程的最大连接数,选取哪种事件驱动模型处理连接请求,是否允许同时接受多个网路连接,开启多个网络连接序列化等。 3、http块:可以嵌套多个server,配置代理,缓存,日志定义等绝大多数功能和第三方模块的配置。如文件引入,mime-type定义,日志自定义,是否使用sendfile传输文件,连接超时时间,单连接请求数等。 4、server块:配置虚拟主机的相关参数,一个http中可以有多个server。 5、location块:配置请求的路由,以及各种页面的处理情况。 ``` 一份默认的nignx配置文件如下 ``` # For more information on configuration, see: # * Official English Documentation: http://nginx.org/en/docs/ # * Official Russian Documentation: http://nginx.org/ru/docs/ user nginx; worker_processes auto; error_log /var/log/nginx/error.log; pid /run/nginx.pid; # Load dynamic modules. See /usr/share/nginx/README.dynamic. include /usr/share/nginx/modules/*.conf; events { worker_connections 1024; } http { log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; types_hash_max_size 2048; include /etc/nginx/mime.types; default_type application/octet-stream; # Load modular configuration files from the /etc/nginx/conf.d directory. # See http://nginx.org/en/docs/ngx_core_module.html#include # for more information. include /etc/nginx/conf.d/*.conf; server { listen 80 default_server; listen [::]:80 default_server; server_name _; root /usr/share/nginx/html; # Load configuration files for the default server block. location / { } error_page 404 /404.html; location = /40x.html { } error_page 500 502 503 504 /50x.html; location = /50x.html { } } # Settings for a TLS enabled server. # # server { # listen 443 ssl http2 default_server; # listen [::]:443 ssl http2 default_server; # server_name _; # root /usr/share/nginx/html; # # ssl_certificate "/etc/pki/nginx/server.crt"; # ssl_certificate_key "/etc/pki/nginx/private/server.key"; # ssl_session_cache shared:SSL:1m; # ssl_session_timeout 10m; # ssl_ciphers HIGH:!aNULL:!MD5; # ssl_prefer_server_ciphers on; # # # Load configuration files for the default server block. # include /etc/nginx/default.d/*.conf; # # location / { # } # # error_page 404 /404.html; # location = /40x.html { # } # # error_page 500 502 503 504 /50x.html; # location = /50x.html { # } # } } ``` # 2. main模块 ## 2.1 配置用户用户组 指定Nginx Worker进程运行用户以及用户组 ``` user user [group]; ``` - user, 可运行 Nginx 服务器的用户 - group, 指定可运行用户组 当配置`user nginx;`时,使用root用户启动nginx,查看下进程情况,发现master进程是root,worker进程是nginx。 ``` $ ps -ef | grep nginx root 1190 1 0 Jul20 ? 00:00:00 nginx: master process /usr/sbin/nginx nginx 1191 1190 0 Jul20 ? 00:00:42 nginx: worker process nginx 1192 1190 0 Jul20 ? 00:00:47 nginx: worker process root 7104 7049 0 16:52 pts/0 00:00:00 grep --color=auto --exclude-dir=.bzr --exclude-dir=CVS --exclude-dir=.git --exclude-dir=.hg --exclude-dir=.svn nginx ``` ## 2.2 配置worker process 数 worker角色的工作进程的个数,master进程是接收并分配请求给worker处理。这个数值简单一点可以设置为cpu的核数,也是 auto 值,如果开启了ssl和gzip更应该设置成与逻辑CPU数量一样甚至为2倍,可以减少I/O操作。 ``` worker_processes number | auto; ``` - number, 指定 Nginx 进程最多可产生的 worker process 数 - auto, Nginx 自动 - 查看物理cpu个数 ``` cat /proc/cpuinfo |grep "physical id"|sort |uniq|wc -l 1 ``` 查看逻辑cpu个数 ``` cat /proc/cpuinfo |grep "processor"|wc -l 2 ``` 查看下进程情况,有 一个master进程,两个worker进程 ``` $ ps -ef | grep nginx root 1190 1 0 Jul20 ? 00:00:00 nginx: master process /usr/sbin/nginx nginx 1191 1190 0 Jul20 ? 00:00:42 nginx: worker process nginx 1192 1190 0 Jul20 ? 00:00:47 nginx: worker process root 7104 7049 0 16:52 pts/0 00:00:00 grep --color=auto --exclude-dir=.bzr --exclude-dir=CVS --exclude-dir=.git --exclude-dir=.hg --exclude-dir=.svn nginx ``` 当设置`worker_processes auto;`时,可以看出nginx默认启动的数量是和逻辑cpu数量一致的。 ## 2.3 PID文件存放路径 Nginx 进程作为系统守护进程运行,在文件中保存当前运行程序主进程号,支持配置 PID ``` pid file_path; ``` pid文件的作用 ``` (1) pid文件的内容:pid文件为文本文件,内容只有一行, 记录了该进程的ID。 (2) pid文件的作用:准确判断进程是否正在运行,防止进程启动多个副本。只有获得pid文件(固定路径固定文件名)写入权限(F_WRLCK)的进程才能正常启动并把自身的PID写入该文件中。其它同一个程序的多余进程则自动退出。 ``` ## 2.4 错误日志路径 全局块、http 块 和 server 块都可以对 Nginx 日志进行配置 ``` error_log file | stderr [debug | info | notice | warn | error |crit | alert | emerg]; ``` 日志级别可选,从低到高 debug, info, notice, warn, error, crit, alert, emerg ,其中,debug输出日志最为最详细,需要注意的是 debug 需要编译时使用 --with-debug 开启。 ## 2.5 引入其他配置 Nginx 提供 include 配置来引入其他文件 ``` include file; ``` file 是要引入的配置文件,支持相对路径和正则匹配 # 3. events模块 ## 3.1 use 用来指定Nginx的工作模式。 ``` use select|poll|kqueue|epoll|resig|/dev/poll|eventport; ``` Nginx支持的工作模式有select、poll、kqueue、epoll、rtsig和/dev/poll。其中select和poll都是标准的工作模式,kqueue和epoll是高效的工作模式,不同的是epoll用在Linux平台上,而kqueue用在BSD系统中,因为Mac基于BSD,所以Mac也得用这个模式,对于Linux系统,epoll工作模式是首选。 工作模式的简介: - select: 这是一种标准的请求处理方法。如果一个平台上缺少相应的更加有效的方法,那么Nginx会自动使用select方法。 - poll: 这是一种标准的请求处理方法。如果一个平台上缺少相应的更加有效的方法,那么Nginx会自动使用poll方法。 - kqueue: 这是BSD家族操作系统上可用的一种高效的请求处理方法。可用于FreeBSD, OpenBSD, NetBSD和OS X。kqueue方法会忽略multi_accept。 - epoll: 这是Linux系统上可用的一种高效的请求处理方法,类似于kqueue。它有一个额外的directive,那就是epoll_events。epoll_events指定了Nginx可以向内核传递的事件数量。默认的值是512。 ## 3.2 worker_connections 用于定义Nginx每个进程的最大连接数 ``` worker_connections number; ``` 即接收前端的最大请求数。最大客户端连接数由worker_processes和worker_connections决定,即Max_clients = worker_processes * worker_connections,在作为反向代理时,Max_clients变为:Max_clients = worker_processes * worker_connections / 4。 进程的最大连接数受Linux系统进程的最大打开文件数限制,在执行操作系统命令“ulimit -n 65536”后worker_connections的设置才能生效。 ## 3.3 设置网路连接序列化,防止惊群现象发生,默认为on ``` accept_mutex on; ``` 惊群现象 主进程(master 进程)首先通过 socket() 来创建一个 sock 文件描述符用来监听,然后fork生成子进程(workers 进程),子进程将继承父进程的 sockfd(socket 文件描述符),之后子进程 accept() 后将创建已连接描述符(connected descriptor)),然后通过已连接描述符来与客户端通信。 那么,由于所有子进程都继承了父进程的 sockfd,那么当连接进来时,所有子进程都将收到通知并“争着”与它建立连接,这就叫“惊群现象”。大量的进程被激活又挂起,只有一个进程可以accept() 到这个连接,这当然会消耗系统资源。 Nginx对惊群现象的处理 Nginx 提供了一个 accept_mutex 这个东西,这是一个加在accept上的一把共享锁。即每个 worker 进程在执行 accept 之前都需要先获取锁,获取不到就放弃执行 accept()。有了这把锁之后,同一时刻,就只会有一个进程去 accpet(),这样就不会有惊群问题了。accept_mutex 是一个可控选项,我们可以显示地关掉,默认是打开的。 ## 3.4 worker_rlimit_nofile 由于每一个socket都会打开一个文件描述符,所以服务器可以同时处理连接数量受到系统文件描述符数量的限制。如果nginx打开的socket数量超过了文件描述符的数量,那么在error.log文件中会出现too many opened files错误。我们可以用下面的命令来查看文件描述符的数量: ``` $ ulimit -n ``` Nginx worker进程默认的用户名是www-data,用户www-data所拥有的文件描述符的数量要大于worker进程数量与worker_connections之乘积。 nginx有一个worker_rlimit_nofile directive,可以用来设置系统可用的文件描述符。这与ulimit设置可用文件描述符的作用是一样的。如果它们都设置了可用文件描述符,那么worker_rlimit_nofile会覆盖ulimit的设置。 ``` worker_rlimit_nofile 20960; ``` 查看操作系统对一个进程施加的限制,我们可以用命令读取/etc/$pid/limits文件,$pid是进程的pid。 ## 3.5 设置一个进程是否同时接受多个网络连接,默认为off ``` multi_accept on; ``` multi_accept可以让nginx worker进程尽可能多地接受请求。它的作用是让worker进程一次性地接受监听队列里的所有请求,然后处理。如果multi_accept的值设为off,那么worker进程必须一个一个地接受监听队列里的请求。 # 4. http模块 ## 4.1 定义 MIME TYPE 类型 浏览器使用 MIME Type 来区分不同的媒体类型, Nginx 作为 Web 服务器,必须能够识别前端请求的资源类型。 ``` include mime.types; default_type application/octet-stream; ``` 1、include 用来设定文件的mime类型,类型在配置文件目录下的mime.type文件定义,来告诉nginx来识别文件类型。 2、default_type 设定了默认的类型为二进制流,也就是当文件类型未定义时使用这种方式,例如在没有配置asp的locate 环境时,Nginx是不予解析的,此时,用浏览器访问asp文件就会出现下载窗口了。 以下是mime.types文件的内容,该文件中包含了浏览器能够识别的 MIME 类型,以及对应的文件后缀名。 ``` types { text/html html htm shtml; text/css css; text/xml xml; image/gif gif; image/jpeg jpeg jpg; application/javascript js; application/atom+xml atom; application/rss+xml rss; text/mathml mml; text/plain txt; text/vnd.sun.j2me.app-descriptor jad; text/vnd.wap.wml wml; text/x-component htc; image/png png; image/tiff tif tiff; image/vnd.wap.wbmp wbmp; image/x-icon ico; image/x-jng jng; image/x-ms-bmp bmp; image/svg+xml svg svgz; image/webp webp; application/font-woff woff; application/java-archive jar war ear; application/json json; application/mac-binhex40 hqx; application/msword doc; application/pdf pdf; application/postscript ps eps ai; application/rtf rtf; application/vnd.apple.mpegurl m3u8; application/vnd.ms-excel xls; application/vnd.ms-fontobject eot; application/vnd.ms-powerpoint ppt; application/vnd.wap.wmlc wmlc; application/vnd.google-earth.kml+xml kml; application/vnd.google-earth.kmz kmz; application/x-7z-compressed 7z; application/x-cocoa cco; application/x-java-archive-diff jardiff; application/x-java-jnlp-file jnlp; application/x-makeself run; application/x-perl pl pm; application/x-pilot prc pdb; application/x-rar-compressed rar; application/x-redhat-package-manager rpm; application/x-sea sea; application/x-shockwave-flash swf; application/x-stuffit sit; application/x-tcl tcl tk; application/x-x509-ca-cert der pem crt; application/x-xpinstall xpi; application/xhtml+xml xhtml; application/xspf+xml xspf; application/zip zip; application/octet-stream bin exe dll; application/octet-stream deb; application/octet-stream dmg; application/octet-stream iso img; application/octet-stream msi msp msm; application/vnd.openxmlformats-officedocument.wordprocessingml.document docx; application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx; application/vnd.openxmlformats-officedocument.presentationml.presentation pptx; audio/midi mid midi kar; audio/mpeg mp3; audio/ogg ogg; audio/x-m4a m4a; audio/x-realaudio ra; video/3gpp 3gpp 3gp; video/mp2t ts; video/mp4 mp4; video/mpeg mpeg mpg; video/quicktime mov; video/webm webm; video/x-flv flv; video/x-m4v m4v; video/x-mng mng; video/x-ms-asf asx asf; video/x-ms-wmv wmv; video/x-msvideo avi; } ``` ## 4.2 自定义 Access 日志 与 error_log 不同的是,Nginx 进程运行时访问日志,由 Nginx 提供服务过程中应答前端请求的日志。 Nginx 服务器支持对服务日志的格式、大小、输出等进行配置,需要使用两个配置 `log_format` 和 `access_log` 配置日志格式的语法是: ``` log_format format_name 'set_of_variables_to_define_format'; ``` 并且配置访问日志的语法是: ``` access_log /path/to/log_file format_name; #simplest form //OR access_log /path/to/log_file [format [buffer=size] [gzip[=level]] [flush=time] [if=condition]]; ``` ### 4.2.1 log_format 自定义日志格式 ``` log_format format_name 'set_of_variables_to_define_format'; ``` - format_name : 给定义的格式起的名称,应该是全局唯一的 - set_of_variables_to_define_format自定义格式化字符串,也可以增删部分参数 默认的配置格式 ``` log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; ``` 实际产生的日志 ``` 123.151.43.110 - - [02/Aug/2018:03:30:16 +0800] "GET / HTTP/1.1" 200 3700 "-" "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.89 Safari/537.36" "-" ``` 常见的内置变量 ``` $remote_addr, $http_x_forwarded_for 记录客户端IP地址 $remote_user 记录客户端用户名称 $request 记录请求的URL和HTTP协议 $status 记录请求状态 $body_bytes_sent 发送给客户端的字节数,不包括响应头的大小; 该变量与Apache模块mod_log_config里的“%B”参数兼容。 $bytes_sent 发送给客户端的总字节数。 $connection 连接的序列号。 $connection_requests 当前通过一个连接获得的请求数量。 $msec 日志写入时间。单位为秒,精度是毫秒。 $pipe 如果请求是通过HTTP流水线(pipelined)发送,pipe值为“p”,否则为“.”。 $http_referer 记录从哪个页面链接访问过来的 $http_user_agent 记录客户端浏览器相关信息 $request_length 请求的长度(包括请求行,请求头和请求正文)。 $request_time 请求处理时间,单位为秒,精度毫秒; 从读入客户端的第一个字节开始,直到把最后一个字符发送给客户端后进行日志写入为止。 $time_iso8601 ISO8601标准格式下的本地时间。 $time_local 通用日志格式下的本地时间。 ``` ### 4.2.2 access_log ``` access_log path [format [buffer=size]]; ``` - path, 配置服务日志的文件存放路劲及名称 - format 可选,自定义日志格式,也可以通过 log_format 配置指定好,直接引用格式名 - size 临时存放日志的内存缓存区大小 可以使用同一级别的access_log指令指定多个日志,两个日志文件都会被记录 ``` access_log /var/log/nginx/access.log; access_log /var/log/nginx/custom_log custom; ``` 如果要取消记录日志功能,使用 ``` access_log off; ``` ### 4.3.3 error_log 前面在全局模块已经提到过error_log命令,和access_log类似,error_log也是设置记录日志的指令。不过它记录的是错误日志。 该指令在 http, stream, server 和 location 段都可以被指定,可以覆盖更外面的段的设置。 ``` error_log file | stderr [debug | info | notice | warn | error |crit | alert | emerg]; ``` 这些问题属于不同的严重程度级别: 调试 , 信息 , 通知 , 警告 , 错误 (这是默认级别,全球工作), 暴击 , 警报或重大事件 。 例如: ``` error_log /var/log/nginx/error_log warn; ``` 这将指示Nginx记录所有类型警告和更严重的日志级别暴击 , 警报和emerg消息的消息。 在下一个示例中,将会记录暴击 , 警报和紧急级别的消息。 ``` error_log /var/www/example1.com/log/error_log crit; ``` 和access_log类似,可以使用同一级别的error_log指令指定多个日志,两个日志文件都会被记录 ``` error_log /var/www/example1.com/log/error_log warn; error_log /var/log/nginx/example1.error_log crit; ``` ## 4.4 sendfile 当一个程序需要传输文件时,Linux内核首先将文件数据缓冲,然后将文件数据传送给程序缓冲,最后程序将文件数据传输到目的地。Sendfile方法是一种数据传输的更高效的方法,数据在内核中的文件描述符之间传输,而不需要将数据传输给程序缓冲。这种方法的结果是改善了对操作系统资源的利用。 我们可以用sendfile directive来启用sendfile方法,在http,server,location三个模块都可以定义。 ``` http { sendfile on ; } ``` 默认情况下,sendfile 的值是on。 ## 4.5 配置连接超时时间 用户连接回话连接后, Nginx 服务器可以保持打开一段时间,在超过这个时间之后,服务器会关闭该连接。 ``` keepalive_timeout timeout [header_timeout]; ``` - timeout 对连接的保持时间 - header_timeout 可选,在 Response 头部 Keep-Alive 域设置超时时间 示例 ``` keepalive_timeout 120s 100s; ``` # 5. server模块 erver模块是http的子模块,它用来定一个虚拟主机,我们先讲最基本的配置,这些在后面再讲。下面是一个简单的server ``` server{ server_name www.xxx.cn xxx.cn; listen 80; #工程根目录 root /data/laravel-vue/public/; charset UTF-8; #日志文件位置,自己选择 access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log; index index.php index.html index.htm; #error_page 500 502 503 504 404 /missing.html; #error_page 403 =404 /missing.html; location / { try_files $uri $uri/ /index.php$is_args$args; } location ~ \.php$ { fastcgi_pass 127.0.0.1:9000; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } } ``` 1、server 标志定义虚拟主机开始。 2、listen 用于指定虚拟主机的服务端口。 监听端口,默认80,小于1024的要以root启动。可以为listen *:80、listen 127.0.0.1:80等形式。 同时监听IPv4和IPv6地址 ``` listen [::]:80; ``` 但是从nginx 1.3某个版本起,上面语句只是监听ipv4地址,因为有个参数ipv6only是默认打开的,上面就相当于 ``` listen [::]:80 ipv6only=on; #改版后,只是监听ipv6地址了 ``` 所以要同时监听ipv4和ipv6 ``` listen 80; listen [::]:80; ``` 3、server_name 用来指定IP地址或者域名 多个域名之间用空格分,还可以使用通配符 * ,但通配符只能放到首尾,server_name中还能使用正则表达式,使用 ~ 开始 ``` server_name ~^ww\d+\.einverne\.info$; ``` 匹配 ww1.einverne.info 但不匹配 www.einverne.info 对于不同的匹配方式,Nginx 按照如下优先级选择虚拟主机 ``` 准确匹配 server_name 通配符在开始时匹配 server_name 成功 通配符在结尾时匹配 server_name 成功 正则表达式匹配 ``` 在以上四种匹配方式中,如果 server_name 被处于同一优先级匹配方式匹配多次成功,则首次匹配成功的虚拟主机处理请求。 4、root 表示在这整个server虚拟主机内,全部的root web根目录。 5、index 全局定义访问的默认首页地址。 当找不到时候,会尝试按照index 指令后面定义的顺序查找文件,有则按照找到的文件运行。 ``` index index.php index.html index.htm; ``` 先查找 index.php,然后index.html ,最后index.htm 6、charset 用于设置网页的默认编码格式。 7、access_log 和 error_log 用来指定此虚拟主机的日志存放路径,前面说的比较详细了,这里的优先级高于http块。 # 6 location块 location模块是nginx中用的最多的,也是最重要的模块了,什么负载均衡、反向代理等都与它相关,location根据它字面意思就知道是来定位的,定位URL,解析URL。 下面分析一份平常在用的站点配置。 ``` server{ server_name www.xxx.cn xxx.cn; listen 80; #工程根目录 root /data/laravel-vue/public/; charset UTF-8; #日志文件位置,自己选择 access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log; index index.php index.html index.htm; #error_page 500 502 503 504 404 /missing.html; #error_page 403 =404 /missing.html; location / { #第一种写法 try_files $uri $uri/ /index.php$is_args$args; #第二种写法 #try_files $uri $uri/ /index.php?$query_string; } location ~ \.php$ { fastcgi_pass 127.0.0.1:9000; #第一种写法     fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;     include fastcgi_params;     #第二种写法,区别在于第一种,include引入的配置已经包括上面的参数     # include fastcgi.conf; } } ``` 分析下上面的配置, 1、 `location /` 是一个通用配置,如果没有优先级更高的匹配则都会走到这个通用路由下, 2、 `try_files`指令负责了重定向操作, 实际上这里做了动静分离,静态文件直接去相应目录拿,动态文件进行改写 如果是`$uri`或`$uri/`的形式,则直接匹配到相应文件,找不到静态文件,则会尝试按照index的顺序,后置加上后进行匹配,比如这里首先匹配index.php,如果匹配上则送入`location ~ \.php$`路由下。 如果不是`$uri`或`$uri/`的形式的话,则中间加个index.php,然后拼接上`?`和参数,此时有了index.php,根据匹配规则会被送到`location ~ \.php$`路由下。 3、 `location ~ \.php$`用来处理php动态语言 我们启动php-fpm,监听9000端口 ``` fastcgi_pass 127.0.0.1:9000; ``` 就是说将请求转发到9000端口,交给php-fpm处理,此时从nginx到php-fpm可能有点语言不通,需要翻一下,所以就有了下面的引入参数 ``` fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; ``` 还有另一种写法,这里面已经包括了SCRIPT_FILENAME参数 ``` include fastcgi.conf; ``` # 7. 其它一些问题 上面介绍了nginx的基本配置,这一章节探讨一些没有讲到的问题。 ## 7.1 alias目录和root目录的区别: 配置demo: ``` location /test.html { root /data/ceshi/; # root /data/ceshi;路径结尾加不加/,不影响结果 } location /xx/test.html { root /data/ceshi/; } ``` - 浏览器访问 xxx.com/test.html,实际访问的是 /data/ceshi/test.html - 浏览器访问 xxx.com/xx/test.html,实际访问的是 /data/ceshi/xx/test.html 结论: root属性,会把root的值(这里是yyy)加入到访问路径(locaition)之前 配置demo: ``` location /xxx { alias /data/ceshi/; # alias /data/ceshi; 查看资料说必须加上/,否则会找不到文件,实测可以找到,这里自己可以尝试下。 } ``` - 浏览器访问 xxx.com/xxx,实际访问的是 /data/ceshi - 浏览器访问 xxx.com/xxx/test.html,实际访问的是 /data/ceshi/test.html 结论:alias属性,和root的逻辑不通,会把alias的值(这里/data/ceshi/)替代访问路径匹配的部分(这里是/xxx) ## 7.2 在写location的时候,匹配url,加不加 /的探讨 以`location /test/` 和 `location /test` 为例 测试1: ``` location / { return 601; try_files $uri /index.php$is_args$args; } location /test { return 602; } location /test/ { return 603; } ``` ``` 访问 http://xxx.com/test => 602 访问 http://xxx.com/test/ => 603 ``` 测试2: ``` location / { return 601; try_files $uri /index.php$is_args$args; } location /test { return 602; } ``` ``` 访问 http://xxx.com/test => 602 访问 http://xxx.com/test/ => 602 ``` 测试3: ``` location / { return 601; try_files $uri /index.php$is_args$args; } location /test/ { return 603; } ``` ``` 访问 http://xxx.com/test => 601 访问 http://xxx.com/test/ => 603 ``` ## 7.3 nginx中的变量 ``` $arg_name 请求中的的参数名,即“?”后面的arg_name=arg_value形式的arg_name $args 请求中的参数值 $binary_remote_addr 客户端地址的二进制形式, 固定长度为4个字节 $body_bytes_sent 传输给客户端的字节数,响应头不计算在内;这个变量和Apache的mod_log_config模块中的“%B”参数保持兼容 $bytes_sent 传输给客户端的字节数 (1.3.8, 1.2.5) $connection TCP连接的序列号 (1.3.8, 1.2.5) $connection_requests TCP连接当前的请求数量 (1.3.8, 1.2.5) $content_length “Content-Length” 请求头字段 $content_type “Content-Type” 请求头字段 $cookie_name cookie名称 $document_root 当前请求的文档根目录或别名 $document_uri 同 $uri $host 优先级如下:HTTP请求行的主机名>”HOST”请求头字段>符合请求的服务器名 $hostname 主机名 $http_name 匹配任意请求头字段; 变量名中的后半部分“name”可以替换成任意请求头字段,如在配置文件中需要获取http请求头:“Accept-Language”,那么将“-”替换为下划线,大写字母替换为小写,形如:$http_accept_language即可。 $https 如果开启了SSL安全模式,值为“on”,否则为空字符串。 $is_args 如果请求中有参数,值为“?”,否则为空字符串。 $limit_rate 用于设置响应的速度限制,详见 limit_rate。 $msec 当前的Unix时间戳 (1.3.9, 1.2.6) $nginx_version nginx版本 $pid 工作进程的PID $pipe 如果请求来自管道通信,值为“p”,否则为“.” (1.3.12, 1.2.7) $proxy_protocol_addr 获取代理访问服务器的客户端地址,如果是直接访问,该值为空字符串。(1.5.12) $query_string 同 $args $realpath_root 当前请求的文档根目录或别名的真实路径,会将所有符号连接转换为真实路径。 $remote_addr 客户端地址 $remote_port 客户端端口 $remote_user 用于HTTP基础认证服务的用户名 $request 代表客户端的请求地址 $request_body 客户端的请求主体 此变量可在location中使用,将请求主体通过proxy_pass, fastcgi_pass, uwsgi_pass, 和 scgi_pass传递给下一级的代理服务器。 $request_body_file 将客户端请求主体保存在临时文件中。文件处理结束后,此文件需删除。如果需要之一开启此功能,需要设置client_body_in_file_only。如果将次文件传递给后端的代理服务器,需要禁用request body,即设置proxy_pass_request_body off,fastcgi_pass_request_body off, uwsgi_pass_request_body off, or scgi_pass_request_body off 。 $request_completion 如果请求成功,值为”OK”,如果请求未完成或者请求不是一个范围请求的最后一部分,则为空。 $request_filename 当前连接请求的文件路径,由root或alias指令与URI请求生成。 $request_length 请求的长度 (包括请求的地址, http请求头和请求主体) (1.3.12, 1.2.7) $request_method HTTP请求方法,通常为“GET”或“POST” $request_time 处理客户端请求使用的时间 (1.3.9, 1.2.6); 从读取客户端的第一个字节开始计时。 $request_uri 这个变量等于包含一些客户端请求参数的原始URI,它无法修改,请查看$uri更改或重写URI,不包含主机名,例如:”/cnphp/test.php?arg=freemouse”。 $scheme 请求使用的Web协议, “http” 或 “https” $sent_http_name 可以设置任意http响应头字段; 变量名中的后半部分“name”可以替换成任意响应头字段,如需要设置响应头Content-length,那么将“-”替换为下划线,大写字母替换为小写,形如:$sent_http_content_length 4096即可。 $server_addr 服务器端地址,需要注意的是:为了避免访问linux系统内核,应将ip地址提前设置在配置文件中。 $server_name 服务器名,www.cnphp.info $server_port 服务器端口 $server_protocol 服务器的HTTP版本, 通常为 “HTTP/1.0” 或 “HTTP/1.1” $status HTTP响应代码 (1.3.2, 1.2.2) $tcpinfo_rtt, $tcpinfo_rttvar, $tcpinfo_snd_cwnd, $tcpinfo_rcv_space 客户端TCP连接的具体信息 $time_iso8601 服务器时间的ISO 8610格式 (1.3.12, 1.2.7) $time_local 服务器时间(LOG Format 格式) (1.3.12, 1.2.7) $uri 请求中的当前URI(不带请求参数,参数位于$args),可以不同于浏览器传递的$request_uri的值,它可以通过内部重定向,或者使用index指令进行修改,$uri不包含主机名,如”/foo/bar.html”。 ``` # 参考资料 https://www.jianshu.com/p/bed000e1830b http://www.cnphp.info/nginx-embedded-variables-lasted-version.html