Nginx反向代理功能-實現HTTP反向代理客戶端IP透傳案例
作者:尹正傑
版權聲明:原創作品,謝絕轉載!否則將追究法律責任。
一.Nginx反向代理概述
1>.什么是反向代理
反向代理也叫reverse proxy,指的是代理外網用戶的請求到內部的指定web服務器,並將數據返回給用戶的一種方式,這是用的比較多的一種方式。
2>.Nginx支持的反向代理
Nginx除了可以在企業提供高性能的web服務之外,另外還可以將本身不具備的請求通過某種預定義的協議轉發至其它服務器處理,不同的協議就是Nginx服務器與其他服務器進行通信的一種規范,主要在不同的場景使用以下模塊實現不同的功能:
ngx_http_proxy_module:
將客戶端的請求以http協議轉發至指定服務器進行處理。
ngx_stream_proxy_module:
將客戶端的請求以tcp協議轉發至指定服務器處理,很少有人使用Nginx來跑TCP的反向代理,因為它的這種功能出來的比較晚,一般TCP反向代理使用Haproxy或者LVS的居多。
ngx_http_fastcgi_module:
將客戶端對php的請求以fastcgi協議轉發至指定服務器助理,比如使用Laravel,Yii Framework等Web開發工具開發的程序就可以使用這種方式部署LNMP
ngx_http_uwsgi_module:
將客戶端對Python的請求以uwsgi協議轉發至指定服務器處理,比如使用Django等Web開發的程序就可以使用這種方式部署LNMP。
博主推薦閱讀:
https://nginx.org/en/docs/http/ngx_http_proxy_module.html
3>.Nginx邏輯調用關系如下圖所示
二.試驗環境說明
1>.虛擬機操作系統配置
[root@node101.yinzhengjie.org.cn ~]# uname -r 3.10.0-957.el7.x86_64 [root@node101.yinzhengjie.org.cn ~]# [root@node101.yinzhengjie.org.cn ~]# uname -m x86_64 [root@node101.yinzhengjie.org.cn ~]# [root@node101.yinzhengjie.org.cn ~]# cat /etc/redhat-release CentOS Linux release 7.6.1810 (Core) [root@node101.yinzhengjie.org.cn ~]# [root@node101.yinzhengjie.org.cn ~]# free -h total used free shared buff/cache available Mem: 7.6G 152M 6.7G 9.7M 851M 7.2G Swap: 7.9G 0B 7.9G [root@node101.yinzhengjie.org.cn ~]# [root@node101.yinzhengjie.org.cn ~]# [root@node101.yinzhengjie.org.cn ~]# hostname -i 172.30.1.101 [root@node101.yinzhengjie.org.cn ~]# [root@node101.yinzhengjie.org.cn ~]# cat /etc/hosts 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 172.30.1.101 node101.yinzhengjie.org.cn node101.yinzhengjie.com 172.30.1.102 node102.yinzhengjie.org.cn 172.30.1.103 node103.yinzhengjie.org.cn 172.30.1.104 node104.yinzhengjie.org.cn 172.30.1.105 node105.yinzhengjie.org.cn 172.30.1.106 node106.yinzhengjie.org.cn 172.30.1.107 node107.yinzhengjie.org.cn 172.30.1.108 node108.yinzhengjie.org.cn [root@node101.yinzhengjie.org.cn ~]#
2>.反向代理說明
node101.yinzhengjie.org.cn:
Nginx反向代理服務器
node108.yinzhengjie.org.cn:
Apache httpd的web服務器
三.Apache httpd服務器部署
1>.安裝Apache httpd服務

