Showing posts with label Apache2. Show all posts
Showing posts with label Apache2. Show all posts

Saturday, July 02, 2011

Modifying the Query String In mod_rewrite of Apache2

RewriteRule backreferences: These are backreferences of the form $N (0 <= N <= 9), which provide access to the grouped parts (in parentheses) of the pattern, from the RewriteRule which is subject to the current set of RewriteCond conditions..
RewriteCond backreferences: These are backreferences of the form %N (1 <= N <= 9), which provide access to the grouped parts (again, in parentheses) of the pattern, from the last matched RewriteCond in the current set of conditions.

By default, the query string is passed through unchanged. You can, however, create URLs in the substitution string containing a query string part. Simply use a question mark inside the substitution string to indicate that the following text should be re-injected into the query string. When you want to erase an existing query string, end the substitution string with just a question mark. To combine new and old query strings, use the [QSA] flag.


# rewrite without old query string
RewriteCond %{QUERY_STRING} ^page_id=(.*)$
RewriteRule ^index.php$ /index/%1.php? [R=301,L]

# rewrite with new query string
RewriteCond %{QUERY_STRING} ^page_id=(.*)$
RewriteRule ^index.php$ /index/%1.php\?test=1 [R=301,L]

# rewrite with combined old query string
RewriteCond %{QUERY_STRING} ^page_id=(.*)$
RewriteRule ^index.php$ /index/%1.php\?test=1 [QSA,R=301,L]

Monday, May 24, 2010

在CentOS 5中开启apache2的mod_ssl模块

在配置完/etc/httpd/conf.d/ssl.conf文件之后,进行配置文件语法正确性测试时,报语法错误如下:
$> httpd -t
Syntax error on line 5 of /etc/httpd/conf.d/ssl.conf:
Invalid command 'SSLPassPhraseDialog', perhaps misspelled or defined by a module not included in the server configuration

移除ssl.conf文件之后,语法检查正确,列出httpd的模块检查:
$> httpd -M
Loaded Modules:
core_module (static)
mpm_prefork_module (static)
http_module (static)
so_module (static)
auth_basic_module (shared)
auth_digest_module (shared)
authn_file_module (shared)
authn_alias_module (shared)
authn_anon_module (shared)
authn_dbm_module (shared)
authn_default_module (shared)
authz_host_module (shared)
authz_user_module (shared)
authz_owner_module (shared)
authz_groupfile_module (shared)
authz_dbm_module (shared)
authz_default_module (shared)
ldap_module (shared)
authnz_ldap_module (shared)
include_module (shared)
log_config_module (shared)
logio_module (shared)
env_module (shared)
ext_filter_module (shared)
mime_magic_module (shared)
expires_module (shared)
deflate_module (shared)
headers_module (shared)
usertrack_module (shared)
setenvif_module (shared)
mime_module (shared)
dav_module (shared)
status_module (shared)
autoindex_module (shared)
info_module (shared)
dav_fs_module (shared)
vhost_alias_module (shared)
negotiation_module (shared)
dir_module (shared)
actions_module (shared)
speling_module (shared)
userdir_module (shared)
alias_module (shared)
rewrite_module (shared)
proxy_module (shared)
proxy_balancer_module (shared)
proxy_ftp_module (shared)
proxy_http_module (shared)
proxy_connect_module (shared)
cache_module (shared)
suexec_module (shared)
disk_cache_module (shared)
file_cache_module (shared)
mem_cache_module (shared)
cgi_module (shared)
version_module (shared)
proxy_ajp_module (shared)
Syntax OK

发现apache没有加载ssl_module,并且/etc/httpd/modules目录中无mod_ssl.so文件,需要在线安装:
$> yum search mod_ssl
mod_ssl.x86_64 : SSL/TLS module for the Apache HTTP server

$> yum install mod_ssl
Installed: mod_ssl.x86_64 1:2.2.3-43.el5.centos
Dependency Installed: distcache.x86_64 0:1.4.5-14.1
Updated: httpd.x86_64 0:2.2.3-43.el5.centos
Complete!

安装mod_ssl会增加一个用户类型,所以会修改/etc/passwd文件。
安装完成之后,修改ssl.conf文件,在文件顶部添加以下一行代码,加载ssl_module:

LoadModule ssl_module modules/mod_ssl.so
Listen 443
AddType application/x-x509-ca-cert .crt
AddType application/x-pkcs7-crl .crl
SSLPassPhraseDialog builtin
SSLSessionCache shmcb:/var/cache/mod_ssl/scache(512000)
SSLSessionCacheTimeout 300
SSLMutex default

<VirtualHost _default_:443>
DocumentRoot "/path/to/wwwroot"
ServerName www.test.com:443
ServerAdmin test.yu@gmail.com
SSLEngine on
SSLCipherSuite ALL:!ADH:!EXPORT:!SSLv2:RC4+RSA:+HIGH:+MEDIUM:+LOW
SSLCertificateFile /usr/local/apache2/conf/ssl.crt/server.crt
SSLCertificateKeyFile /usr/local/apache2/conf/ssl.key/server.key
SSLCACertificateFile /usr/local/apache2/conf/ssl.crt/cacertificate.crt
<FilesMatch "\.(cgi|shtml|phtml|php)$">
SSLOptions +StdEnvVars
</FilesMatch>
<Directory "/usr/local/apache2/cgi-bin">
SSLOptions +StdEnvVars
</Directory>
SetEnvIf User-Agent ".*MSIE.*" \
nokeepalive ssl-unclean-shutdown \
downgrade-1.0 force-response-1.0
</VirtualHost>
再测试httpd配置文件:
$> httpd -t
Syntax OK

Saturday, December 27, 2008

添加deflate gzip模块到apache2服务器

$> ./configure --prefix=/usr/local/apache2 --enable-so --enable-mods-shared=all --enable-modules=all
Configuring Apache Portable Runtime Utility library...

