前言:在網站架構當中,使用varnish緩存服務器爲網站做緩存,後端再使用lnmp架構已經是很平常的事情了,但是,在很多種情況下,後端的nginx服務器,無法獲取到用戶的真實ip.日誌中總是記錄着前端的varnish服務器ip。這也讓一些站長很煩惱。其實nginx有這種功能的。下面我就來講解一下,如何讓nginx在使用varnish做緩存的情況下獲取到用戶的真實ip。
我們先弄兩臺測試機器
- A:192.168.1.151 服務: varnishd
- B:192.168.1.150 服務: nginx
一,我們先安裝好這兩個服務。
1..在A服務器上安裝varnishd
- # yum install pcre*
- # wget http://repo.varnish-cache.org/source/varnish-3.0.0.tar.gz
- # tar -xvf varnishd-3.0.0.tar.gz
- # cd varnish-3.0.0
- # ./configure --prefix=/usr/local/varnishd
- # make&&make install
2,在B服務器上安裝nginx
- # yum install pcre*
- # wget http://soft.vpser.net/web/nginx/nginx-1.0.10.tar.gz
- # cd nginx-1.0.10/
- # ./configure --user=www --group=www --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module --with-http_gzip_static_module --with-ipv6 --with-http_realip_module
- # make && make install
這裏在nginx安裝時,添加了一個 --with-http_realip_module 的模塊來獲取真實ip.
這樣我們就在兩臺服務器上分別安裝好了這兩個服務。
二.關於一些基本配置
這裏我直接在varnishd配置文件裏,加上一個緩存的網站 www.yaozhibingceshi.com ,配置文件如下:
- #Cache for linuxtone sites
- #backend vhost
- backend wwwyaozhibingceshicom {
- .host = "www.yaozhibingceshi.com";
- .port = "80";
- }
- #acl
- acl purge {
- "localhost";
- "127.0.0.1";
- "192.168.0.0"/24;
- }
- sub vcl_recv {
- if (req.http.Accept-Encoding) {
- if (req.url ~ "\.(jpg|png|gif|jpeg|flv)$" ) {
- remove req.http.Accept-Encoding;
- remove req.http.Cookie;
- } else if (req.http.Accept-Encoding ~ "gzip") {
- set req.http.Accept-Encoding = "gzip";
- } else if (req.http.Accept-Encoding ~ "deflate") {
- set req.http.Accept-Encoding = "deflate";
- } else {
- remove req.http.Accept-Encoding;
- }
- }
- if (req.http.host ~ "(.*)yaozhibingceshi.com") {
- set req.backend = wwwyaozhibingceshicom;
- }
- else {
- error 404 "This website is maintaining or not exist!";
- }
- if (req.request == "PURGE") {
- if (!client.ip ~purge) {
- error 405 "Not Allowed";
- }
- #.dd.....
- return(lookup);
- }
- #...GET...url...jpg,png,gif. ..cookie
- if (req.request == "GET"&& req.url ~ "\.(png|gif|jpeg|jpg|ico|swf|css|js|html|htm|gz|tgz|bz2|tbz|mp3|ogg|mp4|flv|f4v|pdf)$") {
- unset req.http.cookie;
- }
- #..GET...url.php....cache....
- if (req.request =="GET"&&req.url ~ "\.php($|\?)"){
- return (pass);
- }
- # }
- #........pipe..
- if (req.request != "GET" &&
- req.request != "HEAD" &&
- req.request != "PUT" &&
- req.request != "POST" &&
- req.request != "TRACE" &&
- req.request != "OPTIONS" &&
- req.request != "DELETE") {
- return (pipe);
- }
- #..GET .HEAD.....
- if (req.request != "GET" && req.request != "HEAD") {
- return (pass);
- }
- if (req.http.Authorization) {
- return (pass);
- }
- return (lookup);
- }
- #..url+host hash......
- sub vcl_hash {
- hash_data(req.url);
- if (req.http.host) {
- hash_data(req.http.host);
- } else {
- hash_data(server.ip);
- }
- return (hash);
- }
- # .....purge .....
- sub vcl_hit {
- if (req.request == "PURGE") {
- set obj.ttl = 0s;
- error 200 "Purged";
- }
- return (deliver);
- }
- sub vcl_fetch {
- if (req.url ~ "\.(jpeg|jpg|png|gif|gz|tgz|bz2|tbz|mp3|ogg|ico|swf|flv|dmg|js|css|html|htm)$") {
- set beresp.ttl = 2d;
- set berespberesp.http.expires = beresp.ttl;
- set beresp.http.Cache-Control = "max-age=172800";
- unset beresp.http.set-cookie;
- }
- if (req.url ~ "\.(dmg|js|css|html|htm)$") {
- set beresp.do_gzip = true;
- }
- if (beresp.status == 503) {
- set beresp.saintmode = 15s;
- }
- }
- sub vcl_deliver {
- set resp.http.x-hits = obj.hits ;
- if (obj.hits > 0) {
- set resp.http.X-Cache = "HIT You!";
- } else {
- set resp.http.X-Cache = "MISS Me!";
- }
- }
並在A服務器的host文件裏綁定 www.yaozhibing.com 爲 192.168.1.150
- # vim /etc/hosts
- 192.168.1.150 www.yaozhibingceshi.com
啓動varnish
- # /usr/local/varnishd/etc/varnish/vcl.conf -s malloc,10M -T 127.0.0.1:2000 -a 0.0.0.0:80
B服務器上的Nginx 可參考網上一些配置,都是大同小異的,
我在這裏添加一個虛擬主機:
- # vim /usr/local/nginx/conf/nginx.conf
- server
- { listen 80;
- server_name www.yaozhibingceshi.com;
- index index.php index.html index.htm;
- root /home/yaozhibing;
- log_format wwwlogs '$remote_addr - $http_x_real_ip - $http_X_Forwarded_For - $remote_user [$time_local] "$request" ';
- access_log /home/yaozhibingceshi.log wwwlogs;
- }
我們在日誌文件裏定義了 $http_real_ip, $http_X_forwarded_for的值,其實這兩個值是一樣的。 http_real_ip是指用戶的真實ip。$http_X_forwarded_for是指通過上一級代理之前的ip。如果有多級代理,這個值裏面就有很多的ip.我們這裏只有一級代理,所以。這裏的$http_X_forwarded_for 指的也是用戶的真實ip.
很明顯這些值,是獲取不到的,只能獲取到前端varnishd服務器 192.168.1.151的ip.
三,配置varnishd,讓nginx獲取到真實用戶的ip.
那麼現在我們來整一下varnish的配置。讓varnish把$http_real_ip和$http_X_forwarded_for值傳給nginx.
我們在A服務器的varnish配置文件裏的sub vcl_recv 裏面加入以下這段:
- remove req.http.X-real-ip;
- set req.http.X-real-ip = client.ip;
- set req.http.X-Forwarded-For = client.ip;
意思就是獲取用戶的真實ip 即 client.ip 並賦值給 http.X-real-ip 和 http.X-Forwarded-For。
現在的varnishd配置文件爲:
- #Cache for linuxtone sites
- #backend vhost
- backend wwwyaozhibingceshicom {
- .host = "www.yaozhibingceshi.com";
- .port = "80";
- }
- #acl
- acl purge {
- "localhost";
- "127.0.0.1";
- "192.168.0.0"/24;
- }
- sub vcl_recv {
- #此處爲添加內容
- remove req.http.X-real-ip;
- set req.http.X-real-ip = client.ip;
- set req.http.X-Forwarded-For = client.ip;
- if (req.http.Accept-Encoding) {
- if (req.url ~ "\.(jpg|png|gif|jpeg|flv)$" ) {
- remove req.http.Accept-Encoding;
- remove req.http.Cookie;
- } else if (req.http.Accept-Encoding ~ "gzip") {
- set req.http.Accept-Encoding = "gzip";
- } else if (req.http.Accept-Encoding ~ "deflate") {
- #以下略。。
這下我們獲取到了我本機的真實ip。192.168.1.5,但是我們從定義的日誌格式來看,這個值應該是 http.X_Forwarded_For 的值。當有多級代理的時候,這個值不能代表用戶的真實ip.但是我在varnishd確實把http_real_ip傳過來了啊,爲什麼不能顯示呢。這下,我們用要用到nginx的 http_realip_modul這個模塊了。接下來,我們在nginx裏,做一下設置,來獲取 real_ip.
四:修改nginx配置文件,來獲取用戶真實ip.
Nginx 的http_realip_modul很好用。在nginx裏定義一下從哪獲取值。獲取哪個值。就OK 了,
我們把虛擬主機的配置文件修改成下面這樣的:
- server
- {
- listen 80;
- server_name www.yaozhibingceshi.com;
- index index.php index.html index.htm;
- root /home/yaozhibing;
- location / {
- set_real_ip_from 192.168.1.151;
- real_ip_header X-Real-ip;
- }
- log_format wwwlogs '$remote_addr - $http_x_real_ip - $http_X_Forwarded_For - $remote_user [$time_local] "$request" ';
- access_log /home/yaozhibingceshi.log wwwlogs;
- }
也就是在虛擬機主機的配置文件裏,添加了:
- location / {
- set_real_ip_from 192.168.1.151;
- real_ip_header X-Real-ip;
- }
set_real_ip_from 是定義獲取的源,就是從哪裏獲取值
real_ip_header 是定義獲取哪個值。
我們看到,http.X_real_ip 和 http.X_Forwarded_For的值。都能正常顯示了。
如果不想看到上級代理的值。在nginx配置文件裏把 log_format 的 $remote_addr去掉就可以了。
日誌還能添加更多內容,這裏我們只看ip,所以把日誌簡化寫的。
如果不清楚請加QQ:410018348 共同探討。