[root@node108.yinzhengjie.org.cn ~]# yum -y install httpd Loaded plugins: fastestmirror Determining fastest mirrors * base: mirrors.neusoft.edu.cn * extras: mirror.bit.edu.cn * updates: mirror.bit.edu.cn base | 3.6 kB 00:00:00 extras | 2.9 kB 00:00:00 updates | 2.9 kB 00:00:00 (1/4): extras/7/x86_64/primary_db | 153 kB 00:00:00 (2/4): base/7/x86_64/primary_db | 6.0 MB 00:00:01 (3/4): updates/7/x86_64/primary_db | 5.9 MB 00:00:02 (4/4): base/7/x86_64/group_gz | 165 kB 00:00:04 Resolving Dependencies --> Running transaction check ---> Package httpd.x86_64 0:2.4.6-90.el7.centos will be installed --> Processing Dependency: httpd-tools = 2.4.6-90.el7.centos for package: httpd-2.4.6-90.el7.centos.x86_64 --> Processing Dependency: libaprutil-1.so.0()(64bit) for package: httpd-2.4.6-90.el7.centos.x86_64 --> Processing Dependency: libapr-1.so.0()(64bit) for package: httpd-2.4.6-90.el7.centos.x86_64 --> Running transaction check ---> Package apr.x86_64 0:1.4.8-5.el7 will be installed ---> Package apr-util.x86_64 0:1.5.2-6.el7 will be installed ---> Package httpd-tools.x86_64 0:2.4.6-90.el7.centos will be installed --> Finished Dependency Resolution Dependencies Resolved ============================================================================================================================================================================ Package Arch Version Repository Size ============================================================================================================================================================================ Installing: httpd x86_64 2.4.6-90.el7.centos base 2.7 M Installing for dependencies: apr x86_64 1.4.8-5.el7 base 103 k apr-util x86_64 1.5.2-6.el7 base 92 k httpd-tools x86_64 2.4.6-90.el7.centos base 91 k Transaction Summary ============================================================================================================================================================================ Install 1 Package (+3 Dependent packages) Total download size: 3.0 M Installed size: 9.9 M Downloading packages: (1/4): apr-util-1.5.2-6.el7.x86_64.rpm | 92 kB 00:00:00 (2/4): httpd-2.4.6-90.el7.centos.x86_64.rpm | 2.7 MB 00:00:00 (3/4): httpd-tools-2.4.6-90.el7.centos.x86_64.rpm | 91 kB 00:00:00 (4/4): apr-1.4.8-5.el7.x86_64.rpm | 103 kB 00:00:05 ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Total 505 kB/s | 3.0 MB 00:00:06 Running transaction check Running transaction test Transaction test succeeded Running transaction Installing : apr-1.4.8-5.el7.x86_64 1/4 Installing : apr-util-1.5.2-6.el7.x86_64 2/4 Installing : httpd-tools-2.4.6-90.el7.centos.x86_64 3/4 Installing : httpd-2.4.6-90.el7.centos.x86_64 4/4 Verifying : apr-1.4.8-5.el7.x86_64 1/4 Verifying : httpd-tools-2.4.6-90.el7.centos.x86_64 2/4 Verifying : apr-util-1.5.2-6.el7.x86_64 3/4 Verifying : httpd-2.4.6-90.el7.centos.x86_64 4/4 Installed: httpd.x86_64 0:2.4.6-90.el7.centos Dependency Installed: apr.x86_64 0:1.4.8-5.el7 apr-util.x86_64 0:1.5.2-6.el7 httpd-tools.x86_64 0:2.4.6-90.el7.centos Complete! [root@node108.yinzhengjie.org.cn ~]#
2>.創建Apache httpd測試首頁並修改apache的默認日志格式
[root@node108.yinzhengjie.org.cn ~]# echo "<h1>The Apache Web App01 index.</h1>" > /var/www/html/index.html [root@node108.yinzhengjie.org.cn ~]# [root@node108.yinzhengjie.org.cn ~]# cat /var/www/html/index.html <h1>The Apache Web App01 index.</h1> [root@node108.yinzhengjie.org.cn ~]# [root@node108.yinzhengjie.org.cn ~]# grep yinzhengjie_nginx_ip_forwarded /etc/httpd/conf/httpd.conf #注意,關於"yinzhengjie_nginx_ip_forwarded"變量名稱要和nginx配置配置文件的要一致喲~ LogFormat "\"%{yinzhengjie_nginx_ip_forwarded}i\" %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined [root@node108.yinzhengjie.org.cn ~]#