checking for APR-util... yes
configure: error: Cannot use an external APR-util with the bundled APR

如果编译过程中发现APR-util的错误,可以加上--with-included-apr这个参数,如下:
$> ./configure --prefix=/usr/local/apache2 --enable-so --enable-mods-shared=all --enable-modules=all --with-included-apr
$> make
$> cp ./modules/filters/.libs/mod_deflate.so /usr/local/apache2/modules
$> vi /usr/local/apache2/conf/httpd.conf
# append 2 line to httpd.conf
LoadModule deflate_module modules/mod_deflate.so
AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript application/x-json application/x-javascript
$> /usr/local/apache2/bin/apachectl graceful

更多关于deflate module的设置可参考官方说明:http://httpd.apache.org/docs/2.0/mod/mod_deflate.html

Reference:
http://yuweijun.blogspot.com/2007/09/apache22module.html

Monday, December 22, 2008

在ubuntu 8.10 上安装passenger 2.0.6

按照http://www.rubyenterpriseedition.com/download.html#ubuntu上的说明,在ubuntu8.10上安装passenger时报以下错误:
Welcome to the Phusion Passenger Apache 2 module installer, v2.0.6.

This installer will guide you through the entire installation process. It
shouldn't take more than 3 minutes in total.

Here's what you can expect from the installation process:

1. The Apache 2 module will be installed for you.
2. You'll learn how to configure Apache.
3. You'll learn how to deploy a Ruby on Rails application.

Don't worry if anything goes wrong. This installer will advise you on how to
solve any problems.

Press Enter to continue, or Ctrl-C to abort.

Checking for required software...

* GNU C++ compiler... found at /usr/bin/g++
* Ruby development headers... found
* OpenSSL support for Ruby... found
* RubyGems... found
* Rake... found at /opt/ruby-enterprise/bin/rake
* Apache 2... found at /usr/sbin/apache2
* Apache 2 development headers... found at /usr/bin/apxs2
* Apache Portable Runtime (APR) development headers... found at /usr/bin/apr-1-config
* Apache Portable Runtime Utility (APR) development headers... found at /usr/bin/apu-1-config
* fastthread... found
* rack... found
--------------------------------------------

