正在浏览 linux网络服务 里的文章

简述:利用(LVS+Piranha)基于完整开源软件的架构可以提供一个简单的负载均衡及高可用的服务架构。LVS 集群采用 IP 负载均衡技术和基于内容请求分发技术。调度器具有很好的吞吐率(在DR模式下),将请求均衡地转移到不同的服务器上执行,且调度器自动屏蔽掉服务器的故 障,从而将一组服务器构成一个高性能的、高可用的虚拟服务器。

生产环境中使用效果图:

环境:CentOS 5.5  x64

lb01:  192.168.0.111
lb02:  192.168.0.112
VIP:   192.168.0.115
web01: 192.168.0.114
web02: 192.168.0.115

安装piranha:

yum -y install piranha ipvsadm

#通过piranha-passwd设置Piranha的管理员密码

piranha-passwd  

#启动piranha的WEB管理界面(可选)

/etc/init.d/piranha-gui start  

通过浏览器访问http://192.168.0.111:3636,单击"Login",使用用户名piranha及刚刚设定的密码进行登录

注:在此界面下可以图形化配置,也可不启用此WEB界面,直接编辑配置文件来配置

vi /etc/sysconfig/ha/lvs.cf

继续阅读

所需软件:

ipvsadm-1.24-10.x86_64.rpm
heartbeat-2.1.3-3.el5.centos.x86_64.rpm
heartbeat-pils-2.1.3-3.el5.centos.x86_64.rpm
heartbeat-stonith-2.1.3-3.el5.centos.x86_64.rpm
PyXML-0.8.4-4.x86_64.rpm

系统环境:
CentOS 5.4 64-bit

HA1                    10.0.0.108
HA1                    10.0.0.109
web1                   10.0.0.110
web2                   10.0.0.111
VIP                    10.0.0.100

ipvsadm-1.24安装

rpm -ivh ipvsadm-1.24-10.x86_64.rpm
/sbin/ipvsadm

heartbeat 安装

rpm -ivh heartbeat-pils-2.1.3-3.el5.centos.x86_64.rpm
rpm -ivh heartbeat-stonith-2.1.3-3.el5.centos.x86_64.rpm
rpm -ivh PyXML-0.8.4-4.x86_64.rpm
rpm -ivh heartbeat-2.1.3-3.el5.centos.x86_64.rpm

注:若heartbeat一次未安装好,再装一次

rpm -q heartbeat -d              //查看安装路径

echo "service heartbeat start" >> /etc/rc.local


配置heartbeat 继续阅读

假设我这里有大量图像、CSS、javascript等静态文件,分别放在后端服务器  192.168.1.5 和 192.168.1.6上,那么我如何利用nginx的反向代理功能将不同的 http_user_agent 请求发送到指定的服务器上呢?如 "Mozilla" 转发到 192.168.1.5 ,MSIE  转发到 192.168.1.6 。

Nginx web 服务器支持if条件表达式,由此来跳转或者使用不同的配置变量。在本文中需要使用 $http_user_agent 变量,它标记了用户浏览器的类别,版本以及操作系统的一些信息,语法如下:

if ( condition ){
  do_something
}
if ( $http_user_agent = "wget" ){
   do_something
}
if ( $http_user_agent ~ MSIE ){
   return 403;
}

if指令会就检查后面表达式的值是否为真(true),如果为真,则执行后面大括号中的内容。以下是一些条件表达式的比较方法:
1、变量的完整比较可以使用=或!=操作符
2、 部分匹配可以使用正则表达式来表示,~或~*
3、~表示区分大小写
4、~*表示不区分大小写(firefox与FireFox是一样的)
5、!~与!~* 是取反操作,也就是不匹配的意思
6、检查文件是否存在使用 -f 或 !-f 操作符
7、检查目录是否存在使用-d或!-d操作符
8、检查文件,目录或符号连接是否存在使用-e或!-e操作符
9、检查文件是否可执行使用-x或!-x操作符
10、正则表达式的部分匹配可以使用括号,匹配的部分在后面可以用$1~$9变量代替,这些和apache一致。

例子:

编辑 /usr/local/nginx/conf/nginx.conf 文件
#vi /usr/local/nginx/conf/nginx.conf
设置upstream服务器:

upstream myproxybackend  {
       server 192.168.1.1;
       server 192.168.1.2;
       server 192.168.1.3;
       server 192.168.1.4;
}
 
upstream msiebackend  {
       server 192.168.1.6;
}
 
upstream mozillabackend  {
       server 192.168.1.5;
}

更新虚拟主机配置文件