[root@node108.yinzhengjie.org.cn ~]# egrep -v "^ *#|^$" /etc/httpd/conf/httpd.conf ServerRoot "/etc/httpd" Listen 80 Include conf.modules.d/*.conf User apache Group apache ServerAdmin root@localhost <Directory /> AllowOverride none Require all denied </Directory> DocumentRoot "/var/www/html" <Directory "/var/www"> AllowOverride None Require all granted </Directory> <Directory "/var/www/html"> Options Indexes FollowSymLinks AllowOverride None Require all granted </Directory> <IfModule dir_module> DirectoryIndex index.html </IfModule> <Files ".ht*"> Require all denied </Files> ErrorLog "logs/error_log" LogLevel warn <IfModule log_config_module> LogFormat "\"%{yinzhengjie_nginx_ip_forwarded}i\" %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined LogFormat "%h %l %u %t \"%r\" %>s %b" common <IfModule logio_module> LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio </IfModule> CustomLog "logs/access_log" combined </IfModule> <IfModule alias_module> ScriptAlias /cgi-bin/ "/var/www/cgi-bin/" </IfModule> <Directory "/var/www/cgi-bin"> AllowOverride None Options None Require all granted </Directory> <IfModule mime_module> TypesConfig /etc/mime.types AddType application/x-compress .Z AddType application/x-gzip .gz .tgz AddType text/html .shtml AddOutputFilter INCLUDES .shtml </IfModule> AddDefaultCharset UTF-8 <IfModule mime_magic_module> MIMEMagicFile conf/magic </IfModule> EnableSendfile on IncludeOptional conf.d/*.conf [root@node108.yinzhengjie.org.cn ~]# [root@node108.yinzhengjie.org.cn ~]#
3>.啟動Apache httpd服務
[root@node108.yinzhengjie.org.cn ~]# ss -ntl State Recv-Q Send-Q Local Address:Port Peer Address:Port LISTEN 0 128 *:22 *:* LISTEN 0 128 :::22 :::* [root@node108.yinzhengjie.org.cn ~]# [root@node108.yinzhengjie.org.cn ~]# systemctl start httpd [root@node108.yinzhengjie.org.cn ~]# [root@node108.yinzhengjie.org.cn ~]# ss -ntl State Recv-Q Send-Q Local Address:Port Peer Address:Port LISTEN 0 128 *:80 *:* LISTEN 0 128 *:22 *:* LISTEN 0 128 :::22 :::* [root@node108.yinzhengjie.org.cn ~]# [root@node108.yinzhengjie.org.cn ~]#
4>.驗證服務是否可以正常訪問
瀏覽器訪問"http://node108.yinzhengjie.org.cn/",發現的確是咱們的測試頁面,如下圖所示,服務是正常的。
5>.創建多業務模擬數據
[root@node108.yinzhengjie.org.cn ~]# mkdir /var/www/html/{static,image,dynamic} [root@node108.yinzhengjie.org.cn ~]# [root@node108.yinzhengjie.org.cn ~]# echo "<h1>The apache httpd static page.</h1>" > /var/www/html/static/index.html [root@node108.yinzhengjie.org.cn ~]# [root@node108.yinzhengjie.org.cn ~]# echo "<h1>The apache httpd image page.</h1>" > /var/www/html/image/index.html [root@node108.yinzhengjie.org.cn ~]# [root@node108.yinzhengjie.org.cn ~]# echo "<h1>The apache httpd dynamic page.</h1>" > /var/www/html/dynamic/index.html [root@node108.yinzhengjie.org.cn ~]# [root@node108.yinzhengjie.org.cn ~]# ll /var/www/html/ -R /var/www/html/: total 4 drwxr-xr-x 2 root root 24 Dec 26 14:19 dynamic drwxr-xr-x 2 root root 24 Dec 26 14:18 image -rw-r--r-- 1 root root 37 Dec 26 14:04 index.html drwxr-xr-x 2 root root 24 Dec 26 14:18 static /var/www/html/dynamic: total 4 -rw-r--r-- 1 root root 40 Dec 26 14:19 index.html /var/www/html/image: total 4 -rw-r--r-- 1 root root 38 Dec 26 14:18 index.html /var/www/html/static: total 4 -rw-r--r-- 1 root root 39 Dec 26 14:18 index.html [root@node108.yinzhengjie.org.cn ~]#
四.Nginx服務器實現http反向代理配置客戶端IP透傳實戰
1>.編輯主配置文件
[root@node101.yinzhengjie.org.cn ~]# cat /yinzhengjie/softwares/nginx/conf/nginx.conf worker_processes 4; worker_cpu_affinity 00000001 00000010 00000100 00001000; events { worker_connections 100000; use epoll; accept_mutex on; multi_accept on; } http { include mime.types; default_type text/html; server_tokens off; charset utf-8; log_format my_access_json '{"@timestamp":"$time_iso8601",' '"host":"$server_addr",' '"clientip":"$remote_addr",' '"size":$body_bytes_sent,' '"responsetime":$request_ti me,' '"upstreamtime":"$upstream_response_time",' '"upstreamhost":"$upstream_addr",' '"http_host":"$host",' '"uri":"$uri",' '"domain":"$host",' '"xff":"$http_x_forwarded_for",' '"referer":"$http_referer",' '"tcp_xff":"$proxy_protocol_addr",' '"http_user_agent":"$http_user_agent",' '"status":"$status"}'; access_log logs/access_json.log my_access_json; ssl_certificate /yinzhengjie/softwares/nginx/certs/www.yinzhengjie.org.cn.crt; ssl_certificate_key /yinzhengjie/softwares/nginx/certs/www.yinzhengjie.org.cn.key; ssl_session_cache shared:sslcache:20m; ssl_session_timeout 10m; include /yinzhengjie/softwares/nginx/conf.d/*.conf; } [root@node101.yinzhengjie.org.cn ~]# [root@node101.yinzhengjie.org.cn ~]# nginx -t nginx: the configuration file /yinzhengjie/softwares/nginx/conf/nginx.conf syntax is ok nginx: configuration file /yinzhengjie/softwares/nginx/conf/nginx.conf test is successful [root@node101.yinzhengjie.org.cn ~]#
2>.編輯子配置文件
[root@node101.yinzhengjie.org.cn ~]# cat /yinzhengjie/softwares/nginx/conf.d/node101_yinzhengjie_org.cn.conf server { listen 80; listen 443 ssl; server_name node101.yinzhengjie.org.cn; access_log /yinzhengjie/softwares/nginx/logs/node101_yinzhengjie_org_cn_access.log my_access_json; error_log /yinzhengjie/softwares/nginx/logs/node101_yinzhengjie_org_cn_error.log; location / { root /yinzhengjie/data/web/nginx/static/cn; index index.html; #定義有效的請求referer,用空格隔開即可 valid_referers none blocked server_names *.baidu.com example.* ~\.google\.; #如果沒有在上面的有效鏈接定義那么均屬於無效請求referer if ($invalid_referer) { return 403; } #如果是一些常見的壓測試工具,咱們直接進給他拒絕訪問 if ($http_user_agent ~ "ApacheBench|WebBench|TurnitinBot|Sougou web spider|Grid Server"){ return 403; } } location = /favicon.ico { root /yinzhengjie/data/web/nginx/images/jd; } location /app01 { #proxy_pass指令用來設置將客戶端請求轉發給的后端服務器的主機,可以是主機名、IP地址:端口的方式,也可以代理到預先設置的主機群組,需要模塊gx_http_upstream_module支持。 #帶斜線,等於訪問后端服務器的http://172.30.108:80/index.html內容返回給客戶端。 proxy_pass http://172.30.1.108/; #proxy_connect_timeout time;配置nginx服務器與后端服務器嘗試建立連接的超時時間,默認為60秒,用法如下: proxy_connect_timeout 60s; } location /static { #不帶斜線將訪問的/static,等於訪問后端服務器 http://172.30.1.108:80/static/index.html,即后端服務器配置的站點根目錄要有/static目錄才可以被訪問。 proxy_pass http://172.30.1.108; } location /image { proxy_pass http://172.30.1.108; #proxy_hide_header指令用於nginx作為反向代理的時候,在返回給客戶端http響應的時候,用於隱藏后端服務器特定的響應首部, #默認nginx在響應報文中不傳遞后端服務器的首部字段Dte, Server, XPad,X-Accel等,可以設置在http,server,location塊. #隱藏掉ETag的文本值,CDN會根據ETag的值是否發生變化而決定該文件內容是否發生變化,一旦發生變化CDN會重新抓取該數據並緩存,此處我故意隱藏該值。 proxy_hide_header ETag; } location /dynamic { proxy_pass http://172.30.1.108; #proxy_set_header可以更改或添加客戶端的請求頭部信息內容並轉發至后端服務器,比如在后端服務器想要獲取客戶端的真實IP的時候,就要更改每一個報文的頭部。 #添加HOST到報文頭部,如果客戶端為NAT上網那么其值為客戶端的共用的公網IP地址。 proxy_set_header yinzhengjie_nginx_ip_forwarded $proxy_add_x_forwarded_for; } } [root@node101.yinzhengjie.org.cn ~]# [root@node101.yinzhengjie.org.cn ~]# nginx -t nginx: the configuration file /yinzhengjie/softwares/nginx/conf/nginx.conf syntax is ok nginx: configuration file /yinzhengjie/softwares/nginx/conf/nginx.conf test is successful [root@node101.yinzhengjie.org.cn ~]#
3>.重新加載nginx的配置文件
[root@node101.yinzhengjie.org.cn ~]# ps -ef | grep nginx | grep -v grep root 21155 1 0 13:38 ? 00:00:00 nginx: master process nginx nginx 21156 21155 5 13:38 ? 00:00:00 nginx: worker process nginx 21157 21155 5 13:38 ? 00:00:00 nginx: worker process nginx 21158 21155 6 13:38 ? 00:00:00 nginx: worker process nginx 21159 21155 8 13:38 ? 00:00:00 nginx: worker process [root@node101.yinzhengjie.org.cn ~]# [root@node101.yinzhengjie.org.cn ~]# [root@node101.yinzhengjie.org.cn ~]# nginx -s reload [root@node101.yinzhengjie.org.cn ~]# [root@node101.yinzhengjie.org.cn ~]# ps -ef | grep nginx | grep -v grep root 21155 1 3 13:38 ? 00:00:00 nginx: master process nginx nginx 21165 21155 32 13:38 ? 00:00:00 nginx: worker process nginx 21166 21155 28 13:38 ? 00:00:00 nginx: worker process nginx 21167 21155 32 13:38 ? 00:00:00 nginx: worker process nginx 21168 21155 10 13:38 ? 00:00:00 nginx: worker process [root@node101.yinzhengjie.org.cn ~]# [root@node101.yinzhengjie.org.cn ~]#
4>.瀏覽器訪問"http://node101.yinzhengjie.org.cn/app01",如下圖所示。
5>.瀏覽器訪問"http://node101.yinzhengjie.org.cn/static/",如下圖所示。
6>.瀏覽器訪問"http://node101.yinzhengjie.org.cn/image/",如下圖所示。
7>.瀏覽器訪問"http://node101.yinzhengjie.org.cn/dynamic/",如下圖所示。
五.Nginx服務器反向代理常用的配置指令說明
1>.proxy_pass
用來設置將客戶端請求轉發給的后端服務器的主機,可以是主機名、IP地址:端口的方式,也可以代理到預先設置的主機群組,需要模塊gx_http_upstream_module支持。 博主推薦閱讀:
https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass
2>.proxy_hide_header
用於nginx作為反向代理的時候,在返回給客戶端http響應的時候,隱藏后端服務版本相應頭部的信息,可以設置在http/server或location塊,用於隱藏后端服務器特定的響應首部,默認nginx在響應報文中不傳遞后端服務器的首部字段Date, Server, XPad,X-Accel等。 博主推薦閱讀: https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_hide_header
3>.proxy_pass_request_body
是否向后端服務器發送HTTP包體部分,可以設置在http/server或location塊,默認即為開啟。 博主推薦閱讀: https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass_request_body
4>.proxy_pass_request_headers
是否將客戶端的請求頭部轉發給后端服務器,可以設置在http/server或location塊,默認即為開啟。
博主推薦閱讀: https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass_request_headers
5>.proxy_set_header
可以更改或添加客戶端的請求頭部信息內容並轉發至后端服務器,比如在后端服務器想要獲取客戶端的真實IP的時候,就要更改每一個報文的頭部。即添加HOST到報文頭部,如果客戶端為NAT上網那么其值為客戶端的共用的公網IP地址。 博主推薦閱讀: https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_set_header
6>.proxy_connect_timeout
配置nginx服務器與后端服務器嘗試建立連接的超時時間,默認為60秒。 博主推薦閱讀:
https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_connect_timeout
7>.proxy_read_timeout
配置nginx服務器向后端服務器或服務器組發起read請求后,等待的超時時間,默認60s。 博主推薦閱讀: https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_read_timeout
8>.proxy_send_timeout
配置nginx項后端服務器或服務器組發起write請求后,等待的超時時間,默認60s 博主推薦閱讀:
https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_send_timeout
9>.proxy_http_version
用於設置nginx提供代理服務的HTTP協議的版本,默認http 1.0版本。 博主推薦閱讀: https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_http_version
10>.proxy_ignore_client_abort
當客戶端網絡中斷請求時,nginx服務器中斷其對后端服務器的請求。即如果此項設置為on開啟,則服務器會忽略客戶端中斷並一直等着代理服務執行返回,如果設置為off,則客戶端中斷后Nginx也會中斷客戶端請求並立即記錄499日志,默認為off。 博主推薦閱讀: https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_ignore_client_abort
11>.proxy_headers_hash_bucket_size
當配置了 proxy_hide_header和proxy_set_header的時候,用於設置nginx保存HTTP報文頭的hash表的上限。 博主推薦閱讀: https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_headers_hash_bucket_size
12>.proxy_headers_hash_max_size
設置proxy_headers_hash_bucket_size的最大可用空間,設置服務器名稱的hash表上限大小。 博主推薦閱讀: https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_headers_hash_max_size