在日常運維工作中,會碰到這樣的需求:設置網站訪問只對某些ip開放,其他ip的客戶端都不能訪問。可以通過下面四種方法來達到這種效果:
1)針對nginx域名配置所啟用的端口(比如80端口)在iptables里做白名單,比如只允許100.110.15.16、100.110.15.17、100.110.15.18訪問.但是這樣就把nginx的所有80端口的域名訪問都做了限制,范圍比較大!
[root@china ~]# vim /etc/sysconfig/iptables ...... -A INPUT -s 100.110.15.16 -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT -A INPUT -s 100.110.15.17 -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT -A INPUT -s 100.110.15.18 -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT
2)如果只是針對nginx下的某一個域名進行訪問的白名單限制,那么可以在nginx的配置文件里進行設置,利用$remote_addr參數進行訪問的分發限制,如下:
[root@china vhosts]# cat testwww.wangshibo.com.conf server { listen 80; server_name testwww.wangshibo.com; root /var/www/vhosts/testwww.wangshibo.com/httpdocs/main; access_log /var/www/vhosts/testwww.wangshibo.com/logs/access.log main; error_log /var/www/vhosts/testwww.wangshibo.com/logs/error.log; ##白名單設置,只允許下面三個來源ip的客戶端以及本地能訪問該站。主要是下面這三行 if ($remote_addr !~ ^(100.110.15.16|100.110.15.17|100.110.15.18|127.0.0.1)) { rewrite ^.*$ /maintence.php last; } location / { try_files $uri $uri/ @router; index index.php; } error_page 500 502 503 504 /50x.html; location @router { rewrite ^.*$ /index.php last; } location ~ \.php$ { fastcgi_pass 127.0.0.1:9001; fastcgi_read_timeout 30; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; #include fastcgi_params; include fastcgi.conf; } } 錯誤頁面內容設置: [root@china vhosts]# cat /var/www/vhosts/testwww.wangshibo.com/main/maintence.html <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> </head> <body> 網站臨時維護中,請稍后訪問... </body> </html>
3)也可以使用$http_x_forwarded_for參數進行訪問的分發限制,如下:
server { listen 80; server_name testwww.wangshibo.com; root /var/www/vhosts/testwww.wangshibo.com/httpdocs/main; access_log /var/www/vhosts/testwww.wangshibo.com/logs/access.log main; error_log /var/www/vhosts/testwww.wangshibo.com/logs/error.log; ##白名單設置,只允許下面三個來源ip的客戶端以及本地能訪問該站。 if ($http_x_forwarded_for !~ ^(100.110.15.16|100.110.15.17|100.110.15.18|127.0.0.1)) { rewrite ^.*$ /maintence.php last; } location / { try_files $uri $uri/ @router; index index.php; } error_page 500 502 503 504 /50x.html; location @router { rewrite ^.*$ /index.php last; } location ~ \.php$ { fastcgi_pass 127.0.0.1:9001; fastcgi_read_timeout 30; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; #include fastcgi_params; include fastcgi.conf; } }
4)還可以利用nginx的allow、deny參數進行訪問限制
[root@china vhosts]# cat testwww.wangshibo.com.conf server { listen 80; server_name testwww.wangshibo.com; root /var/www/vhosts/testwww.wangshibo.com/httpdocs/main; access_log /var/www/vhosts/testwww.wangshibo.com/logs/access.log main; error_log /var/www/vhosts/testwww.wangshibo.com/logs/error.log; ##白名單設置,只允許下面三個來源ip的客戶端以及本地能訪問該站。 allow 100.110.15.16; allow 100.110.15.17; allow 100.110.15.18; allow 127.0.0.1; deny all; location / { try_files $uri $uri/ @router; index index.php; } error_page 500 502 503 504 /50x.html; location @router { rewrite ^.*$ /index.php last; } location ~ \.php$ { fastcgi_pass 127.0.0.1:9001; fastcgi_read_timeout 30; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; #include fastcgi_params; include fastcgi.conf; } }
---------------------------------nginx中remote_addr和x_forwarded_for參數使用說明---------------------------------
做網站時經常會用到remote_addr和x_forwarded_for這兩個頭信息來獲取客戶端的IP,然而當有反向代理或者CDN的情況下,這兩個值就不夠准確了,需要調整一些配置。 1)什么是remote_addr remote_addr代表客戶端的IP,但它的值不是由客戶端提供的,而是服務端根據客戶端的ip指定的,當你的瀏覽器訪問某個網站時,假設中間沒有任何代理,那么網站的 web服務器(Nginx,Apache等)就會把remote_addr設為你的機器IP,如果你用了某個代理,那么你的瀏覽器會先訪問這個代理,然后再由這個代理轉發到網站,這樣web 服務器就會把remote_addr設為這台代理機器的IP。 2)什么是x_forwarded_for 正如上面所述,當你使用了代理時,web服務器就不知道你的真實IP了,為了避免這個情況,代理服務器通常會增加一個叫做x_forwarded_for的頭信息,把連接它的客戶 端IP(即你的上網機器IP)加到這個頭信息里,這樣就能保證網站的web服務器能獲取到真實IP -------------------使用HAProxy做反向代理---------------------- 通常網站為了支撐更大的訪問量,會增加很多web服務器,並在這些服務器前面增加一個反向代理(如HAProxy),它可以把負載均勻的分布到這些機器上。你的瀏覽器訪 問的首先是這台反向代理,它再把你的請求轉發到后面的web服務器,這就使得web服務器會把remote_addr設為這台反向代理的IP,為了能讓你的程序獲取到真實的客戶端 IP,你需要給HAProxy增加以下配置: option forwardfor 它的作用就像上面說的,增加一個x_forwarded_for的頭信息,把你上網機器的ip添加進去 ------------------使用Nginx的realip模塊-------------------- 當Nginx處在HAProxy后面時,就會把remote_addr設為HAProxy的IP,這個值其實是毫無意義的,你可以通過nginx的realip模塊,讓它使用x_forwarded_for里的值。使用這 個模塊需要重新編譯Nginx,增加--with-http_realip_module參數 set_real_ip_from 10.1.10.0/24; real_ip_header X-Forwarded-For; 上面的配置就是把從10.1.10這一網段過來的請求全部使用X-Forwarded-For里的頭信息作為remote_addr ------------------將Nginx架在HAProxy前面做HTTPS代理--------------- 網站為了安全考慮通常會使用https連接來傳輸敏感信息,https使用了ssl加密,HAProxy沒法直接解析,所以要在HAProxy前面先架台Nginx解密,再轉發到HAProxy做負載均 衡。這樣在Web服務器前面就存在了兩個代理,為了能讓它獲取到真實的客戶端IP,需要做以下配置。 首先要在Nginx的代理規則里設定: proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 這樣會讓Nginx的https代理增加x_forwarded_for頭信息,保存客戶的真實IP。 其次修改HAProxy的配置: option forwardfor except 10.1.10.0/24 這個配置和之前設定的差不多,只是多了個內網的IP段,表示如果HAProxy收到的請求是由內網傳過來的話(https代理機器),就不會設定x_forwarded_for的值,保證后面的 web服務器拿到的就是前面https代理傳過來的。 -----------------為什么PHP里的HTTP_X_FORWARDED_FOR和Nginx的不一樣------------------ 當你的網站使用了CDN后,用戶會先訪問CDN,如果CDN沒有緩存,則回源站(即你的反向代理)取數據。CDN在回源站時,會先添加x_forwarded_for頭信息,保存用戶的真實IP, 而你的反向代理也會設定這個值,不過它不會覆蓋,而是把CDN服務器的IP(即當前remote_addr)添加到x_forwarded_for的后面,這樣x_forwarded_for里就會存在兩個值。 Nginx會使用這些值里的第一個,即客戶的真實IP,而PHP則會使用第二個,即CDN的地址。為了能讓PHP也使用第一個值,你需要添加以下fastcgi的配置。 fastcgi_param HTTP_X_FORWARDED_FOR $http_x_forwarded_for; 它會把nginx使用的值(即第一個IP)傳給PHP,這樣PHP拿到的x_forwarded_for里其實就只有一個值了,也就不會用第二個CDN的IP了。 忽略x_forwarded_for 其實,當你使用了Nginx的realip模塊后,就已經保證了remote_addr里設定的就是客戶端的真實IP,再看下這個配置 set_real_ip_from 10.1.10.0/24; real_ip_header X-Forwarded-For; 它就是把x_forwarded_for設為remote_addr,而nginx里的x_forwarded_for取的就是其中第一個IP。 使用這些設置就能保證你的remote_addr里設定的一直都是客戶端的真實IP,而x_forwarded_for則可以忽略了:)
---------------------------------下面簡單說明下nginx location匹配規則-------------------------------------------
location匹配命令 ~ 表示執行一個正則匹配,區分大小寫 ~* 表示執行一個正則匹配,不區分大小寫 ^~ 表示普通字符匹配,如果該選項匹配,只匹配該選項,不匹配別的選項,一般用來匹配目錄 = 進行普通字符精確匹配 @ 定義一個命名的 location,使用在內部定向時,例如 error_page, try_files =前綴的指令嚴格匹配這個查詢。如果找到,停止搜索。 所有剩下的常規字符串,最長的匹配。如果這個匹配使用^〜前綴,搜索停止。 正則表達式,在配置文件中定義的順序。 如果第3條規則產生匹配的話,結果被使用。否則,如同從第2條規則被使用。 location 匹配的優先級(與location在配置文件中的順序無關) = 精確匹配會第一個被處理。如果發現精確匹配,nginx停止搜索其他匹配。 普通字符匹配,正則表達式規則和長的塊規則將被優先和查詢匹配,也就是說如果該項匹配還需去看有沒有正則表達式匹配和更長的匹配。 ^~ 則只匹配該規則,nginx停止搜索其他匹配,否則nginx會繼續處理其他location指令。 最后匹配理帶有"~"和"~*"的指令,如果找到相應的匹配,則nginx停止搜索其他匹配;當沒有正則表達式或者沒有正則表達式被匹配的情況下,那么匹配程度最高的逐字匹配指令會被使用。 location = / { # 只匹配"/". [ configuration A ] } location / { # 匹配任何請求,因為所有請求都是以"/"開始,但是更長字符匹配或者正則表達式匹配會優先匹配 [ configuration B ] } location ^~ /images/ { # 匹配任何以 /images/ 開始的請求,並停止匹配 其它location [ configuration C ] } location ~* \.(gif|jpg|jpeg)$ { # 匹配以 gif, jpg, or jpeg結尾的請求. 但是所有 /images/ 目錄的請求將由 [Configuration C]處理. [ configuration D ] }