Apache 是一款使用量排名第一的 web 服务器,LAMP 中的 A 指的就是它。由于其开源、稳定、安全等特性而被广泛使用。前边的一篇文章中已经记录过如何搭建 LAMP 架构,搭建仅是第一步,其中最为重要的就是 Apache 服务,也是 LAMP 的核心。下边记录了使用 Apache 以来经常用到的功能。
一、Apache的三种工作模式
Apache 一共有3种稳定的 MPM 模式(多进程处理模块),它们分别是 prefork、worker、event。http-2.2版本的httpd默认的mpm工作模式为prefork,2.4版本的httpd默认是event工作模式。可以通过 httpd -V 来查看。
[root@linuxblogs ~]# httpd -V | grep -i "server mpm" Server MPM: Prefork
编译的时候,可以通过 configure 的参数来指定:
--with-mpm=prefork|worker|event
1、prefork 工作模式Apache在启动之初,就预先fork一些子进程,然后等待请求进来。之所以这样做,是为了减少频繁创建和销毁进程的开销。每个子进程只有一个线程,在一个时间点内,只能处理一个请求。优点:成熟稳定,兼容所有新老模块。同时,不需要担心线程安全的问题。缺点:一个进程相对占用更多的系统资源,消耗更多的内存。而且,它并不擅长处理高并发请求。2、worker 工作模式使用了多进程和多线程的混合模式。它也预先fork了几个子进程(数量比较少),然后每个子进程创建一些线程,同时包括一个监听线程。每个请求过来,会被分配到1个线程来服务。线程比起进程会更轻量,因为线程通常会共享父进程的内存空间,因此,内存的占用会减少一些。在高并发的场景下,因为比起prefork有更多的可用线程,表现会更优秀一些。优点:占据更少的内存,高并发下表现更优秀。缺点:必须考虑线程安全的问题。3、event 工作模式它和worker模式很像,最大的区别在于,它解决了keep-alive场景下,长期被占用的线程的资源浪费问题。event MPM中,会有一个专门的线程来管理这些keep-alive类型的线程,当有真实请求过来的时候,将请求传递给服务线程,执行完毕后,又允许它释放。这样增强了高并发场景下的请求处理能力。 HTTP采用keepalive方式减少TCP连接数量,但是由于需要与服务器线程或进程进行绑定,导致一个繁忙的服务器会消耗完所有的线程。Event MPM是解决这个问题的一种新模型,它把服务进程从连接中分离出来。在服务器处理速度很快,同时具有非常高的点击率时,可用的线程数量就是关键的资源限 制,此时Event MPM方式是最有效的,但不能在HTTPS访问下工作。
二、Apache的用户认证
有时候,我们需要给一些特殊的访问设置一个用户认证机制,增加安全。比如我们的个人网站,一般都是有一个管理后台的,虽然管理后台本身就有密码,但我们为了更加安全,可以再设置一层用户认证。1、编辑配置文件
vim /usr/local/apache2/conf/extra/httpd-vhosts.conf
在对应的虚拟主机配置中加入如下配置:(加粗部分是添加内容)
<VirtualHost *:80> DocumentRoot "/usr/local/apache2/htdocs" ServerName www.123.com ServerAlias www.abc.com <Directory /usr/local/apache2/htdocs/admin.php> AllowOverride AuthConfig AuthName "Please input you acount." AuthType Basic AuthUserFile /usr/local/apache2/htdocs/.htpasswd require valid-user </Directory> </VirtualHost>
说明:首先指定要对哪个目录进行验证,AuthName自定义,AuthUserFile指定用户密码文件在哪里。2、创建加密用的用户名和密码文件
htpasswd -c /usr/local/apache2/htdocs/.htpasswd liwei htpasswd -m /usr/local/apache2/htdocs/.htpasswd admin
创建第一个用户时-c选项创建.htpasswd文件,-m选项增加用户,根据提示输入密码。3、重启apache服务
apachectl -t apachectl graceful
先检查配置是否正确,然后用graceful相当于是reload配置,不用重启apache服务,效果一样。测试,通过浏览器输入 www.123.com/admin.php 提示输入密码。
三、设置默认虚拟主机
默认虚拟主机就是配置文件里的第一个虚拟主机。关于默认虚拟主机有个特点,凡是解析到这台服务器的域名,不管是什么域名,只要在配置文件中没有配置,那么都会访问到这个主机上来。如果我们直接用IP访问,会访问到这个站点上来。为了避免别人乱解析,所以应该把默认也就是第一个虚拟主机给禁止掉。我们使用allow,deny语句,已经禁止掉了。1、配置默认虚拟主机
vim /usr/local/apache2/conf/extra/httpd-vhosts.conf
添加一个虚拟主机的记录:
<VirtualHost *:80> DocumentRoot "/var/123" ServerName xxxxx.com.cn <Directory /var/123> Order allow,deny Deny from all </Directory> </VirtualHost>
创建/var/123目录,并且设置600权限,daemon用户无法访问:
mkdir /var/123 chmod -R 600 /var/123
2、重启apache服务器
apachectl -t apachectl graceful
如果用IP或其它解析的域名访问,发现提示:
Forbidden You don't have permission to access / on this server.
四、域名301跳转一个站点难免会有多个域名,而多个域名总得有一个主次,比如我的网站可以用两个域名访问:www.itepub.cn 和 www.linuxblogs.cn 但大家发现不管我用哪个域名访问,最终都会跳转到www.linuxblogs.con 上来。这个行为就叫做域名跳转,这里的301只是一个状态码,跳转除了301还有302,301是永久跳转,302 是临时跳转,网站上一定要设置为301,这样对搜索引擎是比较友好的。1、配置域名跳转
# vim /usr/local/apache2/conf/extra/httpd-vhosts.conf <IfModule mod_rewrite.c> RewriteEngine on RewriteCond %{HTTP_HOST} ^www.abc.com$ RewriteRule ^/(.*)$ http://www.123.com/$1 [R=301,L] </IfModule>
配置为:当访问aaa时,跳转到123的网站。2、配置多个域名跳转
<IfModule mod_rewrite.c> RewriteEngine on RewriteCond %{HTTP_HOST} ^www.abc.com$ [OR] RewriteCond %{HTTP_HOST} ^www.abcd.com$ RewriteRule ^/(.*)$ http://www.123.com/$1 [R=301,L] </IfModule>
3、重启服务器并测试
apachectl -t apachectl graceful
测试:
# curl -x192.168.0.8:80 www.abc.com -I HTTP/1.1 301 Moved Permanently Date: Tue, 25 Oct 2016 15:48:10 GMT Server: Apache/2.2.31 (Unix) PHP/5.5.38 Location: http://www.123.com/
# curl -x192.168.0.8:80 www.abcd.com -I HTTP/1.1 301 Moved Permanently Date: Tue, 25 Oct 2016 15:48:49 GMT Server: Apache/2.2.31 (Unix) PHP/5.5.38 Location: http://www.123.com/ Content-Type: text/html; charset=iso-8859-1
通过上述测试,发现无论是abc或abcd都可以跳转到 www.123.com 域名上来,通过浏览器访问也一样。
五、Apache日志切割
我们每访问一次网站,那么就会记录若干条日志。当然前提是已经设置了日志,日志不去管理,时间长了日志文件会越来越大,如何避免产生这么大的日志文件?其实apache有相关的配置,使日志按照我们的需求进行归档,比如每天一个新日志,或者每小时一个新的日志。1、首先简单设置日志的路径名称
vim /usr/local/apache2/conf/extra/httpd-vhosts.conf
编辑添加内容如下:
ErrorLog "logs/error.log" CustomLog "logs/access.log" combined
指定了日志存放在/usr/local/apache2/logs目录下分别为error.log和access.log,combined为日志显示的格式,日志格式可以参考配置文件httpd.conf中格式的指定,如下:
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined LogFormat "%h %l %u %t \"%r\" %>s %b" common
2、设置apache日志分割同样编辑配置文件httpd-vhosts.conf
ErrorLog "|/usr/local/apache2/bin/rotatelogs -l /usr/local/apache2/logs/aaa-error_%Y%m%d.log 86400" CustomLog "|/usr/local/apache2/bin/rotatelogs -l /usr/local/apache2/logs/aaa-access_%Y%m%d.log 86400" combined
ErrorLog是错误日志,CustomLog是访问日志。|就是管道符,意思是把产生的日志交给rotatelog这个工具,而这个工具就是apache自带的切割日志的工具。-l的作用是校准时区为UTC,也就是北京时间。86400,单位是秒,正好是一天,那么日志会每天切割一次。而最后面的combined为日志的格式,在httpd.conf中有定义。
六、不记录指定文件类型的日志
如果一个网站访问量特别大,那么访问日志就会很多,但有一些访问日志我们其实是可以忽略掉的,比如网站的一些图片,还有js、css等静态对象。而这些文件的访问往往是巨量的,而且即使记录这些日志也没有什么用,那么如何忽略不记录这些日志呢?1、配置日志不记录图片的访问
vim /usr/local/apache2/conf/extra/httpd-vhosts.conf
相关配置为:
SetEnvIf Request_URI ".*\.gif$" image-request SetEnvIf Request_URI ".*\.jpg$" image-request SetEnvIf Request_URI ".*\.png$" image-request SetEnvIf Request_URI ".*\.bmp$" image-request SetEnvIf Request_URI ".*\.swf$" image-request SetEnvIf Request_URI ".*\.js$" image-request SetEnvIf Request_URI ".*\.css$" image-request CustomLog "|/usr/local ... _%Y%m%d.log 86400" combined env=!image-request
说明:在原来日志配置基础上,增加了一些image-request的定义,比如把gif、jpg、bmp、swf、js、css等结尾的全标记为image-request,然后在配置日志后加一个标记env=!image-request,表示取反。
七、Apache配置静态缓存
所说的静态文件指的是图片、js、css等文件,用户访问一个站点,其实大多数元素都是图片、js、css等,这些静态文件其实是会被客户端的浏览器缓存到本地电脑上的,目的就是为了下次再请求时不再去服务器上下载,这样就加快了速度,提高了用户体验。但这些静态文件总不能一直缓存,它总有一些时效性,那么就得设置这个过期时间。1、配置静态缓存
# vim /usr/local/apache2/conf/extra/httpd-vhosts.conf <IfModule mod_expires.c> ExpiresActive on ExpiresByType image/gif "access plus 1 days" ExpiresByType image/jpeg "access plus 24 hours" ExpiresByType image/png "access plus 24 hours" ExpiresByType text/css "now plus 2 hour" ExpiresByType application/x-javascript "now plus 2 hours" ExpiresByType application/javascript "now plus 2 hours" ExpiresByType application/x-shockwave-flash "now plus 2 hours" ExpiresDefault "now plus 0 min" </IfModule>
或者使用 mod_headers 模块实现:
<IfModule mod_headers.c> # htm,html,txt 类的文件缓存一个小时 <filesmatch "\.(html|htm|txt)$"> header set cache-control "max-age=3600" </filesmatch> # css, js, swf 类的文件缓存一个星期 <filesmatch "\.(css|js|swf)$"> header set cache-control "max-age=604800" </filesmatch> # jpg,gif,jpeg,png,ico,flv,pdf 等文件缓存一年 <filesmatch "\.(ico|gif|jpg|jpeg|png|flv|pdf)$"> header set cache-control "max-age=29030400" </filesmatch> </IfModule>
说明:这里的时间单位可以 days、 hours 甚至是 min,两种不同的方法,上面使用的是mod_expires,而下面用的是 mod_headers,要想使用这些模块,必须要事先已经支持。如何查看是否支持,使用命令:
# /usr/local/apache2/bin/apachectl -M
2、重启服务器并验证
apachectl -t apachectl graceful
验证:
# curl -x127.0.0.1:80 'http://www.123.com/static/image/common/online_admin.gif' -I HTTP/1.1 200 OK Date: Wed, 26 Oct 2016 03:51:26 GMT Server: Apache/2.2.31 (Unix) PHP/5.5.38 Last-Modified: Tue, 31 May 2016 03:08:36 GMT ETag: "46891b-16b-5341ab0597500" Accept-Ranges: bytes Content-Length: 363 Cache-Control: max-age=86400 Expires: Thu, 27 Oct 2016 03:51:26 GMT Content-Type: image/gif
八、Apache配置防盗链
如果你的网站有很多漂亮的图片,比如你网站域名 www.123.com,图片地址为 www.123.com/image/111.jpg,那么其它人就可以直接把这个地址放到他自己的网站上,他的用户可以直接从他网站查看这张图片,而实际图片是从你的网站访问的,所产生的带宽消耗对你没有任何意义,应该对这些图片限制一下,凡是在第三方站点上,严禁访问你站点的图片,如何配置呢?1、配置防盗链
# vim /usr/local/apache2/conf/extra/httpd-vhosts.conf SetEnvIfNoCase Referer "^http://.*\.123\.com" local_ref SetEnvIfNoCase Referer ".*\.abc\.com" local_ref SetEnvIfNoCase Referer "^$" local_ref <filesmatch "\.(txt|doc|mp3|zip|rar|jpg|gif)"> Order Allow,Deny Allow from env=local_ref </filesmatch>
说明:在这段配置中涉及到一个名词referer,其实就是上次访问的网站链接。配置referer是根据来源链接做限制的,如果来源链接不是我们想要的,就直接拒绝,这就是防盗链的原理。当然不止是图片,mp3、rar、zip等文件同样支持。上述配置中默认是除了定义的列表中的referer,其它都拒绝。
九、Apache访问控制
其实我们可以对apache的访问进行控制,可以设置白名单或黑名单。前面更改httpd.conf时候就已经看到了allow,deny这两个关键词,先来看看allow和deny的规则。1、举例1
Order deny,allow deny from all allow from 127.0.0.1
我们的判断依据是这样的:
看Order后面的,哪个在前,哪个在后
如果deny在前,那么就需要看deny from这句,然后看allow from这句
规则是一条一条匹配的,不管是deny在前还是allow在前,都会生效的。
2、举例2
Order allow,deny deny from all allow from 127.0.0.1
这个就会deny所有了,127.0.0.1也会被deny。因为顺序是先allow然后deny,虽然开始allow了127,但是后面又拒绝了它。3、举例3
Order allow,deny deny from all
上面的规则就表示,全部都不能通过。4、举例4
Order deny,allow deny from all 上面的规则表示,全部都不能通。 Order deny,allow 只有顺序,没有具体规则,表示全部都可以通行(默认的),因为allow在最后了。 Order allow,deny 这个表示,全部都不能通行(默认的),因为deny在最后。
5、针对某个目录限制比如这个目录很重要,只允许我们公司的IP访问,当然这个目录可以是网站根目录,也就是整个站点。
<Directory /usr/local/apache2/htdocs> Order deny,allow Deny from all Allow from 127.0.0.1 </Directory>
6、针对请求的URL去限制
<filesmatch "(.*)admin(.*)"> Order deny,allow Deny from all Allow from 127.0.0.1 </filesmatch>
这里用到了filesmatch语法,表示匹配的意思。7、验证
# curl -x192.168.0.8:80 www.123.com/admin.php -I HTTP/1.1 403 Forbidden Date: Wed, 26 Oct 2016 06:24:54 GMT Server: Apache/2.2.31 (Unix) PHP/5.5.38 Content-Type: text/html; charset=iso-8859-1
# curl -x127.0.0.1:80 www.123.com/admin.php -I HTTP/1.1 401 Authorization Required Date: Wed, 26 Oct 2016 06:25:03 GMT Server: Apache/2.2.31 (Unix) PHP/5.5.38 WWW-Authenticate: Basic realm="Please input you acount." Content-Type: text/html; charset=iso-8859-1
十、禁止解析PHP某个目录下禁止解析PHP,这个很有作用,我们做网站安全的时候,这个用的很多,比如某些目录可以上传文件,为了避免上传的文件有木马,所以我们禁止这个目录下面的访问解析PHP。1、配置禁止解析php
<Directory /usr/local/apache2/htdocs/data> php_admin_flag engine off <filesmatch "(.*)php"> Order deny,allow Deny from all </filesmatch> </Directory>
说明:php_admin_flag engine off这个语句就是禁止解析php的控制语句,但只这样配置还不够,因为这样配置后用户依然可以访问php文件,只不过不解析了,但可以下载,用户下载php文件也是不合适的,所以有必要再禁止一下。
十一、禁止指定user_agent
user_agent叫做浏览器标识,目前主流的浏览器有IE、chrome、Firefox、360、iphone的Safari、Android手机上的、百度搜索引擎、google搜索引擎等很多,每一种浏览器都有对应的user_agent。为了避免一些无用的搜索引擎或机器爬虫之类引起的带宽的无辜消耗。
<IfModule mod_rewrite.c> RewriteEngine on RewriteCond %{HTTP_HOST} ^www.abc.com$ [OR] RewriteCond %{HTTP_HOST} ^www.abcd.com$ RewriteRule ^/(.*)$ http://www.123.com/$1 [R=301,L] RewriteCond %{HTTP_USER_AGENT} ".*Firefox.*" [NC,OR] RewriteCond %{HTTP_USER_AGENT} ".*Tomato Bot.*" [NC] RewriteRule .* - [F] </IfModule>
同样是使用rewrite模块来实现限制指定user_agent。本例中,RewriteRule .* - [F]可以直接禁止访问,rewritecond用user_agent来匹配,NC表示不区分大小写,OR表示或者,连接下一个条件。假如我们要把百度的搜索引擎限制掉,可以加一条这样的规则:
RewriteCond %{HTTP_USER_AGENT} ^.*Baiduspider/2.0.* [NC] RewriteRule .* - [F]
十二、限制某个目录
我们可以allow和deny去现在网站根目录下的某个子目录,当然这个rewrite也可以实现,配置如下:
<IfModule mod_rewrite.c> RewriteEngine on RewriteCond %{REQUEST_URI} ^.*/tmp/* [NC] RewriteRule .* - [F] </IfModule>
这段配置,会把只要是包含 /tmp/ 字样的请求都限制了。