之前,我写过一个基于Windows平台运行VMware Server虚拟机的服务器托管方案。一直在朋友的服务器上运行了4年多。后来慢慢接触了Linux系统,经过一段时间的学习,发现Linux系统的性能及稳定性比Windows要强很多。所以,我打算将原来的服务器虚拟化方案转到Linux系统平台下。

经过近段时间的研究和测试,最后成功的将朋友的服务器迁移到了Linux平台,使用Linux系统和一些开源软件使服务器托管利用虚拟化技术和免费开源软件、系统再次降低成本,同时又提高了系统的性能。

此方案中实现的功能及特点:

1、  共享一个公网IP地址,发布多个虚拟机中的各种服务。

2、  多个虚拟机中的web站点共享80端口,实现通过域名访问虚拟机中的站点。

3、  宿主机上全部使用免费开源的操作系统及软件,节省软件费用。

4、  利用Linux下强大的iptables来保护服务器,相比Windows下的防火墙性能更优秀。

5、  Nginx超强的高并发处理能力、低系统资源开销,使服务器能够处理更多的并发web访问请求。

6、  利用Nginx的反向代理缓存功能,为Windows虚拟机站点加速。(新加入的一个优化配置)

CentOS中配置支持NTFS文件系统格式(宿主机)

添加此节内容,是为一些需要将Windows下的数据导入到Linux平台的用户方便。

CentOS系统默认情况下并不支持挂载ntfs分区,需要我们单独安装ntfs的驱动才能对ntfs分区进行读写操作,用uname –r命令查看系统内核版本信息,并下载相应的NTFS驱动。本例中版本是kernel-module-ntfs-2.6.18-128.el5

安装命令:

 rpm -ivh kernel-module-ntfs-2.6.18-128.el5-2.1.27-0.rr.10.11.i686.rpm

运行/sbin/modprobe ntfs加载内核模块,检查是否加载成功。

[root@localhost ~]# dmesg | grep NTFS

NTFS driver 2.1.27 [Flags: R/W MODULE].

如果出现上面的信息,说明已经可以对ntfs分区进行读写操作了。也可以运行cat /proc/filesystems命令进行查看。

接下来就是将要迁移的磁盘分区挂载到CentOS系统下,然后迁移数据。挂载NTFS分区(/dev/hda6为原Windows系统下的C盘分区)命令如下:

mount -t ntfs /dev/hda6 /mnt/c

系统配置环境

下表中列出了本方案的各种配置信息:

操作系统

相关软件

网络配置

备注

CentOS/Linux(版本自选)此为宿主机,安装到物理服务器上

Vmware Server 2.0(用于虚拟化的实现)

Eth0:192.168.10.5/24

Eth1:10.10.5.254 (ip为实验环境,实际应用时要修改此IP)

后文对物理主机上的操作系统称为宿主机