server {
      access_log  logs/access.log;
      error_log   logs/error.log;
      index       index.html;
      listen      202.54.1.5:80 default;
      root        /usr/local/nginx/html;
      server_name example.com www.example.com 0.example.com;
 
     ## PROXY - Web
      location / {
        proxy_pass  http://myproxybackend;
        if ($http_user_agent ~ MSIE ) {
              proxy_pass  http://msiebackend;
        }
        if ($http_user_agent ~ Mozilla ) {
              proxy_pass  http://mozillabackend;
        }
 
        proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;
# many more...
# many more...
}

最后重启/重新载入nginx
#/usr/local/nginx/sbin/nginx -s reload

原创文章,转载请注明: 转自 http://salogs.com

一、目的

利用autobench工具结合httperf命令对web服务器进行测试,得出该服务器可以承载的最大并发连接数与最佳并发数。

二、测试工具

工具介绍

1、Httperf

httperf 是一款高性能的HTTP测试工具,使用它我们可以准确定位服务器的并发连接能力。下面介绍一下它的主要特征

(1) 可以观察测试客户端(并非被测服务器)在发起压力测试时的负载情况。这样在测试高并发的情况下可以准确的分析问题。(被测服务器无法承载高并发还是测试客户端无法发起过多请求)
(2)支持HTTP/1.1和SSL
(3)可以生成可扩展的测试计划

下载http://code.google.com/p/httperf/downloads/list

安装
# tar xvzf httperf-0.9.0.tar.gz
# cd httperf-0.9.0
#./configure
# make && make install

更多的使用方法参见man page。

2、autobench

autobench 是一款基于httperf的Perl脚本。它会在一次测试中调用多次httperf来对web服务器进行测试,每次会按照给定的参数增加并发连接数,将httperf的测试结果保存为CSV格式的文件,该文件可以被Excel直接读取,方便生成测试报告。借助于autobench自带的bench2graph工具可以生成漂亮的测试结果对比图,如下:

results.gif

下载:http://www.xenoclast.org/autobench/downloads/

安装

# yum install gd gnuplot pcre pcre-devel texinfo -y
# tar zxvf autobench-2.1.2.tar.gz
# cd autobench-2.1.2
# make && make install
# sed -i 's/postscript color/png xffffff/g' /usr/local/bin/bench2graph (修改bench2graph脚本,否则生成的图像背景有问题)

使用方法:参见下文在实际测试中的使用

三、测试环境

系统环境
CentOS 5.3 64bit

web软件环境
httpd-2.0.6
php5.2.6+ eAccelerator
php-fpm  开启20个php-cgi进程
nginx-0.7.67

在测服务器并发能力时会将apache与nginx对比测试

硬件环境

CPU::E5504  2.00GHz
内存:1G
虚拟机环境

四、测试方法

1、  分别测试静态文件和动态php文件
2、  静态并发数从50开始,1500结束,增长幅度为50,动态5~100,增幅为5
3、  分别测试apache和nginx的并发能力,二者进行对比
4、  每次测试进行3次,最终结果求三次平均值
5、  每进行一次测试后均重启httpd或nginx(php-fpm)服务,释放内存后再进行下一轮测试
6、  为了减少磁盘IO,均关掉了访问日志

1、开始测试

(1)静态文件

测试命令

# autobench --single_host --host1=192.168.8.8 --port1=80 --uri1=/logo.gif  --quiet  --low_rate=50 --high_rate=1500 --rate_step=50 --num_call=1 --num_conn=2000 --timeout=10 --file /tmp/result.tsv

测试结果对比分析
static.png

测试结果总结:

Apache与Nginx在并发50~1500时表现得都还可以,只不过在并发数达到1500后Apache的响应时间变得很长,由于系统环境的制约,我没有再测试大于1500的并发连接情况,但可以对比看出nginx在1500个并发连接的情况下还能保持较低的响应时间。

(2)动态文件

测试命令

# autobench --single_host --host1=192.168.8.8 --port1=80 --uri1=/test.php --quiet --low_rate=5 --high_rate=100 --rate_step=5 --num_call=1 --num_conn=200 --timeout=10 --file /tmp/nginx_php1.tsv

测试结果数据

并发连接数 nginx实际并发数 apache实际并发数 nginx应答时间 apache应答时间
5.0 5.0 5.0 36.0 36.3
10.0 10.0 10.0 33.0 31.7
15.0 15.0 15.0 35.6 31.9
20.0 19.9 19.9 36.8 32.3
25.0 25.0 25.0 42.6 36.2
30.0 29.8 29.7 45.1 67.6
35.0 34.3 32.4 115.5 248.5
40.0 35.5 34.9 396.8 427.3
45.0 35.3 33.4 699.0 865.8
50.0 35.7 30.5 962.3 1394.0
55.0 35.5 33.3 1103.9 1354.7
60.0 35.7 32.9 1269.2 1471.3
65.0 34.9 33.5 1445.8 1573.6
70.0 37.6 29.7 1458.0 2049.5
75.0 37.2 35.9 1610.1 1496.8
80.0 23.9 31.2 1588.2 1993.3
85.0 24.7 33.2 1674.9 1880.2
90.0 37.1 34.5 1838.6 1946.0
95.0 35.0 30.3 2027.4 2387.2
100.0 35.3 36.4 1996.3 1904.5

测试数据

测试结果对比图
total_php-2.png

测试总结

由上面的报表以及这张曲线图可以看出,无论是apache还是nginx其php并发大于30其响应时间的就会直线上升,nginx略好于apache,因此可以判断这台服务器的php并发极限在30左右,当然这里指的php连接中是没有连接数据库的,也没有加入memcached等缓存机制。

(3)高并发下系统资源情况

CPU使用情况对比
cpu.png


内存使用情况对比

memory.png

系统负载对比
load.png

分析测试结果

CPU使用情况
在极限并发的情况下apache和nginx都占用很多CPU资源,这也是情理之中的事          情。nginx略好于apache平均占用90%而apache则在95%左右

内存使用情况
在内存对比中可以清楚的看到,nginx在极限并发的情况下内存控制得很好,到达一定程度后就不在变化了,而apache则会直线上升

负载情况
负载情况与内存情况类似,如果高并发时间很长的话apache服务器绝对会挂掉!nginx的负载也很高,但一直保持在10以下,这也和内存占用有关。

五、结论

利用httperf结合autobench可以很方便的测试出单台服务器的极限并发数,这样对服务器性能评估有很大帮助,借助于autobench的bench2graph脚本可以生成更为直观的对比图。

针对被测服务器,经过apache与nginx的对比发现,在静态文件的处理方面如果并发小于1500,apache和nginx之间的差距还是很小的。在动态php文件的并发测试中,nginx体现出其强大的性能优势,如果内存足够大,通过调整php-cgi数量,相信可以承载更多的并发连接。

六、附录

1、问题解决

(1)当运行时报如下错误

httperf: warning: open file limit > FD_SETSIZE; limiting max. # of open files to FD_SETSIZE

解决方法

其意思是说在httperf在发起连接请求时,单个进程已经无法再打开更多的文件描述符。在发起连接请求时httperf使用select()方法使用一个新的文件描述符。因此需要增加文件描述符限制

步骤1:编辑/etc/security/limits.conf 在最后添加下面两行内容
*       hard    nofile          102400
*       soft    nofile          102400

步骤2:编辑 /usr/include/bits/typesizes.h 文件修改__FD_SET_SIZE常量值,如下
#define __FD_SETSIZE            1024
修改为
#define __FD_SETSIZE            102400

步骤3:重新编译httperf

2、参考文章

http://www.cppblog.com/qiujian5628/archive/2008/03/10/44060.html
http://wiki.nginx.org/
http://www.joeandmotorboat.com/2008/02/28/apache-vs-nginx-web-server-performance-deathmatch/

原创文章,转载请注明: 转自 http://salogs.com

简介:

PureFTPd是免费、安全、符合国际标准的FTP 服务器程序。它并没有那些无用而又花哨的功能,而是将重点放到了提高效率和易用性上,独特的实用功能为个人用户和托管服务提供商提供了一个新的选择。

下载:

从官方网站下载最新的稳定版本http://www.pureftpd.org/ 其最新版本是1.0.29,下载地址
为:http://download.pureftpd.org/pub/pure-ftpd/releases/pure-ftpd-1.0.29.tar.bz2

系统环境

CentOS 5.5
PureFTPd 1.0.29

编译安装

# tar -xvjf pure-ftpd-1.0.29.tar.bz2
# cd pure-ftpd-1.0.29
# ./configure --help # 查看编译选项

PureFTPd有很多的编译配置选项,下面就列出部分主要的配置

--prefix=PREFIX
--with-sysquotas        使用系统磁盘配额 (非虚拟)
--with-altlog           支持选择日志格式(类似Apache)
--with-puredb           支持虚拟用户 (FTP登陆用户而非系统用户)
--with-extauth          支持扩展验证模块
--with-pam              启用PAM验证支持 (默认=禁用)
--with-cookie           启用Cookie支持 (-F 选项)
--with-throttling       支持带宽控制 (默认=禁用)
--with-ratios           支持 上传/下载 速度控制
--with-quotas           支持 .ftpquota 文件(指定磁盘配额使用)
--with-ftpwho           支持pure-ftpwho(查看在线用户的程序)
--with-largefile        支持大于2G的文件
--with-welcomemsg       支持 welcome.msg 向后兼容(已经过时)
--with-uploadscript     上传后允许执行外部脚本 (测试阶段)
--with-virtualhosts     在不同的IP地址提供虚拟服务器功能
--with-virtualchroot    允许在chroot的环境下通过符合连接跳转到外部
--with-diraliases       启用目录别名
--with-nonroot          普通模式或者说是限制模式. 如果你在该服务器上没有root权限
那只有启用该项
--with-peruserlimits    支持每个用户的并发限制
--with-language=        语言支持< english | traditional-chinese | simplified-chinese>
--with-ldap             在LDAP目录中提供用户数据库
--with-mysql            在MySQL数据库中存放用户数据
--with-pgsql            在PostgreSQL数据库中存放用户数据
--with-privsep          启用权限分离
--with-tls              启用 SSL/TLS 支持 (测试阶段, 需要安装 OpenSSL)
--with-certfile=        证书文件 (默认目录: /etc/ssl/private/pure-ftpd.pem)
--with-rfc2640          启用兼容 RFC 2640 支持(UTF-8 编码的文件名,测试阶段,需要安装iconv)
--with-everything       启用大多数选项,编译完功能版本的服务器端。

为了方便起见,我在这里使用了几个基本的编译命令来配置编译一个全功能版本的程序

# ./configure --prefix=/usr/local/pure-ftpd/ --with-language=simplified-chinese --with-everything
注意:如果要指定安装路径,那么路径最好是/usr/local/pure-ftpd或/usr/local/pureftpd/ 或者干脆就不指定。如果不指定目录的话默认是将程序的文件安装到/usr/local下的相应目录下。我这里指定目录是为了便于管理。至于为什么安装目录也有如此的讲究,在下面再做说明。

# make && make check && make install

# mkdir /usr/local/pure-ftpd/etc
# cp configuration-file/pure-ftpd.conf /usr/local/pure-ftpd/etc/ # 配置文件拷贝到/etc目录下
# cp configuration-file/pure-config.pl /usr/local/pure-ftpd/sbin/
//似乎make install忘记了将这个文件复制到相应的目录了,我们只有手动自己做了
# chmod 755 /usr/local/pure-ftpd/sbin/pure-config.pl # 设置相应的权限

系统集成

这里所说的系统集成就是制定系统变量,使系统可以找到我们刚刚安装的程序,最简单的方法就是将一些可执行的程序,man文件在系统指定的path中建立符号链接就可以了。当然我们也可以修改系统变量,如PATH变量,man page的配置文件等等。但是我还是习惯在相应的目录建立符合连接。

# cd /usr/local/bin/
# ln -s /usr/local/pure-ftpd/bin/* .
# ln -s /usr/local/pure-ftpd/sbin/* /usr/local/sbin/
# ln -s /usr/local/pure-ftpd/man/man8/* /usr/local/share/man/man8/

PureFTPd配置

PureFTPd 程序的一大特点就是官方推荐使用命令行参数的形式来启动服务,而非我们经常使用的配置文件加命令的形式来启动服务。不过PureFTPd也是支持读取配置文件的。只不过要用到一个Python编写的脚本,利用这个脚本来将配置文件中的值转换为命令行参数!

(1)创建一个匿名访问的FTP服务器

匿名用户访问的FTP服务器比较好配置,只需要做一下与匿名用户相关的配置即可。如果只开启匿名访问的ftp服务器那么其ftp目录就是系统中ftp用户的home目录。可以使用finger命令来查看:
# finger ftp

Login: ftp                              Name: FTP User
Directory: /var/ftp                     Shell: /sbin/nologin
Never logged in.
No mail.
No Plan.

当然这个目录我也可以通过修改/etc/passwd文件来修改。但要记住,这个目录只针对匿名用户

●修改匿名用户上传/下载目录,以及相关的权限
# usermod -d /home/ftp
# mkdir /home/ftp;chown ftp.ftp /home/ftp

●修改相关配置
# vi /etc/pure-ftpd.conf

ChrootEveryone              yes     # 启用chroot
BrokenClientsCompatibility  yes     # 兼容不同客户端
Daemonize                   yes     # 后台运行
MaxClientsPerIP             20      # 每个ip最大连接数
VerboseLog                  yes     # 记录日志
DisplayDotFiles             no      # 显示隐藏文件
AnonymousOnly               yes     # 只允许匿名用户访问
NoAnonymous                 no      # 运行匿名用户连接
SyslogFacility              none        # 不将日志在syslog日志中显示
DontResolve                 yes     # 不进行客户端DNS解析
MaxIdleTime                 15      # 最大空闲时间
LimitRecursion              2000 8      # 浏览限制,文件2000,目录8层
AnonymousCanCreateDirs      yes     # 匿名用户可以创建目录
MaxLoad                     4           # 超出负载后禁止下载
PassivePortRange            45000 50000 # 被动模式端口范围
AnonymousRatio              1 10        # 匿名用户上传/下载比率
AntiWarez                   yes     # 禁止下载匿名用户上传但未经验证的文件
AnonymousBandwidth          200     # 匿名用户带宽限制(KB)
Umask                       133:022     # 创建文件/目录默认掩码
MinUID                      100     # 最大UID限制
AllowUserFXP                no      # 仅运行用户进行FXP传输
AllowAnonymousFXP           no      # 对匿名用户和非匿名用户允许进行匿名 FXP 传输
ProhibitDotFilesWrite       no      # 不能删除/写入隐藏文件
ProhibitDotFilesRead        no      # 禁止读取隐藏文件
AutoRename                  yes     # 有同名文件时自动重新命名
AnonymousCantUpload         no      # 不允许匿名用户上传文件
AltLog                      clf:/var/log/pureftpd.log   # clf格式日志文件位置
MaxDiskUsage                99      # 当磁盘使用量打到99%时禁止上传
CustomerProof               yes     # 防止命令误操作

配置一个匿名访问的服务器,上面的参数就够用了。可以根据自己的要求做一些具有针对性
的设置。详细的参数说明参见附录

●启动pureFTPd服务
# pure-config.pl /usr/local/pure-ftpd/etc/pure-ftpd.conf
屏幕上会显示下面的信息
Running: /usr/local/pure-ftpd/sbin/pure-ftpd -A -b -B -C20 -d -e -fnone -H -I15 -L2000:8 -M -m4 - p45000:50000 -q1:10 -s -t200 -U133:022 -u100 -r -Oclf:/var/log/pureftpd.log -k99 -Z

(2)创建一个虚拟用户验证的FTP服务器

●配置 FTP登录账户
pure-ftp默认采用Linux的root用户。虚拟用户则能够更好的控制访问权限。虚拟用户是和Linux系统用户关联的独立的账户系统。所以在创建虚拟用户之前最好先创建一个系统的账户和组。
创建一个ftpgroup组和ftpuser用户
# groupadd ftpgroup
# useradd -g ftpgroup -d /dev/null -s /etc ftpuser
接下来所有与虚拟用户相关的操作都可以用‘pure-pw’命令来完成。当然你也可以手动的来编辑相应的文件。

下面为虚拟用户存储文件的详细格式,一行一个用户
<account>:<password>:<uid>:<gid>:<gecos>:<home directory>:<upload bandwidth>
:<download bandwidth>:<upload ratio>:<download ratio>:<max numberof connections>
:<files quota>:<size quota>:<authorized local IPs>:<refusedlocal IPs>
:<authorized client IPs>:<refused client IPs>:<timerestrictions>
密码字段是加密后的密码,加密方式与系统的用户密码加密方式相同,用户可以执行setup命令配置。
除了account, password, uid, gid, home directory字段外,其他的字段可以为空

●使用命令添加一个虚拟用户
pure-pw命令的格式

pure-pw useradd <login> [-f <passwd file>] -u <uid> [-g <gid>]
-D/-d <home directory> [-c <gecos>]
[-t <download bandwidth>] [-T <upload bandwidth>]
[-n <max number of files>] [-N <max Mbytes>]
[-q <upload ratio>] [-Q <download ratio>]
[-r <allow client host>[/<mask>][,...]
[-R <deny client host>[/<mask>][,...]
[-i <allow local host>[/<mask>][,...]
[-I <deny local host>[/<mask>][,...]
[-y <max number of concurrent sessions>]
[-z <hhmm>-<hhmm>] [-m]

例如:
pure-pw useradd joe -u ftpuser -d /home/ftpusers/joe
回车后提示输入两次密码
使用 -d 参数指定一个用户的home目录后,该用户就被固定到这个目录了,其不能切换到上级目录如果要想让用户可以访问到别的目录,那么使用-D参数来指定hone目录。
如果pureFTPd的配置文件中指定了CreateHomeDir yes 的话,/home/ftpusers/joe 目录是没有必要手动创建的。当用户首次登录时如果目录不存在程序会自动创建相应的目录。
使用-z参数可以指定用户只能在一天中的某个时间段可以登陆ftp服务器。例如 -z 0900-1800那么joe只能在早上9点和下午6点这个时间段登陆。注意:如果设置登陆时间的用户已经通过验证登陆到ftp服务器上了,那么所做的登陆时间限制只能在他下次登陆验证的时候才能生效。
-r 与 -R 参数是约束用户从哪些IP登陆的。可以使用IP/mask的形式,如-r 192.168.1.0/24多个段用逗号隔开,如:-r 192.168.1.0/24,10.1.0.0/16,127.0.0.1/32 。单独的IP:-r 192.168.1.4,10.1.1.5主机名:-r bla.bla.net,yopcitron.com。以及一些相兼容的格式。
-y 参数是限制同一时刻一个用户最多能发起多少个会话(sessions)。''或0 代表无限制。该选项可以降低系统负载。效果同配置文件中的 MaxClientsPerIP
ok,现在用户 "joe" 已经创建成功了默认的虚拟用户列表文件存储在 安装目录的/etc/目录下,可以使用-f参数指定文件的存储路径
查看一下文件内容
# cat /usr/local/pure-ftpd/etc/pureftpd.passwd
joe:$1$ocfl1XW0$R0JaEh3CjGFByGbdN7qNy/:501:501::/home/ftpusers/joe/./::::::::::::
密码字段是经过加密的。

●更改用户信息
虚拟用户创建之后,你也可以通过pure-pw命令来修改其相关的信息,如限制下载
带宽、磁盘配额、用户全名、下载上传率等等
例如:我要修改用户joe的最大文件数为1000个,大小为10MB,命令如下:
# pure-pw usermod joe -n 1000 -N 10
查看一下虚拟用户列表文件
# cat /usr/local/pure-ftpd/etc/pureftpd.passwd
joe:$1$ocfl1XW0$R0JaEh3CjGFByGbdN7qNy/:501:501::/home/ftpusers/joe/./::::::1000:10485760:::::

●重置用户属性
要禁用文件数配额,执行 pure-pw usermod -n ''
要禁用文件大小配额,执行 pure-pw usermod -N ''
要禁用上传/下载比率,执行 pure-pw usermod -q '' -Q ''
要禁用下载带宽限制,执行 pure-pw usermod -t ''
要禁止上传带宽限制,执行 pure-pw usermod -T ''
要禁止IP地址过滤,使用 pure-pw usermod <-i,-I,-r or -R> ''
要禁止登陆时间限制,执行 pure-pw usermod -z ''
要禁止最大并发数控制,执行 pure-pw usermod -y ''

●删除用户
使用pure-pw userdel 命令可以删除一个已经存在的用户
pure-pw userdel <login> [-f <passwd file>] [-m]
如:pure-pw userdel joe
用户home目录中的文件不会被删除,需要手动删除

●更改密码
更改用户密码的命令
# pure-pw passwd <login> [-f <passwd file>] [-m]

●利用pure-pw命令查看用户信息
# pure-pw show joe

Login              : joe
Password           : $1$ocfl1XW0$R0JaEh3CjGFByGbdN7qNy/
UID                : 501 (ftpuser)
GID                : 501 (ftpgroup)
Directory          : /home/ftpusers/joe/./
Full name          :
Download bandwidth : 0 Kb (unlimited)
Upload   bandwidth : 0 Kb (unlimited)
Max files          : 0 (enabled)
Max size           : 10 Mb (enabled)
Ratio              : 0:0 (unlimited:unlimited)
Allowed local  IPs :
Denied  local  IPs :
Allowed client IPs :
Denied  client IPs :
Time restrictions  : 0000-0000 (unlimited)
Max sim sessions   : 0 (unlimited)

★应用更改
重要:
你可以通过上面提到的命令或者手动的来添加/删除用户,修改用户相关限制属性等等,但是这些改动都是针对虚拟用户列表文件的(pureftpd.passwd)。pureFTPd服务器程序是不认识这个文件的。要想让ftp server能够识别的我们所做的更改,必须要通过pure-pw mkdb 命令生成PureDB格式的文件,实际上PureDB数据文件就是从pureftpd.passwd文件转换过来的,为了ftp server可以更快的检索到指定的用户。
例如:
# pure-pw mkdb -> 当使用pure-pw 生成虚拟用户之后一定要使用pure-pw mkdb命令生成数据库文件,否则pure-ftp启动之后也无法验证虚拟用户
默认情况下会在软件安装目录/etc目录下生成pureftpd.pdb文件。
如:/usr/local/pure-ftpd/etc/pureftpd.pdb

或者直接指定生成的pdb文件和参照的虚拟用户列表文件
如:pure-pw mkdb /etc/accounts/myaccounts.pdb -f /etc/accounts/myaccounts.txt

当更改了虚拟用户列表文件之后都要重新生成pdb数据库文件。但不必要重新启动pureFTPd服务。可以使用-m参数来将更改立即应用到pdb数据库文件中,如:
# pure-pw passwd joe -m
当输入完两次新密码之后,密码的更改就同时应用到列表文件和pdb数据库文件中了。是不是很方便!

☆启用虚拟用户验证登陆
1、编译ftp服务器端的时候一定要加入--with-puredb 选项,或者干脆--with-everything
2、配置文件中加入PureDB /etc/pureftpd.pdb 或者启动服务器程序的时候加入参数
-l puredb/usr/local/pure-ftpd/etc/pureftpd.pdb
3、一定要注意自己的pdb文件的位置在哪

○配置文件 vi /usr/local/pure-ftpd/etc/pure-ftpd.conf

ChrootEveryone              yes         # 启用chroot
BrokenClientsCompatibility  yes         # 兼容不同客户端
Daemonize                   yes         # 后台运行
MaxClientsPerIP             20          # 每个ip最大连接数
VerboseLog                  yes         # 记录日志
DisplayDotFiles             no          # 显示隐藏文件
AnonymousOnly               no          # 只允许匿名用户访问
NoAnonymous                 yes         # 不允许匿名用户连接
SyslogFacility              none        # 不将日志在syslog日志中显示
DontResolve                 yes         # 不进行客户端DNS解析
MaxIdleTime                 15          # 最大空闲时间
LimitRecursion              2000 8      # 浏览限制,文件2000,目录8层
AnonymousCanCreateDirs      no          # 匿名用户可以创建目录
MaxLoad                     4           # 超出负载后禁止下载
PassivePortRange          45000 50000   # 被动模式端口范围
#AnonymousRatio                1 10     # 匿名用户上传/下载比率
UserRatio                 1 10          # 所有用户上传/下载比率
AntiWarez                   yes         # 禁止下载匿名用户上传但未经验证的文件
#AnonymousBandwidth            200      # 匿名用户带宽限制(KB)
UserBandwidth               8           # 所有用户最大带宽(KB)
Umask                       133:022     # 创建文件/目录默认掩码
MinUID                      100         # 最大UID限制
AllowUserFXP                no          # 仅运行用户进行FXP传输
AllowAnonymousFXP           no          # 对匿名用户和非匿名用户允许进行匿名 FXP 传输
ProhibitDotFilesWrite       no          # 不能删除/写入隐藏文件
ProhibitDotFilesRead        no          # 禁止读取隐藏文件
AutoRename                  yes         # 有同名文件时自动重新命名
AnonymousCantUpload         yes         # 不允许匿名用户上传文件
AltLog                     clf:/var/log/pureftpd.log                # clf格式日志文件位置
PureDB                     /usr/local/pure-ftpd/etc/pureftpd.pdb        # 用户数据库文件
MaxDiskUsage               99           # 当磁盘使用量打到99%时禁止上传
CreateHomeDir              yes          # 如果虚拟用户的目录不存在则自动创建
CustomerProof              yes          # 防止命令误操作

●启动pureFTPd服务
# pure-config.pl /usr/local/pure-ftpd/etc/pure-ftpd.conf
若要pureFTPd随系统启动,将命令加入到 /etc/rc.local文件中,如下
# echo "pure-config.pl /usr/local/pure-ftpd/etc/pure-ftpd.conf " >> /etc/rc.local

附录1:pure-config.pl 文件

#! /usr/bin/perl

# (C) 2001-2006 Aristotle Pagaltzis
# derived from code (C) 2001-2002 Frank Denis and Matthias Andree

use strict;

my ($conffile, @flg) = @ARGV;

my $PUREFTPD;
-x && ($PUREFTPD=$_, last) for qw(
${exec_prefix}/sbin/pure-ftpd
/usr/local/pure-ftpd/sbin/pure-ftpd
/usr/local/pureftpd/sbin/pure-ftpd
/usr/local/sbin/pure-ftpd
/usr/sbin/pure-ftpd
);

my %simple_switch_for = (
IPV4Only                  => "-4",
IPV6Only                  => "-6",
ChrootEveryone          => "-A",
BrokenClientsCompatibility  => "-b",
Daemonize                 => "-B",
VerboseLog                => "-d",
DisplayDotFiles         => "-D",
AnonymousOnly           => "-e",
NoAnonymous             => "-E",
DontResolve             => "-H",
AnonymousCanCreateDirs      => "-M",
NATmode             => "-N",
CallUploadScript            => "-o",
AntiWarez               => "-s",
AllowUserFXP            => "-w",
AllowAnonymousFXP           => "-W",
ProhibitDotFilesWrite       => "-x",
ProhibitDotFilesRead        => "-X",
AllowDotFiles           => "-z",
AutoRename              => "-r",
AnonymousCantUpload     => "-i",
LogPID              => "-1",
NoChmod             => "-R",
KeepAllFiles            => "-K",
CreateHomeDir           => "-j",
NoRename                => "-G",
CustomerProof           => "-Z",
NoTruncate              => "-0",
);

my %string_switch_for = (
FileSystemCharset       => "-8",
ClientCharset       => "-9",
SyslogFacility      => "-f",
FortunesFile        => "-F",
ForcePassiveIP      => "-P",
Bind                => "-S",
AnonymousBandwidth  => "-t",
UserBandwidth       => "-T",
TrustedIP           => "-V",
AltLog          => "-O",
PIDFile         => "-g",
);

my %numeric_switch_for = (
MaxIdleTime         => "-I",
MaxDiskUsage        => "-k",
TrustedGID          => "-a",
MaxClientsNumber        => "-c",
MaxClientsPerIP     => "-C",
MaxLoad         => "-m",
MinUID          => "-u",
TLS             => "-Y",
);

my %numpairb_switch_for = (
LimitRecursion      => "-L",
PassivePortRange        => "-p",
AnonymousRatio      => "-q",
UserRatio           => "-Q",
);

my %numpairc_switch_for = (
Umask               => "-U",
Quota               => "-n",
PerUserLimits       => "-y",
);

my %auth_method_for = (
LDAPConfigFile      => "ldap",
MySQLConfigFile     => "mysql",
PGSQLConfigFile     => "pgsql",
PureDB          => "puredb",
ExtAuth         => "extauth",
);

my $simple_switch = qr/(@{[join "|", keys %simple_switch_for ]})\s+yes/i;
my $string_switch = qr/(@{[join "|", keys %string_switch_for ]})\s+(\S+)/i;
my $numeric_switch = qr/(@{[join "|", keys %numeric_switch_for ]})\s+(\d+)/i;
my $numpairb_switch = qr/(@{[join "|", keys %numpairb_switch_for ]})\s+(\d+)\s+(\d+)/i;
my $numpairc_switch = qr/(@{[join "|", keys %numpairc_switch_for ]})\s+(\d+):(\d+)/i;
my $auth_method = qr/(@{[join "|", keys %auth_method_for ]})\s+(\S+)/i;

die "Usage: pure-config.pl  [extra options]\n"
unless defined $conffile;

open CONF, "< $conffile" or die "Can't open $conffile: $!\n";

!/^\s*(?:$|#)/ and (chomp, push @flg,
/$simple_switch/i             ? ($simple_switch_for{$1}) :
/$string_switch/i             ? ($string_switch_for{$1} . $2) :
/$numeric_switch/i      ? ($numeric_switch_for{$1} . $2) :
/$numpairb_switch/i     ? ($numpairb_switch_for{$1} . "$2:$3") :
/$numpairc_switch/i     ? ($numpairc_switch_for{$1} . "$2:$3") :
/$auth_method/i         ? ("-l" . "$auth_method_for{$1}:$2") :
/UnixAuthentication\s+yes/i ? ("-l" . "unix") :
/PAMAuthentication\s+yes/i  ? ("-l" . "pam") :
()
) while ;

close CONF;

print "Running: $PUREFTPD ", join(" ", @flg), "\n";
exec { $PUREFTPD } ($PUREFTPD, @flg) or die "cannot exec $PUREFTPD: $!";

附录2:pure-ftpd.conf 文件

# vi sample pure-ftpd.conf

# 将每个用户限制在自己的home目录下
ChrootEveryone              yes

# 兼容ie等比较非正规化的ftp客户端。默认:no
BrokenClientsCompatibility  yes

# 最大用户连接数。默认:50
MaxClientsNumber            2000

# 后台模式(守护进程模式)
Daemonize                   yes

# 同一个IP允许连接数(可以防止迅雷、快车等程序疯狂开线程)。默认:8
MaxClientsPerIP             20

# 如果要记录所有的客户端命令,请设置为‘yes’该选项可以将日志同步复制到日志服务器。默认:no
VerboseLog                  yes

# 显示隐藏文件。默认:yes
DisplayDotFiles             yes

# 不允许验证用户。只作为匿名ftp服务器。默认:no
AnonymousOnly               no

# 不允许匿名用户连接。只允许验证用户连接。默认:no
NoAnonymous                 no

# 该选项是说将何种类型的日志同步写入到syslog中。
# 类型包括(auth, authpriv, daemon, ftp, security, user, local*)
# 默认是"ftp"如果不想将ftp的日志显示在/var/log/message中。则禁用即可: "none"
SyslogFacility              none

# 显示 cookies
# FortunesFile              /usr/share/fortune/zippy

# 在日志文件中不解析主机名。日志越详细所需要的带宽也就越大。如果服务器的
# DNS解析有问题或者服务器的负载过大,建议将该选项配置yes。默认为:yes
DontResolve                 yes

# 最大空闲时间。单位:分钟 (默认 = 15 分钟)
MaxIdleTime                 15

# LDAP 配置文件
# LDAPConfigFile                /etc/pureftpd-ldap.conf

# MySQL 配置文件 (详情见 README.MySQL)
# MySQLConfigFile               /etc/pureftpd-mysql.conf

# Postgres 配置文件 (详情见 README.PGSQL)
# PGSQLConfigFile               /etc/pureftpd-pgsql.conf

# PureDB 用户数据库 (详情见 README.Virtual-Users)
# PureDB                        /etc/pureftpd.pdb

# pure-authd 的 socket 路径 (详见 README.Authentication-Modules)
# ExtAuth                       /var/run/ftpd.sock

# 如果要使用PAM验证,取消下面行的注释
# PAMAuthentication             yes

# 如果要使用/etc/passwd 文件验证。取消下面行的注释
# UnixAuthentication            yes

# 注意:LDAPConfigFile, MySQLConfigFile, PAMAuthentication 与 UnixAuthentication
# 只能启用一个,但他们可以联合使用。例如:你启用了 MySQLConfigFile 之后又启用了
# UnixAuthentication那么同一时刻只有SQL server 可用。如果SQL authentication 失败,
# 例如用户没有找到,那么系统会重试其他的方式来验证,这时候它就会找/etc/passwd 和
# /etc/shadow文件. 如果通过 SQL 验证的结果是因为密码错误,那么就不会在进行下面的
# 验证了。由此得知,验证方法可以写多个,但同一个时刻只有一个工作,且当验证时找不
# 到信息时才会进行下一个验证方式。但当验证错误时就终止验证了。

# 'ls' 递归限制。第一个参数是最大可显示的文件数。第二个参数是子文件夹深度
LimitRecursion              2000 8

# 匿名用户是否可以创建新文件夹
AnonymousCanCreateDirs      no

# 如果系统负载超过下面所给的数字,那么匿名用户将无法下载
MaxLoad                     4

# 在被动连接模式下为其分配的端口范围。便于制定防火墙配置。
PassivePortRange          45000 50000

# 强制某个IP地址工作在 PASV/EPSV/SPSV 模式. - for NAT.
# ForcePassiveIP                192.168.0.1

# 匿名用户上传/下载比率
# AnonymousRatio                1 10

# 所有用户 上传/下载 比率。该选项可以取代上面的选项
# UserRatio                 1 10

# 禁止下载所有者为‘ftp’的文件。例如:那些匿名用户上传后未被本地管理员验证的文件。
AntiWarez                   yes

# 用来监听的IP地址和端口 (默认=所有 IP 和 21 端口).
# Bind                      127.0.0.1,21

# 匿名用户最大带宽限制,单位 KB/s
AnonymousBandwidth            200

# 所有用户的最大带宽限制(包括匿名)单位 KB/s
# 没有必要同时开启 AnonymousBandwidth 和 UserBandwidth
# UserBandwidth             8

# 新建文件默认掩码. <文件掩码>:<目录掩码>
# 为了安全起见可以设置为 177:077
Umask                       133:022

# 验证登录用户的最小UID
MinUID                      100

# 仅允许认证用户进行 FXP 传输
AllowUserFXP                no

# 对匿名用户和非匿名用户允许进行匿名 FXP 传输
AllowAnonymousFXP           no

# 用户不能删除/写入隐藏文件,即便是文件的拥有者也不允许。
# 如果 TrustedGID 选项为 enabled 文件所属组用户可以访问隐藏文件
ProhibitDotFilesWrite       no

# 禁止读取隐藏文件 (如 .history, .ssh...)
ProhibitDotFilesRead        no

# 永不覆盖文件。如果上传的文件已经存在,系统会自动将其命名为file.1, file.2, file.3, ...
AutoRename                  yes

# 不允许匿名用户上传文件 (no = 允许上传)
AnonymousCantUpload         no

# 仅允许来自以下IP地址的非匿名用户连接。你可以使用这个指令来打开几个公
# 网IP来提供匿名FTP,而保留一个私有的防火墙保护的IP来进行远程管理。你
# 还可以只允许一内网地址进行认证,而在另外一个IP上提供纯匿名的FTP服务。
#TrustedIP                  10.1.1.1

# 如果你要在登陆日志的每一行添加PID标记,去掉下行的注释
#LogPID                     yes

# 使用类似于Apache格式创建一个附加的日志文件,如:
# fw.c9x.org - jedi [13/Dec/1975:19:36:39] "GET /ftp/linux.tar.bz2" 200 21809338
# 这个日志文件可以被www流量分析工具来处理
AltLog                     clf:/var/log/pureftpd.log

# 使用优化过的格式为统计报告创建一个额外的日志文件
# AltLog                     stats:/var/log/pureftpd.log

# 使用标准的W3C格式创建一个额外的日志文件。(与大部分的商业日志分析器兼容)
# AltLog                     w3c:/var/log/pureftpd.log

# 不允许使用chmod命令.用户不能修改他们上传文件的属性
#NoChmod                     yes

# 允许用户恢复和上传文件,但不能够上除他们
#KeepAllFiles                yes

# 用户主目录不存在的话,自动创建目录
#CreateHomeDir               yes

# 启用虚拟磁盘配额。第一个参数是最大文件数,第二个参数是总共的大小,单位是MB
# 如: 1000:10 限制每个用户最大文件1000个且不能超过10MB
#Quota                       1000:10

# 如果你在编译 pure-ftpd 时加入了‘standalone’选项,那么你可以更改pid文件位置
# 默认目录 /var/run/pure-ftpd.pid
#PIDFile                     /var/run/pure-ftpd.pid

# 如果你在编译 pure-ftpd 时加入了 pure-uploadscript 选项,这个指令将会使
# pure-ftpd 发送关于新上传的情况信息到 /var/run/pure-ftpd.upload.pipe,
# 这样 pure-uploadscript 就能读然后调用一个脚本去处理新的上传。
#CallUploadScript yes

# 这个选项对于匿名上传的服务器是很有用的。/var/ftp 在 /var 里时,需要保留一定
# 磁盘空间来保护日志文件。当所在磁盘分区使用超过百分之 X 时,将不在接受新的上传。
MaxDiskUsage               99

# 如果不想让用户来重命名文件,请将其设置为yes
#NoRename                  yes

# 'customer proof' : 选项可以阻止普通用户因误操作而执行的错误命令
# 如:'chmod 0 public_html', 这是有效的命令,但执行完命令之后用户
# 就将他们自己的文件锁定了,这时你的麻烦就来了,你需要给用户解决这
# 些由于用户而造成的愚蠢问题。如果你确信的你用户都具有一些unix基础
# 知识的话,那么该选项就没有必要设置,否则建议启用它。
CustomerProof              yes

# 所有用户都做同样的限制。只有编译时加入了--with-peruserlimits 选项
# 才可以启用。格式为: <每一个用户最大许可的进程>:<匿名用户最大进程>
# 例如:3:20 同一个认证用户最大可以有3个同时活动的进程。而且同时最多
# 只能有20个匿名用户进程
# PerUserLimits            3:20

# 当文件上传时,服务器上之前已经有一个同名的文件时,旧的文件既不会被移动
# 也不会被删除。在新文件上传完毕之前会将上传的部分暂时放到一个临时的文件
# 中,当上传完毕之后会自动的切换到新上传的文件。例如:当服务器上有一个PHP
# 脚本正在执行,但我现在要上传一个新的PHP脚本,那么当我在上传完毕之后才将
# 旧的文件切换到新的文件。而不是像某些程序那样在开始上传的时候就将旧的文件
# 覆盖掉了,这样做的目的就是可以最大程度的减少正在运行中的程序错误。该选项
# 与虚拟配额不能同时使用。
# NoTruncate               yes

# 该选项可以接受3个可选值:
# 0 : 禁用 SSL/TLS 加密层 (默认).
# 1 : 同时接受传统的和加密的连接
# 2 : 拒绝没有经过 SSL/TLS 安全验证的连接,包括匿名连接
# 在没有确定下面三个问题之前不要盲目的取消注释:
# 1) 编译PureFTPd时是否启用了 SSL/TLS 支持 (--with-tls),
# 2) 系统中是否包含一个有效的证书
# 3) 开启后只有兼容的客户端才能登陆
# TLS                      1

# 在 standalone 模式下只监听IPV4的地址 (与禁用 IPv6 相同)
# 默认是IPV4与IPV6同时监听
# IPV4Only                 yes

# 在 standalone 模式下只监听IPV6的地址 (与禁用 IPv4 相同)
# IPV6Only                 yes

# 文件名的UTF-8支持
# FileSystemCharset big5
# ClientCharset     big5

原创文章,转载请注明: 转自 http://salogs.com

根据 http://dengweihua1.blog.51cto.com/134932/332676 的文章,自己也做了下测试,下面是测试步骤:
1、修改main.cf 配置文件,添加relocated_maps 项
# vi /etc/postfix/main.cf
relocated_maps= hash:/etc/postfix/relocated

2、编辑relocated文件
# vi /etc/postfix/relocated
cooper@abc.com cooper@163.com

这句话的意思就是说收件人的地址已经从cooper@abc.com变更为cooper@163.com。relocated文件支持正则表达式,详细情况参见官方man page

3、生成relocated.db文件
# postmap /etc/postfix/relocated
# ls -l /etc/postfix/relocated*
-rw-r--r-- 1 root root 6852 Jun 17 13:47 /etc/postfix/relocated
-rw-r--r-- 1 root root 12288 Jun 17 14:22 /etc/postfix/relocated.db

4、重新载入postfix服务
# service postfix reload

5、客户端测试
--利用foxmail给cooper@abc.com发送邮件,得到如下对话框

--利用qq邮箱给cooper@abc.com发送邮件,得到退信内容如下:
postfix_relocated_2.png

漏洞介绍:nginx是一款高性能的web服务器,使用非常广泛,其不仅经常被用作反向代理,也可以非常好的支持PHP的运行。80sec发现其中存在一个较为严重的安全问题,默认情况下可能导致服务器错误的将任何类型的文件以PHP的方式进行解析,这将导致严重的安全问题,使得恶意的攻击者可能攻陷支持php的nginx服务器。

漏洞分析:nginx默认以cgi的方式支持php的运行,譬如在配置文件当中可以以

location ~ \.php$ {
root html;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
include fastcgi_params;
}

的方式支持对php的解析,location对请求进行选择的时候会使用URI环境变量进行选择,其中传递到后端Fastcgi的关键变量 SCRIPT_FILENAME由nginx生成的$fastcgi_script_name决定,而通过分析可以看到$fastcgi_script_name是直接由URI环境变量控制的,这里就是产生问题的点。而为了较好的支持PATH_INFO的提取,在PHP 的配置选项里存在cgi.fix_pathinfo选项,其目的是为了从SCRIPT_FILENAME里取出真正的脚本名。
那么假设存在一个http://www.80sec.com/80sec.jpg,我们以如下的方式去访问

http://www.80sec.com/80sec.jpg/80sec.php

将会得到一个URI
/80sec.jpg/80sec.php

经过location指令,该请求将会交给后端的fastcgi处理,nginx为其设置环境变量SCRIPT_FILENAME,内容为

/scripts/80sec.jpg/80sec.php

而在其他的webserver如lighttpd当中,我们发现其中的SCRIPT_FILENAME被正确的设置为

/scripts/80sec.jpg

所以不存在此问题。
后端的fastcgi在接受到该选项时,会根据fix_pathinfo配置决定是否对SCRIPT_FILENAME进行额外的处理,一般情况下如果不对fix_pathinfo进行设置将影响使用PATH_INFO进行路由选择的应用,所以该选项一般配置开启。Php通过该选项之后将查找其中真正的脚本文件名字,查找的方式也是查看文件是否存在,这个时候将分离出SCRIPT_FILENAME和PATH_INFO分别为

/scripts/80sec.jpg和80sec.php

最后,以/scripts/80sec.jpg作为此次请求需要执行的脚本,攻击者就可以实现让nginx以php来解析任何类型的文件了。

POC: 访问一个nginx来支持php的站点,在一个任何资源的文件如robots.txt后面加上/80sec.php,这个时候你可以看到如下的区别:

访问http://www.80sec.com/robots.txt

HTTP/1.1 200 OK
Server: nginx/0.6.32
Date: Thu, 20 May 2010 10:05:30 GMT
Content-Type: text/plain
Content-Length: 18
Last-Modified: Thu, 20 May 2010 06:26:34 GMT
Connection: keep-alive
Keep-Alive: timeout=20
Accept-Ranges: bytes

访问访问http://www.80sec.com/robots.txt/80sec.php

HTTP/1.1 200 OK
Server: nginx/0.6.32
Date: Thu, 20 May 2010 10:06:49 GMT
Content-Type: text/html
Transfer-Encoding: chunked
Connection: keep-alive
Keep-Alive: timeout=20
X-Powered-By: PHP/5.2.6

其中的Content-Type的变化说明了后端负责解析的变化,该站点就可能存在漏洞。

漏洞厂商:http://www.nginx.org

解决方案:

我们已经尝试联系官方,但是此前你可以通过以下的方式来减少损失

关闭cgi.fix_pathinfo为0

或者

if ( $fastcgi_script_name ~ \..*\/.*php ) {
return 403;
}

PS: 鸣谢laruence大牛在分析过程中给的帮助

转自:http://www.80sec.com/nginx-securit.html


看过这篇文章,和同事讨论了一下,其中上文提到的解决方法2,实际上还是无法解决问题的。如果允许用户上传,最好还是在允许上传文件的程序中判断用户上传的文件类型,如:是否为text/xxx类型的文件,如果是则还需要再判断该文件中是否有可执行的php脚本。

针对解决方法1,不建议修改,其可能会影响正常程序的运行。

以下是我们的处理方法:限制uploads目录下的php程序执行

...
    location ~ ^/.+\.php(/.*)?$ {
      set $script    $fastcgi_script_name;

      if ($script ~* "^/uploads/.+"){
        return 404;
      }
...

测试目的

(1)弄清楚HTTP Upstream 模块中Server指令的max_failsfail_timeout参数的关系、它们对后端服务器健康情况的检查起到了什么作用、它们的取值对Http proxy模块中的其它指令是否有直接或间接的影响等……

(2)测试HTTP Proxy模块中proxy_next_upstream、proxy_connect_timeout、proxy_read_timeout、proxy_send_timeout指令的作用、对nginx性能的影响、对后端服务器响应的处理等……

测试方法

本文测试不会使用压力测试,所有的测试都是通过浏览器手动刷新来实现的。后端服务器使用简单的php程序来实现。

测试环境

Nginx负载均衡/反向代理服务器
系统:CentOS 5.4 64bit
Nginx:0.7.65
IP:192.168.108.10

后端web服务器
系统:CentOS 5.4 64bit
Web环境:apache+php
Web-1 IP:192.168.108.163
Web-2 IP:192.168.108.164

本次测试主要针对HTTP Upstream和HTTP Proxy模块进行,下面测试环境中http upstream 和http proxy模块参数的初始化设置,后文会针对测试的参数进行相应的修改:


upstream test  {
server 192.168.108.163 ;
server 192.168.108.164:80;
}

server {
listen          80;
server_name     .test.com;
index           index.php index.html index.htm;

location / {
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504 http_404;

proxy_connect_timeout       10s;
proxy_read_timeout          2s;
#proxy_send_timeout          10s;
proxy_pass http://test;
}
}

提出server指令后面的参数部分,以下摘抄nginx wiki 内容

语法:server name [parameters]

parameters包含:

·weight = NUMBER - 设置服务器权重,默认为1。

·max_fails = NUMBER - 在一定时间内(这个时间在fail_timeout参数中设置)检查这个服务器是否可用时产生的最多失败请求数,默认为1,将其设置为0可以关闭检查,这些错误在proxy_next_upstream或fastcgi_next_upstream(404错误不会使max_fails增加)中定义。

·fail_timeout = TIME - 在这个时间内产生了max_fails所设置大小的失败尝试连接请求后这个服务器可能不可用,同样它指定了服务器不可用的时间(在下一次尝试连接请求发起之前),默认为10秒,fail_timeout与前端响应时间没有直接关系,不过可以使用proxy_connect_timeout和 proxy_read_timeout来控制。

·down - 标记服务器处于离线状态,通常和ip_hash一起使用。

·backup - (0.6.7或更高)只用于本服务器,如果所有的非备份服务器都宕机或繁忙。

关于max_fails参数的理解根据上面的解释,max_fails默认为1,fail_timeout默认为10秒,也就是说,默认情况下后端服务器在10秒钟之内可以容许有一次的失败,如果超过1次则视为该服务器有问题,将该服务器标记为不可用。等待10秒后再将请求发给该服务器,以此类推进行后端服务器的健康检查。但如果我将max_fails设置为0,则代表不对后端服务器进行健康检查,这样一来fail_timeout参数也就没什么意义了。那若后端服务器真的出现问题怎么办呢?上文也说了,可以借助proxy_connect_timeout和proxy_read_timeout进行控制。

下面介绍http proxy模块中的相关指令:

proxy_next_upstream
语法: proxy_next_upstream [error|timeout|invalid_header|http_500|http_502|http_503|http_504|http_404|off]
确定在何种情况下请求将转发到下一个服务器。转发请求只发生在没有数据传递到客户端的过程中。

proxy_connect_timeout
后端服务器连接的超时时间_发起握手等候响应超时时间

proxy_read_timeout
连接成功后_等候后端服务器响应时间_其实已经进入后端的排队之中等候处理(也可以说是后端服务器处理请求的时间)

proxy_send_timeout
后端服务器数据回传时间_就是在规定时间之内后端服务器必须传完所有的数据

proxy_pass
这个指令设置被代理服务器的地址和被映射的URI

开始测试

情况1:后端程序执行时间超过或等于proxy_read_timeout设置值,max_fails=0 关闭后端服务器健康检查。

Nginx配置修改内容 server 192.168.108.163 max_fails = 0;
server 192.168.108.164 max_fails = 0;
proxy_next_upstream error timeout
proxy_read_timeout 2s
后端web服务器
Web1 test.php Web2 test.php
<?php
header('RS:Web1');
$t = 2;
sleep($t);
echo "sleep {$t}s<br>";
echo "web-1<br>";
?>
<?php
header('RS:Web2');
$t = 5;
sleep($t);
echo "sleep {$t}s<br>";
echo "web-2<br>";
?>
备注:

我这里的两台后端web服务器,他们的主页文件均为一个test.php程序,该程序分别sleep了2秒和5秒,等于和超过了proxy_read_timeout的时间,[max_fails=0] 即关闭后端服务器健康检查。[proxy_next_upstream error timeout] 说明碰到错误或超时的情况切到下一个后端服务器。如此设置后利用curl命令对nginx发起连接请求,看nginx会作何反应。

测试开始:

(1)curl -I -w %{time_total}:%{time_connect}:%{time_starttransfer} www.test.com/test.php
HTTP/1.1 504 Gateway Time-out
Server: nginx/0.7.65
Date: Tue, 18 May 2010 02:43:08 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 183
Connection: keep-alive

4.008:0.002:4.007

说明:

连续请求3次后得到的http返回结果是一样的,均为504 Gateway Time-out 错误。这种情况只有在后端服务器都有问题的时才会出现这个错误,很显然我这里的proxy_read_timeout设置的时间太短,后端程序还没来得及把程序执行完,nginx就迫不及待的将请求甩给upstream定义的另一台服务器上了,当发现另外一台服务器同样2秒没有返回后,nginx这回没有服务器可用,只有返回504 Gateway Time-out 。这也是为什么最后的time_total时间是4秒。(经查看两台web服务器的访问日志得知,均有一条访问记录,且返回代码为200,说明nginx确实来过,但没有等到执行完成就匆匆的离去了)如果我有3台服务器,在保证任何不变的情况下,time_total时间一定会是6秒,因为nginx会一个接一个的将3台服务器都走一遍。

-----------------------------------------------------------------------------------------------------------------------

好了,确认是我proxy_read_timeout设置时间太短后,我将它的值设置为3秒,再通过curl命令访问:

(2)curl -I -w %{time_total}:%{time_connect}:%{time_starttransfer} www.test.com/test.php
HTTP/1.1 200 OK
Server: nginx/0.7.65
Date: Tue, 18 May 2010 03:07:58 GMT
Content-Type: text/html; charset=UTF-8
Connection: keep-alive
Vary: Accept-Encoding
X-Powered-By: PHP/5.1.6
RS: Web1

5.042:0.005:5.042

说明:通过3次连续请求,得到的结果是一样的,RS:Web1 也就是说我这三次的请求都甩到了web1上。但我web1中的程序只需要2秒后就可以返回结果,但为什么我通过nginx代理后时间总是我的 程序执行时间+proxy_read_timeout时间呢?

-----------------------------------------------------------------------------------------------------------------------

继续将proxy_read_timeout设置为4s

(3)curl -I -w %{time_total}:%{time_connect}:%{time_starttransfer} www.test.com/test.php
HTTP/1.1 200 OK
Server: nginx/0.7.65
Date: Tue, 18 May 2010 03:15:25 GMT
Content-Type: text/html; charset=UTF-8
Connection: keep-alive
Vary: Accept-Encoding
X-Powered-By: PHP/5.1.6
RS: Web1

6.004:0.000:6.004

三次请求后结果也是一样,这次花的时间更长了,但确实是程序执行时间+proxy_read_timeout 时间。但为什么每次都需要6秒呢?按照upstream中定义的权重应该是平分请求的,最起码应该有2秒的时候。经过分析得知:最终返回给用户请求的是web1,那么当再次请求的时候一定会分给web2,由于web2是sleep 5秒的,因此经过proxy_read_timeout的时间(4s)后会跳到web1,结果还是web1返回的请求,所花时间就是nginx在web2等待的时间+web1执行的时间,以此类推下一次nginx自然的还会分给web2……。如果有更多的后端web,则判断下一个请求服务器可以看当前返回给最终用户的是那台服务器,然后根据upstream中定义的顺序向下查询(权重一样的情况)

结论:

(1)上面的三次测试分别将proxy_read_timeout的值设置为2s、3s、4s的情况进行的。最终的测试结果也都在后面做了解释与说明。由于我关闭了后端服务器的健康检查(max_fails=0)因此判断后端服务器情况的唯一依据便是proxy_read_timeout参数,如果这个参数设置得过小,但后端程序的执行或多或少会超过这个时间的话,这种情况nginx的效率是非常低的。

(2)上面的测试都是后端服务器正常但执行超时的情况下nginx根据proxy_read_timeout和proxy_next_upstream的值来选择下一个服务器,那如果我后端服务器直接报错的情况呢?可以想到如果报错信息在proxy_next_upstream 中有定义的话nginx还会跳到下一台服务器。否则直接将保存信息返回给nginx从而最终呈献给用户

情况2:打开后端服务器健康检查,测试程序执行时间超过或等于proxy_read_timeout值或后端服务器直接报错的情况

Nginx配置修改内容 server 192.168.108.163 max_fails = 1;
server 192.168.108.164 max_fails = 1;
proxy_next_upstream error timeout http_500 http_502 http_504
proxy_read_timeout 2s
后端web服务器
Web1 test.php Web2 test.php
<?php
header('RS:Web1');
$t = 2;
sleep($t);
echo "sleep {$t}s<br>";
echo "web-1<br>";
?>
<?php
header('RS:Web2');
header('http/1.1 500 Internal Server Error ');
#$t = 5;
#sleep($t);
echo "sleep {$t}s<br>";
echo "web-2<br>";
?>
备注:

开启了后端服务器健康检查
proxy_read_timeout 2s (下面会随着测试变更)
Web1程序仍然sleep 2s
修改了Web2程序,让他直接返回500错误

测试开始:

(1)连续测试三次结果如下:

curl -I -w %{time_total}:%{time_connect}:%{time_starttransfer} www.test.com/test.php
HTTP/1.1 504 Gateway Time-out
Server: nginx/0.7.65
Date: Tue, 18 May 2010 07:01:48 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 183
Connection: keep-alive

2.005:0.001:2.005

curl -I -w %{time_total}:%{time_connect}:%{time_starttransfer} www.test.com/test.php
HTTP/1.1 502 Bad Gateway
Server: nginx/0.7.65
Date: Tue, 18 May 2010 07:01:50 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 173
Connection: keep-alive

0.001:0.001:0.001

curl -I -w %{time_total}:%{time_connect}:%{time_starttransfer} www.test.com/test.php
HTTP/1.1 504 Gateway Time-out
Server: nginx/0.7.65
Date: Tue, 18 May 2010 07:01:57 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 183
Connection: keep-alive

2.005:0.001:2.005

说明:

第1次请求所用时间是2秒,web1执行超时,web2返回了500错误,upstream没有更多的后端,因此nginx直接把504扔出来了,同时标记web2,web1不可用。查看后端2台web服务器的访问日志,均有nginx代理的访问记录。
第2次请求时间很短,报502错误,说明没有可用的后端服务器接受请求。查看后端两台web服务器访问日志,没有任何变化,说明这两台服务器被nginx标记为不可用,没有把请求转向后端,直接返回用户502错误
第3次请求同第1次

(2)修改 proxy_read_timeout 3s 连续访问6次后结果以及2台web服务器的日志情况
curl -I -w %{time_total}:%{time_connect}:%{time_starttransfer} www.test.com/test.php
HTTP/1.1 200 OK
Server: nginx/0.7.65
Date: Tue, 18 May 2010 07:30:15 GMT
Content-Type: text/html; charset=UTF-8
Connection: keep-alive
Vary: Accept-Encoding
X-Powered-By: PHP/5.1.6
RS: Web1

2.003:0.001:2.002

访问日志

Web1
[18/May/2010:15:30:00
[18/May/2010:15:30:03
[18/May/2010:15:30:05
[18/May/2010:15:30:08
[18/May/2010:15:30:11
[18/May/2010:15:30:13

Web2

[18/May/2010:15:30:00
[18/May/2010:15:30:11

说明:

由访问日志可知:
第1次请求是被分到web2上的,由于它返回了500错误,因此请求被转到web1,并标记web2不可用。
第2次至第4次均将请求给了web1,第四次请求完毕后距第一请求已经过去了8秒。
第5次请求时已经是fail_timeout参数默认的10s也就是标记web2不可用的时间已经过去了,因此在第5次访问实际上和第一次情况是一样的。

结论:

(1proxy_next_upstream参数很有用,他可以避免很多错误
(2max_fails 参数在繁忙的大型系统中建议设置为3,如果没有几个后端服务器的话保持默认即可。
(3proxy_read_timeout要根据自身程序而定,不要过大,也不要太小。如果是php程序,请参照php.ini中的max_execution_time选项值。

原创文章,转载请注明:   转自 http://salogs.com

需求比标题复杂些,如下:

(1)在dns注册 *.test.com的域名指向一台服务器,如:210.87.12.5
(2)在这台服务器上,安装有web程序,该程序可以根据用户输入的二级域名跳转到该用户的产品主页
(3)对于非法的域名指向,进行rewrite处理(返回404错误,否则一经被查,断电处理)
(4)用户访问合法的域名但不是https连接的,跳转到https页面(即若是80端口则跳转到443端口)
(5)对于指定的二级域名,只准许某个(些)ip访问

针对各个需求作如下处理:

需求1:简单,在dns注册泛域名即可

需求2:纯粹的程序处理,略过

需求3:rewrite规则如下:

RewriteCond %{HTTP_HOST} !^abc|^apple|^banana|^demo\.test\.com [NC]
RewriteRule ^/$ default [R=404]

即:不是我上面列出的域名,其他的都返回404错误。这里注意每一项的前面都要加^

需求4:rewrite规则如下:

RewriteCond %{SERVER_PORT} !^443$
RewriteRule ^/?(.*)$ https://%{SERVER_NAME}%{REQUEST_URI} [L,R]

需求5:rewrite规则如下:

RewriteCond %{REMOTE_ADDR} !^124.11.12.141 [OR]
RewriteCond %{REMOTE_ADDR} !^124.11.12.142 [NC]
RewriteCond %{HTTP_HOST} ^abc\.test\.com [NC]
RewriteRule ^/$ default [R=404]

即:如果用户的ip不是124.11.12.141或124.11.12.142但却访问了 abc.jobkoo.com 则直接返回404错误,也就是说只有列出的ip可以访问。

注意:

(1)由于本机同时开放了80和443端口,因此在设置rewrite规则时需要在两端口的虚拟主机配置中同时添加。
(2)rewrite是有顺序的,我这里的顺序如下:

# 限制ip访问域名
RewriteCond %{REMOTE_ADDR} !^124.11.12.141 [OR]
RewriteCond %{REMOTE_ADDR} !^124.11.12.142 [NC]
RewriteCond %{HTTP_HOST} ^abc\.test\.com [NC]
RewriteRule ^/$  default [R=404]

# 拒绝非法域名指向
RewriteCond %{HTTP_HOST} !^abc|^apple|^banana|^demo\.test\.com [NC]
RewriteRule ^/$ default [R=404]

# 非443端口跳转
RewriteCond %{SERVER_PORT} !^443$
RewriteRule ^/?(.*)$ https://%{SERVER_NAME}%{REQUEST_URI} [L,R]

原创文章,转载请注明: 转自 http://salogs.com

最后更新于:2010年06月18日10:58

在配置多个SSL的虚拟主机的时候,很容易想当然的像配置普通HTTP虚拟主机一样,新建一个Virtualhost 后reload服务器。可用浏览器访问的时候,却提示证书为已经存在的某个虚拟主机的SSL证书,造成配置失败。
网上查询得知,一个普通的SSL证书是独占服务器端口。也就是说,如果Apache服务器上的虚拟主机A使用了SSL_A,并监听端口443,那即使新配置了虚拟主机B,如果虚拟主机是按照配置的,那用户访问时候读取的仍然是SSL_A。这和普通虚拟空间可以通过设置域名来区别虚拟主机是不同的。

要解决这个问题,实现一个Apache服务器上提供多个SSL虚拟主机,可以:

1、使用多域名SSL证书,可以实现一个IP,一个443端口上多个SSL虚拟主机;
为所有SSL虚拟主机配置单独的端口。比如,默认的虚拟主机使用443,其他的使用8080或8081等,且每个SSL虚拟主机必须独占一个端口;
2、为Apache服务器配置多个IP,每个SSL虚拟主机独占IP。如果只有一张物理网卡,可以配置为网卡配置子接口;
3、使用mod_gnutls模块,创建多个SSL虚拟主机

总之,Apache的SSL虚拟主机配置需要保证每个SSL虚拟主机有独立的IP:Port组合,如果不能提供这个条件,那只好多域名SSL证书了。