Nginx+SSL+Tomcat+CDN部署总结

之前在度娘搜索资料,无意间看到一些个人站点的博客都用了https协议,在浏览器地址栏中被标记为绿色的“安全”,前些天特地给自己负责的小项目升级成https协议,其优点这里不再赘述,小伙伴们可以自行百度,今天把整合部署分享在这里,希望小伙伴们少走弯路~

效果如下:

未分类

软件版本如下:

未分类

一、生成SSL证书

首先我们创建一个用来存放letsencrypt生成证书项目的路径并进入:

cd /usr/local/letsencrypt

接下来我们克隆letsencrypt项目:

git clone https://github.com/letsencrypt/letsencrypt

开始生成SSL证书:

./letsencrypt-auto certonly --standalone --email [email protected] -d www.test1.com -d www.test2.com --agree-tos

这里一定注意:

(1). 域名绑定在国内DNS服务器无法生成,需要先将DNS服务器切换到DNS服务商,例如ClouldFlare、Godaddy、Dnsever后才能正常生成!
(2). web服务需要处于关闭状态,注意关闭nginx和80端口的占用!(不间断服务方式生成可以自行百度)
(3). -d 代表domain 可以同时生成多个域名对应证书,生成后我们可以在默认目录中看到:

/etc/letsencrypt/live/www.test.com/
cert.pem(用户证书) 
chain.pem(中间证书) 
fullchain.pem(证书链) 
privkey.pem(证书私钥)

最后我们生成Perfect Forward Security(PFS)键值,具体作用可以自行百度:

mkdir /etc/ssl/private/ -p
cd /etc/ssl/private/
openssl dhparam 2048 -out dhparam.pem

二、Nginx配置SSL证书及Tomcat代理

    #Tomcat 8080端口
    upstream tomcat_8080{
        server    127.0.0.1:8080  weight=1;
    }

    #将所有http协议内容重定向到https协议
    server {
        listen 80;
        server_name www.test.com;
        rewrite ^ https://$server_name$request_uri? permanent;
    }

    #https协议
    server {
        listen 443;
        server_name www.test.com;

        # letsencrypt生成的文件
        ssl on;
        ssl_certificate /etc/letsencrypt/live/www.test.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/www.test.com/privkey.pem;

        ssl_session_timeout 1d;
        ssl_session_cache shared:SSL:50m;
        ssl_session_tickets on;

        ssl_dhparam /etc/ssl/private/dhparam.pem;

        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        # 一般推荐使用的ssl_ciphers值: https://wiki.mozilla.org/Security/Server_Side_TLS
        ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128:AES256:AES:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK';
        ssl_prefer_server_ciphers on;

        # 代理tomcat
        location / {   
            proxy_set_header    Host                $http_host;             
            proxy_set_header    X-Real-IP           $remote_addr;     
            proxy_set_header    X-Forwarded-For     $proxy_add_x_forwarded_for;     
            proxy_set_header    Cookie              $http_cookie;
            proxy_pass          http://tomcat_8080;
            #proxy_redirect     default;
        }

        access_log /home/wwwlogs/www.test.com_access.log;
        error_log  /home/wwwlogs/www.test.com_error.log;
    }

三、Tomcat的SSL配置

1、Connector节点将redirectPort=”8443″修改为 redirectPort=”443″ proxyPort=”443″最终为:

<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="443" proxyPort="443" />

2、找到Engine节点,在最后一个Host标签后加入:

<Host name="www.test.com" debug="0" appBase="webapps" unpackWARs="true" autoDeploy="true" xmlValidation="false" xmlNamespaceAware="false">
    <Valve className="org.apache.catalina.valves.RemoteIpValve"
        remoteIpHeader="x-forwarded-for"
        remoteIpProxiesHeader="x-forwarded-by"
        protocolHeader="x-forwarded-proto"/>
    <Context docBase="/www/java/projectName" path="" crossContext="true" debug="3" privileged="true"  reloadable="false" deubt="true" />
</Host>

四、CloudFlare CDN设置(这里很重要)

我们将域名解析到自己服务器后,点击Crypto选项卡,将SSL状态修改为Full(strict)模式,在这种模式下会使用你服务器中的ssl证书,否则会导致页面无限301跳转,导致chrome提示重定向次数过多,请求失败!

Linux下Nginx+Tomcat整合与配置

安装JDK

下载的jdk文件为:jdk-6u45-linux-x64.bin,执行如下命令进行安装:

#./jdk-6u12-linux-i586.bin

安装tomcat

#tar zxvf apache-tomcat-6.0.18.tar.gz
#mv apache-tomcat-6.0.29 tomcat

这里我将解压后的apache-tomcat-6.0.29重命名为了tomcat方便操作。

配置环境变量

编辑/etc下的profile文件,加上如下内容:

JAVA_HOME="/opt/app/jdk1.6.0_45"
CLASS_PATH="$JAVA_HOME/lib:$JAVA_HOME/jre/lib"
PATH=".:$PATH:$JAVA_HOME/bin"
CATALINA_HOME="/opt/app/tomcat"
export JAVA_HOME CATALINA_HOME

执行下面命令使变更生效:

# source /etc/profile

启动tomcat并输入http://domain:8080,如果看到猫的页面即tomcat和jdk安装成功

新建文件目录/home/www为网站存放目录,设置server.xml文件,在Host name=”localhost”处将appBase=的指向路径改为/home/www/web

创建index.jsp至/home/www/web/ROOT,内容为:“hello!” 重新启动tomcat,重新访问,如果看到index.jsp文件内容hello!表示设置成功。

安装Nginx

执行如下命令解压nginx:

# tar zxvf nginx-1.4.4.tar.gz
# mv nginx-1.4.4 nginx

同样重命名了一下。

安装nginx:

# ./configure --prefix=/opt/app/nginx

结果出现了错误:error: C compiler cc is not found,按网上所说安装编译源码所需的工具和库:

#yum install gcc gcc-c++ ncurses-devel perl

再次安装,发现还有错误:the HTTP rewrite module requires the PCRE library.

执行

# yum -y install pcre-devel openssl openssl-devel

终于成功,

# ./configure --prefix=/opt/app/nginx
# make
# make install

nginx安装成功后的安装目录为/opt/app/nginx

在conf文件夹中新建proxy.conf,用于配置一些代理参数,内容如下:

#!nginx (-) 
# proxy.conf 
proxy_redirect          off;
proxy_set_header        Host $host;
proxy_set_header        X-Real-IP $remote_addr;  #获取真实ip
#proxy_set_header       X-Forwarded-For   $proxy_add_x_forwarded_for; #获取代理者的真实ip
client_max_body_size    10m;
client_body_buffer_size 128k;
proxy_connect_timeout   90;
proxy_send_timeout      90;
proxy_read_timeout      90;
proxy_buffer_size       4k;
proxy_buffers           4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;

编辑安装目录下conf文件夹中的nginx.conf,输入如下内容

