Nginx + tomcat + SSL 安裝配置手冊
1. 介紹
Nginx ("engine x") 是一個高性能的 HTTP 和 反向代理 服務器,也是一個 IMAP/POP3/SMTP 代理服務器。
nginx有以下幾項基本特性:
Ø 模塊化結構
過濾器包括gzipping, byte ranges, chunked responses,以及 SSI-filter等filter。
Ø 高性能
支持內核Poll模型,能經受高負載的考驗,有報告表明能支持高達 50,000個併發連接數。
Ø 高穩定性
Nginx採取了分階段資源分配技術,使得它的CPU與內存佔用率非常低。官方表示保持10,000個沒有活動的連接,它只佔2.5M內存。
Ø 多負載策略
多種分配策略,並且分配均勻。
自Nginx 發佈四年來,Nginx 已經因爲它的穩定性、豐富的功能集、 示例配置文件和低系統資源的消耗而聞名了。目前國內各大門戶網站已經部署了Nginx,如新浪、網易、騰訊等;國內幾個重要的視頻分享網站也部署了Nginx,如六房間、酷6等。
2. 準備
2.1 資源
Nginx中文網站:http://www.nginxcn.com/
Nginx英文網站:http://nginx.org/
PCRE網站:http://www.pcre.org/
2.2 相關軟件
1) PCRE
PCRE(Perl Compatible Regular Expressions)中文含義:perl語言兼容正則表達式)是一個用C語言編寫的正則表達式函數庫。
neginx中使用正則表達式進行靈活配置,安裝之前需要確認PCRE已安裝。
下載地址:http://www.pcre.org/,使用版本pcre-8.12.tar.gz
2) nginx-upstream-jvm-route
nginx_upstream_jvm_route 是一個 Nginx 的擴展模塊,用來實現基於 Cookie 的 Session Sticky 的功能。
下載地址(svn): http://nginx-upstream-jvm-route.googlecode.com/svn/trunk/
3. 部署結構
4. 環境安裝
4.1 Windows版安裝
安裝文件爲.zip文件,解壓縮後,運行目錄中的nginx.exe(或使用命令),服務啓動。
瀏覽器中輸入:http://192.168.15.30,出現“Welcome to nginx!”頁面,安裝成功。
4.2 Linux版安裝
l 安裝說明
本例將nginx安裝在/home/apps目錄下。
將pcre-8.12.tar.gz、nginx-0.8.54.tar.gz文件ftp到/home/apps目錄下。
將nginx-upstream-jvm-route文件夾ftp到/home/apps目錄下。
l 安裝步驟
1) PCRE安裝
#cd /home/apps
#tar –zxf pcre-8.12.tar.gz
#cd pcre-8.12
#./config
#make
#make install
默認安裝路徑爲:/usr/local/lib
2) nginx-upstream-jvm-route安裝
#cd /home/apps
#tar –zxf nginx-0.8.54.tar.gz
#mv nginx-0.8.54 nginx-0.8.54-src
#cd nginx-0.8.54-src
# patch -p0 < ../nginx-upstream-jvm-route/jvm_route.patch
3) nginx安裝
#cd /home/apps/nginx-0.8.54
#./configure --prefix=/home/apps/nginx-0.8.54 --with-http_ssl_module --with-http_gzip_static_module --with-http_stub_status_module --add-module=/home/apps/nginx-upstream-jvm-route
#make
#make install
l 啓動、驗證
#cd /home/apps/nginx-0.8.54/sbin
#./nginx
瀏覽器中輸入:http://192.168.15.30,出現“Welcome to nginx!”頁面,安裝成功。
5. Nginx配置
5.1 通用參數配置
1) worker_processes:指明瞭nginx要開啓的進程數,據官方說法,一般開一個就夠了,多開幾個,可以減少機器io帶來的影響。(網上經驗,設置爲cpu數的兩倍)。
2) worker_connections:每個工作進程允許最大的同時連接數。
5.2 負載均衡配置
Ø 說明
Nginx使用upstream模塊配置負載均衡,upstream目前支持5鍾配置方式,每種方式是不同的負載策略,除了這五種外可以使用nginx-upstream-jvm-route擴展模塊,在配置部分會針對6中進行示例。
Ø 準備工作
安裝nginx-upstream-jvm-route擴展模塊。修改tomcat的server.xml文件,在“<Engine”節點增加“jvmRoute="tomcat1"”和“jvmRoute="tomcat2"”。
Ø 配置
1) 輪詢(默認)
每個請求按時間順序逐一分配到不同的後端服務器,如果後端服務器down掉,能自動剔除。
upstream ppg.com
{
server 192.168.15.40:8080;
server 192.168.15.41:8081;
}
2) weight
指定輪詢機率,weight和訪問比率成正比,用於後端服務器性能不均的情況。weight 默認爲1.weight越大,負載的權重就越大。
upstream ppg.com
{
server 192.168.15.40:8080 weight=1;
server 192.168.15.41:8081 weight=2;
}
3) ip_hash
每個請求按訪問ip的hash結果分配,這樣每個訪客固定訪問一個後端服務器,可以解決session的問題。
upstream ppg.com
{
ip_hash;
server 192.168.15.40:8080;
server 192.168.15.41:8081;
}
4) fair
按後端服務器的響應時間來分配請求,響應時間短的優先分配。
upstream ppg.com
{
server 192.168.15.40:8080;
server 192.168.15.41:8081;
fair;
}
5) url
按訪問url的hash結果來分配請求,使每個url定向到同一個後端服務器,後端服務器爲緩存時比較有效。
upstream ppg.com
{
server 192.168.15.40:8080;
server 192.168.15.41:8081;
hash
$request_uri;
hash_method crc32;
}
6) nginx-upstream-jvm-route
Nginx 的擴展模塊,用來實現基於 Cookie 的 Session Sticky 的功能。
upstream ppg.com
{
server 192.168.15.40:8080 srun_id=tomcat1;
server 192.168.15.41:8081 srun_id=tomcat2;
jvm_route $cookie_JSESSIONID|sessionid reverse;
}
5.3 SSL模塊配置
準備證書,使用openssl將p12文件導出服務器證書文件、服務器私鑰文件、客戶證書的簽發證書(CA證書)。見openssl命令。
Ø 說明
Nginx可是實現SSL的配置,實現單向和雙向認證,並能夠驗證證書的狀態。
Ø 準工作
配置單項SSL需要準備服務器證書文件和私鑰文件,配置雙向SSL還需要準備用戶證書的簽發證書。
CA服務器證書文件爲p12格式(nginx不能配置p12格式?),需將p12格式轉化爲crt/cer、key文件格式。使用openssl做轉換,命令如下:
openssl pkcs12 -in www.push.com.pfx -nodes -nocerts -out server.key
openssl pkcs12 -in www.push.com.pfx -nodes -nokeys -clcerts -out server.crt
openssl pkcs12 -in rootca.pfx -nodes -nokeys -clcerts -out ca.crt
Ø 配置HTTPS
修改nginx.conf文件,配置HTTPS模塊,配置如下:
server {
listen 443;
server_name localhost;
ssl on;
ssl_certificate server.crt;
ssl_certificate_key server.key;
ssl_client_certificate ca.crt;#雙向認證
ssl_verify_client on; #雙向認證
ssl_session_timeout 5m;
ssl_protocols SSLv2 SSLv3 TLSv1;
ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;
ssl_prefer_server_ciphers on;
location /XXXX_center/ {
proxy_pass http://192.168.15.40/XXXX_center/;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header SSL_CERT $ssl_client_cert;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location / {
root html;
index index.html index.htm;
}
}
Ø 注意
1、 Nginx配置了SSL後,tomcat不需要再配置SSL,因爲代理轉向地址爲http而非https,如:proxy_pass http://192.168.15.30/XXXX_center/;
2、 Nginx配置SSL後,web服務器部署的應用不能再獲取到用戶證書,而服務器平臺必須要拿到用戶證書進行業務驗證。這就需要nginx將用戶證書透傳到web服務器,在這裏將用戶證書添加到http頭中,應用從http頭獲取用戶證書,達到透傳的目的,如:proxy_set_header SSL_CERT $ssl_client_cert;
5.4 靜態文件配置
Ø 說明
Nginx可處置靜態文件,應用服務器只處理動態文件,提高訪問和處理能力。
Ø 準備工作
將靜態文件放入nginx服務器:在nginx目錄下創建web目錄,將XXXX_center下的XXXX_center/static/sj和XXXX_center/static/smpush文件放入web目錄,目錄結構爲:XXXX_center/static/sj、/nginx-0.8.54/web/XXXX_center/static/smpush。
Ø 配置
location ~ /.(css|js){
root web;#將應用的靜態內容放入web目錄下
expires 1h;
}
Ø 注意
1、 過濾條件根據需求改變表達式即可。
2、 Tomcat下發布的XXXX_center應用不需要在包含靜態文件,只需維護nginx的靜態文件即可。
5.5 監控模塊
Ø 說明
Ø 配置
location ~ ^/NginxStatus{
stub_status on;
}
Ø 監控信息
輸入nginx的URL:http://192.168.15.30/NginxStatus,顯示如下內容:
Active connections: 70
server accepts handled requests
14553819 14553819 19239266
Reading: 0 Writing: 3 Waiting: 67
ü active connections:當前 Nginx 正處理的活動連接數。
ü server accepts handled requests -- 總共處理了 14553819 個連接 , 成功創建 14553819 次握手 ( 證明中間沒有失敗的 ), 總共處理了 19239266 個請求 ( 平均每次握手處理了 1.3 個數據請求 )。
ü reading -- nginx 讀取到客戶端的 Header 信息數。
ü writing -- nginx 返回給客戶端的 Header 信息數。
ü waiting -- 開啓 keep-alive 的情況下,這個值等於 active - (reading + writing),意思就是 Nginx 已經處理完正在等候下一次請求指令的駐留連接。
6. Tomcat集羣配置:
實現多臺web服務器的session同步。
6.1 條件
1、 確定nginx 服務器和兩臺tomcat服務器可以互訪,並且兩個tomcat機器在一個網段內。
2、 確定兩臺tomcat host多播已經打開,在Linux機器上可以使用cat /proc/net/dev_mcast檢查,如果文件存在基本上就是打開了。
6.2 配置
1、 修改web.xml,在其中<display-name>XXXX_center</display-name>節點後添加<distributable/>,表明此應用與集羣服務器複製Session。
2、 修改tomcat的server.xml文件,在“<Engine”節點增加“jvmRoute="tomcat1"”,改後爲:<Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat1">、<Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat2">。
3、 修改tomcat的server.xml文件,在“<Engine”節點下增加如下內容:
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster" channelSendOptions="6">
<Manager className="org.apache.catalina.ha.session.DeltaManager" expireSessionsOnShutdown="false" notifyListenersOnReplication="true"/>
<Channel className="org.apache.catalina.tribes.group.GroupChannel">
<Membership className="org.apache.catalina.tribes.membership.McastService" address="228.0.0.5" port="45564" frequency="500" dropTime="3000"/>
<Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver" address="192.168.15.40" port="4001" selectorTimeout="100" maxThreads="6"/>
<Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter">
<Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/>
</Sender>
<Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/>
<Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor"/>
</Channel>
<Valve className="org.apache.catalina.ha.tcp.ReplicationValve" filter=".*/.gif;.*/.js;.*/.jpg;.*/.png;.*/.htm;.*/.html;.*/.css;.*/.txt;"/>
<ClusterListener className="org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener"/>
<ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>
</Cluster>
6.3 驗證
在兩臺tomcat服務器部署的應用中放置test.jsp文件,在瀏覽器輸入URL:http://192.168.15.40:8081/XXXX_center/test.jsp, 輸入URL:http://192.168.15.41:8082/XXXX_center/test.jsp,兩個頁面顯示出tomcat1和tomcat2上的session值,說明session同步起作用了。參考附錄中的test.jsp文件。
7. Web服務器比較
server |
Apache |
Nginx |
Lighttpd |
Proxy代理 |
非常好 |
非常好 |
一般 |
Rewriter |
好 |
非常好 |
一般 |
Fcgi |
不好 |
好 |
非常好 |
熱部署 |
不支持 |
支持 |
不支持 |
系統壓力比較 |
很大 |
很小 |
比較小 |
穩定性 |
好 |
非常好 |
不好 |
安全性 |
好 |
一般 |
一般 |
技術支持 |
非常好 |
很少 |
一般 |
靜態文件處理 |
一般 |
非常好 |
好 |
Vhosts虛擬主機 |
支持 |
不支持 |
支持 |
反向代理 |
一般 |
非常好 |
一般 |
Session sticky |
支持 |
不支持 |
不支持 |
8. 附錄
8.1 nginx相關命令
#啓動
./nginx
#停止
./nginx –s stop
#重新加載
./nginx –s reload
#測試配置文件
./nginx -t
8.2 openssl相關命令
openssl pkcs12 -in www.push.com.pfx -nodes -nocerts -out server.key
openssl pkcs12 -in www.push.com.pfx -nodes -nokeys -clcerts -out server.crt
openssl pkcs12 -in rootca.pfx -nodes -nokeys -clcerts -out ca.crt
8.3 nginx配置文件
#user nobody;
worker_processes 1;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
gzip on;
proxy_connect_timeout 3s;
upstream ppg.com
{
#ip_hash;
server 192.168.15.40:8080 srun_id=tomcat1;
server 192.168.15.40:8081 srun_id=tomcat2;
jvm_route $cookie_JSESSIONID|sessionid reverse;
}
server {
listen 80;
server_name localhost;
charset utf-8;
#access_log logs/host.access.log main;
location ~ ^/NginxStatus{
stub_status on;
}
location /XXXX_center/ {
proxy_pass http://ppg.com/XXXX_center/;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /provider_demo/ {
proxy_pass http://ppg.com/provider_demo/;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location / {
root html;
index index.html index.htm;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
# HTTPS server
#
server {
listen 443;
server_name localhost;
ssl on;
ssl_certificate server.crt;
ssl_certificate_key server.key;
ssl_client_certificate ca.crt;
ssl_verify_client on;
ssl_session_timeout 5m;
ssl_protocols SSLv2 SSLv3 TLSv1;
ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;
ssl_prefer_server_ciphers on;
#error_page 497 "https://$host$uri$is_args$args";
location /XXXX_center/ {
proxy_pass http://ppg.com/XXXX_center/;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header SSL_CERT $ssl_client_cert;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /provider_demo/ {
proxy_pass http://ppg.com/provider_demo/;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header SSL_CERT $ssl_client_cert;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location / {
root html;
index index.html index.htm;
}
}
}
8.4 test.jsp文件
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
%>
<html>
<head>
</head>
<body>
tomcat1
<br />
<%out.print(request.getSession()) ;%>
<!--輸出session-->
<br />
<%out.println(request.getHeader("Cookie")); %>
<!--輸出Cookie-->
<b>Session屬性列表:</b>
<!--設置隨機session-->
<%
session.setAttribute("tomcat1:","tomcat------1");
%>
<br />
<%
Enumeration<String> e = (Enumeration<String>) session
.getAttributeNames();
while (e.hasMoreElements()) {
java.lang.String name = e.nextElement();
java.lang.String value = (java.lang.String) session.getAttribute(name);
out.println(name + " = " + value + "<br>");
}
%>
</body>
</html>