Nginx知识集锦
Nginx读作Engine X,在被广泛的用作:
- HTTP服务器
- 反向代理服务器
- 邮件代理服务器
- 通用的TCP/UDP代理
Nginx服务由一个Master进程和多个Worker进程构成。Master进程的主要职责是读取、解析配置文件,并维护工作进程。工作进程则负责实际的请求处理。为了高效的在Worker之间分发请求,Nginx引入了依赖于操作系统的、高效的事件驱动模型。Worker进程的数量常常根据CPU核心数设置。
Apache2 | Nginx | |
Web服务器 |
适合处理动态请求 稳定,功能强 更强大的rewrite 超多的模块 |
更少的资源消耗:10000非活跃Keep-Alive连接仅仅消耗2.5M内存 更多的并发连接,理论上不受限制,取决于内存,10W没问题 静态处理性能比Apache2高3倍 简单,效率高 热部署:Master管理进程和Worker工作进程分离,可以在不停机的前提下升级二进制文件、修改配置、更换日志文件 |
负载均衡器 | 通常不作为NLB |
作为反向代理抗住并发 —— 异步模型 |
通信模型 | 同步多进程模型,一个连接对应一个进程 | 异步模型,多个连接(万级别)可以对应一个进程 |
1 2 3 4 5 6 7 8 9 10 |
sudo apt-get install libpcre3 libpcre3-dev sudo apt-get install zlib1g zlib1g.dev sudo apt-get install openssl libssl-dev wget https://nginx.org/download/nginx-1.13.8.tar.gz tar xzf nginx-1.13.8.tar.gz && rm nginx-1.13.8.tar.gz cd nginx-1.13.8/ ./configure --prefix=/usr make -j8 sudo make install |
参数 | 说明 |
prefix | 安装前缀 |
sbin-path | 二进制文件安装前缀,默认$prefix/sbin/nginx |
conf-path | Nginx主配置文件位置,默认$prefix/conf/nginx.conf. |
pid-path | PID文件位置 |
error-log-path | 主错误日志位置,默认$prefix/logs/error.log |
http-log-path | 主请求日志位置,默认$prefix/logs/access.log |
user group |
Nginx工作进程的用户、组 |
with-*_module without-*_module |
启用/禁用特定模块 --with-stream 启用第四层代理/LB,即ngx_stream_core_module模块 |
with-* | 从指定位置寻找依赖库基础 |
add-module | 安装第三方模块到Nginx的二进制文件中 |
add-dynamic-module | 指定动态模块目录 |
配置示例:
1 2 3 4 5 6 7 |
./configure --sbin-path=/usr/bin/nginx --conf-path=/etc/nginx/nginx.conf --pid-path=/var/run/nginx/nginx.pid --with-http_ssl_module --with-pcre=../pcre-8.41 --with-zlib=../zlib-1.2.11 |
如果前缀设置为/usr,则主要路径如下:
1 2 3 4 5 6 7 8 |
nginx path prefix: "/usr" nginx binary file: "/usr/sbin/nginx" nginx modules path: "/usr/modules" nginx configuration prefix: "/usr/conf" nginx configuration file: "/usr/conf/nginx.conf" nginx pid file: "/usr/logs/nginx.pid" nginx error log file: "/usr/logs/error.log" nginx http access log file: "/usr/logs/access.log" |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
# nginx [-?hvVtTq] [-s signal] [-c filename] [-p prefix] [-g directives] # -V : 显示版本和构建配置选项,然后退出 # -t : 测试配置然后退出 # -T : 测试并输出配置,然后退出 # -q : 测试配置时抑制非错误类信息 # -s signal : 向Master进程发送信号: # stop 快速关闭 # quit 优雅关闭 # reopen 重新打开日志文件 # reload 重新载入配置文件 # -c filename :指定配置文件 # -g directives : 设置全局指令 # 启动Nginx并在后台运行 sudo nginx # 检查服务器是否成功启动 curl http://localhost:80 # 停止服务器 sudo nginx -s stop |
可以在编译Nginx期间,把模块编译进来:
1 2 |
# 目录/path/to/echo-nginx-module中存放echo模块的源代码 ./configure --prefix=/opt/nginx \ --add-module=/path/to/echo-nginx-module |
从1.9.11版本开始,Nginx支持动态模块。在编译Nginx时,你可以指定动态模块的存放目录:
1 |
./configure --add-dynamic-module=/usr/local/nginx/modules |
需要添加动态模块时,首先独立编译模块,然后在Nginx配置文件中指定:
1 2 |
# 加载动态模块 load_module /path/to/modules/ngx_http_echo_module.so; |
Nginx由很多模块组成,这些模块由控制文件中的指令(Directives)控制。指令可以分为:简单指令、块指令:
- 简单指令格式: directive-name param1 param2;
- 块指令格式:
1234567# 跨指令体使用花括号包围directive param1 {# 块指令内部可以包含其它指令directive {}}块指令中可以包含其它指令,外部的指令称为上下文(Context)。不位于任何{}内的指令,可以认为是位于主上下文(Main Context)。例如events、http指令位于主上下文中,server可以位于http中,location可以位于server中
-
以#号开头的部分表示注释
你可以在Nginx配置文件中读写变量,Nginx的变量只有一种类型 —— 字符串。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
# 创建变量并赋值 set $a "hello world"; # 支持插值 set $b "$a, $a"; # 用花括号包围变量名,可以防止歧义 set $b "${first}world"; # 要使用$符号本身,可以使用ngx_geo模块的指令geo geo $dollar { default "$"; } server { location /test { # ngx_echo没看的echo指令可以将指定的内容输出为响应 echo "This is a dollar sign: $dollar"; } } |
注意:
- 变量的作用域是全局性的,所有Nginx配置共享之
- 每个HTTP请求都具有任何变量的独立副本,类似于线程本地变量
- 变量的创建发生在Nginx配置文件加载阶段,赋值则发生在实际请求处理阶段
- 即使发生内部跳转(即跳转到不同location处理),变量仍然是同一副本
多个Nginx模块提供了预定义变量。其中很多预定义变量都是只读的,尝试修改会导致意外的后果。
在读写变量时,Nginx会执行一小段代码,分别称为读处理程序(get handler)、写处理程序(set handler)。不同的模块可能为它们的变量准备不同的处理程序,从而影响变量读写的行为。
ngx_map模块提供的map指令,可以设置用户定义变量之间的映射关系,并且自动缓存结果:
1 2 3 4 5 6 7 |
# 相当于为$foo变量注册取处理程序 # 该变量的默认值是0,如果$args=debug则该变量的值为1 # 仅仅在需要取$foo的值时,下面的指令才被计算,且一旦计算结果就被缓存,请求处理期间不会重新计算 map $args $foo { default 0; debug 1; } |
Nginx变量的生命周期是和请求绑定的。在Nginx中存在两种请求:
- 主请求:由HTTP客户端发给Nginx的请求
- 子请求:Nginx在处理主请求时,内部发起的请求。这些请求类似于HTTP请求但是不牵涉任何网络通信。任何主请求/子请求都可以串行、并行发起多个子请求,甚至递归的向自己发起子请求
子请求的示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
http { server { listen 80; location /var { # 发起两个子请求 echo_location /hello; echo_location /world "p1=v1&p2=v2"; } location /hello { echo Greetings; } location /world { echo World; } } } |
关于父子请求中的变量,需要注意:
- 当前请求(不管是主、子请求)都具有变量的独立副本,通常不会相互干扰
- 大部分预定义变量都具有针对当前请求的副本。一些例外情况包括:$request_method总是返回主请求的HTTP方法
注意子请求和内部跳转(rewrite指令可以引发)不同,后者不会产生新的变量副本。
ngx_echo模块的echo_location可以产生子请求,ngx_auth_request模块也可以产生子请求。ngx_auth_request比较特殊的地方是共享父请求的变量。
Nginx配置文件虽然类似于编程语言,但是它在整体上是声明性的,而非过程性的。
处理每一个用户请求时,Nginx都是按照若干个不同阶段(phase)依次处理的,一般的配置指令仅仅会注册并运行在某一个阶段。这些阶段一共有11个。
即使在同一个阶段内,也不能对不同指令的执行顺序进行假设(通常先加载的模块,其指令先执行)。例如more_set_input_headers、rewrite_by_lua都在rewrite阶段的尾部执行,你不能假设其中哪个会先执行。
于Nginx读取并解析完请求头后执行此阶段。模块ngx_realip的指令 set_real_ip_from、real_ip_header运行在此阶段:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
http { server { listen 80; # 如果请求来自于本机,则改写其$remote_addr。支持CIDR set_real_ip_from 127.0.0.1; # 该指令可以指定多次 set_real_ip_from 127.0.0.0/24; # 将$remote_addr改写为自定义头中的值 real_ip_header X-Original-Addr; location /test { # rewrite阶段位于post-read之后,因此这里读取到的是篡改后的$remote_addr set $addr $remote_addr; echo "from: $addr"; } } } # curl -H 'X-Original-Addr: 8.8.8.8' $url # 输出: # from: 8.8.8.8 |
当ngx_rewrite模块的指令配置在server块中时,则这些指令在此阶段执行。
不支持Nginx模块在此阶段注册处理程序(指令)。在此阶段,Nginx 核心完成当前请求与 location 配置块之间的配对工作。
在此阶段后,location中的指令才可能生效。
这个阶段的配置指令一般用来对当前请求进行各种修改,例如修改URL或者请求参数。运行在该阶段的指令例如:set、set_by_lua、rewrite_by_lua等。
ngx_set_misc模块、ngx_encrypted_session模块提供的指令、 set_by_lua指令都在此阶段执行,且可以ngx_rewrite模块提供的指令(例如set、rewrite)混合使用,不需要担心执行顺序的问题。
rewrite_by_lua总是在rewrite阶段的最后执行。
不支持Nginx模块在此阶段注册处理程序(指令)。在此阶段,Nginx 核心完成rewrite阶段所声明的内部跳转操作。
标准模块ngx_limit_req、ngx_limit_zone运行在此阶段,前者控制访问的频度,后者控制访问的并发度。
这个阶段的配置指令一般用于进行访问控制,例如检查用户访问权限、检查来源IP地址。运行在该阶段的指令例如:allow、deny、ngx_auth_request、access_by_lua等。
标准模块ngx_access提供的allow和deny指令可以控制IP地址的访问权限:
1 2 3 4 5 6 7 8 |
location /hello { # ngx_access模块的指令按照配置顺序执行,遇到第一条满足条件的allow/deny指令就不再检查后续的allow/deny allow 169.200.179.4/24; allow 127.0.0.1; deny all; echo "hello world"; } |
ngx_lua模块提供的指令access_by_lua,在此阶段的最后执行,可以在allow/deny指令检查之后执行更加复杂的验证逻辑。示例:
1 2 3 4 5 6 7 8 9 10 |
location /hello { access_by_lua ' # 使用ngx.var前缀来访问Nginx变量 if ngx.var.remote_addr == "127.0.0.1" then return end ngx.exit(403) '; } |
配合access阶段,实现ngx_http_core模块的 satisfy 指令的功能。如果在access阶段注册了多个处理程序,则satisfy可以取值为:
- all 必须所有处理程序都验证通过
- any 只需要一个处理程序验证通过
这个阶段实现try_files指令的功能。
这个阶段的配置指令负责响应内容的生成。运行在该阶段的指令例如:echo、content_by_lua、proxy_pass等。来自不同模块的content阶段指令通常不能声明在同一个location中。
echo指令支持调用多次,而content_by_lua则仅仅支持调用一次,这些细节由具体模块规定。
ngx_echo模块提供的指令echo_before_body、echo_after_body可以和其它运行在content阶段的指令协同工作,因为它工作在Nginx的输出过滤器(output filter,不属于11个请求处理阶段的特殊阶段)中。
如果一个location中没有任何content阶段指令,则Nginx把请求映射到静态资源服务模块。通常Nginx会配置三个静态资源服务模块,按照在content阶段的执行顺序,依次是ngx_index、ngx_autoindex、ngx_static。其中ngx_index、ngx_autoindex仅仅会处理以 / 结尾的URL,而ngx_static则相反,处理非/结尾的URL。
ngx_index主要用于在文件系统中自动查找首页文件,例如:
1 2 3 4 5 |
location / { # 自动在此目录下,依次寻找index.htm、index.html文件。如果找不到,由下一个content阶段指令处理 root /var/www/; index index.htm index.html; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
# 在前台运行 daemon off; # 运行Nginx的用户 user nobody; # 工作进程数量 worker_processes 1; # 错误日志的位置(相对于Prefix) # error_log file [level]; # 日志级别:debug, info, notice, warn, error, crit, alert, emerg # 其中,要使用debug,则必须以--with-debug构建Nginx error_log logs/error.log; error_log logs/error.log notice; # 将日志输出到标准错误 error_log stderr debug; # PID文件位置 pid logs/nginx.pid; events { # 每个工作进程的最大客户端连接数 # HTTP服务最大连接数 worker_processes * worker_connections # 反向代理最大连接数 worker_processes * worker_connections / 4 worker_connections 1024; # 在接收到新连接通知后,让工作进程尽可能接受多的连接请求 multi_accept on; # 明确指定连接处理方法 # epoll为Linux 2.6+的高效方式;kqueue为FreeBSD 4.1+, OpenBSD 2.9+, NetBSD 2.0, macOS的高效方式 use epoll; } |
作为HTTP服务器使用时,Nginx具有以下主要特性:
- 支持静态文件、自动索引、文件描述符缓存
- 支持缓存的反向代理、负载均衡、容错
- 支持缓存FastCGI, uwsgi, SCGI
- 模块化架构。支持gzipping、byte ranges、chunked responses、XSLT、SSI(Server Side Includes,服务器端包含)、图像转换等过滤器。单个页面中的多个SSI可以被并行的包含进来
- SSL和TLS支持
- 支持HTTP/2
其它特性包括:
- 基于名称或者IP的虚拟服务器
- Keep-alive和管道化连接(pipelined connections)支持
- 日志:定制格式、缓冲写入、快速轮换、syslog支持
- 3xx-5xx错误码重定向
- URL重写,支持基于正则式的重写
- 根据客户端地址执行不同函数
- 基于客户端地址、密码、子请求结果的身份验证
- 验证HTTP referer
- 支持PUT, DELETE, MKCOL, COPY, MOVE等HTTP方法
- FLV和MP4流媒体支持
- 响应限速
- 限制同一IP地址的并发连接数、请求数
- 基于IP地址获取地理位置信息
- 支持A/B测试
- 请求镜像
- 内嵌Perl
- nginScript,一个JavaScript子集语言
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
http { # 在此处包含其它配置文件,mime.types包含了MIME类型和扩展名之间的映射关系 include mime.types; # 如果不匹配任何MIME类型,使用下面的默认值 default_type application/octet-stream; # 定义一个日志格式,注意多行字符串的语法 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 path [format [buffer=size] [gzip[=level]] [flush=time] [if=condition]]; # access_log off; # 指定访问日志位置和格式 access_log logs/access.log main; # 访问日志可以输出到标准输出 access_log /dev/stdout; # 这个将为打开文件指定缓存,默认是没有启用的,max 指定缓存数量, # 建议和打开文件数一致,inactive 是指经过多长时间文件没被请求后删除缓存。 open_file_cache max=204800 inactive=20s; # 在上一条配置的inactive时间段内,文件被使用的最少次数,不小于该次数,则认为是active open_file_cache_min_uses 1; # 多长时间检查一次缓存的有效信息 open_file_cache_valid 30s; # 是否启用基于内核态完成的文件描述符之间的数据拷贝 sendfile on; # 是否启用SOCKET选项 TCP_CORK tcp_nopush on; # 启用TCP_NODELAY,即禁用Nagle算法,适用于低延迟需求、小数据量场景 tcp_nodelay on; # 客户端连接的保活时间 keepalive_timeout 65; # 启用GZIP压缩,默认关闭,开启可以节约流量,但是消耗CPU gzip on; # 插入Vary: Accept-Encoding响应头 gzip_vary on; # 根据指定正则式匹配的UA,禁用压缩 gzip_disable "MSIE [1-6]\.(?!.*SV1)"; # 启用GZIP的MIME类型 gzip_types text/plain application/x-javascript text/css application/xml; # 启用服务器端包含 ssi on; # 抑制SSI处理出错时输出的[an error occurred while processing the directive]信息 ssi_silent_errors on; # 在text/html的基础上,附加的需要处理SSI命令的MIME类型 ssi_types text/shtml; server { # 服务器名称 + 监听端口唯一的确定一个服务器 # listen 127.0.0.1:8000; # listen 127.0.0.1; # listen 8000; # listen *:8000; # listen localhost:8000; listen 80; # 根据虚拟服务器(Virtual Server)的定义,Nginx会比对请求Host头和下面的配置项,选择第一个匹配的server # 比对按照如下优先级进行 # 1、全限定的静态server_name # 2、前导通配,例如*.gmem.cc形式的server_name # 3、后缀通配,例如www.gmem.*形式的server_name配置 # 4、正则式定义的server_name # 如果没有任何server.server_name匹配,则按下面的规则Fallback: # 1、寻找标记为默认服务器的server # 2、寻找第一个listen和请求端口匹配的server server_name localhost; # 用于设置响应头Content-Type charset utf-8; # 为本服务器指定访问日志 access_log logs/host.access.log main; # URL到文件系统的映射 location / { # / 映射到html目录 # 指定请求的根目录 root html; # Index文件列表 index index.html index.htm; } # 定义错误页面 error_page 404 /404.html; error_page 500 502 503 504 /50x.html; # try_files file ... uri; 或者 try_files file ... =code; # 逐个判断文件是否存在,使用第一个找到的文件来处理请求 # file的完整路径依赖于root和alias # 如果要检查目录的存在性,需要用 / 结尾,例如$uri/ # 如果所有文件都不存在,则向uri发起一个内部跳转 location /images/ { # 如果请求的URI不存在,则使用默认图片代替 try_files $uri /images/default.gif; } # Wordpress伪静态配置 try_files $uri $uri/ /index.php?$args; # URL可以精确到文件 location = /50x.html { root html; } location /i/ { # 请求/i/top.gif则返回/data/w3/images/top.gif这个文件 # alias指令为指定的location定义一个代替的位置 # alias必须以 / 结尾,且只能用于location块内部 alias /data/w3/images/; } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
http { server { listen 443 ssl; server_name localhost; # 数字证书 ssl_certificate cert.pem; # 私钥 ssl_certificate_key cert.key; # SSL会话缓存时间和超时时间 ssl_session_cache shared:SSL:1m; ssl_session_timeout 5m; # 声明服务器支持的用于建立安全连接的密码算法 ssl_ciphers HIGH:!aNULL:!MD5; # 优先使用服务器端的密码算法 ssl_prefer_server_ciphers on; location / { root html; index index.html index.htm; } } } |
模块ngx_http_core定义了以下变量:
变量 | 说明 |
$uri |
经过解码,不包含请求参数的URL 当你请求http://localhost:8080/media/时$uri为/media/ |
$request_uri | 原始URL,未经解码 |
$args | 请求的URL参数部分,支持写: set $args "a=3&b=4"; |
$arg_XXX | 名字为XXX(大小写不敏感)的未经解码的URL参数 |
$cookie_XXX | 名字为XXX的Cookie |
$http_XXX | 名字为XXX的请求头 |
$sent_http_XXX | 名字为XXX的响应头 |
$request_method | 请求使用的HTTP方法 |
$remote_addr | 请求客户端的IP地址 |
到底哪个location匹配请求,优先级如下:
- 检查具有 = 前缀的location,如果找到匹配,停止搜索
- 检查具有 ^~ 前缀的location,如果找到匹配,停止搜索
- 按照声明顺序检查 ~ ~*前缀的location,如果多个匹配,选取正则式最长的那个
- 常规匹配,也就是URL前缀匹配
各种Pattern的说明如下:
模式 | 说明 |
location = /uri | = 表示精确匹配,只有完全匹配上才能生效 |
location ^~ /uri | ^~ 开头对URL路径进行前缀匹配,并且优先于正则式匹配 |
location ~ pattern | 表示区分大小写的正则匹配 |
location ~* pattern | 表示不区分大小写的正则匹配 |
location /uri | 不带任何修饰符,也表示前缀匹配,但是优先级比正则式低 |
location / | 默认匹配,任何未匹配到其它location的请求都会匹配到这里 |
日志格式中可用的变量如下表:
变量 | 说明 |
$remote_addr $http_x_forwarded_for | 记录客户端IP地址 |
$remote_user | 记录客户端用户名称 |
$request | 记录请求的URI和HTTP协议 |
$status | 记录请求状态 |
$body_bytes_sent | 发送给客户端的字节数,不包括响应头的大小 |
$bytes_sent | 发送给客户端的总字节数 |
$connection | 连接的序列号 |
$connection_requests | 当前通过一个连接获得的请求数量 |
$msec | 日志写入时间。单位为秒,精度是毫秒 |
$pipe | 如果请求是通过HTTP流水线发送 |
$http_referer | 记录从哪个页面链接访问过来的 |
$http_user_agent | 记录客户端浏览器相关信息 |
$request_length | 请求的长度(包括请求行,请求头和请求正文) |
$request_time | 请求处理时间,单位为秒,精度毫秒 |
$time_iso8601 | ISO8601标准格式下的本地时间 |
$time_local | 记录访问时间与时区 |
反向代理功能主要由模块ngx_http_proxy_module提供。反向代理的很多指令以在http块中直接声明。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
http { server { # 反向代理,默认所有请求转发给 8080端口处理 location / { proxy_pass http://localhost:8080; } # 反向代理,将PHP请求转发给8000端口 location ~ \.php { proxy_pass http://127.0.0.1:8000; } # gif/jpg/png文件不走反向代理 # = 前缀表示精确匹配 # ~ 前缀表示大小写敏感的正则式匹配 # ~* 前缀表示大小写不敏感的正则式匹配 location ~ \.(gif|jpg|png)$ { root /data/images; } # 联用Rewrite # http://localhost/v2/xxx 重写为 http://localhost/v2/google_containers/xxx # 然后转发给 https://gcr.azk8s.cn/v2/google_containers/xxx location /v2/ { rewrite /v2/(.*) /v2/google_containers/$1 break; proxy_pass https://gcr.azk8s.cn; proxy_set_header Host gcr.azk8s.cn; } } } |
要将请求转发给非HTTP的被代理服务器,选择适当的***_pass指令:
指令 | 说明 |
fastcgi_pass | 将请求转发给FastCGI服务器 |
uwsgi_pass | 将请求转发给uwsgi服务器 |
scgi_pass | 将请求转发给SCGI服务器 |
memcached_pass | 将请求转发给Memcached服务器 |
默认情况下Nginx会修改两个请求头:Host、Connection并清除值为空的请求头,然后再转发给被代理服务器。
Host默认被设置为$proxy_host变量,Connection默认被设置为Close。你可以改变这些默认行为:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
location /some/path/ { # 改写、添加转发给被代理服务器的请求头 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; # X-Forwarded-Fo不是标准请求头 # 格式:X-Forwarded-For: client1, proxy1, proxy2,第一个是真实客户端IP,后续的是经过的代理 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 要阻止某个请求头被转发,将其设置为空 proxy_set_header Accept-Encoding ""; proxy_pass http://localhost:8000; } |
默认情况下Nginx不会把Date、Server、X-Pad、X-Accel-*响应头转发给客户端,使用proxy_hide_header指令可以指定额外的需要隐藏的响应头。示例:
1 |
proxy_hide_header X-Powered-By; |
默认情况下,Nginx接收被代理服务器的响应并放入内部缓冲,直到整个响应都接收到了才发送给客户端。这可以避免同步传输时因为客户端网速太慢,而拖累被代理服务器。
1 2 3 4 5 6 7 |
location / { # 为单个请求分配的缓冲的大小和数量 proxy_buffers 16 4k; # 被代理服务器返回的第一部分被存放在下面的缓冲中 proxy_buffer_size 2k; proxy_pass http://localhost:8000; } |
如果禁用缓冲,则响应被同步的发送给客户端。在某些交互式应用场景下可能需要禁用缓冲以获得最快响应时间:
1 2 3 4 |
location / { proxy_buffering off; proxy_pass http://localhost:8000; } |
如果Nginx有多重网络可以到达被代理服务器,你可能需要明确指定使用哪个网络接口:
1 2 3 4 5 6 7 8 9 10 11 |
location /app1/ { # 通过127.0.0.1向被代理服务器转发请求 proxy_bind 127.0.0.1; proxy_pass http://gmem.cc/app1/; } location /app2/ { # 变量$server_addr为接收原始请求的网络接口的IP地址 proxy_bind $server_addr; proxy_pass http://gmem.cc/app2/; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
# 代理的HTTP协议版本,默认1.0,如果需要使用Keepalive则设置为1.1 proxy_http_version 1.1; # 连接到被代理服务器的超时时间 proxy_connect_timeout 50; # 从被代理服务器读取响应的超时时间,仅仅用于两次连续的读操作,而不是整个响应内容的传输所消耗的时间 proxy_read_timeout 20; # 向被代理服务器发送请求的超时时间,仅仅用于两次连续的写操作,如果在此时间内被代理服务器每有接收任何数据,则关闭连接 proxy_send_timeout 20; # 是否缓冲来自被代理服务器的响应 proxy_buffering on; # 响应的一部分缓冲缓冲的大小, proxy_buffer_size 32k; # 缓冲区数量和大小 proxy_buffers 4 32k; # busy_buffers是缓冲的一部分,通常设置为单个缓冲区的2倍大小 # 这部分缓冲用于存放向客户端返回的响应数据,满了则写入到临时文件 proxy_busy_buffers_size 64k; # 临时文件(硬盘缓冲)的大小,默认是内存缓冲总大小的2倍,设置为0则关闭硬盘缓冲 proxy_temp_file_write_size 256k; # 用于修改被代理服务器的响应的location头 proxy_redirect ~^http://10.0.0.1:8080(.*) http://zircon.gmem.cc$1; proxy_redirect off; # 设置proxy_hide_header、proxy_set_header指令使用的哈希表的大小 proxy_headers_hash_max_size 51200; proxy_headers_hash_bucket_size 6400; |
模块ngx_http_proxy_module定义了以下变量:
变量 | 说明 |
$proxy_host | 被代理服务器的名字和端口 |
$proxy_port | 被代理服务器的端口 |
$proxy_add_x_forwarded_for | 客户端的请求头X-Forwarded-For后缀以$remote_addr,如果请求头没有X-Forwarded-For字段则该变量等于$remote_addr |
模块ngx_http_proxy_module提供了基础的缓存功能:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
# /path/to/cache/ 用于缓存的本地磁盘目录 # levels=1:2 设置一个两级层次结构的目录,大量的文件放置在单个目录中会导致访问缓慢,推荐使用两级目录 # keys_zone 设置一个共享内存区,该内存区用于存储缓存键和元数据。可以让Nginx不需要读取磁盘即确定缓存HIT or MISS # 10MB 为共享内存区大小,平均1MB可以存放8000键 # max_size=10g 缓存占用磁盘的最大空间,如果不指定则无限增长 # inactive=60m 文件多长时间不被访问,则从内存移除 proxy_cache_path /path/to/cache levels=1:2 keys_zone=my_cache:10m max_size=10g inactive=60m # 默认情况下,Nginx先把缓存写到一个临时区域,然后再拷贝到缓存目录 # 建议关闭临时区域,避免不必要的拷贝 use_temp_path=off; server { location / { # 此命令启动匹配此location的URL的缓存,其键存放到my_cache proxy_cache my_cache; # 被代理的上游服务器 proxy_pass http://my_upstream; # 无法从原始服务器获取最新的内容时,Nginx 可以分发缓存中的过期(Stale)数据给客户端 # 当上游服务器返回错误、超时、50X状态码时,即使缓存陈旧了,仍然使用 # 所谓陈旧,依据上游服务器响应中设置的过期时间 proxy_cache_use_stale error timeout http_500 http_502 http_503 http_504; } } |
你可以把缓存文件分发到多个磁盘上:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
proxy_cache_path /path/to/hdd1 levels=1:2 keys_zone=my_cache_hdd1:10m max_size=10g; proxy_cache_path /path/to/hdd2 levels=1:2 keys_zone=my_cache_hdd2:10m max_size=10g; split_clients $request_uri $my_cache { # 两个缓存区域分别负担一半缓存文件 50% "my_cache_hdd1"; 50% "my_cache_hdd2"; } server { location / { proxy_cache $my_cache; } } |
Nginx本身不支持正向代理,可以使用第三方模块:ngx_http_proxy_connect_module。
下载模块源码后,需要对Nginx本身源码进行patch:
1 2 3 4 |
# 注意选择和Nginx版本匹配的patch patch -p1 < /root/CPP/tools/ngx_http_proxy_connect_module/patch/proxy_connect_rewrite_1018.patch ./configure --add-module=/root/CPP/tools/ngx_http_proxy_connect_module make |
下面是将Nginx作为一个HTTPS代理的配置示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
http { server { listen 8088 ssl; resolver 8.8.8.8 ipv6=off; server_name proxy.gmem.cc; ssl_certificate_key /etc/nginx/certs/proxy.gmem.cc.key; ssl_certificate /etc/nginx/certs/proxy.gmem.cc_bundle.pem; proxy_connect; proxy_connect_allow all; proxy_connect_connect_timeout 10s; proxy_connect_read_timeout 10s; proxy_connect_send_timeout 10s; } } |
模块ngx_http_upstream_module为Nginx提供了负载均衡的支持。使用该模块,你可以定义一个服务器组,并在proxy_pass, fastcgi_pass, uwsgi_pass, scgi_pass,memcached_pass等指令中引用这些组。
定义一个服务器组,服务器可以监听不同的端口,甚至可以监听UNIX域套接字。
默认情况下,请求会根据权重,使用round-robin方式在组内各服务器之间分发。如果和一个服务器通信失败,会转而尝试下一个服务器,如果所有服务器都不能获得正确响应,则最后一个服务器的结果被发送给客户端。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
resolver 10.96.0.10; upstream backend { # upstream指令中可以包含多个server指令,其格式为:server address [parameters]; # 此服务器的权重为5 server backend1.example.com weight=5; # 此服务器的权重为默认值1,30s内最多失败3次,最多允许100个同时的连接 server 127.0.0.1:8080 max_fails=3 fail_timeout=30s max_conns=100; server unix:/tmp/backend3; # 此服务器为备份服务器,仅当主服务器不可用时,请求才发送到备份服务器 server backup1.example.com:8080 backup; # 此服务器被标记为永久不可用 server down.example.com down; # 访问DNS服务器,监控服务器域名对应的IP地址,自动更新服务器对应的IP地址 # 必须在http块中添加resolver指令才能生效 # slow_start,当服务从不健康变为健康、不可用变为可用时,其权重恢复正常值所需要的时间 # drain,此模式下的服务器,仅仅bound到该服务器的请求才发送给它 # route,上游服务器的route名,用于会话绑定 server media-api.dev.svc.k8s.gmem.cc resolve slow_start=10 drain route=string; # 指定存放动态配置的组的配置信息的文件 state /var/lib/nginx/state/servers.conf; # 缓存到上游服务器的TCP连接,每个工作进程缓存32个连接,如果超过此数量则使用LRU算法清除 # 需要配合proxy_http_version 1.1使用 keepalive 32; # 如果处理请求时,不能立刻选取适用的上游服务器,可以让请求排队 # 如果排队满了,或者超时,则返回502给客户端 queue number [timeout=time]; # 定义一个名为name,大小为size的共享内存区域。此区域存放此服务器组的配置、运行时状态 # 所有Worker进程共享此内存区域。多个服务器组可以共享单个区域(name相同),这种情况下size只需要声明一次 zone name [size]; } |
ngx_http_upstream_module支持多种负载均衡算法,这些算法对应不同的指令。所有指令均必须位于upstream块中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
# 负载均衡算法:客户端和上游服务器的对应关系依赖于key的哈希值 # key可以包含文本、变量,或者两者的组合 # 默认情况下不使用一致性哈希,添加服务器节点后可能导致大量的key重新映射到不同服务器 # 如果指定consistent参数,则采用一致性哈希算法。添加服务器后,仅少量key重新映射,可以保证缓存服务器的命中率 hash key [consistent]; # 负载均衡算法:基于客户端的IP地址来映射请求到上游服务器 # 可以保证来自一个客户端的请求,总是由同一服务器处理,除非目标服务器不可用 ip_hash; # 负载即均衡算法:将请求发送给具有最少活动连接数的上游服务器,同时考虑服务器的权重 least_conn; # 负载均衡算法:将请求转发给具有最短响应时间+最少活动连接数的服务器,同时考虑服务器的权重 # 格式:least_time header | last_byte [inflight]; # header以收到请求头时间计,last_byte以收到完整响应时间计 least_time; |
该指令用于实现会话绑定(session affinity),必须位于upstream块中。指令格式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
# 基于Cookie的绑定,会话绑定到的目标服务器信息,由Nginx自动产生的Cookie传递 # 对于尚未绑定到特定服务器的请求,Nginx会使用负载均衡算法为其选取一个上游服务器,并种植Cookie sticky cookie name [expires=time] [domain=domain] [httponly] [secure] [path=path]; # 示例: sticky cookie srv_id expires=1h domain=.example.com path=/; # 基于Route的绑定 # 被代理服务器第一次接收到客户端请求时,会为客户端分配一个route信息,此客户端的所有后续请求均在 # Cookie或者URI中附带route信息。此信息和server的route参数进行比较,从而确定哪个服务器负 # 责处理请求 # 如果没有为server指定route参数,则其route为IP和端口的MD5的HEX形式 sticky route $variable ...; # 示例: map $cookie_jsessionid $route_cookie { ~.+\.(?P\w+)$ $route; } map $request_uri $route_uri { ~jsessionid=.+\.(?P\w+)$ $route; } upstream backend { server backend1.example.com route=a; server backend2.example.com route=b; # 优先从Cookie JSESSIONID中获取route信息,如果没有则从URI参数jsessionid中获取 sticky route $route_cookie $route_uri; } # 由Nginx来分析上游服务器的响应,从中学习到服务器初始化的会话(通常以Cookie的形式传递给客户端) # create,lookup分别用于获取服务器创建的会话ID、客户端传递的会话ID。这两个指令都可以声明多次 # 第一个不为空的变量生效 # 会话和上游服务器的对应关系,被存放在共享内存区域zone中。1MB的共享内存在64bit机器上可以存放8000会话 # 连续timeout没有被访问的会话,自动重共享内存区域中清除,默认timeout=10分钟 # header用于从上游服务器接收到指定的响应头后,创建一个session sticky learn create=$variable lookup=$variable zone=name:size [timeout=time] [header]; # 示例: upstream backend { server backend1.example.com:8080; server backend2.example.com:8081; sticky learn # 上游服务器将会话ID存放在Cookie EXAMPLECOOKIE中 create=$upstream_cookie_examplecookie # 读取客户端请求的Cookie EXAMPLECOOKIE来确定其上游服务器 lookup=$cookie_examplecookie # 会话-服务器对应关系存放在名为client_essions的共享内存中 zone=client_sessions:1m; } |
变量 | 说明 |
$upstream_addr |
上游服务器的地址端口。如果处理请求过程中牵涉到多个上游服务器,则用逗号分隔,例如 192.168.1.1:80, 192.168.1.2:80, unix:/tmp/sock 如果发生跨越多组服务器的内部跳转,则不同组的服务器用分号分隔,例如 192.168.1.2:80, unix:/tmp/sock : 192.168.10.1:80 |
$upstream_bytes_received | 从上游服务器接收到的字节数 |
$upstream_cache_status | 存放响应缓存的状态,取值:MISS、BYPASS、EXPIRED、STALE、UPDATING、REVALIDATED、HIT |
$upstream_connect_time | 与上游服务器创建连接所消耗的时间 |
$upstream_cookie_name | 上游服务器通过Set-Cookie响应头种植的名为name的Cookie的值 |
$upstream_header_time | 上游服务器通过响应头设置的时间 |
$upstream_response_length | 上游服务器的响应长度 |
$upstream_response_time | 接收上游服务器响应所消耗的时间 |
$upstream_status | 上游服务器的响应状态码 |
下面是一个L7负载均衡配合SSL Termination的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
http { upstream ceph-dashboard { server ceph-1.gmem.cc:8443; server ceph-2.gmem.cc:8443 backup; } server { listen 443 ssl; server_name ceph.gmem.cc; ssl_certificate /etc/ssl/gmem.cc/fullchain.pem; ssl_certificate_key /etc/ssl/gmem.cc/privkey.pem; location / { proxy_pass https://ceph-dashboard; proxy_ssl_verify off; } } } |
模块ngx_http_rewrite_module提供了URL重写功能。该模块的指令的执行顺序如下:
- 位于server块的指令依次顺序执行
- 循环执行:
- 根据请求URL找到匹配的location
- 顺序执行location块中的指令
- 如果URL被重写,则返回到2.1重复执行,但是最多不超过10次
停止继续为当前请求处理ngx_http_rewrite_module模块的指令。
执行URL重写: rewrite regex replacement [flag];
如果regex匹配请求URL(去除http://host:port剩余的部分),则将URL改写为replacement。rewrite指令按照其声明的顺序依次执行。flag可以是:
flag | 说明 |
last | 停止处理当前location中的ngx_http_rewrite_module指令。并且,如果URL被改写了,寻找匹配的新location进行处理 |
break | 停止处理当前location中的ngx_http_rewrite_module指令。行为类似于break指令 |
redirect |
使用302状态码返回一个临时的重定向(24-48小时之内临时发生的网页转移),replacement必须以http://、https://或$scheme开头 |
permanent | 使用301状态码返回永久重定向 |
如果replacement以http://、https://或$scheme开头,则表示进行重定向。示例:
1 2 3 4 5 6 7 |
http { # 永久重定向 server { listen 80; rewrite / https://blog.gmem.cc permanent; } } |
在满足条件的情况下,执行花括号内的指令: if (condition) { ... }
应当仅仅在花括号内使用return、rewrite、last等rewrite指令,否则可能导致意外行为,甚至出现段错误SIGSEGV。
其中condition可以是以下之一:
- $变量名,如果变量值为0或空串则condition为false
- 基于 = 或 != 操作符比较变量和字符串
- 基于 ~ 或 *~操作符(以及 !~或 !~*)来匹配变量和正则式,*~表示大小写不敏感。正则式中可以包含捕获,并在随后通过$1..$9引用
- 基于 -f 或 !-f 操作符检查文件是否存在
- 基于 -x 或 !-x 操作符检查可执行文件是否存在
- 基于 -d 或 !-d 操作符检查目录是否存在
- 基于 -e 或 !-e 操作符检查目录、文件、符号连接是否存在
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
# 如果UA为IE if ($http_user_agent ~ MSIE) { # 则将URL前缀以/msie rewrite ^(.*)$ /msie/$1 break; # 可以重写为外部URL rewrite ^(.*)$ https://nginx.gmem.cc/grafana/avatar.png; } # 如果Cookie中有id则设置变量 if ($http_cookie ~* "id=([^;]+)(?:;|$)") { set $id $1; } # 如果HTTP方法为POST则返回405状态码 if ($request_method = POST) { return 405; } # 如果缓慢则限速 if ($slow) { limit_rate 10k; } # 根据扩展名来设置缓存过期时间 location ~* \.(js|css|jpg|jpeg|gif|png|swf)$ { # 如果文件存在,则设置过期时间为1小时 if (-f $request_filename) { expires 1h; break; } } # 防盗链 location ~* \.(gif|jpg|swf)$ { valid_referers none blocked www.gmem.cc; if ($invalid_referer) { rewrite ^/ http://$host/logo.png; } } |
停止处理并返回状态码给客户端,格式:
1 2 3 |
return code [text]; return code URL; return URL; |
如果设置为on则记录URL重写日志
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
http { client_max_body_size 4g; server { listen 443 ssl; server_name git.gmem.cc; ssl_certificate /etc/letsencrypt/live/gmem.cc/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/gmem.cc/privkey.pem; location / { proxy_pass https://127.0.0.1:2443; proxy_ssl_verify off; } } server { listen 443 ssl; server_name harbor.gmem.cc; ssl_certificate /etc/letsencrypt/live/gmem.cc/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/gmem.cc/privkey.pem; client_max_body_size 0; location / { proxy_pass https://127.0.0.1:4443; proxy_ssl_verify off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_buffering off; proxy_request_buffering off; } } server { listen 443 ssl default_server; ssl_certificate /etc/letsencrypt/live/gmem.cc/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/gmem.cc/privkey.pem; return 404; } } |
而不是放到location中,这样可以让所有location使用相同的root
1 2 3 |
http { index index.php index.htm index.html; } |
要检查文件是否存在,使用try_files。if仅仅用于配合rewrite模块的指令使用。
1 2 3 4 5 6 7 8 9 10 11 |
server { location / { # 先尝试本地静态文件,然后才发送给代理 try_files $uri $uri/ @proxy; } location @proxy { include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_pass unix:/tmp/phpcgi.socket; } } |
作为TCP/UDP代理服务器时,Ngin具有以下特性:
- 可以作为通用的TCP/UDP代理
- 为TCP添加SSL和TLS SNI支持
- 负载均衡和容错
- 基于客户端地址的访问控制
- 根据客户端地址执行不同函数
- 限制同一IP地址的并发连接数
- 日志:定制格式、缓冲写入、快速轮换、syslog支持
- 基于IP地址获取地理位置信息
- 支持A/B测试
- nginScript
在1.9.0之前的版本,基于TCP的代理和负载均衡需要依赖第三方补丁nginx_tcp_proxy_module。
从1.9.0开始,可以在构建时指定 --with-stream选项,启用内置第四层代理/负载均衡。第四层代理的功能由ngx_stream_core_module模块提供。
Nginx处理客户端的TCP/UDP会话,由以下阶段组成。
此阶段,Nginx刚刚接受了客户端连接。ngx_stream_realip_module模块参与到此阶段。
访问预检查。ngx_stream_limit_conn_module 模块参与到此阶段。
访问权限检查。ngx_stream_access_module模块参与到此阶段。
TLS/SSL termination。ngx_stream_ssl_module模块参与到此阶段。
预读取,读取客户端数据的初始字节到预读取缓冲中。允许ngx_stream_ssl_preread_module等模块对数据进行分析。
实际处理数据的阶段,调用被代理服务器,或者返回一个值给客户端。
记录客户端会话的处理结果,ngx_stream_log_module模块参与此阶段。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
# 定义一个第四层代理 stream { # TCP_NODELAY tcp_nodelay on; upstream mysqld { hash $remote_addr consistent; server 192.168.1.42:3306 weight=5 max_fails=1 fail_timeout=10s; server 192.168.1.43:3306 weight=5 max_fails=1 fail_timeout=10s; # 可以通过UNIX Domain Socket连接上游 server unix:/var/run/mysql.sock; } server { # 该指令可以指定多次 # # listen address:port [ssl] [udp] [proxy_protocol] [backlog=number] [rcvbuf=size] # [sndbuf=size] [bind] [ipv6only=on|off] [reuseport] # [so_keepalive=on|off|[keepidle]:[keepintvl]:[keepcnt]]; # # address:port 代理服务器的监听端口,可以指定 *:3306、10.0.0.1:3306等形式 # # ssl 指定此端口上所有的连接必须工作在SSL模式下 # # udp 指定此端口工作在UDP协议下 # # proxy_protocol 指定此端口上的所有连接必须使用PROXY协议 # 关于此协议,参考http://www.haproxy.org/download/1.8/doc/proxy-protocol.txt # PROXY 2 从1.13.11开始被支持 # # backlog 最大排队等待被接受的连接数 # # rcvbuf SO_RCVBUF # sndbuf SO_SNDBUF # # bind 提示针对每个给出的address:port,分别执行执行bind()调用 # # ipv6only IPV6_V6ONLY # reuseport 基于SO_REUSEPORT选项,为每个Worker创建独立的监听套接字。内核将会分别入站请求 # 给每个Worker,要求Linux 3.9+ # # so_keepalive TCP保活选项:TCP_KEEPIDLE、TCP_KEEPINTVL、TCP_KEEPCNT # listen 3306; # 预读缓冲大小 preread_buffer_size 16k; # 预读超时 preread_timeout 30s; # 读取PROXY协议头的超时时间,如果超过此时间仍然没有传输完整的PROXY头则连接关闭 proxy_protocol_timeout 30s; # 用来解析Upstream的DNS服务器,DNS的缓存有效期 resolver 127.0.0.1 [::1]:5353 valid=30s; # DNS解析超时 resolver_timeout 5s; proxy_connect_timeout 1s; proxy_timeout 3s; proxy_pass mysqld; # 来自模块ngx_stream_limit_conn_module的配置 # limit_conn zone number; # 限制每个地址仅仅允许同时1个连接 limit_conn addr 1; limit_conn_log_level error; } } |
变量 | 说明 |
$binary_remote_addr | 二进制形式的客户端地址 |
$bytes_received | 从客户端接收到的字节数 |
$bytes_sent | 发送到客户端的字节数 |
$connection | 连接串号 |
$hostname | 主机名 |
$msec | 当前时间,毫秒精度 |
$pid | 当前工作进程PID |
$protocol | 当前使用的协议,TCP或UDP |
$proxy_protocol_addr | PROXY协议头中的客户端地址 |
$proxy_protocol_port | PROXY协议头中的客户端端口 |
$remote_addr | 客户端地址、端口 |
$remote_port | |
$server_addr | 接受连接的服务地址、端口 |
$server_port | |
$session_time | 会话持续时间,毫秒精度 |
$status |
会话状态,取值: 200 会话成功完成 |
$time_iso8601 | ISO 8601格式的本地时间 |
$time_local | 本地时间 |
1 2 3 4 5 6 7 8 9 10 11 |
stream { upstream ssh { hash $remote_addr consistent; server 192.168.1.42:22 weight=5; } server { listen 2222; proxy_pass ssh; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
stream { upstream mysqld { hash $remote_addr consistent; server 192.168.1.42:3306 weight=5 max_fails=1 fail_timeout=10s; server 192.168.1.43:3306 weight=5 max_fails=1 fail_timeout=10s; } server { listen 3306; proxy_connect_timeout 1s; proxy_timeout 3s; proxy_pass mysqld; } } |
需要额外编译配置项: --with-stream_ssl_preread_module。示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
daemon off; worker_processes 4; pid /var/run/nginx/nginx.pid; worker_rlimit_nofile 74363; worker_shutdown_timeout 10s ; events { multi_accept on; worker_connections 16384; use epoll; } stream { # 连接日志 log_format log_stream '$remote_addr [$time_local] $protocol [$ssl_preread_server_name] [$ssl_preread_alpn_protocols] [$name] $status $bytes_sent $bytes_received $session_time'; access_log /usr/logs/stream.log log_stream; map $ssl_preread_server_name $name { blog.gmem.cc apache; git.gmem.cc gitea; default apache; } upstream apache { server 127.0.0.1:8443; } upstream gitea { server ::1:3443; } server { listen 0.0.0.0:443; proxy_pass $name; ssl_preread on; } } |
L4配置,上游服务器看到的客户端地址是127.0.0.1,要让上游服务器看到真实客户端IP,有几种方法。
这种方式,需要后端支持代理协议(作为协议的服务器端)。对于Apache,启用代理协议的方法参考Apache HTTP Server知识集锦。
Nginx的配置如下:
1 2 3 4 5 6 7 8 |
stream { server { listen 0.0.0.0:443; proxy_protocol on; proxy_pass $name; ssl_preread on; } } |
在被代理服务中,设置响应头X-Accel-Redirect,可以提示Nginx进行静态转发,例如:
1 |
X-Accel-Redirect: /media/encryp//10/57/1497089.html |
Nginx配置:
1 2 3 |
server { root /datastore/; } |
则Nginx自动从 /datastore/media/encryp//10/57/1497089.html获取静态文件。
Leave a Reply