一、配置 http { server { ... location /http { proxy_pass http://http_backend; proxy_redirect default; proxy_set_header Host $http_host; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Real-IP $remote_addr; proxy_set_heade
一、配置
http { server { ... location /http { proxy_pass http://http_backend; proxy_redirect default; proxy_set_header Host $http_host; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_ignore_headers Set-Cookie; proxy_hide_header Set-Cookie; proxy_connect_timeout 30; proxy_send_timeout 60; proxy_read_timeout 60; ... } }}
二、说明
1、proxy_pass真实服务器2、proxy_redirect指定是否修改被代理服务器返回的响应头中的location头域跟refresh头域数值3、proxy_set_header重新定义或者添加发往后端服务器的请求头4、proxy_set_header X-Real-IP启用客户端真实地址(否则日志中显示的是代理在访问网站)5、proxy_set_header X-Forwarded-For记录代理地址6、proxy_connect_timeout定义与代理服务器建立连接的超时时间。需要注意的是这个超时时间通常不能超过75秒,默认值607、proxy_send_timeout后端服务器数据回传时间_就是在规定时间之内后端服务器必须传完所有的数据8、proxy_read_timeoutnginx接收upstream(上游/真实) server数据超时, 默认60s, 如果连续的60s内没有收到1个字节, 连接关闭。像长连接9、Set-Cookie在默认情况,nginx不缓存从后端响应的http头中带有Set-Cookie的对象。如果客户端发送的请求带有Cookie header,varnish将忽略缓存,直接将请求传递到后端。nginx中通过proxy_ignore_headers设置忽略它们,设置方法如下:解决办法: proxy_ignore_headers Set-Cookie;proxy_hide_header Set-Cookie;10# 有时候后端需要知道客户端是用的http请求还是https请求,加上一个X-Forwarded-Proto头proxy_set_header X-Forwarded-Proto $scheme; # 禅道开启https,需要这个选项才能正确转发额外说明proxy_set_header用来设定被代理服务器接收到的header信息。语法:proxy_set_header field value;field :为要更改的项目,也可以理解为变量的名字,比如hostvalue :为变量的值如果不设置proxy_set_header,则默认host的值为proxy_pass后面跟的那个域名或者IP(一般写IP)proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;用来设置被代理端接收到的远程客户端IP,如果不设置,则header信息中并不会透传远程真实客户端的IP地址。$proxy_host 自然是 proxy_pass后面跟着的host 比如一个请求 https://zhidao.baidu.com/question/22908463.htmlRequest.ServerVariables("HTTP_HOST") 可以获得HTTP_HOST请求标题:zhidao.baidu.com$http_host始终等于HTTP_HOST请求标题$host等于$http_host,小写并且没有端口号(如果存在),除非HTTP_HOST不存在或是空值。在这种情况下,$host等于server_name$proxy_add_x_forwarded_for从客户访问到到最后的后台服务所经理的所有节点的ip汇总221.221.1.100,10.30.30.109,... nginx的自带变量$remote_addr代表客户端的IP$remote_addr代表客户端的IP,但它的值不是由客户端提供的,而是服务端根据客户端的ip指定的,当你的浏览器访问某个网站时,假设中间没有任何代理,那么网站的web服务器(Nginx,Apache等)就会把remote_addr设为你的机器IP,如果你用了某个代理,那么你的浏览器会先访问这个代理,然后再由这个代理转发到网站,这样web服务器就会把remote_addr设为这台代理机器的IP。$remote_addr 只能获取到与服务器本身直连的上层请求ip,所以设置$remote_addr一般都是设置第一个代理上面;但是问题是,有时候是通过cdn访问过来的,那么后面web服务器获取到的,永远都是cdn 的ip 而非真是用户ip,那么这个时候就要用到X-Forwarded-For 了,这个变量的意思,其实就像是链路反追踪,从客户的真实ip为起点,穿过多层级的proxy ,最终到达web 服务器,都会记录下来,所以在获取用户真实ip的时候,一般就可以设置成,proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 这样就能获取所有的代理ip客户ip。 $proxy_add_x_forwarded_for变量包含客户端请求头中的X-Forwarded-For与$remote_addr两部分,他们之间用逗号分开。
三、补充
1、proxy_set_header
经过反向代理后,由于在客户端和web服务器之间增加了中间层,因此web服务器无法直接拿到客户端的ip,通过$remote_addr变量拿到的将是反向代理服务器的ip地址”。这句话的意思是说,当你使用了nginx反向服务器后,在web端使用request.getRemoteAddr()(本质上就是获取$remote_addr),取得的是nginx的地址,即$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.getHeader("X-real-ip")客户端地址(请求服务的地址):192.168.1.1nignx服务器地址:192.168.1.2后端服务器地址:192.168.1.3首先说明proxy_set_header是用来设置请求头的,设置了请求头后,后端服务器就可以获取到这些变量值。一、X-Real-IP是指客户端的真实IP,如果设置了$remote_addr这个值,后端服务器就能获取到客户端的真实IP,也就是此例中的192.168.1.1二、Hosthost的值设置为$proxyhost,是指proxy_pass中设置的host值,也就是192.168.1.3,也就是服务器的IP地址。若客户端发过来的请求header中有HOST这个字段,$http_host和$host表示的就是原始请求host,比如请求的时候HOST的值是http://test.com,那么反代后还是http://test.com。若客户端发过来的请求header中没有HOST这个字段,$host表示nginx代理服务器的地址,也就是此例中的192.168.1.2。$httphost不是一个固定的变量,他其实是$http_HEADER通配后的结果,这里的HEADER是一个通配符,通配的是请求头里的header属性,例如$http_content_type表示请求头里content-type属性的值,同理,$http_host指的就是请求头里的host属性。三、X-Forwarded-For这个变量的值有$proxy_add_x_forwarded_for和$remote_addr,在只有一个代理服务器的转发的情况下,两者的效果貌似差不多,都可以真实的显示出客户端原始ip。举例说明,用户A的IP是192.168.1.1,请求一个经过两次nginx转发的应用,在第一台nginx中(192.168.1.2),配置如下:proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;现在$proxy_add_x_forwarded_for变量的"X-Forwarded-For"部分是空的,所以只有$remote_addr,而$remote_addr的值是用户的ip,那么X-Forwarded-For变量的值就是用户的ip:192.168.1.1。到第二台nginx,配置如下:proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;现在的$proxy_add_x_forwarded_for变量,X-Forwarded-For部分包含的是用户的真实ip,$remote_addr部分的值是上一台nginx的ip地址,那么X-Forwarded-For的值就变成了"用户的真实ip,第一台nginx的ip",也就是“192.168.1.1, 192.168.1.2”所以还是建议X-Forwarded-For的值设置成$proxy_add_x_forwarded_for
2、proxy_redirect重定向url
1、用大白话来说这个参数就是,当客户端访问nginx,nginx访问后端,后端如果返回一个url,这个url肯定是包含后端的ip端口或者域名端口信息当后端返回的url到达nginx以后,nginx将url中的ip端口或者域名端口转换成自身的再发送给客户端客户端需要的一切url的访问都应该是nginx的,然后交给nginx去访问后端在使用Nginx做反向代理功能时,有时会出现重定向的url不是我们想要的url,这时候就可以使用proxy_redirect进行url重定向设置了。proxy_redirect功能比较强大,其作用是对发送给客户端的URL进行修改!!2、语法:proxy_redirect [ default|off|redirect replacement ];默认:proxy_redirect default;配置块(使用的字段):http、server、location当上游服务器返回的响应是重定向或刷新请求(如HTTP响应码是301或者302)时,proxy_redirect可以重设HTTP头部的location或refresh字段。 location /login { proxy_pass http://target_servers/login ; }如果需要修改从被代理服务器传来的应答头中的"Location"和"Refresh"字段,这时候就可以用proxy_redirect这个指令设置。假设被代理服务器返回Location字段为http://localhost:8000/kevin/some/uri/proxy_redirect http://localhost:8000/kevin/ http://frontend/one/;将Location字段重写为http://frontend/one/some/uri/。在代替的字段中可以不写服务器名:proxy_redirect http://localhost:8000/kevin/ /;这样就使用服务器的基本名称和端口,即使它来自非80端口。3、如果使用"default"参数,将根据location和proxy_pass参数的设置来决定。下列两个配置等效:location /one/ { proxy_pass http://upstream:port/kevin/; proxy_redirect default;} location /one/ { proxy_pass http://upstream:port/kevin/; proxy_redirect http://upstream:port/kevin/ /one/;}在指令中可以使用一些变量:proxy_redirect http://localhost:8000/ http://$host:$server_port/;4、这个指令有时可以重复:proxy_redirect default; proxy_redirect http://localhost:8000/ /; 5、参数off将在这个字段中禁止所有的proxy_redirect指令:proxy_redirect off; 6、假设当前nginx的访问地址为http://10.0.9:8080,如果kevin-inc又需要302到10.0.9/xxx那么可以添加下redirect,将302的location改为http://10.0.9:8080/xxxlocation /login { proxy_pass http://kevin-inc/login ; proxy_redirect http://10.0.9/ http://10.0.9:8080/; }--------------------------------host变量如果不想写死ip地址,可以使用nginx的变量location /login { proxy_pass http://kevin-inc/login ; proxy_redirect http://$host/ http://$http_host/; }其中host不带端口的,也就是nginx部署的主机ip,而$http_host是带端口的7、server { listen 80; server_name www.kevin.com; location / { proxy_pass http://10.0.8.40:9080; } }这段配置一般情况下都正常,但偶尔会出错, 抓包发现服务器给客户端的跳转指令里加了端口号,如Location: http://www.kevin.com:9080/abc.html 。因为nginx服务器侦听的是80端口,所以这样的URL给了客户端,必然会出错.针对这种情况, 加一条proxy_redirect指令: proxy_redirect http://www.kevin.com:9080/ / ,即把所有"http://www.kevin.com:9080/"的内容替换成"/"再发给客户端,就解决了。 server { listen 80; server_name www.kevin.com; proxy_redirect http://www.kevin.com:9080/ /; location / { proxy_pass http://10.0.8.40:9080; } } 8、如下启用了proxy_redirect配置(http->https),配置中就不需要"proxy_set_header Host $host;",即不需要"添加发往后端服务器的请求头"的配置了upstream scf_cluster { ip_hash; server 192.168.10.20:9020; server 192.168.10.21:9020; }server { listen 443; server_name www.kevin.com kevin.com; ssl on; ssl_certificate /data/nginx/conf/ssl/kevin.cer; ssl_certificate_key /data/nginx/conf/ssl/kevin.key; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_session_cache shared:SSL:1m; ssl_session_timeout 5m; ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4:!DH:!DHE; ssl_prefer_server_ciphers on; access_log /data/nginx/logs/www.kevin.com-access.log main; error_log /data/nginx/logs/www.kevin.com-error.log; error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } location /scf { proxy_pass http://scf_cluster/scf; proxy_redirect http://scf_cluster/scf https://www.kevin.com/scf; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_connect_timeout 300; proxy_send_timeout 300; proxy_read_timeout 600; proxy_buffer_size 256k; proxy_buffers 4 256k; proxy_busy_buffers_size 256k; proxy_temp_file_write_size 256k; proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504 http_404; proxy_max_temp_file_size 128m; }}9、在看下nginx中非80端口的转发,注意:当端口是非80时,proxy_set_header项的$host后面一定要加上端口如下,当http通过proxy_pass到非80端口的做法:upstream mobi_cluster{ server 10.0.54.20:8080; }server { listen 80; server_name mobi.kevin.com; access_log /data/nginx/logs/mobi.kevin.com-access.log main; error_log /data/nginx/logs/mobi.kevin.com-error.log; location / { proxy_pass http://mobi_cluster; proxy_set_header Host $host; proxy_redirect http://mobi_cluster/ http://mobi.kevin.com/; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } }