Nginx + tomcat + SSL 安装配置手册
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等。
Nginx中文网站:http://www.nginxcn.com/
Nginx英文网站:http://nginx.org/
PCRE网站:http://www.pcre.org/
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/
安装文件为.zip文件,解压缩后,运行目录中的nginx.exe(或使用命令),服务启动。
浏览器中输入:http://192.168.15.30,出现“Welcome to nginx!”页面,安装成功。
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!”页面,安装成功。
1) worker_processes:指明了nginx要开启的进程数,据官方说法,一般开一个就够了,多开几个,可以减少机器io带来的影响。(网上经验,设置为cpu数的两倍)。
2) worker_connections:每个工作进程允许最大的同时连接数。
Ø 说明
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;
}
准备证书,使用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;
Ø 说明
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的静态文件即可。
Ø 说明
Ø 配置
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 已经处理完正在等候下一次请求指令的驻留连接。
实现多台web服务器的session同步。
1、 确定nginx 服务器和两台tomcat服务器可以互访,并且两个tomcat机器在一个网段内。
2、 确定两台tomcat host多播已经打开,在Linux机器上可以使用cat /proc/net/dev_mcast检查,如果文件存在基本上就是打开了。
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>
在两台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文件。
server |
Apache |
Nginx |
Lighttpd |
Proxy代理 |
非常好 |
非常好 |
一般 |
Rewriter |
好 |
非常好 |
一般 |
Fcgi |
不好 |
好 |
非常好 |
热部署 |
不支持 |
支持 |
不支持 |
系统压力比较 |
很大 |
很小 |
比较小 |
稳定性 |
好 |
非常好 |
不好 |
安全性 |
好 |
一般 |
一般 |
技术支持 |
非常好 |
很少 |
一般 |
静态文件处理 |
一般 |
非常好 |
好 |
Vhosts虚拟主机 |
支持 |
不支持 |
支持 |
反向代理 |
一般 |
非常好 |
一般 |
Session sticky |
支持 |
不支持 |
不支持 |
#启动
./nginx
#停止
./nginx –s stop
#重新加载
./nginx –s reload
#测试配置文件
./nginx -t
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
#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;
}
}
}
<%@ 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>