--------------------------------------------
Compiling and installing Apache 2 module...
cd /opt/ruby-enterprise/lib/ruby/gems/1.8/gems/passenger-2.0.6
/opt/ruby-enterprise/bin/ruby -S rake clean apache2
/usr/bin/rake:27:in `require': no such file to load -- rake (LoadError)
from /usr/bin/rake:27

--------------------------------------------
It looks like something went wrong

Please read our Users guide for troubleshooting tips:

/opt/ruby-enterprise/lib/ruby/gems/1.8/gems/passenger-2.0.6/doc/Users guide.html

If that doesn't help, please use our support facilities at:

http://www.modrails.com/

We'll do our best to help you.

在/usr/bin/rake文件的27行前加上一句:
require 'rubygems'
重新运行passenger命令就可以正确安装上。
ubuntu 8.10中原来已经安装了ruby 1.8.7,与ruby-enterprise中的ruby版本不一样,需要在用户根目录下的.bashrc文件中调整一下PATH:
export PATH=/opt/ruby-enterprise/bin:$PATH

另外系统中sudo没有gem命令,需要加个软链接,这样才能用sudo安装gem包:
$> sudo ln -s /opt/ruby-enterprise/bin/gem /usr/bin/gem
(不要用sudo apt-get install rubygems 安装)

之后再生成二个文件:
$> sudo vi /etc/apache2/conf.d/rails
LoadModule passenger_module /opt/ruby-enterprise/lib/ruby/gems/1.8/gems/passenger-2.0.6/ext/apache2/mod_passenger.so
PassengerRoot /opt/ruby-enterprise/lib/ruby/gems/1.8/gems/passenger-2.0.6
PassengerRuby /opt/ruby-enterprise/bin/ruby
RailsEnv development
RailsDefaultUser test

$> sudo vi /etc/apache2/sites-enabled/rails_app
<VirtualHost *:80>
ServerName www.yourhost.com
DocumentRoot /somewhere/public
</VirtualHost>

重启apache2之后访问www.yourhost.com.

Saturday, October 11, 2008

Apache SSL证书请求文件(CSR)生成指南

1. 生成私钥 Generate the private key
$> openssl genrsa -des3 -out www.mydomain.com.key 1024
此命令将生成1024位的RSA私钥,私钥文件名为: www.mydomain.com.key,生成过程中会提示设定私钥密码,设置并备份密码,在以后安装证书到apache服务器之后,重启apache服务器时,需要输入此密码验证通过后才能启动!
2. 生成CSR文件 Generate the CSR
$> openssl req -new -key www.mydomain.com.key -out www.mydomain.com.csr
此命令将提示输入X.509证书所要求的字段信息,包括国家(中国添CN)、省份、所在城市、单位名称、单位部门名称(可以不填直接回车)。注意: 除国家缩写必须填CN外,其余都可以是英文或中文。
输入要申请SSL证书的域名,如果为www.domain.com申请SSL证书就不能只输入domain.com,要输入完整的域名,包括二级域名,SSL证书是严格绑定域名的。

Reference: http://www.wosign.com/support/CSRgen/Apache_CSR.htm

Tuesday, April 08, 2008

Apache2 mod_headers using to modify http response headers

将mod_headers.so复制到modules目录下,修改httpd.conf文件:

LoadModule headers_module modules/mod_headers.so
Header add P3P "CP=\"CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\""
Header set TEST "%D %t"

其中Header可添加在Context: server config, virtual host, directory, .htaccess
Reference: http://httpd.apache.org/docs/1.3/mod/mod_headers.html
http://httpd.apache.org/docs/2.2/mod/mod_headers.html

Thursday, March 13, 2008

Open openssl module for PHP5 in windows

Warning: SoapClient::SoapClient() [function.SoapClient-SoapClient]: I/O warning : failed to load external entity "http://localhost:9090/test?wsdl" in test.php on line 13

google了一下,是因为PHP的openssl模块没有打开。
修改php.ini文件,去掉extension=php_openssl.dll前面的注释。
将PHP安装目录下的libeay32.dll 拷贝一份到system32目录下,重启Apache即可。
如果不行可以把ssleay32.dll也拷过去重启。
完成后可以在phpinfo()中看到类似消息如下:
openssl
OpenSSL support enabled
OpenSSL Version OpenSSL 0.9.8e 23 Feb 2007

Wednesday, January 30, 2008

Why can't I use SSL with name-based/non-IP-based virtual hosts?


参考apache的文档


Why can't I use SSL with name-based/non-IP-based virtual hosts?

The reason is very technical, and a somewhat "chicken and egg" problem. The SSL protocol layer stays below the HTTP protocol layer and encapsulates HTTP. When an SSL connection (HTTPS) is established Apache/mod_ssl has to negotiate the SSL protocol parameters with the client. For this, mod_ssl has to consult the configuration of the virtual server (for instance it has to look for the cipher suite, the server certificate, etc.). But in order to go to the correct virtual server Apache has to know the Host HTTP header field. To do this, the HTTP request header has to be read. This cannot be done before the SSL handshake is finished, but the information is needed in order to complete the SSL handshake phase. Bingo!
Why is it not possible to use Name-Based Virtual Hosting to identify different SSL virtual hosts?

Name-Based Virtual Hosting is a very popular method of identifying different virtual hosts. It allows you to use the same IP address and the same port number for many different sites. When people move on to SSL, it seems natural to assume that the same method can be used to have lots of different SSL virtual hosts on the same server.

It comes as rather a shock to learn that it is impossible.

The reason is that the SSL protocol is a separate layer which encapsulates the HTTP protocol. So the SSL session is a separate transaction, that takes place before the HTTP session has begun. The server receives an SSL request on IP address X and port Y (usually 443). Since the SSL request does not contain any Host: field, the server has no way to decide which SSL virtual host to use. Usually, it will just use the first one it finds, which matches the port and IP address specified.

You can, of course, use Name-Based Virtual Hosting to identify many non-SSL virtual hosts (all on port 80, for example) and then have a single SSL virtual host (on port 443). But if you do this, you must make sure to put the non-SSL port number on the NameVirtualHost directive, e.g.

NameVirtualHost 192.168.1.1:80

Other workaround solutions include:

Using separate IP addresses for different SSL hosts. Using different port numbers for different SSL hosts.

相关的中文说明

为什么我不能在相同IP地址下多个域名的虚拟主机上使用SSL?

这个问题十分专业,有些像“先有鸡还是先有蛋”的问题。SSL协议层是在HTTP协议层的前面,当SSL连接建立时,SSL模块在Web模块之前和浏览器进行通讯并交换证书、建立加密隧道。众所周知,Web服务器是通过 HTTP数据包中的”Host”字段来区分虚拟主机的。而SSL模块在把服务器证书发送到浏览器时,还没有收到任何关于HTTP的数据包,更不知道虚拟主机的域名,因此SSL模块只能固定的将一张SSL证书发送到浏览器,而不能根据域名有选择性的发送证书。因此,您无法在一个IP地址的默认SSL 443端口下为多个虚拟主机配置多张证书。

由于一个IP与一个端口号只能对应一张证书,因此可以采用以下方式解决:

(1) 为需要SSL加密的虚拟主机配置不同的IP地址,端口号都使用443。例如: www.domain1.com 的SSL使用 202.96.101.1:443 www.domain2.com的SSL使用 202.96.101.2:443,通过 https://www.domain1.com 和 https://www.domain2.com 访问这2个SSL网站了

(2) 如果只有一个IP地址,可以为多个网站配置不同的SSL端口。例如: www.domain1.com 的SSL使用 202.96.101.1:443 www.domain2.com的SSL使用 202.96.101.1:1000,通过 https://www.domain1.com 和 https://www.domain2.com:1000 访问这2个SSL网站了

如果多个虚拟主机是1个主域名下的多个子域名,情况发生了转变,因为你可以申请通配符SSL证书。

例如: 有2个虚拟主机 abc.domain.com、xyz.domain.com,你申请一张 *.domain.com的证书,按照前面所说的原理,2个虚拟主机都使用同一个IP和默认的443端口,当浏览器访问IP:443端口时,SSL模块把通配符SSL证书传送给浏览器,建立合法的SSL隧道,然后WEB模块接收到HTTP数据包时判断域名选择虚拟主机。

原理是OK的,不幸的是你无法按照这个原理对IIS进行配置,早期的IIS不支持SSL端口配置域名。只有您使用Windows 2003,安装了Service Pack1后,才可以通过命令行为SSL端口配置域名,Apache是可以为SSL端口配置域名。您需要为所有的虚拟主机配置相同的通配符证书。就是说,我可以建立一个*.domain的域名证书,给所有的子域名来使用。

原文链接:http://wlx.westgis.ac.cn/421/

Wednesday, November 14, 2007

apache mod_usertrack 使用及其问题

为apache增加mod_usertrack module,只要动态生成一个so文件在配置文件里包括进来即可,之前有写了个文章关于这个操作过程。这次又用上了。

在虚拟主机的配置里再加上以下配置,其中具体的参数含义可参考此链接:http://httpd.apache.org/docs/1.3/mod/mod_usertrack.html


CookieTracking on
CookieStyle Cookie
CookieExpires "2 weeks"
CookieDomain .foo.bar
CustomLog logs/cookie-track.log "%{cookie}n %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\""
CookieName FOO_BAR

重启apache即可。
这个模块在Mozilla/Firefox中工作一切正常,而且可以做第3方的Cookie跟踪。
但是在IE(仅测试了IE6和IE7)中这个Cookie工作机制却类似于phpsessionid的工作机制,关闭IE重开之后却重新生了一个Cookie,如果不关则能正常记录用户的clickstream。但是从客户端查看HttpResponse则看得出来服务器端返回来的是正常的
请求,是让IE写个2周的Cookie,不过事实IE并不这样工作。至于用作第3方Cookie跟踪就更是不行,受P3P策略限制。

Friday, September 28, 2007

动态增加Apache2.2的Module

$shell > cd httpd-2.2.4
$shell > ./configure --prefix=/usr/local/apache2 --enable-so --enable-mods-shared=all --enable-modules=all
这里需要自己将需要enable的module一起列在configure中,如--enable-proxy --enable-proxy-http --enable-proxy-ftp等,才会生成对应的so文件
$shell > make
$shell > find . -name "*.so"
将找到的需要的so文件,复制到apache的modules目录下,然后修改http.conf文件,Load这些需要的Modules

Saturday, August 25, 2007

Control Apache from System Preferences in OSX

Filed under Mac

Here’s a cool way to control Apache (other than the included version) on OSX. Apache will also auto start on boot using this method.

First, add this line to your httpd.conf file:

PidFile /private/var/run/httpd.pid

Now, open up Terminal and type the following:

cd /usr/sbin
mv apachectl apachectl_bak
ln -s /usr/local/apache2/bin/apachectl apachectl

Now you can go to System Preferences->Sharing and start or stop Personal Web Sharing. Enjoy!

Tuesday, July 03, 2007

Installing eruby in Apache [programming ruby]

If you want to use erb-like page generation for a Web site that gets a reasonable amount
of traffic, you’ll probably want to switch across to using eruby, which has better per-
formance. You can then configure the Apache Web server to automatically parse Ruby-
embedded documents using eRuby, much in the same way that PHP does. You create
Ruby-embedded files with an .rhtml suffix and configure the Web server to run the
eruby executable on these documents to produce the desired HTML output.

To use eruby with the Apache Web server, you need to perform the following steps.
1. Copy the eruby binary to the cgi-bin directory.
2. Add the following two lines to httpd.conf.
AddType application/x-httpd-eruby .rhtml
Action application/x-httpd-eruby /cgi-bin/eruby
3. If desired, you can also add or replace the DirectoryIndex directive such that
it includes index.rhtml. This lets you use Ruby to create directory listings for
directories that do not contain an index.html. For instance, the following direc-
tive would cause the embedded Ruby script index.rhtml to be searched for and
served if neither index.html nor index.shtml existed in a directory.
DirectoryIndex index.html index.shtml index.rhtml
Of course, you could also simply use a sitewide Ruby script as well.
DirectoryIndex index.html index.shtml /cgi-bin/index.rb

Friday, June 01, 2007

Ruby On Rails With Apache and mod_proxy using .htaccess

If you want your rails app in the same apache html directory, use a .htaccess like this :

RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule (.*) http://localhost:3000/$1 [P]

Sunday, May 27, 2007

[mysql5.1 manual 3.8] 与Apache一起使用MySQL

还有一些项目,你可以从MySQL数据库鉴别用户,并且你还可以将日志文件写入MySQL数据库表。
你可以将以下内容放到Apache配置文件中,更改Apache日志格式,使MySQL更容易读取:

LogFormat \
"\"%h\",%{%Y%m%d%H%M%S}t,%>s,\"%b\",\"%{Content-Type}o\", \
\"%U\",\"%{Referer}i\",\"%{User-Agent}i\""
要想将该格式的日志文件装载到MySQL,你可以使用以下语句:

LOAD DATA INFILE '/local/access_log' INTO TABLE tbl_name
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' ESCAPED BY '\\'
所创建的表中的列应与写入日志文件的LogFormat行对应。

另外可以在apache2 http.conf里在日志记录时利用管道命令直接将apache2 access log写入mysql中,还有个apache2的module可以直接实现此功能:mod_log_mysql,具体到其网站上查看设置使用方法,这种直接将access log写入mysql中的方法个人认为不是很妥当,还是用日志循回,再将日志导入mysql中比较好。
也可以利用php, perl, ruby写个脚本分析access_log后写入mysql中。

上面提到将apache2 access log写入mysql中的3个方法,我个人还是觉得最后自己写个脚本导入日志到mysql中比较好。

Monday, April 23, 2007

Cronolog 设置定期轮循日志

http://cronolog.org/download/index.html
假设安装目录为:/usr/local/cronolog

cat access_log |/usr/local/cronolog/sbin/cronolog -p 12hours /home/test/%Y-%m-%d.log
无提示,正确在/home/test/目录下生成Log文件
cat access_log |/usr/local/cronolog/sbin/cronolog -p 13hours /home/test/%Y-%m-%d.log
提示:/usr/local/cronolog/sbin/cronolog: invalid explicit period specification ((null))
这个需要看一下Cronolog文档说明,如下:
-p PERIOD
--period=PERIOD
specifies the period explicitly as an optional digit string followed by one of units: seconds, minutes,
hours, days, weeks or months. The count cannot be greater than the number of units in the
next larger unit, i.e. you cannot specify "120 minutes", and for seconds, minutes and hours the
count must be a factor of the next higher unit, i.e you can specify 1, 2, 3, 4, 5, 6, 10, 15, 20 or 30
minutes but not say 7 minutes.

假设需要每4小时导出一次Log,则在http.conf里设置
CustomLog "|/usr/local/cronolog/sbin/cronolog -p 4hours /home/test/%Y-%m-%d-%H.log" common
注释原来的CustomLog那一行

Apache2.2 日志滚动和管道日志

http://lamp.linux.gov.cn/Apache/ApacheMenu/logs.html

即使一个并不繁忙的服务器,其日志文件的信息量也会很大,一般每10000个请求,访问日志就会增加1MB或更多。这就有必要定期滚动日志文件。由于Apache会保持日志文件的打开,并持续写入信息,因此服务器运行期间不能执行滚动操作。移动或者删除日志文件以后,必须重新启动服务器才能让它打开新的日志文件。

用优雅的(graceful)方法重新启动,可以使服务器启用新的日志文件,而不丢失原来尚未写入的信息。为此,有必要等待一段时间,让服务器完成正在处理的请求,并将记录写入到原来的日志文件。以下是一个典型的日志滚动和为节省存储空间而压缩旧日志的例子:

mv access_log access_log.old
mv error_log error_log.old
apachectl graceful
sleep 600
gzip access_log.old error_log.old

另一种执行滚动的方法是使用下一节阐述的管道日志。

管道日志
Apache httpd可以通过管道将访问记录和出错信息传递给另一个进程,而不是写入一个文件,由于无须对主服务器进行编程,这个功能显著地增强了日志的灵活性。只要用管道操作符"|"后面跟一个可执行文件名,就可以使这个程序从标准输入设备获得事件记录。Apache在启动时,会同时启动这个管道日志进程,并且在运行过程中,如果这个进程崩溃了,会重新启动这个进程(所以我们称这个技术为"可靠管道日志")。

管道日志进程由其父进程Apache httpd产生,并继承其权限,这意味着管道进程通常是作为root运行的,所以保持这个程序简单而安全极为重要。

管道日志的一种重要用途是,允许日志滚动而无须重新启动服务器。为此,服务器提供了一个简单的程序rotatelogs 。每24小时滚动一次日志的例子如下:

CustomLog "|/usr/local/apache/bin/rotatelogs /var/log/access_log 86400" common

注意:引号用于界定整个管道命令行。虽然这是针对访问日志的,但是其用法对于其他日志也一样。

在其他站点,有一个类似但更灵活的日志滚动程序叫cronolog 。

如果有较简单的离线处理日志的方案,就不应该使用条件日志和管道日志,即使它们非常强大。

Apache2.2条件日志

http://lamp.linux.gov.cn/Apache/ApacheMenu/logs.html

许多时候,根据与请求特征相关的环境变量来有选择地记录某些客户端请求会带来便利。首先,需要使用SetEnvIf指令来设置特定的环境变量以标识符合某种特定条件的请求,然后用CustomLog指令的 env= 子句,根据这些环境变量来决定记录或排除特定的请求。例如:

# 不记录本机发出的请求
SetEnvIf Remote_Addr "127\.0\.0\.1" dontlog
# 不记录对robots.txt文件的请求
SetEnvIf Request_URI "^/robots\.txt$" dontlog
# 记录其他请求
CustomLog logs/access_log common env=!dontlog

再如,将使用英语的请求记录到一个日志,而记录非英语的请求到另一个日志:

SetEnvIf Accept-Language "en" english
CustomLog logs/english_log common env=english
CustomLog logs/non_english_log common env=!english

虽然上述已经展示了条件日志记录的强大和灵活,但这不是控制日志内容的唯一手段,还可以用日志后继处理程序来剔除你不关心的内容,从而使日志更加有用。

多服务器的日志合并统计——apache日志的cronolog轮循

作者:车东 发表于:2003-04-12 11:04 最后更新于:2007-04-13 22:04
版权声明:可以任意转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本声明。
http://www.chedong.com/tech/rotate_merge_log.html
内容摘要:你完全不必耐心地看完下面的所有内容,因为结论无非以下2点:
1 用 cronolog 干净,安全地轮循apache日志
2 用 sort -m 合并排序多个日志

根据个人的使用经历:
1 先介绍apache日志的合并方法;
2 然后根据由此引出的问题说明日志轮循的必要性和解决方法,介绍如何通过cronolog对apache日志进行轮循;
中间有很多在设计日志合并过程中一些相关工具的使用技巧和一些尝试的失败经历……
我相信解决以上问题的路径不止这一条途径,以下方案肯定不是最简便或者说成本最低的,希望能和大家有更多的交流。


多服务器日志合并统计的必要性

越来越多大型的WEB服务使用DNS轮循来实现负载均衡:使用多个同样角色的服务器做前台的WEB服务,这大大方便了服务的分布规划和扩展性,但多个服务器的分布使得日志的分析统计也变得有些麻烦。如果使用webalizer等日志分析工具对每台机器分别做日志统计:
1 会对数据的汇总带来很多麻烦,比如:统计的总访问量需要将SERVER1 SERVER2...上指定月份的数字相加。
2 会大大影响统计结果中唯一访客数unique visits,唯一站点数unique sites的等指标的统计,因为这几个指标并非几台机器的代数相加。

统一日志统计所带来的好处是显而易见的,但如何把所有机器的统计合并到一个统计结果里呢?
首先也许会想:多个服务器能不能将日志记录到同一个远程文件里呢?我们不考虑使用远程文件系统记录日志的问题,因为带来的麻烦远比你获得的方便多的多……
因此,要统计的多个服务器的日志还是:分别记录=>并通过一定方式定期同步到后台=>合并=>后用日志分析工具来进行分析。

首先,要说明为什么要合并日志:因为webalizer没有将同一天的多个日志合并的功能
先后运行
webalizer log1
webalizer log2
webalizer log3
这样最后的结果是:只有log3的结果。

能不能将log1<<log2<<log3简单叠加呢?
因为一个日志的分析工具不是将日志一次全部读取后进行分析,而且流式的读取日志并按一定时间间隔,保存阶段性的统计结果。因此时间跨度过大(比如2条日志间隔超过5分钟),一些日志统计工具的算法就会将前面的结果“忘掉”。因此, log1<<log2<<log3直接文件连接的统计结果还是:只有log3的统计结果。

多台服务日志合并问题:把多个日志中的记录按时间排序后合并成一个文件

典型的多个日志文件的时间字段是这样的:
log1 log2 log3
00:15:00 00:14:00 00:11:00
00:16:00 00:15:00 00:12:00
00:17:00 00:18:00 00:13:00
00:18:00 00:19:00 00:14:00
14:18:00 11:19:00 10:14:00
15:18:00 17:19:00 11:14:00
23:18:00 23:19:00 23:14:00

日志合并必须是按时间将多个日志的交叉合并。合并后的日志应该是:
00:15:00 来自log1
00:15:00 来自log2
00:16:00 来自log1
00:17:00 来自log3
00:18:00 来自log2
00:19:00 来自log1
....

如何合并多个日志文件?
下面以标准的clf格式日志(apache)为例:
apche的日志格式是这样的:
%h %l %u %t \"%r\" %>s %b
具体的例子:
111.222.111.222 - - [03/Apr/2002:10:30:17 +0800] "GET /index.html HTTP/1.1" 200 419

最简单的想法是将日志一一读出来,然后按日志中的时间字段排序
cat log1 log2 log3 |sort -k 4 -t " "
注释:
-t " ": 日志字段分割符号是空格
-k 4: 按第4个字段排序,也就是:[03/Apr/2002:10:30:17 +0800] 这个字段
-o log_all: 输出到log_all这个文件中

但这样的效率比较低,要知道。如果一个服务已经需要使用负载均衡,其服务的单机日志条数往往都超过了千万级,大小在几百M,这样要同时对多个几百M的日志进行排序,机器的负载可想而之……
其实有一个优化的途径,要知道:即使单个日志本身已经是一个“已经按照时间排好序“的文件了,而sort对于这种文件的排序合并提供了一个优化合并算法:使用 -m merge合并选项,
因此:合并这样格式的3个日志文件log1 log2 log3并输出到log_all中比较好方法是:
sort -m -t " " -k 4 -o log_all log1 log2 log3
注释:
-m: 使用 merge优化算法

注意:合并后的日志输出最好压缩以后再发给webalizer处理
有的系统能处理2G的文件,有的不能。有的程序能处理大于2G的文件,有的不能。尽量避免大于2G的文件,除非确认所有参与处理的程序和操作系统都能处理这样的文件。所以输出后的文件如果大于2G,最好将日志gzip后再发给webalizer处理:大于2G的文件分析过程中文件系统出错的可能性比较大,并且gzip后也能大大降低分析期间的I/O操作。

日志的按时间排序合并就是这样实现的。

日志的轮循机制

让我们关心一下数据源问题:webalizer其实是一个按月统计的工具,支持增量统计:因此对于大型的服务,我可以按天将apache的日志合并后送给 webalizer统计。WEB日志是如何按天(比如每天子夜00:00:00)截断呢?
如果你每天使用crontab:每天0点准时将日志备份成access_log_yesterday
mv /path/to/apache/log/access_log /path/to/apache/log/access_log_yesterday
的话:你还需要:马上运行一下:apache restart 否则:apache会因为的日志文件句柄丢失不知道将日志记录到哪里去了。这样归档每天子夜重启apache服务会受到影响。
比较简便不影响服务的方法是:先复制,后清空
cp /path/to/apache/log/access_log /path/to/apache/log/access_log_yesterday
echo >/path/to/apache/log/access_log

严肃的分析员会这样做发现一个问题:
但cp不可能严格保证严格的0点截断。加入复制过程用了6秒,截断的access_log_yesterday日志中会出现复制过程到00:00:06期间的日志。对于单个日志统计这些每天多出来几百行日志是没有问题的。但对于多个日志在跨月的1天会有一个合并的排序问题:
[31/Mar/2002:59:59:59 +0800]
[31/Mar/2002:23:59:59 +0800]
[01/Apr/2002:00:00:00 +0800]
[01/Apr/2002:00:00:00 +0800]

要知道[01/Apr/2002:00:00:00 这个字段是不可以进行“跨天排序”的。因为日期中使用了dd/mm/yyyy,月份还是英文名,如果按照字母排序,很有可能是这样的结果:排序导致了日志的错误
[01/Apr/2002:00:00:00 +0800]
[01/Apr/2002:00:00:00 +0800]
[01/Apr/2002:00:00:00 +0800]
[01/Apr/2002:00:00:00 +0800]
[01/Apr/2002:00:00:00 +0800]
[01/Apr/2002:00:00:00 +0800]
[01/Apr/2002:00:00:00 +0800]
[31/Mar/2002:59:59:59 +0800]
[31/Mar/2002:59:59:59 +0800]
[31/Mar/2002:23:59:59 +0800]
[31/Mar/2002:59:59:59 +0800]
[31/Mar/2002:23:59:59 +0800]

这些跨天过程中的非正常数据对于webalizer等分析工具来说简直就好像是吃了一个臭虫一样,运行的结果是:它可能会把前一个月所有的数据都丢失!因此这样的数据会有很多风险出现在处理上月最后一天的数据的过程中。

问题的解决有几个思路:
1 事后处理:
。所以一个事后的处理的方法是:用grep命令在每月第1天将日志跨月的日志去掉,比如:
grep -v "01/Apr" access_log_04_01 > access_log_new

修改SORT后的日志:所有跨天的数据去掉。也许对日志的事后处理是一个途径,虽然sort命令中有对日期排序的特殊选项 -M(注意是:大写M),可以让指定字段按照英文月份排序而非字母顺序,但对于apache日志来说,用SORT命令切分出月份字段很麻烦。(我尝试过用 "/"做分割符,并且使用“月份” “年:时间”这两个字段排序)。虽然用一些PERL的脚本肯定可以实现,但最终我还是放弃了。这不符合系统管理员的设计原则:通用性。并且你需要一直问自己:有没有更简单的方法呢?
还有就是将日志格式改成用TIMESTAMP(象SQUID的日志就没有这个问题,它的日志本身就是使用TIMESTAMP做时间时间戳的),但我无法保证所有的日志工具都能识别你在日期这个字段使用了特别的格式。

2 优化数据源:
最好的办法还是优化数据源。将数据源保证按天轮循,同一天的日志中的数据都在同一天内。这样以后你无论使用什么工具(商业的,免费的)来分析日志,都不会因为日志复杂的预处理机制受到影响。

首先可能会想到的是控制截取日志的时间:比如严格从0点开始截取日志,但在子夜前1分钟还是后一分钟开始截取是没有区别的,你仍然无法控制一个日志中有跨 2天记录的问题,而且你也无法预测日志归档过程使用的时间。
因此必须要好好考虑一下使用日志轮循工具的问题,这些日志轮循工具要符合:
1 不中断WEB服务:不能停apache=>移动日志=>重启apache
2 保证同一天日志能够按天轮循:每天一个日志00:00:00-23:59:59
3 不受apache重启的影响:如果apache每次重启都会生成一个新的日志是不符合要求的
4 安装配置简单

首先考虑了apache/bin目录下自带的一个轮循工具:rotatelogs 这个工具基本是用来按时间或按大小控制日志的,无法控制何时截断和如何按天归档。
然后考虑logrotate后台服务:logrotate是一个专门对各种系统日志(syslogd,mail)进行轮循的后台服务,比如SYSTEM LOG,但其配置比较复杂,放弃,实际上它也是对相应服务进程发出一个-HUP重启命令来实现日志的截断归档的。

在apache的FAQ中,推荐了经过近2年发展已经比较成熟的一个工具cronolog:安装很简单:configure=>make=> make install

他的一个配置的例子会让你了解它有多么适合日志按天轮循:对httpd.conf做一个很小的修改就能实现:
TransferLog "|/usr/sbin/cronolog /web/logs/%Y/%m/%d/access.log"
ErrorLog "|/usr/sbin/cronolog /web/logs/%Y/%m/%d/errors.log"

然后:日志将写入
/web/logs/2002/12/31/access.log
/web/logs/2002/12/31/errors.log
午夜过后:日志将写入
/web/logs/2003/01/01/access.log
/web/logs/2003/01/01/errors.log
而2003 2003/01 和 2003/01/01 如果不存在的话,将自动创建

所以,只要你不在0点调整系统时间之类的话,日志应该是完全按天存放的(00:00:00-23:59:59),后面日志分析中: [31/Mar/2002:15:44:59这个字段就和日期无关了,只和时间有关。

测试:考虑到系统硬盘容量,决定按星期轮循日志
apache配置中加入:
#%w weekday
TransferLog "|/usr/sbin/cronolog /path/to/apache/logs/%w/access_log"

重启apache后,除了原来的CustomLog /path/to/apche/logs/access_log继续增长外,系统log目录下新建立了 3/目录(测试是在周3),过了一会儿,我忽然发现2个日志的增长速度居然不一样!
分别tail了2个日志才发现:
我设置CustomLog使用的是combined格式,就是包含(扩展信息的),而TransferLog使用的是缺省日志格式,看了apache的手册才知道,TransferLog是用配置文件中离它自己最近的一个格式作为日志格式的。我的httpd.conf里写的是:
LogFormat ..... combined
LogFormat ... common
...
CustomLog ... combined
TransferLog ...

所以TrasferLog日志用的是缺省格式,手册里说要让TRANSFER日志使用指定的格式需要:
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\""
TransferLog "|/usr/local/sbin/cronolog /path/to/apache/logs/%w/access_log"

重启,OK,日志格式一样了。
这样的设置结果其实是同时在logs目录下分别记录2个日志access_log和%w/access_log,能不能只记录%w/下的日志那?
查apache手册,更简单的方法:直接让CustomLog输出到cronolog归档日志,并且还能指定格式。
CustomLog "|/usr/local/sbin/cronolog /path/to/apache/logs/%w/access_log" combined

最后是一个日志同步的问题。

任务:每天凌晨找到前1天的日志,另存一个文件准备发送到服务器上。
比如我要保留前1周的日志:每天复制前1天的日志到指定目录,等待日志服务器来抓取:
/bin/cp -f /path/to/apache/logs/`date -v-1d +%w`/access_log /path/for/backup/logs/access_log_yesterday

在FREEBSD上使用以下命令
date -v-1d +%w
注释:
-v-1d: 前1天,而在GNU/Linux上这个选项应该是date -d yesterday
+%w: weekday,由于使用的都是标准时间函数库,所有工具中的WEEKDAY定义都是一样的 0-6 => 周日-周六

注意:
写到CRONTAB里的时候"%"前面需要加一个"\"转义:每天0点5分进行一次日志归档,
另外一个问题就是在cront中需要用:rm -f {} ; 而不是rm -f {}\;
5 0 * * * /bin/cp /path/to/logs/`date -v-1d +\%w`/access_log /path/to/for_sync/logs/access_yesterday
37 10 * * * /usr/bin/find /home/apache/logs/ -name access_log -mtime +1 -exec /bin/rm -f {} ;

首次开始cronolog日志统计是周3,一周以后日志又将轮循回3/access_log
但这次日志是追加到3/access_log还是重新创建一个文件呢?>>access_log or >access_log?
我测试的结果是日志将被追加:
[01/Apr/2002:23:59:59 +0800]
[01/Apr/2002:23:59:59 +0800]
[08/Apr/2002:00:00:00 +0800]
[08/Apr/2002:00:00:00 +0800]

肯定是不希望每次日志还带着上周的数据的并重复统计一次的(虽然对结果没影响),而且这样%w/下的日志不是也越来越多了吗?
解决方法1 把每天的cp改成mv
解决方法2 每天复制完成后:删除6天以前的access_log日志
find /path/to/apache/logs -name access_log -mtime +6 -exec rm -f {}\;
多保留几天的日志还是有必要的:万一日志分析服务器坏了一天呢?

以下是把apache安装在/home/apache下每天统计的一个脚本文件:
#!/bin/sh

#backup old log
/bin/cp -f /home/apache/logs/`date -d yesterday +%w`/access_log /home/apache/logs/access_log_yesterday

#remove old log
/usr/bin/find /home/apache/logs -name access_log -mtime +6 -exec rm -f {}\;

#analysis with webalizer
/usr/local/sbin/webalizer

总结:
1 用 cronolog 干净,安全地轮循日志
2 用 sort -m 排序合并多个日志


参考资料:

日志分析统计工具:
http://directory.google.com/Top/Computers/Software/Internet/Site_Management/Log_Analysis/

Apche的日志设置:
http://httpd.apache.org/docs/mod/mod_log_config.html

Apache的日志轮循:
http://httpd.apache.org/docs/misc/FAQ.html#rotate

Cronolog
http://www.cronolog.org

Webalizer
http://www.mrunix.net/webalizer/
Webalzer的Windows版
http://www.medasys-lille.com/webalizer/

AWStats的使用简介
http://www.chedong.com/tech/awstats.html

Sunday, April 22, 2007

JMETER 命令行运行及JTL的LOG查看

Jmeter full list of command-line options

Invoking JMeter as "jmeter -?" will print a list of all the command-line options. These are shown below.


-h, --help
print usage information and exit
-v, --version
print the version information and exit
-p, --propfile {argument}
the jmeter property file to use
-q, --addprop {argument}
additional property file(s)
-t, --testfile {argument}
the jmeter test(.jmx) file to run
-l, --logfile {argument}
the file to log samples to
-n, --nongui
run JMeter in nongui mode
-s, --server
run the JMeter server
-H, --proxyHost {argument}
Set a proxy server for JMeter to use
-P, --proxyPort {argument}
Set proxy server port for JMeter to use
-u, --username {argument}
Set username for proxy server that JMeter is to use
-a, --password {argument}
Set password for proxy server that JMeter is to use
-J, --jmeterproperty {argument}={value}
Define additional JMeter properties
-D, --systemproperty {argument}={value}
Define additional System properties
-S, --systemPropertyFile {filename}
a property file to be added as System properties
-L, --loglevel {argument}={value}
Define loglevel: [category=]level
e.g. jorphan=INFO or jmeter.util=DEBUG
-r, --runremote
Start remote servers from non-gui mode
-d, --homedir {argument}
the jmeter home directory to use

C:\jmeter\bin>jmeter -n -t test.jmx -l test.jtl
Created the tree successfully
Starting the test
Tidying up ...
... end of run

上面的jmx文件是用Jmeter控制台生成的。详见官方文档:http://wiki.apache.org/jakarta-jmeter/UserManual/BuildWebTest
命令行运行后生成jtl的LOG文件之后需要在Jmeter控制台里任意添加一个 Listener ,然后点击“Browse” 按钮,选择要查看的 jtl 文件。不过中文看到的"HTTP请求"这里的中文字乱码了。

Saturday, April 21, 2007

ab - Apache HTTP server benchmarking tool

ab is a tool for benchmarking your Apache Hypertext Transfer Protocol (HTTP) server. It is designed to give you an impression of how your current Apache installation performs. This especially shows you how many requests per second your Apache installation is capable of serving.

Usage: ab [options] [http://]hostname[:port]/path
Options are:
-n requests Number of requests to perform
-c concurrency Number of multiple requests to make
-t timelimit Seconds to max. wait for responses
-p postfile File containing data to POST
-T content-type Content-type header for POSTing
-v verbosity How much troubleshooting info to print
-w Print out results in HTML tables
-i Use HEAD instead of GET
-x attributes String to insert as table attributes
-y attributes String to insert as tr attributes
-z attributes String to insert as td or th attributes
-C attribute Add cookie, eg. 'Apache=1234. (repeatable)
-H attribute Add Arbitrary header line, eg. 'Accept-Encoding: gzip'
Inserted after all normal header lines. (repeatable)
-A attribute Add Basic WWW Authentication, the attributes
are a colon separated username and password.
-P attribute Add Basic Proxy Authentication, the attributes
are a colon separated username and password.
-X proxy:port Proxyserver and port number to use
-V Print version number and exit
-k Use HTTP KeepAlive feature
-d Do not show percentiles served table.
-S Do not show confidence estimators and warnings.
-g filename Output collected data to gnuplot format file.
-e filename Output CSV file with percentages served
-h Display usage information (this message)

Example:
ab -c 5 -n 200 http://www.test.com/

Results:
This is ApacheBench, Version 2.0.40-dev <$Revision: 1.146 $> apache-2.0
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Copyright 2006 The Apache Software Foundation, http://www.apache.org/

Benchmarking www.test.com (be patient)
Completed 100 requests
Finished 200 requests


Server Software: Apache/2.2.3
Server Hostname: www.test.com
Server Port: 80

Document Path: /
Document Length: 10087 bytes

Concurrency Level: 5
Time taken for tests: 65.31250 seconds
Complete requests: 200
Failed requests: 155
(Connect: 0, Length: 155, Exceptions: 0)
Write errors: 0
Non-2xx responses: 200
Total transferred: 2102126 bytes
HTML transferred: 2017726 bytes
Requests per second: 3.08 [#/sec] (mean)
Time per request: 1625.781 [ms] (mean)
Time per request: 325.156 [ms] (mean, across all concurrent requests)
Transfer rate: 31.55 [Kbytes/sec] received

Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 2.4 0 15
Processing: 687 1611 418.0 1515 3171
Waiting: 671 1599 417.0 1500 3156
Total: 687 1611 418.0 1515 3171

Percentage of the requests served within a certain time (ms)
50% 1515
66% 1593
75% 1640
80% 1703
90% 2109
95% 2921
98% 3078
99% 3125
100% 3171 (longest request)