#运行nginx所在的用户名和用户组
#user  www www; 
#启动进程数
worker_processes 8;
#全局错误日志及PID文件
error_log  /opt/app/nginx/logs/nginx_error.log  crit;
pid        /opt/app/nginx/nginx.pid;
#Specifies the value for maximum file descriptors that can be opened by this process.
worker_rlimit_nofile 65535;
#工作模式及连接数上限
events
{
  use epoll;
  worker_connections 65535;
}
#设定http服务器,利用它的反向代理功能提供负载均衡支持
http
{
  #设定mime类型
  include       mime.types;
  default_type  application/octet-stream;
  include /opt/app/nginx/conf/proxy.conf;
  #charset  gb2312;
  #设定请求缓冲    
  server_names_hash_bucket_size 128;
  client_header_buffer_size 32k;
  large_client_header_buffers 4 32k;
#  client_max_body_size 8m;
  sendfile on;
  tcp_nopush     on;
  keepalive_timeout 60;
  tcp_nodelay on;
#  fastcgi_connect_timeout 300;
#  fastcgi_send_timeout 300;
#  fastcgi_read_timeout 300;
#  fastcgi_buffer_size 64k;
#  fastcgi_buffers 4 64k;
#  fastcgi_busy_buffers_size 128k;
#  fastcgi_temp_file_write_size 128k;
#  gzip on;
#  gzip_min_length  1k;
#  gzip_buffers     4 16k;
#  gzip_http_version 1.0;
#  gzip_comp_level 2;
#  gzip_types       text/plain application/x-javascript text/css application/xml;
#  gzip_vary on;
#limit_zone  crawler  $binary_remote_addr  10m;
###禁止通过ip访问站点
 # server{
#        server_name _;
 #       return 404;
 #       }
  server
  {
    listen       80;
    server_name  localhost;
    index index.html index.jsp;
    root  /opt/www/static;
    #limit_conn   crawler  20;    
    location ~ .*.(jsp|shtml)$ #所有shtml的页面均交由tomcat处理
    {
      index index.jsp;
      proxy_pass http://localhost:8080;#转向tomcat处理
      }
    location ~ .*.(gif|jpg|jpeg|png|bmp|swf)$ #设定访问静态文件直接读取不经过tomcat
    {
      expires      30d;
    }
    location ~ .*.(js|css)?$
    {
      expires      1h;
    }    
   }  
#定义访问日志的写入格式
     log_format  access  '$remote_addr - $remote_user [$time_local] "$request" '
              '$status $body_bytes_sent "$http_referer" '
              '"$http_user_agent" $http_x_forwarded_for';
    access_log  /opt/app/nginx/logs/localhost.log access;#设定访问日志的存放路径   
}

修改/usr/local/nginx/conf/nginx.conf配置文件后,请执行以下命令检查配置文件是否正确:

#/opt/app/nginx/sbin/nginx -t

如果出现下面两行,说明正确:

the configuration file /opt/app/nginx/conf/nginx.conf syntax is ok
the configuration file /opt/app/nginx/conf/nginx.conf was tested successfully

如果提示unknown host,则可在服务器上执行:ping www.baidu.com如果也是同样提示unknown host则有两种可能:

a、服务器没有设置DNS服务器地址,查看/etc/resolv.conf下是否设置,若无则加上

b、防火墙拦截

启动nginx的命令

#/opt/app/nginx/sbin/nginx

这时,输入以下命令查看Nginx主进程号:

ps -ef | grep "nginx: master process" | grep -v "grep" | awk -F ' ' '{print $2}'

停止nginx的命令

#/opt/app/nginx/sbin/nginx -s stop

在不停止Nginx服务的情况下平滑变更Nginx配置

输入以下命令查看Nginx主进程号:

ps -ef | grep "nginx: master process" | grep -v "grep" | awk -F ' ' '{print $2}'

屏幕显示的即为Nginx主进程号,例如:

6302

这时,执行以下命令即可使修改过的Nginx配置文件生效:

kill -HUP 6302

或者无需这么麻烦,找到Nginx的Pid文件:

kill -HUP `cat /usr/local/nginx/nginx.pid`

tomcat 配置日志切割

tomcat 配置日志切割如下

  • jdk 版本 1.7
  • tomcat8.5
  • centos6.8 mini

Linux 下使用 cronolog工具来切分catalina.out

1、下载安装cronolog。

yum install -y cronolog

2、修改$tomcat/bin/catalina.sh文件。

如下:

446行左右,

