nginx 的反向代理
反向代理 (Reverse Proxy) 方式是指以代理服务器来接受 Internet 上的连接请求, 然后将请求转发给内部网络上的服务器; 并将从服务器上得到的结果返回给 Internet 上请求连接的客户端, 此时代理服务器对外就表现为一个服务器.
通常的代理服务器, 只用于代理内部网络对 Internet 的连接请求, 客户机必须指定代理服务器, 并将本来要直接发送到 web 服务器上的 http 请求发送到代理服务器中. 当一个代理服务器能够代理外部网络上的主机, 访问内部网络时, 这种代理服务的方式称为反向代理服务.
nginx 可以作为七层协议上的负载均衡主机, 即在应用层上的负载均衡主机, 七层负载是面向服务的, 报文已经被转发至用户空间, 这是不同于四层负载的地方 (四层负载在内核(TCP 协议栈) 就被转发给后台 RS).
Nginx 通过 proxy 模块实现反向代理功能. 在作为 web 反向代理服务器时, nginx 负责接收客户请求, 并能够根据 URI, 客户端参数或其它的处理逻辑将用户请求调度至上游服务器上 (upstream server).nginx 在实现反向代理功能时的最重要指令为 proxy_pass, 它能够将 location 定义的某 URI 代理至指定的上游服务器(组) 上.
proxy_pass URL;
设置后端服务器的协议和地址; 这条指令可以设置的协议是 "http" 或者 "https", 而地址既可以使用域名或者 IP 地址加端口 (可选) 的形式来定义:
proxy_pass http://localhost:8000/uri/;
如果解析一个域名得到多个地址, 所有的地址都会以轮转的方式被使用. 当然, 也可以使用服务器组来定义多个地址.
如果 proxy_pass 没有使用 URI, 传送到后端服务器的请求 URI 一般是客户端发起的原始 URI, 如果 nginx 改变了请求 URI, 则请求路径与配置中的路径的匹配部分将被替换为指令中定义的 URI:
若 nginx 接到的请求的 uri 是 / name/a.html
- location /name/ {
- proxy_pass http://192.168.30.20/remote/;
- } #传送到后端服务器的 URI 是 / remote/a.html
- location /name/ {
- proxy_pass http://192.168.30.20;
- } #传送到后端服务器的 URI 是 / name/a.html
- location /name/ {
- proxy_pass http://192.168.30.20/;
- } #注意与上面用法的区别, 这里地址末尾带有斜线, 实际上被认为定义了 URI, 该 "/" 会替换 "/name/", 传送到后端服务器的 URI 是 / a.html.
如果使用正则表达式定义路径, 则 proxy_pass 指令不应使用 URI
- location ~ \.php$ {
- proxy_pass http://127.0.0.1;
- }
在需要代理的路径中, 使用 rewrite 指令改变了 URI, 那么 nginx 将使用重写后的 URI 处理请求, 而忽略 proxy_pass 指令设置的 URI. 如下面所示的例子中, 传送给上游服务器的 URI 为 / index.php?page=<match>.
- location / {
- rewrite /(.*)$ /index.php?page=$1 break;
- proxy_pass http://localhost:8080;
- }
proxy 模块的其它指令
proxy_connect_timeout time;
与后端服务器建立连接的超时时间. 一般不可能大于 75 秒;
- proxy_cookie_domain off; #取消当前配置级别的所有 proxy_cookie_domain 指令
- proxy_cookie_domain domain replacement;
设置 "Set-Cookie" 响应头中的 domain 属性的替换文本, 其值可以为一个字符串, 正则表达式的模式或一个引用的变量; 例如:
proxy_cookie_domain localhost example.org;
说明:
浏览器对 Cookie 有很多限制, 如果 Cookie 的 Domain 部分与当前页面的 Domain 不匹配就无法写入. 所以如果请求 A 域名, 服务器 proxy_pass 到 B 域名, 然后 B 服务器输出 Domian=B 的 Cookie, 前端的页面依然停留在 A 域名上, 于是浏览器就无法将 Cookie 写入.
不仅是域名, 浏览器对 Path 也有限制. 我们经常会 proxy_pass 到目标服务 0 器的某个 Path 下, 不把这个 Path 暴露给浏览器. 这时候如果目标服务器的 Cookie 写死了 Path 也会出现 Cookie 无法写入的问题.
- proxy_cookie_path off;
- proxy_cookie_path path replacement;
设置 "Set-Cookie" 响应头中的 path 属性的替换文本, 其值可以为一个字符串, 正则表达式的模式或一个引用的变量; 例如:
proxy_cookie_path /two//;
若 "Set-Cookie" 响应头含有属性 "path=/two/some/uri/", 那么该指令会将这个属性改写为 "path=/some/uri/".
proxy_hide_header field;
nginx 默认不会将 "Date","Server","X-Pad", 和 "X-Accel-..." 响应头发送给客户端. 该指令则可以设置额外隐藏的响应头, 这些响应头也不会发送给客户端. 相反的, 如果希望允许传递某些响应头给客户端, 可以使用 proxy_pass_header 指令.
proxy_set_header field value;
重新定义或者添加发往后端服务器的请求头. value 可以包含文本, 变量或者它们的组合. 例如:
- proxy_set_header X-Real-IP $remote_addr; #给请求头中添加客户端 IP
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
默认情况下, 只有两个请求头会被重新定义:
- proxy_set_header Host $proxy_host;
- proxy_set_header Connection close;
如果某个请求头的值为空, 那么这个请求头将不会传送给后端服务器:
- proxy_set_header Accept-Encoding "";
- proxy_pass_request_headers on|off; #是否将 http 首部发往上游服务器
- proxy_pass_request_body on|off; #是否将 http 请求报文的包体部分发往上游服务器
- proxy_redirect [default|off|redirect replacement];
修改上游服务器传来的响应头中的 "Location" 和 "Refresh" 字段. 例如:
proxy_redirect http://localhost:8000/two/ http://frontend/one/;
replacement 字符串可以省略服务器名:
proxy_redirect http://localhost:8000/two//;
此时将使用代理服务器的主域名和端口号来替换. 如果端口是 80, 可以不加.
proxy_send_timeout time;
在连接断开之前两次发送至 upstream server 的写操作的最大间隔时长;
proxy_read_timeout time;
在连接断开之前两次从接收 upstream server 接收读操作的最大间隔时长;
proxy 模块的内置变量
$proxy_host: 后端服务器的主机名和端口;
$proxy_port: 后端服务器的端口;
$proxy_add_x_forwarded_for
将 $remote_addr 变量值添加在客户端 "X-Forwarded-For" 请求头的后面, 并以逗号分隔. 如果客户端请求未携带 "X-Forwarded-For" 请求头,$proxy_add_x_forwarded_for 变量值将与 $remote_addr 变量相同
设置示例:
- proxy_redirect 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;
- client_max_body_size 10m;
- client_body_buffer_size 128k;
- proxy_connect_timeout 30;
- proxy_send_timeout 15;
- proxy_read_timeout 15;
当在 192.168.2.18 的配置文件中定义了反向代理, 指向 192.168.2.29, 此时我们访问 192.168.2.18 就会把请求代理转发给 192.168.2.29 这台主机
二, 缓存服务器功能
nginx 做为反向代理时, 能够将来自上游服务器的响应缓存至本地, 并在后续的客户端请求同样内容时直接从本地构造响应报文. nginx 使用磁盘做缓存
nginx 缓存大致上由两部分组成:
cache: 共享内存(存储键和缓存对象元数据), 查找在内存上
data: 数据在磁盘空间
(1) proxy_cache_path: 定义缓存空间(不能定义在 server 段中, 定义在 http 段中), 属于 proxy 模块
proxy_cache_path [levels=levels] keys_zone=name:size [inactive=time] [max_size=size] [loader_files=number] [loader_sleep=time] [loader_threshold=time] ; 定一个用记保存缓存响应报文的目录, 及一个保存缓存对象的键及响应元数据的共享内存区域(keys_zone=name:size), 其可选参数有:
levels: 每级子目录名称的长度, 有效值为 1 或 2, 每级之间使用冒号分隔, 最多为 3 级; 1:2 表示两个级别目录, 一级子目录由一个字符组成, 二级子目录由二个字符组成
keys_zone: 给共享内存命名, 存储键的区域, 可以定义多个区域, 每个区域要有个名称引用.
inactive: 非活动缓存项从缓存中剔除之前的最大缓存时长;
max_size: 缓存空间大小的上限, 当需要缓存的对象超出此空间限定时, 缓存管理器将基于 LRU 算法对其进行清理;
loader_files: 缓存加载器 (cache_loader) 的每次工作过程最多为多少个文件加载元数据;
loader_sleep: 缓存加载器的每次迭代工作之后的睡眠时长;
loader_threashold: 缓存加载器的最大睡眠时长;
如 proxy_cache_path /nginx/cache levels=1:1 keys_zone=nginx_cache:64m
(2) proxy_cache zone | off; #定义一个用于缓存的共享内存区域, 其可被多个地方调用; zone 为我们之前定义的 keys_zone 名字, 如之前的 nginx_cache
(3)proxy_cache_min_uses: 某响应报文被缓存之前至少应该被请求的次数;
- (4) proxy_cache_lock on | off; #启用此项, 可在缓存未命令中阻止多个相同的请求同时发往 upstream, 其生效范围为 worker 级别
- (5)proxy_cache_lock_timeout time; #proxy_cache_lock 功能的锁定时长;
- (6)proxy_cache_min_uses number; #某响应报文被缓存之前至少应该被请求的次数;
(7)proxy_cache_use_stale error | timeout | invalid_header | updating | http_500 | http_502 | http_503 |http_504 | http_403 | http_404 | off ...; 在无法联系到 upstream 服务器时的哪种情形下 (如 error,timeout 或 http_500 等) 让 nginx 使用本地缓存的过期的缓存对象直接响应客户端请求
例如 proxy_cache_usr_stale error ;
(8)proxy_cache_valid [code ...] time;
用于为不同的响应设定不同时长的有效缓存时长, 例如: proxy_cache_valid 200 302 10m; 为 200 和 302 响应设置缓存时长为 10 分钟
(9) proxy_cache_methods GET | HEAD | POST ...; #为哪些请求方法启用缓存功能; 默认 GET 和 HEAD
如 proxy_cache_methods GET; 把 GET 请求给缓存
(10) proxy_cache_bypass string;
设定在哪种情形下, nginx 将不从缓存中取数据. 例如:
- proxy_cache_bypass $cookie_nocache $arg_nocache $arg_comment;
- proxy_cache_bypass $http_pragma $http_authorization;
- (11) proxy_cache_key string; #设定在存储及检索缓存时用于 "键" 的字符串, 可以使用变量为 $uri 其值, 但使用不当时有可能会为同一个内容缓存多次; 另外, 将用户私有信息用于键可以避免将用户的私有信息返回给其它用户;
例如: proxy_cache_key "$host$request_uri;
负载均衡
负载均衡使用的是 upstream 模块, upstream 模块可定义一个新的上下文, 它包含了一组 upstream 服务器, 这些服务器可能被赋予了不同的权重, 不同的类型, 可以检查各个负载服务器的状态甚至可以基于维护等原因被标记为 down.
配置语法:
upstream 服务器列表名称 {
- server address [parameters];
- ...
- }
upstream 模块常用的指令有:
weight: 权重; 默认为 1
max_fails=number; 设定 Nginx 与服务器通信的尝试失败的次数. 在 fail_timeout 参数定义的时间段内, 如果失败的次数达到此值, Nginx 就认为服务器不可用. 在下一个 fail_timeout 时间段, 服务器不会再被尝试. 失败的尝试次数默认是 1. 设为 0 就会停止统计尝试次数, 认为服务器是一直可用的.
- fail_timeout=time #默认是 10 秒
- backup #标记为备用服务器. 当主服务器不可用以后, 请求会被传给这些服务器.
- down #标记服务器永久不可用, 可以跟 ip_hash 指令一起使用
upstream 模块的其它负载均衡算法(用于 upstream 上下文):
ip_hash;
作用同 lvs 中的 sh 调度算法, 将来自于同一个客户端的请求始终调度至同一台后端服务器(除了当服务器不可用的时候)
least_conn;
将请求发送到活动连接数最少的那台服务器. 如果这样的服务器有多台, 就尝试按加权轮循来调度
sticky cookie name [expires=time] [domain=domain] [httponly] [secure] [path=path];
session 绑定, 将来自于同一个客户端的请求始终调度至同一台后端服务器, 从而实现客户端与后端服务器的 session 保持.
ip_hash 指令无法实现对内网 NAT 用户的均衡, 而 sticky 指令可以做到;
sticky 工作原理:
1. 浏览器首次发起请求, 请求头未带 cookie.nginx 接收请求, 发现请求头没有 cookie, 则以轮询方式将请求代理给后端服务器.
2. 后端服务器处理完请求, 将响应头和内容返回给 nginx.
3.nginx 生成 cookie, 返回给客户端浏览器. cookie 的值与后端服务器对应, 可能是明文, 也可能是 md5,sha1 等 Hash 值.
4. 浏览器接收请求, 并创建 cookie.
5. 浏览器再次发送请求时, 带上 cookie.
6.nginx 接收到 cookie, 直接转给对应的后端服务器
参数说明:
domain:cookie 作用的域名
path:cookie 作用的路径
expires:cookie 的过期时长
7,health_check [interval=time] [fails=number] [passes=number] [uri=uri] [match=name];
对上游服务器组进行健康状态检测, 用于 location 中;
参数说明:
- interval=time #检测的间隔时长, 默认为 5 秒
- fails=number #连续检测失败多少次即认为上游服务器不可用, 默认为 1 次
- passes=number #上游服务器从不可用到可用状态时需要连续检测的次数, 默认为 1 次
- uri=uri #定义用于健康检测的 URI, 默认为 "/", 即默认检测目标服务器的主页
- match=name #指定一段配置来当作检测条件, 默认当响应码为 2XX 或 3XX 时认为上游服务器是可用的
uptream 使用注意:
只能用于 http 上下文
各 server 只能直接使用 IP 或主机名, 不要加协议
默认情况下, nginx 按加权轮转的方式将请求代理到各上游服务器. 与上游服务器通信的时候, 如果出现错误, 请求会被传给下一个服务器, 直到所有可用的服务器都被尝试过. 如果所有服务器都返回失败, 客户端将会得到最后通信的那个服务器的 (失败) 响应结果.
地址可以是域名或者 IP 地址, 端口是可选的(默认是 80), 或者是指定 "unix:" 前缀的 UNIX 域套接字的路径. 如果一个域名解析到多个 IP, 本质上是定义了多个 server.
例如:
- http{
- listen 80;
- upstream php_nginx{
- server 192.168.2.29 weight=2;
- server 192.168.2.30:8080 weight=3 max_fails=5 fail_timeout=30;
- server 192.168.2.109 backup;
- }
- location / {
- proxy_pass http://php_ngix; http://php_ngix;/
- health_check interval=30 fails_time=5 url=/ match=check-php;
- }
- mtach check-php{
- status 200;
- header Content-Type = text/html;
- body ~ "Welcome to nginx!";
- }
- }
- linux-nginx-3(反向代理 + 负载均衡)
来源: http://www.bubuko.com/infodetail-2676384.html