宿主机的eth0:内网网卡(与虚拟机相连的虚拟网卡vmnet1

宿主机eth1 :外网网卡(此网卡绑定了公网IP地址)

虚拟机系统,对外提供各种服务

虚拟机网卡的连接方式选Host-only

CentOS/Linux(版本根据需要可自选)

安装相关应用程序ApacheFTPMysql

Etho0192.168.10.20/24

网关:192.168.10.5

Windows操作系统

IISFTPMSSqlMail

本地连接:192.168.10.10/24

网关:192.168.10.5

其他虚拟机系统

  

虚拟机和宿主机的拓扑图如下:

安装配置Nginx 0.8.35(宿主机)

1、  安装Nginx所需的pcre:

http://www.pcre.org/去下载最新版

tar zxvf pcre-8.01.tar.gz

cd pcre-8.01/

./configure

make && make install

cd ../

2、  安装Nginx清理缓存模块

使用此模块可以实现缓存的清理任务

wget http://labs.frickle.com/files/ngx_cache_purge-1.0.tar.gz
tar zxvf ngx_cache_purge-1.0.tar.gz

只要将模块解压出来即可,在编译Nginx时同时编译此模块。

3、  安装Nginx

http://www.nginx.org/en/download.html下载最新版

/usr/sbin/groupadd www

/usr/sbin/useradd -g www www

tar zxvf nginx-0.8.35.tar.gz

cd nginx-0.8.35/

./configure --user=www --group=www --add-module=../ngx_cache_purge-1.0 --with-http_stub_status_module --with-http_ssl_module --with-http_sub_module

make && make install

cd ../

4、  修改Nginx全局配置文件

worker_processes  2;

access_log off;

error_log off;

events {

    use epoll;

    worker_connections  65535;

}

  #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相关配置可以删除不使用,仅做记录暂不使用.

  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;

5、  配置开机自动启动Nginx

修改/etc/rc.local文件,在最后加入如下命令

ulimit -SHn 65535

/usr/local/nginx/sbin/nginx

优化Linux内核参数(宿主机)

修改/etc/sysctl.conf文件,在最后加入以下内容:

net.ipv4.tcp_max_syn_backlog = 65536

net.core.netdev_max_backlog =  32768

net.core.somaxconn = 32768

net.core.wmem_default = 8388608

net.core.rmem_default = 8388608

net.core.rmem_max = 16777216

net.core.wmem_max = 16777216

net.ipv4.tcp_timestamps = 0

net.ipv4.tcp_synack_retries = 2

net.ipv4.tcp_syn_retries = 2

net.ipv4.tcp_tw_recycle = 1

#net.ipv4.tcp_tw_len = 1

net.ipv4.tcp_tw_reuse = 1

net.ipv4.tcp_mem = 94500000 915000000 927000000

net.ipv4.tcp_max_orphans = 3276800

#net.ipv4.tcp_fin_timeout = 30

#net.ipv4.tcp_keepalive_time = 120

net.ipv4.ip_local_port_range = 1024  65535

使配置立即生效:

/sbin/sysctl –p

设置Web站点的域名请求转发及缓存加速(宿主机)

相对于之前的转发方法,感觉这个方法比较直观也比较简单、容易理解。

下面是整个nginx的配置文件内容,里边包括了Nginx的反向代理设置和缓存配置方法。

[root@localhost conf]# cat nginx.conf

#user  nobody;

worker_processes  2;

#error_log  logs/error.log;

#error_log  logs/error.log  notice;

#error_log  logs/error.log  info;

pid        logs/nginx.pid;

#access_log logs/access.log;

error_log logs/error.log;

events {

    use epoll;

    worker_connections  65535;

}

http {

    include       mime.types;

default_type  application/octet-stream;

    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '

    #                  '$status $body_bytes_sent "$http_referer" '

    #                  '"$http_user_agent" "$http_x_forwarded_for"';

    log_format test '$remote_addr - $uri'

    sendfile        on;

    #tcp_nopush     on;

    #keepalive_timeout  0;

    keepalive_timeout  65;

    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;

    proxy_temp_path   /var/proxy_temp_dir;

    proxy_cache_path  /var/proxy_cache_dir  levels=1:2   keys_zone=cache_one:300m inactive=1d max_size=5g;

    proxy_cache_valid  200 304 12h;

    add_header X-Cache Nginx-X;

    proxy_set_header Host $host;

    proxy_set_header X-Real-IP $remote_addr;

    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    proxy_cache_key $host$uri$is_args$args;

  server

  {

    listen       80;

server_name  www1.duxt.net www2.duxt.net;

access_log off;

    #limit_conn   crawler  20;

    location / {

       proxy_cache cache_one;

       proxy_pass http://192.168.10.10:80;

    }

    location ~ /p(/.*)

    {

     allow            127.0.0.1;

     allow            10.10.5.0/24;

     deny            all;

     proxy_cache_purge    cache_one   $host$1$is_args$args;

    }

    location ~* .*\.(php|jsp|cgi|asp|aspx)$ {

       proxy_pass http://192.168.10.10:80;

    }

  }

  server  #每个虚拟机对应一个 server 配置,用来做判断和转发对站点的请求。

  {

    listen       80;

server_name  ~www[34]\.duxt\.net;  #虚拟机中绑定的域名全部写到这里,可以用正则表达式

access_log off; #关闭日志,避免访问日志过大占用大量磁盘空间.

    location / {

       proxy_cache cache_one;

       proxy_pass http://192.168.10.20:80; #虚拟机的IP地址

    }

    location ~ /p(/.*)                  #清缓存连接地址

    {

     allow            127.0.0.1;

     allow            10.10.5.0/24;

     deny            all;

     proxy_cache_purge    cache_one   $host$1$is_args$args;

    }

    location ~* .*\.(php|jsp|cgi|asp|aspx)$ {   #不缓存动态页面文件,如果有其他动态页面扩展名可以写到这里

       proxy_pass http://192.168.10.20:80;

    }

  }

}

以上测试环境配置中涉及到的域名www1.duxt.netwww2.duxt.net是虚拟机192.168.10.10上的站点域名,www3.duxt.netwww4.duxt.net是虚拟机192.168.10.20上的站点域名。

同样,与之前的方法一样,server name指令也是支持利用正则表达式对域名进行匹配的,域名之间用空格隔开。

防火墙策略设置部分(宿主机)

对宿主机的iptables进行基本的初始化配置,设置防火墙策略的默认配置。首先要开启防火墙的路由功能,使用以下命令实现:

echo 1 > /proc/sys/net/ipv4/ip_forward

允许访问宿主机SSH

/sbin/iptables -t filter -I INPUT -s 0.0.0.0/0 -p tcp --dport 22 -j ACCEPT

设置默认策略

/sbin/iptables -P INPUT Drop

/sbin/iptables -P OUTPUT ACCEPT

/sbin/iptables -P FORWARD ACCEPT

/sbin/iptables -t nat -P PREROUTING ACCEPT

/sbin/iptables -t nat -P OUTPUT ACCEPT

/sbin/iptables -t nat -P POSTROUTING ACCEPT

允许内网虚拟机系统访问外网

iptables -t nat -A POSTROUTING -o eth1 -s 192.168.10.0/24 -j SNAT --to 10.10.5.254

利用iptables来发布虚拟机中的各种服务(宿主机)

设置IIS FTP连接端口为10000。被动模式的端口范围(10001-10005),使用以下vbs脚本命令进行修改

cscript.exe adsutil.vbs set /MSFTPSVC/PassivePortRange "10001-10005" (在Windows虚拟机中执行)

发布内网虚拟机192.168.6.10010000-10005端口

iptables  -t nat -A  PREROUTING -i eth1 -p tcp --dport 10000:10005 -j DNAT --to 192.168.10.10

发布内网虚拟机192.168.6.100的远程桌面端口

iptables  -t nat -A  PREROUTING -i eth1 -p tcp --dport 3389 -j DNAT --to 192.168.10.10:3389

发布内网虚拟机192.168.6.100MSsql端口

iptables  -t nat -A  PREROUTING -i eth1 -p tcp --dport 1433 -j DNAT --to 192.168.10.10:1433

发布内网虚拟机192.168.6.20020000-20005端口

iptables  -t nat -A  PREROUTING -i eth1 -p tcp --dport 20000:20005 -j DNAT --to 192.168.10.20

发布内网虚拟机192.168.6.200SSH端口

iptables  -t nat -A  PREROUTING -i eth1 -p tcp --dport 19222 -j DNAT --to 192.168.10.20:22

发布内网虚拟机192.168.6.200Mysql端口

iptables  -t nat -A  PREROUTING -i eth1 -p tcp --dport 3306 -j DNAT --to 192.168.10.20:3306

发布宿主机的Nginx,用于转发对虚拟机web的请求。

iptables -t filter -A INPUT -i eth1 -p tcp --dport 80 -j ACCEPT

iptables -t filter -A INPUT -s 192.168.10.0/24 -p tcp -j ACCEPT

iptables -t filter -A OUTPUT -o eth0 -p tcp --dport 80 -j ACCEPT

保存防火墙规则

service iptables save

解决虚拟机中网站日志中客户端真实IP问题(虚拟机)

通过Nginx转发一次http请求到虚拟机系统后,网站的日志文件中记录的都是宿主机的内网IP,影响网站日志的访问统计。为了让虚拟机系统中的网站日志能够记录客户端真实IP地址,需要做相关的修改。

解决虚拟机中Apache日志中客户端IP问题

Apache的修改相对比较简单

修改Apache的配置文件httpd.conf,找到LogFormat将后边的%h替换成%{X-Forwarded-For}i 并重启Apache.

LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" Forwarded

CustomLog logs/test2.com1.log Forwarded

解决虚拟机中IIS日志中客户端IP问题

WindowsIIS比较麻烦一些,不能直接修改IIS日志中的参数。

实现日志记录真实客户端IP,需要借助F5提供的一个客户端软件F5XforwardedFor。可以到F5网站下载到(我的博客地址也有下载http://www.duxt.net/article.asp?id=92)

下载后,会得到一个F5XforwardedFor.dll文件,将此文件解压到IIS目录或者自己创建一个目录。

打开IIS,打开网站属性,如下图12

1

2

选择ISAPI筛选器,添加一个新的筛选器,就是刚才解压的F5XforwardedFor.dll文件。相关配置如图34

3

4

添加完成后,需要重启IIS才能生效。

5

如果重启后不生效,打开IIS web服务扩展,设置 所有未知ISAPI扩展 允许,如图6

6

最后,将域名www1.duxt.net解析到宿主机的公网地址上,然后访问此域名,如图7

7

访问几次后,就可以到虚拟机上去查看站点的IIS日志了。

8

总结

本文中涉及到的iptables配置,只是用于实现对虚拟机中各种服务及端口的发布,未涉及到宿主机及虚拟机中的安全配置。可根据个人的需要,参考其他iptables相关的安全文档进行设置。

另外,可以将相关的iptables命令编写成shell脚本,设置开机启动运行。

有关宿主机中的Nginx作为一个转发代理,可以将它的日志功能关闭,避免不必要的日志占用大量磁盘空间。

使用iptables发布各种服务器,在本文档中只是简单举了几个比较典型的实例,可以根据个人的需要参照本文档中的命令,可以实现所有服务及端口的发布。需要注意的是,如果你使用的防火墙规则过多,要注意规则的顺序,iptables对规则的顺序是有要求的。出现设置防火墙策略不生效时,要仔细检查一下顺序是否正常。

宿主机的CentOS系统可以根据个人需要,有选择的添加组件。建议最小化安装CentOS,保留yum用于以后宿主机的补丁升级或者安装各种所需要的组件。不推荐在宿主机系统中安装过多的服务。

在解决根据域名来发布web站点问题时,也曾经使用squid来实现,但是后来经过多次试验发现,无论从配置的简易程度及效率上,还是nginx比较优秀。如果你对squid比较熟悉或者热衷于squid也可以使用squid来做网站的发布。

最后,此方案中没有提到服务器硬件的配置,这个可以根据不同的需求配置硬件。我个人建议增加内存和提高磁盘IO是关键。因为运行的虚拟机多了,磁盘IO就会成为瓶颈。

补充

1、宿主机使用32位系统后,对于大内存(4GB以上)支持问题。默认情况下如果是CentOS一般会自动启用PAE来支持大内存,如果你用的是其他发布版本,可能默认情况下不会启用PAE。手动安装PAE命令如下:

yum install kernel-PAE

yum remove kernel

安装完成后,重启系统即可。

如果服务器内存超过4GB,建议最好还是使用64位的系统,毕竟PAE方式做了一次地址映射,速度还是会受到影响。

2、(未完待续)