#touch “$CATALINA_OUT” //注释掉
if [ “$1” = “-security” ; then
if [ $have_tty -eq 1 ]; then
echo “Using Security Manager”
fi
shift
eval “”$_RUNJAVA”” “”$LOGGING_CONFIG”” $LOGGING_MANAGER $JAVA_OPTS $CATALINA_OPTS 
-Djava.endorsed.dirs=””$JAVA_ENDORSED_DIRS”” -classpath “”$CLASSPATH”” 
-Djava.security.manager 
-Djava.security.policy==””$CATALINA_BASE/conf/catalina.policy”” 
-Dcatalina.base=””$CATALINA_BASE”” 
-Dcatalina.home=””$CATALINA_HOME”” 
-Djava.io.tmpdir=””$CATALINA_TMPDIR”” 
org.apache.catalina.startup.Bootstrap “$@” start 
>> “$CATALINA_OUT” 2>&1 “&” //删除此行
2>&1 |/usr/sbin/cronolog “$CATALINA_BASE”/logs/catalina-%Y-%m-%d.out & /添加此行

else
eval “”$_RUNJAVA”” “”$LOGGING_CONFIG”” $LOGGING_MANAGER $JAVA_OPTS $CATALINA_OPTS 
-Djava.endorsed.dirs=””$JAVA_ENDORSED_DIRS”” -classpath “”$CLASSPATH”” 
-Dcatalina.base=””$CATALINA_BASE”” 
-Dcatalina.home=””$CATALINA_HOME”” 
-Djava.io.tmpdir=””$CATALINA_TMPDIR”” 
org.apache.catalina.startup.Bootstrap “$@” start 
>> “$CATALINA_OUT” 2>&1 “&” /删除此行
2>&1 |/usr/sbin/cronolog “$CATALINA_BASE”/logs/catalina-%Y-%m-%d.out & //添加此行

【注意:】tomcat7之前的版本位置一样、但是配置有所不同

touch “$CATALINA_BASE”/logs/catalina.out //注释
>> “$CATALINA_BASE”/logs/catalina.out 2>&1 & //删除
2>&1 |/usr/sbin/cronolog “$CATALINA_BASE/logs/catalina-%Y-%m-%d.out” & //添加

3、保存 catalina.sh 文件,重启Tomcat即可。

如何解决 Tomcat 不能自动刷新静态页面的问题

一次笔者需要部署一个Tomcat环境,展示一些静态页面的内容。通过Tomcat的Web Application Manager添加了指向静态页面所在路径的Application,用浏览器查看页面,页面内容正常展现,非常顺利。

但在后续对静态页面进行修改更新后,通过浏览器再次查看,页面仍是旧的内容。笔者也怀疑是不是因为浏览器缓存引起这个问题,但清空浏览器、换用其他浏览器,都只能看到旧的页面内容。

那么就应该是服务端的问题了。笔者在服务端重启了Tomcat服务,在Tomcat的Web Application Manager中Stop/Start这个Application,都没有效果,甚至把静态页面文件从磁盘删除,并重启Tomcat服务,仍能在浏览器中看到旧的页面内容!简直无语了!

最后在网上反复搜索,总算找到一个方法。

首先在Tomcat的Web Application Manager中删除这个静态页面的Application。

然后编辑 [apache-tomcat]/conf/server.xml 文件,[apache-tomcat]表示tomcat的安装路径。

在这个文件的最后,有一个 Host 节点:

<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true">
<!-- 这里有一些内容 -->

</Host>

在这个节点中,添加一行内容:

<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true">

<!-- 添加下面这行内容 -->
<Context path="/staticpage" docBase="/home/mypage" reloadable="true" debug="0" crossContext="true" />
</Host>

重启Tomecat后,再次更新静态页面,页面内容正确展现。

添加的 Context 节点,表示一个新的虚拟路径,path 为路径名称,需添加到url中访问这个虚拟路径,例如:http://localhost/staticpage,docBase 为磁盘上的路径名称,即实际页面文件放在磁盘的哪个路径下,reloadable 表示页面文件被修改后,网站是否自动更新页面内容,测试环境设为 true 方便开发测试,生产环境就要设为 false 以提升性能。

大功告成!

使用Docker部署一个tomcat+mysql应用玩玩

Docker已经成为目前最流行的系统部署解决方案,几乎可以部署任何系统应用,下面我们用两个小实例,来熟悉一下Docker.

前提是要先安装好一个docker环境,可以参考:

http://www.lazyedu.com/docker/centos-docker.html

一、使用docker部署debain镜像

1、获取最新的debain镜像

docker pull debain    

这一步docker会从docker.io官方服务资源中下载最新的debain系统镜像

2、成功后查看已经下载images

docker images 

3、运行并进入docker容器

docker run -t -i debian /bin/bash

exit命令可以退出容器。

4、进入一个已经启动了的容器

docker exec -it debian /bin/bash

5、查看已经运行的容器

docker ps

6、查看全部容器,包括没有启动的

docker ps -a

简单的几个命令,我们就可以开始Docker的学习了。

二、使用docker部署mysql

1、下载mysql官方镜像,同样系统会自动下载最新版本的mysql

docker pull mysql

2、运行方式A

运行docker容器,使用外部配置文件、日志、数据库,设置初始密码

docker run -p 3306:3306 --name mysql -v $PWD/conf/:/etc/mysql/ -v $PWD/logs:/var/log/mysql -v $PWD/data:/usr/share/mysql -e MYSQL_ROOT_PASSWORD=123456 -d mysql

$PWD表示你在运行docker中的mysql数据库时的系统目录,如果你希望docker使用你本地磁盘中的配置文件、系统日志和数据库文件时,可以使用上面的参数,不过这时需要你在当前目录中有这些文件。记住设个-v参数,如果有需要让docker运行时访问你本地硬盘时都可以使用这个参数创建容器。

3、运行方式B

运行docker容器,使用内部文件,设置初始密码:

docker run -p 3306:3306 --name mysql -e MYSQL_ROOT_PASSWORD=123456 -d mysql

要注意的是,不管用什么方式创建和启动mysql docker容器,都需要制定初始的root密码,通过-e MYSQL_ROOT_PASSWORD=123456参数制定,不然这个容器是不会启动的。

三、使用docker部署tomcat

1、下载官方最新版本

docker pull tomcat

2、运行方式

这种方式创建容器,是将你当前目录中test应用映射到docker中的ROOT

docker run --name tomcat -p 8080:8080 -v $PWD/test:/usr/local/tomcat/webapps/ROOT -d tomcat  

这种方式只在docker中启动tomcat

docker run --name tomcat -p 8080:8080 -d tomcat  

我们可以使用下面的命令进入这个tomcat容器

docker exec -it tomcat bash

经过这个几个实例,我们来体验一下什么docker,它是如何运行的部署的,我们后面会逐渐深入解析docker。

tomcat https配置方法(免费证书)

相较于http,https提供了身份验证与加密通信方法.于是,出于安全性考虑,越来越多的网站开始使用https协议.

一、环境准备

为了成功配置https,你需要具备以下环境:

  • java jdk
  • tomcat

二、SSL证书简介

要想使用https,首先,我们需要有SSL证书,证书可以通过两个渠道获得:

1、公开可信认证机构
例如CA,但是申请一般是收费的,一般几百到几千一年.

2、自己生成
虽然安全性不是那么高,但胜在成本低.

目前证书有以下常用文件格式:JKS(.keystore),微软(.pfx),PEM(.key + .crt)。其中,tomcat使用JKS格式,nginx使用PEM格式.
虽然两种方式博主都已经实现过,但是这里只讲JKS格式.

三、JKS格式证书生成

好了,我们的jdk要派上用场了

1、打开你的终端或者命令行或者其他黑窗口,输入:

keytool -genkey -v -alias testKey -keyalg RSA -validity 3650 -keystore ~/Lee/test.keystore
  • alias: 别名 这里起名testKey
  • keyalg: 证书算法,RSA
  • validity:证书有效时间,10年
  • keystore:证书生成的目标路径和文件名,替换成你自己的路径即可,我定义的是~/Lee/test.keystore

2、回车,然后会让你输入一些信息,其中秘钥库口令和秘要口令最好输入同一个,并且记下这个口令,其他的随便填即可

未分类

3、在你刚才的目标路径里拿到生成好的test.keystore.

四、tomcat配置https

1、把keystore证书上传到你的tomcat服务器上(如果你的tomcat在本地,那么不移动也可以),并记下证书所在路径.

2、cd到tomcat的conf目录下,打开server.xml文件,搜索https找到下面这项:

未分类

3、先去掉注释,然后将keystoreFile和keystorePass处替换成你自己的证书路径和生成证书时的口令即可.

<Connector port="8443" protocol="org.apache.coyote.http11.Http11Protocol"
               maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
               clientAuth="false" sslProtocol="TLS" keystoreFile="你的keystore路径" keystorePass="生成证书时的口令"  />
  • port: https的端口,默认8443
  • clientAuth:设置是否双向验证,默认为false,设置为true代表双向验证keystoreFile
  • keystoreFile: keystore证书的路径
  • keystorePass: 生成keystore时的口令

4、启动tomcat,然后就可以使用https和8443端口访问你的服务了!

Tomcat 安全部署实战指南

0x01 关于Tomcat,更多详情大家可直接参考百科说明

https://zh.wikipedia.org/wiki/Apache_Tomcat

此次演示环境:

CentOS7 x86_64  ip: 192.168.3.64
Apache Tomcat/8.5.24    建议大家用稳定的相对比较新的版本

0x02 首先,在正式部署Tomcat之前,需要先来准备好jdk环境,因为毕竟底层还是在靠java来处理,所以必须要得先有java的运行环境才行,其实,在实际生产环境中,也可以单独使用jre,不过个人觉得这和安全的关系并不大,试想,如果你手里都已经拿到了一个可以运行java的环境了,我在本地用对应版本的jdk编译好了再丢上运行也是一样,防不住啥,太泛泛

# tar xf jdk-8u151-linux-x64.tar.gz
# mv jdk1.8.0_151/ /usr/local/
# ln -s /usr/local/jdk1.8.0_151/ /usr/local/jdk
# tar xf apache-tomcat-8.5.24.tar.gz
# mv apache-tomcat-8.5.24 /usr/local/
# ln -s /usr/local/apache-tomcat-8.5.24/ /usr/local/tomcat
# ll /usr/local/
# vi /etc/profile
  export JAVA_HOME=/usr/local/jdk/ 
  export PATH=$JAVA_HOME/bin:$JAVA_HOME/jre/bin:$PATH 
  export CLASSPATH=.$CLASSPATH:$JAVA_HOME/lib:$JAVA_HOME/jre/lib:$JAVA_HOME/lib/tools.jar
  export TOMCAT_HOME=/usr/local/tomcat
# source /etc/profile
# java -version
# javac

0x03 务必专门创建一个普通用户来运行tomcat服务,防止入侵者直接拿到root权限的webshell,极度建议大家在实际应用中在满足当前及拓展业务需求的前提下,尽量把tomcat压缩在一个极小的系统权限下

# useradd -u 301 tomcat
# passwd tomcat
# chown -R tomcat:tomcat /usr/local/tomcat/
# chown -R tomcat:tomcat /usr/local/jdk/
# ll /usr/local/jdk/ /usr/local/tomcat/
# su - tomcat
$ /usr/local/tomcat/bin/catalina.sh start
$ netstat -tulnp
$ cat /usr/local/tomcat/logs/catalina.out  启动过程中如果有什么问题可以去该日志

0x04 理解Tomcat的基本目录结构

# tree -L 1 /usr/local/tomcat/
/usr/local/tomcat/
├── bin        主要用来放置各种tomcat服务管理脚本
├── conf       用于存放Tomcat服务的各类配置文件
├── lib        此目录用于存放Tomcat的核心类库文件
├── LICENSE
├── logs       主要用于放置Tomcat的启动和访问日志文件
├── NOTICE
├── RELEASE-NOTES
├── RUNNING.txt
├── temp       存放一些缓存临时数据的目录
├── webapps    默认的站点根目录
└── work       把jsp代码转换为java代码[class]文件时的存放目录,这就是为什么访问速度极快的原因之一

0x05 理解Tomcat各个配置文件的主要功用

# tree -L 1 /usr/local/tomcat/conf/
/usr/local/tomcat/conf/
├── Catalina                
├── catalina.policy   当带上-security选项启动tomcat时,会自动读取应用该文件中的策略配置
├── catalina.properties   有关Tomcat内部各种类加载器的一些配置
├── context.xml       此处的context.xml是作用域全局的,一般情况下,每个站点目录下都应有一个context.xml文件,用于定义会话管理器,JDBC等
├── jaspic-providers.xml
├── jaspic-providers.xsd
├── logging.properties    指定不同类日志的格式
├── server.xml        tomcat主配置文件
├── tomcat-users.xml      用于tomcat web管理端认证的配置文件
├── tomcat-users.xsd
└── web.xml       站点被部署时使用的默认部署配置项

0x06 深入理解tomcat的运作细节及常用组件

简单回顾Tomcat的基本运作细节

-> 此处,以请求 http://www.rootkit.org:8080/demo/index.jsp 为例
  -> 首先,客户端来请求www.rootkit.org的8080端口,正好被监听于此的Http Connector所捕获
    -> 随后,Connector会把该请求交给它所在的Service中的Engine去处理并等待Engine回应
      -> 当Engine拿到这个请求后,会自动根据请求中的www.rootkit.org这个域名来匹配到它内部属于哪个Host,然后直接丢给那个Host
    -> 当请求到达指定的Host时,Host会自动匹配出Path为/demo所在的Context
      -> 之后,对应Context会拿到/index.jsp请求,再到映射表中找出对应的Servlet类去处理,如,构造HttpServletRequest和HttpServletResponse对象
        -> Context会把处理好之后的HttpServletResponse对象返回给Host
          -> Host再把HttpServletResponse对象返回给Engine
        -> 最后,Engine把HttpServletResponse对象返回对应的Connector,至此,一次相对完整的Tomcat请求响应过程就基本完成了

关于上述提到的各个组件功用简介

Server     一个Server即一个Tomcat实例,实际中机器性能好的情况,建议多实例,不建议用自身的虚拟主机功能,虚拟主机之间影响较大   
Service    通常由一个Engine以及一个或多个Connector组成,一个
Connector  主要就是用来监听指定端口,然后把指定端口的请求都交给Engine
Engine     其实就是实际的处理引擎,下面可以同时配置多个虚拟主机,它自身会根据域名来匹配到对应的虚拟主机
Host       即虚拟主机,一个即一个虚拟主机
Context    Context在创建的时候会根据配置文件$CATALINA_HOME/conf/web.xml
       和$WEBAPP_HOME/WEB-INF/web.xml载入Servlet类,当Context收到请求时
       将到自己的映射表 [mapping table]中寻找相匹配的Servlet类,如果找到,则执行该类,并回应该请求

tomcat 主配置文件结构大致如下

<Server>
  <Service>
    <Connector/>
    <Engine>
      <Host>
        <Context></Context>
      </Host>
     </Engine>
  </Service>
  <Service>
   ...
  </Service>
</Server>

0x07 一个标准的 Java web 目录结构,如下

未分类

0x08 如何快速纯手工在Tomcat中自定义一个基于域名的虚拟主机,还是那句话,实际中机器性能够的情况下,建议用tomcat多实例,不建议用虚拟主机

先准备好站点所需的各种目录,务必要严格按照上面的java web标准来

# mkdir /data/{javaweb,logs} -p
# chown -R tomcat:tomcat /data/
$ su - tomcat
$ cd /data/javaweb/
$ mkdir secapp/{lib,classes,WEB-INF,META-INF} -p
$ vi secapp/index.jsp
  <html>
  <body>
  <br>
  <center><h1>This is a Tomcat Server 8.x </h1> 
  <br><h2>Now time is: <%=new java.util.Date()%></h2></center>
  </body>
  </html>

再到tomcat主配置文件中添加Host标签段,记得禁用自动部署和自动解war包

$ vi /usr/local/tomcat/conf/server.xml
  <Host name="www.sec.org" appBase="/data/javaweb/secapp" autoDeploy="false" unpackWARs="true">
    <Context path="" docBase="." debug="0" />
    <Valve className="org.apache.catalina.valves.AccessLogValve" directory="/data/logs"
        prefix="www.sec.org_access_log" suffix=".txt"
        pattern="%h %l %u %t "%r" %s %b" />
  </Host>
$ /usr/local/tomcat/bin/catalina.sh stop
$ cd /usr/local/tomcat/   重启前最好把下面两个目录中的内容清空,防止缓存作祟
$ rm -fr ./temp/*
$ rm -fr ./work/*
$ /usr/local/tomcat/bin/catalina.sh start 
$ cat /usr/local/tomcat/logs/catalina.out   查看tomcat启动日志,一般来这儿都是为了看报错
$ tail -f /data/logs/www.sec.org_access_log.2017-12-17.txt
$ tree /usr/local/tomcat/work/

未分类

0x09 配置Tomcat的web端管理功能,此功能比较危险,容易被人跑到管理账号密码,直接进来即可部署webshell,如非必须,建议删除

$ vi /usr/local/tomcat/conf/tomcat-users.xml
  <role rolename="manager-gui"/>
  <role rolename="admin-gui"/>
  <user username="tomcat" password="tomcat" roles="manager-gui,admin-gui"/> 让tomcat同时应用于两个角色
$ /usr/local/tomcat/bin/catalina.sh start    修改完配置后重启tomcat
$ /usr/local/tomcat/bin/catalina.sh stop

0x10 修改管理端口及用于关闭服务的字符串,默认为8005,SHUTDOWN,实际中,一般也不会用这种方式来关闭tomcat,所以可以把关闭字符串设的更长更随机一些,不过,好在最新版本tomcat默认只监听在127.0.0.1,所以对此项不必太过紧张

$ vi /usr/local/tomcat/conf/server.xml
  <Server port="9301" shutdown="a8HelEd45fm43LseDF">

0x11 修改AJP协议通信端口,其实你可以直接把该项注释掉,因为绝大多数情况下我们都只会使用http进行反向代理,而不会用AJP

$ vi /usr/local/tomcat/conf/server.xml
  <!-- <Connector port="8010" protocol="AJP/1.3" redirectPort="8443" />-->

0x12 禁止tomcat目录遍历,将param-value标签中的值改为false,其实默认就是禁止的,只不过为了保险,还是需要再确认一下

$ vi /usr/local/tomcat/conf/web.xml
  <init-param>
    <param-name>listings</param-name>
    <param-value>false</param-value>   <!-- false即表示禁止目录遍历 --> 
  </init-param>

  <welcome-file-list> <!-- 设置主页索引文件 -->
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>demo.jsp</welcome-file>
  </welcome-file-list>

未分类

0x13 隐藏服务器版本信息,为了能一定程度上防止被人用0day批量打,我需要将tomcat的详细版本稍微隐藏下,比如,在出现403,404,500这样的状态码时,就很容易会暴露我们web服务器的详细版本,当然,你也可以直接把指定的状态码重定向到指定的页面中

$ cd /usr/local/tomcat/lib/
$ unzip catalina.jar
$ cd org/apache/catalina/util/
$ vi ServerInfo.properties
  server.info=Microsoft-IIS/7.5
  server.number=7.5
  server.built=Nov 27 2017 13:05:30 UTC
$ cd /usr/local/tomcat/lib/
$ jar uvf catalina.jar org/apache/catalina/util/ServerInfo.properties
$ /usr/local/tomcat/bin/catalina.sh stop
$ /usr/local/tomcat/bin/catalina.sh start

未分类

0x14 修改http响应头中的server字段名称,只需要在http连接器中添加指定的server属性即可

$ vi /usr/local/tomcat/conf/server.xml
  <Connector port="8080" protocol="HTTP/1.1"
    connectionTimeout="20000"
    redirectPort="8443" server="Microsoft-IIS/7.5" />

未分类

0x15 最好把所有host组件中的自动部署选项全部关掉

$ vi /usr/local/tomcat/conf/server.xml
  <Host name="www.sec.org" appBase="/data/javaweb/secapp" autoDeploy="false" unpackWARs="true">

0x16 如果我们是在前面使用apache或者nginx做的反向代理,也可通过限制特定ip的方式来访问,如下,表示仅允许192.168.3.0/24这个段来访问

$ vi /usr/local/tomcat/conf/server.xml
  <Host>
    ...
    <Context path="" docBase="." debug="0" />
      <Valve className="org.apache.catalina.valves.RemoteAddrValve" allow="192.168.4.*" deny="*.*.*.*" />
    ...  
  </Host>

未分类

0x17 限制其他用户对tomcat各类服务管理工具的使用

$ chmod -R 744 /usr/local/tomcat/bin/*

0x18 配置更加详细的访问日志格式,方便后续审查,如添加记录 user-agent,referer 字段数据

$ vi /usr/local/tomcat/conf/server.xml
  <Valve className="org.apache.catalina.valves.AccessLogValve" directory="/data/logs"
    prefix="www.sec.org_access_log" suffix=".txt"
    pattern="%h %l %u %t "%r" %s %b %{Referer}i %{User-Agent}i %D" resolveHosts="false" />

未分类

0x19 关于Tomcat 7.x 版本,你可能还需要手工去禁用一些危险请求方法,将readonly的值设为true,即禁止DELETE及PUT方法,如下,不过在新版中,默认就处于禁用状态,无需关心

$ vi /usr/local/tomcat/conf/web.xml
  <init-param>
    <param-name>readonly</param-name> 
    <param-value>true</param-value> 
  </init-param>

0x20 必要情况下,可直接禁用tomcat提供的默认web管理端,防止入侵者用此方式部署webshell,此处的采用的禁用方式只是把原来web管理端的文件都重新放到别的目录中,而后再到主配置文件中去注释掉默认的locahost所对应的host组件,而后重启tomcat即可,话说回来,status可以留着,因为可能后续还要靠此来监控jvm的一些性能参数,大家还是酌情而定吧

$ cd /usr/local/tomcat/webapps/
$ mkdir tmp
$ mv docs/ examples/ host-manager/ manager/ ROOT/ ./tmp/
<!-- 
<Host name="localhost"  appBase="webapps"
   unpackWARs="true" autoDeploy="true">
-->
<!--
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
   prefix="localhost_access_log" suffix=".txt"
   pattern="%h %l %u %t "%r" %s %b" />
</Host>
-->

0x21 最后,时常去关注tomcat官方发布的一些高危漏洞补丁,tomcat 8.x 已经相对比较稳定了,所以也建议大家,在稳定的前提下使用更新一点的版本

后话:
因为关注的点不同,所以肯定有所偏颇,此处还是旨在防入侵,至于针对jvm的各种性能优化,后续有机会我们再单独说明,因为tomcat几乎都不会直接面向用户,大多都是通过反向代理的方式来提供服务的,另外,java自身的安全性和性能采用编译的方式来运行都要优于php,所以,针对tomcat的安全并没有像nginx或者apache压力那么大,而且由于tomcat是在后端,也相对比较好控制,虽然它到现在对java的一些类库支持的还不是很完整,但那些对我们而言暂时无需关心,以上仅供部署参考,并不完整,后续还会不断更新,大家可根据自己的实际业务需求再做进更进一步调整,关于java对于的功用,比如,免杀…想必大家也都非常熟悉了,这里就不多说了,更多其它内容,也非常欢迎大家来一起私信交流 ^_^

tomcat优化——并发和Tomcat线程数

最近一直在解决线上一个问题,表现是:
Tomcat每到凌晨会有一个高峰,峰值的并发达到了3000以上,最后的结果是Tomcat线程池满了,日志看很多请求超过了1s。
服务器性能很好,Tomcat版本是7.0.54,配置如下:

<Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
       maxThreads="3000" minSpareThreads="800"/>

   <Connector executor="tomcatThreadPool" port="8084" protocol="org.apache.coyote.http11.Http11AprProtocol"
              connectionTimeout="60000"
              keepAliveTimeout="30000"
              maxKeepAliveRequests="8000"
              maxHttpHeaderSize="8192"
              URIEncoding="UTF-8"
              enableLookups="false"
              acceptCount="1000"
              disableUploadTimeout="true"
              redirectPort="8443" />

事后thread dump看其实真正处于RUNNABLE状态的线程很少,绝大部分线程都处于TIMED_WAITING状态:

于是大伙都开始纠结为什么线程会涨到3000,而且发现即使峰值过了线程数并不会降下来。
我们首先想到的是:后端应用的处理瞬间比较慢,“堵住了”导致前端线程数涨了起来。但是优化一个版本上线后发现虽然涨的情况有所好转,但是最终线程池还是会达到3000这个最大值。

==================================分割线=========================================

以上是大背景,中间的过程省略,直接跟各位说下目前我得到的结论:

1、首先是为什么线程不释放的问题?

简单说下我验证的Tomcat(7.0.54)线程池大概的工作机制
Tomcat启动时如果没有请求过来,那么线程数(都是指线程池的)为0;
一旦有请求,Tomcat会初始化minSapreThreads设置的线程数;
Tomcat会停止长时间闲置的线程。Tomcat还有一个参数叫maxIdleTime:

其实从这个参数解释也能看出来Tomcat会停止闲置了超过一定时间的线程的,这个时间就是maxIdleTime。但我之前的测试中确实没有发现线程释放的现象,这是为什么呢?我发现除了这个参数线程池线程是否释放?释放多少?还跟当前Tomcat每秒处理的请求数(从Jmeter或LoadRunner来看可以理解为TPS)有关系。通过下表可以清晰的看出来线程数,TPS和maxIdleTime之间的关系:

TPS     maxIdleTime(ms) Thread Count
10  60,000  600
5   60,000  300
1   60,000  60

依次类推,当然Thread Count这一列是一个大约数,上下相差几个,但基本符合这样一个规则:

Thread Count = min(max((TPS * maxIdleTime)/1000,minSpareThreads),maxThreads)

当然这个Thread Count不会小于minSpareThreads,这个跟之前的结论还是一样的。我现在大胆猜测下(回头看源码验证下,或者哪位同学知道告诉我下,谢谢):

Tomcat线程池每次从队列头部取线程去处理请求,请求完结束后再放到队列尾部,也就是说前后两次请求处理不会用同一个线程。某个线程闲置超过maxIdleTime就释放掉。

未分类

假设首先线程池在高峰时期暴涨到1000,高峰过后Tomcat处理一次请求需要1s(从Jmeter看TPS大约就为1),那么在maxIdleTime默认的60s内会用到线程池中60个线程,那么最后理论上线程池会收缩到60(假设minSpareThreads大于60)。另外:这个跟用不用Keep-Alive没关系(之前测试结论是因为用了Keep-Alive导致程序性能下降,TPS降低了很多导致的)

这就是为什么我之前的测试中、还有我们生产环境中线程数只增不减的原因,因为就算峰值过后我们的业务每秒请求次数仍然有100多,100*60=6000,也就是3000个线程每个线程在被回收之前肯定会被重用。

那么现在有另外一个问题,那么正常情况下为什么每秒100次的请求不会导致线程数暴增呢?也就是说线程暴增到3000的瓶颈到底在哪?这个我上面的结论其实也不是很准确。
真正决定Tomcat最大可能达到的线程数是maxConnections这个参数和并发数,当并发数超过这个参数则请求会排队,这时响应的快慢就看你的程序性能了。
这里没说清楚的是并发的概念,不管什么并发肯定是有一个时间单位的(一般是1s),准确的来讲应该是当时Tomcat处理一个请求的时间内并发数,比如当时Tomcat处理某一个请求花费了1s,那么如果这1s过来的请求数达到了3000,那么Tomcat的线程数就会为3000,maxConnections只是Tomcat做的一个限制。

2、为什么线程池会满?

这是我现在纠结的核心。到底是不是应用的性能慢导致的,我现在的结论是有关系,但关键是并发。

Tomcat的线程池的线程数跟你的瞬间并发有关系,比如maxThreads设置为1000,当瞬间并发达到1000那么Tomcat就会起1000个线程来处理,这时候跟你应用的快慢关系不大。
那么是不是并发多少Tomcat就会起多少个线程呢?这里还跟Tomcat的这几个参数设置有关系,看官方的解释是最靠谱的:

maxThreads:The maximum number of request processing threads to be created by this Connector, which therefore determines the maximum number of simultaneous requests that can be handled. If not specified, this attribute is set to 200. If an executor is associated with this connector, this attribute is ignored as the connector will execute tasks using the executor rather than an internal thread pool.
maxConnections:The maximum number of connections that the server will accept and process at any given time. When this number has been reached, the server will accept, but not process, one further connection. This additional connection be blocked until the number of connections being processed falls below maxConnections at which point the server will start accepting and processing new connections again. Note that once the limit has been reached, the operating system may still accept connections based on the acceptCount setting. The default value varies by connector type. For BIO the default is the value of maxThreads unless an Executor is used in which case the default will be the value of maxThreads from the executor. For NIO the default is 10000. For APR/native, the default is 8192.……
acceptCount:The maximum queue length for incoming connection requests when all possible request processing threads are in use. Any requests received when the queue is full will be refused. The default value is 100.
minSpareThreads:The minimum number of threads always kept running. If not specified, the default of 10 is used.

我简单理解就是:maxThreads:Tomcat线程池最多能起的线程数;maxConnections:Tomcat最多能并发处理的请求(连接);acceptCount:Tomcat维护最大的对列数;minSpareThreads:Tomcat初始化的线程池大小或者说Tomcat线程池最少会有这么多线程。

比较容易弄混的是maxThreads和maxConnections这两个参数:maxThreads是指Tomcat线程池做多能起的线程数,而maxConnections则是Tomcat一瞬间做多能够处理的并发连接数。比如maxThreads=1000,maxConnections=800,假设某一瞬间的并发时1000,那么最终Tomcat的线程数将会是800,即同时处理800个请求,剩余200进入队列“排队”,如果acceptCount=100,那么有100个请求会被拒掉。

注意:根据前面所说,只是并发那一瞬间Tomcat会起800个线程处理请求,但是稳定后,某一瞬间可能只有很少的线程处于RUNNABLE状态,大部分线程是TIMED_WAITING,如果你的应用处理时间够快的话。所以真正决定Tomcat最大可能达到的线程数是maxConnections这个参数和并发数,当并发数超过这个参数则请求会排队,这时响应的快慢就看你的程序性能了。

LVS负载均衡+动静分离+高可用(nginx+tomcat+keepalived)

一、环境介绍

基于LVS(linux virtual server)linux虚拟服务器的http集群搭建
环境:使用VMware pro10,CentOS6.5
一共使用4台虚拟机,两台安装Ngnix,两台安装tomcat。
这四台服务器的作用分别是:其中一台nginx作为主服务器,另一台nginx_bk作为备用服务器,然后两台安装tomcat的虚拟机作为调度服务器。
安装并克隆虚拟机后,将四台虚拟机重新命名,分别命名为nginx, nginx_bk,server1,server2:

四台虚拟机的ip地址分别如下:

centOS_nginx 192.168.20.2.135
centOS_nginx_bk 192.168.20.2.139
CentOS_server1 192.168.20.2.134
CentOS+server2 192.168.20.2.137

未分类

二、环境安装

1、安装JDK

四台虚拟机均安装JDK,因安装过程是一样的,所以此处只截图一台虚拟机jdk安装过程。
首先查看jdk版本,centos默认安装openJDK:
未分类
检查可用的JDK版本:
[图片上传失败…(image-2ebecc-1512133579646)]

卸载原来openJDK
未分类
再次查看,已经卸载成功:
未分类
开始安装JDK,到oracle官网下载liunx jdk包,解压到当前目录下
解压好,进入目录查看:
未分类
配置JDK环境变量,修改/etc/profile
未分类
使环境变量生效:
未分类
参看结果:
未分类
此时可以看到jdk已经安装成功
这边liun下jdk的安装有很详细教程,可以去网上搜

2.两台服务器安装tomcat

下载tomcat,解压到/opt目录
解压后查看:
未分类
Root权限进入/bin目录,启动tomcat
未分类
配置防火墙端口:
未分类
未分类
重新加载防火墙配置:
未分类
未分类
启动tomcat访问,首页访问成功:

至此,tomcat安装完成,另一台server虚拟机可克隆该台虚拟机来实现。

3、nginx安装

下载nginx,解压到/usr/local目录下,解压后查看:
未分类
进入解压目录执行./configure命令进行安装
出现错误及解决方法:
错误1:
未分类
原因:缺少gc++
解决:
未分类
错误2:
未分类
解决:
未分类
错误3:
未分类
解决:
未分类
解决上述错误后,再执行安装命令:
未分类
查看nginx进程号:
未分类
启动nginx
未分类
关闭nginx命令是./nginx -s stop
默认端口是80,此时可在网页访问到:
未分类
至此,Nginx安装完成。

4、keepalive安装

Keepalived是一个基于VRRP协议来实现的服务高可用方案,作用是检测web服务器的状态,如果有一台web服务器死机,或工作出现故障,Keepalived将检测到,并将有故障的web服务器从系统中剔除,当web服务器工作正常后Keepalived自动将web服务器加入到服务器群中,这些工作全部自动完成,不需要人工干涉,需要人工做的只是修复故障的web服务器。
Keepalived实现服务的高可用(HA),应用已经非常广泛,很多软件都会和他搭配使,比如LVS,Nginx,Redis等
下载keepalie,解压到/opt/keepalive目录下
安装依赖插件:

yum install -y gcc openssl-devel popt-devel

编译安装:

./configure –prefix=/usr/local/keepalive
Make
Make install

编译之后的配置:
未分类
获得权限:
未分类
修改/etc/init.d/keepalived文件,将默认路径改成当前alive安装路径
未分类
即默认为前一行注释掉的路径,改为下一行,指向了正确的配置文件位置。

配置环境变量
未分类
建立软连接:
未分类
修改/usr/local/keepalive/etc/sysconfig/keepalived文件,修改正确的启动参数
未分类
启动Keepalived
未分类
设置keepalived服务为开机自启动
未分类
至此keepalived安装配置成功,另一两台nginx_bk可以克隆该台虚拟机。


其实在centos下可以直接用yum install keepalived来安装。默认安装路径为/etc/keepalived
用yum来装比较方便

三、负载均衡

现在有两台服务器192.168.204.134和192.168.204.137,服务器上各有一台tomcat,端口均为8080,在192.168.204上有Nginx
修改nginx安装目录中conf目录下的nginx.conf文件
主要配置信息如下:
未分类

补充知识了解:
nginx负载均衡到多台服务器上时,默认采用轮询策略:
常见策略:
1、轮询
每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除。
2、weight
指定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的情况,数字越大命中率越高。
例如:轮询几率是2:1
upstream bakend {
server 192.168.0.14 weight=2;
server 192.168.0.15 weight=1;
}
2、ip_hash
每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题。
例如:
upstream bakend {
ip_hash;
server 192.168.0.14:88;
server 192.168.0.15:80;
}

启动两台tomcat,重新启动nginx,访问192.168.204.135就会随机访问192.168.204.134和192.168.204.137
测试:
在两台tomcat服务器下webapps目录下创建文件夹21751152,新建index.html文件,index.html文件内容分别如下:
Server1下index.html文件:
未分类
Server2下index.html文件:
未分类
首先测试在两台tomcat服务器下本地能访问这两个页面:
Server1下:
未分类
Server2下:
未分类
可以看到两台服务下均可正常访问
然后在安装Nginx服务器下测试:
未分类
未分类
可以看到,在nginx服务器下,在网页中每次刷新都会随机访问到两台Tomcat服务器中的任意一台,可以看出,已经完成了负载均衡的效果。

四、动静分离

为了提高网站的响应速度,减轻程序服务器(tomcat)的负载,对于js,css,图片等静态文件可以在nginx反向代理服务器中进行缓存,这样浏览器在请求一个静态资源的时候,代理服务器就可以直接处理,而不用将请求转发给后端服务器。而用户请求的动态文件比如jsp则会转发给tomcat服务器处理,这就是动静分离,也是反向服务器的一个重要作用。
在server1这台服务器webapp/21751152目录下建index.jsp文件:
Index.jsp内容如下:
未分类
然后进行Nginx.conf配置文件的修改:
主要修改内容如下:
未分类
Root /usr/local/webapps 这段代码的意思是指定Nginx访问的目录,即静态资源所在的目录。

Expires 30d.指这些资源文件在客户端浏览器的缓存时间,30d值30天,1h指一小时
开始测试:
首先在server1本地进行测试,页面可以正常访问:
未分类
然后在nginx服务器下进行测试:
未分类
可以看到,向日葵这张图片作为静态文件,没被加载出来。这是因为静态资源访问请求已经被Nginx拦截,由Nginx进行处理。但是Nginx服务器的 /usr/local/webapps 目录下并没有图片资源,所以图片没有加载出来。index.jsp页面能够显示,说明动态的请求已经转发到了Tomcat,Tomcat对index.jsp进行了解析。
在Nginx服务器 /usr/local/webapps 目录下放置图片文件,将tomcat上把21751152/img/flower.jpg整个目录拷贝到其中。然后再次刷新。
未分类
未分类
此时,图片就被加载出来了。至此,可以看出已经Nginx已经实现了动静分离的功能。
在配置动静分离后,用户请求你定义的静态资源,默认会去nginx的发布目录请求,而不会到后端请求,这样可以提高网站响应速度,减轻真实Web服务器的负载压力。
不过在开发环境下,为了便于开发,咱们的静态资源和代码还是放在一起的,等开发测试完成,才会将完成的完整程序部署到生成环境上,然而程序代码和静态资源是分别放置到不同的服务器上的。

五、keepalive高可用

编辑ngin服务器的keepalived.conf文件,keepalived.conf文件如下图所示:
未分类
未分类
画出红线部分是主要需要注意的地方
备份的nginx_bk配置文件与此类似
需要注意的以下几个点:
需要修改state为BACKUP , priority比MASTER低,virtual_router_id和master的值一致
配置文件如下:
未分类
未分类
注:在主备机中vip应设置一致

1、遇到的问题1及解决过程

用keepalived方式在主nginx服务器中添加了虚拟Ip,但是用ip addr查看发现仍然只有一个IP地址,即keepaLived.cof文件里面配置的vip没有起到效果
未分类
解决问题过程:
(1)尝试一:
可能是keepalived没有安装成功,所以采用yum重新安装keepalived
但是重装后还是发现VIP没有生效。
(2)最终解决:
后来在同学的提醒下,发现是自己的keepalived服务没有启动好,nginx服务也需要重启。这两个服务启动好后,就可以了。
开始测试:
在两台nginx和nginx_bk服务器中keepalived服务和nginx服务都开启的情况下:
首先测试nginx的IP:
未分类
可以看到在Nginx中已经有虚拟ip了
而在Nginx_bk服务器中:
未分类
可以看到没有绑定虚拟ip
访问192.168.204.177
未分类
未分类
这是访问虚拟ip地址,发现也被转发到了Nginx主机192.168.204.135指向的tomcat服务器上,同时也是随机分配到了两天Tomcat服务器上,即实现了负载均衡。

2、遇到的问题2及解决过程

Nginx主从机器没有顺利切换
在模仿Nginx主机宕机过程中:
用service keepalived stop 命令将Nginx主机服务的keepalived服务停止。
未分类
可以看到虚拟ip就没有绑在主机上
此时再去查看nginx_bk服务器,按道理来说此时Nginx_bk这台机器上应该会绑定vip,但实际查看的时候,发现并没有绑定过来
解决过程:
(1) 尝试1
因为nginx_bk这台服务器是我克隆nginx主机这台虚拟机得到的,所以存在mac地址冲突问题,猜想可能是这个原因导致的无法主从切换。
所以我对nginx_bk这台虚拟机重新生成了mac地址
过程如下:
首先关闭该虚拟机
然后选中该虚拟机点击“设置”,选择“网络适配器”,“高级”
未分类
然后点击“生成”
未分类
这样就重新生成了一个MAC地址。
然后对该虚拟重启后,重新启动keepalived,nginx等服务,发现还是无法正常切换
(2) 尝试2
因为我的几台虚拟机都没有设置静态IP,在同学的建议下,可能是没有设置静态IP导致的问题,所以我对nginx和nginx_bk这两台服务器都设置了静态ip,
设置过程如下:
Nginx主机:
未分类
未分类
对Nginx_bk服务器静态地址设置与此类似

如上设置了静态IP后,问题还是没有得到解决。
但是在多次尝试中,意外发现,当把nginx_bk这台虚拟机的nginx服务关闭后,两台虚拟机之间的主从关系是能够体现的
即当nginx主机中keepalive和nginx服务都正常开启的情况下,nginx主机下绑定了192.168.204.177这个Vip
未分类
当nginx_bk主机中keepaliv服务正常开启的情况下,而nginx服务停止的情况下,该虚拟机是没有绑定虚拟ip的
未分类
然后将nginx主机的keepalived服务停止时:
未分类
如上两张图所示:
主机下绑定的vip已经漂移到了nginx_bk这台主机上
然后此时把nginx_bk这台主机上的nginx服务启动,发现在浏览器上访问vip地址时也顺利转发到了两台tomcat服务器上。
未分类
这时再把nginx主机上的keepalive重新启动,同时关闭nginx_bk主机上的nginx服务
未分类
此时nginx主机上又重新绑定了vip,同时网页也恢复了访问。
再去查看nginx_bk主机情况:
未分类
Nginx_bk上仍然定着vip,当把nginx主机重启后,在该虚拟机上通过vip也能访问到两台tomcat上的内容。
未分类
所以在这种情况下相当于两台nginx都同时被作为了访问入口。
最终我没有把该问题很好的解决掉,猜测的原因可能与Nginx有关。可能会在后期继续研究这个问题

参考博客:
http://www.cnblogs.com/mrlinfeng/p/6146866.html
http://blog.csdn.net/u010028869/article/details/50612571
上述的实现过程我主要参照了这两篇博客,感谢他们的无私分享。

Linux CentOS环境下单机安装tomcat多实例

平台: centos 6.9
安装版本:tomcat 9.0 Binary Distributions

安装目的:安装三个tomcat,对外 web端口分别为8080、8081、8082
原理: 多个tomcat实例公用一个JDK,通过安装目录、端口以及配置文件实现独立实例,每个tomcat猫 都有自己独立的运行环境、配置文件 和站点目录。

按照系统的部署流程记录如下:

1、安装JDK

yum search java,这里我们选取java-1.8.0-openjdk.x86_64 : OpenJDK Runtime Environment。

yum install java-1.8.0-openjdk.x86_64   -y

2、下载安装tomcat

下载地址https://tomcat.apache.org/,这里我们选取tomcat版本后对应下载,以Binary Distributions 9.0做测试。

wget  http://mirrors.shuosc.org/apache/tomcat/tomcat-9/v9.0.1/bin/apache-tomcat-9.0.1.tar.gz   -P  /usr/local/src
cd  /usr/local/src
tar zxvf apache-tomcat-9.0.1.tar.gz 
mv apache-tomcat-9.0.1 tomcat_8080
#说明:这里不建议直接mv到/usr/local目录中,因为这个是原始的tomcat,以后创建多实例可以直接从这里拷贝并优化。
#配置单实例tomcat8080
mkdir  /usr/local/tomcat_8080
cp -rfpu  /usr/local/src/tomcat_8080/* /usr/local/tomcat_8080/

启动tomcat8080:

/usr/local/tomcat_8080/bin/startup.sh

查看效果:

[root@mysqlemn local]# netstat  -tunlp | grep 8080
tcp        0      0 :::8080                     :::*                        LISTEN      13240/java

如果防火墙开启,需要加一个规则进去以便web访问:

iptables  -I  INPUT -p tcp  --dport  8080  -j ACCEPT

web访问测试:

未分类

3、多实例安装

刚才创建了一个8080,下边我们再创建两个tomcat,端口分别为8081、8082。 如果熟练了,可以直接跳过8080,直接创建需要的实例个数。
创建多个tomcat目录:

mkdir -p /usr/local/tomcat_808{1..2}
cp  -rfpu  /usr/locat/src/tomcat_8080/*  /usr/local/tomcat_8081/
cp  -rfpu  /usr/locat/src/tomcat_8080/*  /usr/local/tomcat_8082/

分别修改tomcat的 conf目录下的server.xml,修改三个端口设置(Server、Connector、AJP,至于https根据 是否用到修改),防止和之前的tomcat_8080冲突。修改以后分别启动测试:

/usr/local/tomcat_8081/bin/startup.sh
/usr/local/tomcat_8082/bin/startup.sh

iptables 添加端口并save,web单独访问,单机多实例猫已经实现。剩下的就是根据业务需要、服务器配置进行tomcat的配置优化了,比如包括服务设置、站点发布目录以及 jvm优化等等。

说明:

(1),站点发布目录修改:

未分类

重启tomcat生效。

(2),这里建议将站点目录的catalina.sh设置成tomcatX放于/etc/init.d/tomcatPort ,里边设置下java路径以及环境启动目录比如:

[root@21yunwei ROOT]# cp   /usr/local/tomcat_8080/bin/catalina.sh      /etc/init.d/tomcat8080  -p
[root@21yunwei ROOT]# cp   /usr/local/tomcat_8081/bin/catalina.sh      /etc/init.d/tomcat8081  -p
[root@21yunwei ROOT]# cp   /usr/local/tomcat_8082/bin/catalina.sh      /etc/init.d/tomcat8082  -p

针对每个服务设置自己的启动目录:这里以/etc/init.d/tomcat8080 为例进行修改,第二行加入:

CATALINA_HOME=/usr/local/tomcat_8080 #tomcat容器的启动目录

其他容器的服务也是一样,这样以后就可以通过/etc/init.d/tomcatPort start 启动或者stop了,同时这个可以设置到/etc/rc.local脚本中方便开机启动,目前我们线上就是这样实现。

/etc/init.d/tomcat8080  start
/etc/init.d/tomcat8081  start
/etc/init.d/tomcat8082  start

(3),清理tomcat缓存。解决访问有异常,清理下tomcat服务器端的缓存方法:

find /usr/local/ -name  "work*" | xargs   rm -rf

说明:这里只是针对tomcat安装测试,未进行任何优化。