学习Apache(六)

Apache 是一款使用量排名第一的 web 服务器,LAMP 中的 A 指的就是它。由于其开源、稳定、安全等特性而被广泛使用。下边记录了使用 Apache 以来经常用到的功能,做此梳理,作为日常运维笔记所用。

一、Apache的工作模式
Apache 目前一共有三种MPM 模式(多进程处理模块),它们分别是prefork、worker、enent,主要用到前两种工作模式,且默认的工作模式是prefork。可以通过 httpd -V 来查看。

# /usr/local/apache/bin/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的用户认证
有时候,需要给apache一些特殊的访问设置一个用户认证机制,增加安全。比如公司网站,一般都是有一个管理后台的,虽然管理后台本身就有密码,但为了更加安全,可以再设置一层用户认证。

1)编辑配置文件)
# vim /usr/local/apache2/conf/extra/httpd-vhosts.conf
在对应的虚拟主机配置中加入如下配置:
<VirtualHost *:80>
    DocumentRoot "/usr/local/apache2/htdocs"
ServerName www.kevin.com
ServerAlias www.bobo.com
    <Directory /usr/local/apache2/htdocs/>
        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服务,效果一样。
如上配置后,通过浏览器输入网址,访问就会提示输入密码。

========================================================
在子目录中放宽安全限制
也就是说,比如我们现在已经在/usr/local/apache2/htdocs/这个目录上加上了用户名和密码的认证。
但如果想在/usr/local/apache2/htdocs/php这个目录中不需要认证,使用户可以直接访问。
要达到上面的要求,就需要在配置文件中加入:
  
<Directory "/usr/local/apache2/htdocs/php">
Satisfy Any
Order Deny,Allow
Allow from all
</Directory>

或者: 在
/usr/local/apache2/htdocs/php目录下建立.htaccess文件,把 Satisfy Any Order Deny,Allow Allow from all ================================================= 如果已经限制了一个目录的访问,需要用户名和密码,但想要放开这个目录中的其中一个文件(例如:back.html) 的权限,使其可以任意访问,在配置文件中添加: <Files back.html> Satisfy Any Order Deny,Allow Allow from all </Files> ================================================= 查看通过验证的用户名称: 可以查看REMOTE_USER环境变更。在access_log中也可以看到。 ================================================= 禁止通过代理服务器访问特定的URL <Directory proxy:http://192.168.10.10/music/> Order Allow,Deny Deny from all Satisfy All </Directory> 上述方法都无法满足要求时,可以使用正则表达式的方式,使用Rewrite指令。 ================================================ 想拒绝所有对目录中文件的访问,除了特殊指定扩展名的文件(比如.html文件) <Directory "/usr/local/apache2/htdocs/test"> Satisfy all Order Allow,Deny Deny from all <Files *.html> Order Deny,Allow Allow from all Satisfy any </Files> </Directory> 以上指令,使得test目录及其子目录下的所有非.html文件无法访问,只有.html的文件可以访问。

三、设置默认虚拟主机
默认虚拟主机就是配置文件里的第一个虚拟主机。关于默认虚拟主机有个特点,凡是解析到这台服务器的域名,不管是什么域名,只要在配置文件中没有配置,那么都会访问到这个主机上来。如果直接用IP访问,会访问到这个站点上来。为了避免别人乱解析,所以应该把默认也就是第一个虚拟主机给禁止掉。使用allow,deny语句就可以禁止掉了。

1)配置默认虚拟主机
# vim /usr/local/apache2/conf/extra/httpd-vhosts.conf
 
添加一个虚拟主机的记录:
<VirtualHost *:80>
    DocumentRoot "/data/www"
    ServerName www.kevin.com
    <Directory /data/www>
        Order allow,deny
        Deny from all
    </Directory>
</VirtualHost>
 
创建/data/www目录,并且设置600权限,daemon用户无法访问:
 
# mkdir /data/www
# chmod -R 600 /data/www
 
2)重启apache服务器
# apachectl -t
# apachectl graceful
 
如果用IP或其它解析的域名访问,发现提示:
Forbidden
You don't have permission to access / on this server.

=================================================
只有一个IP,但想在系统上支持多个网站:
  
NameVirtualHost *
<VirtualHost *:80>
    ServerAdmin webmaster@www.kevin.com
    DocumentRoot /www/docs/www.kevin.com
    ServerName www.kevin.com
    ServerAlias www.bobo.com                    ######p这条指令可对虚拟主机设定多个名称
    ErrorLog logs/www.kevin.com-error_log
    CustomLog logs/www.kevin.com-access_log common
</VirtualHost>
  
其中:
"*" 表示所设定的主机可在所有的地址上运行。对于只有单一地址的机器,这表示会在该地址上运行,同时也会在loopback地址上运行。
如果NameVirtualHost 后面放置主机名称可能会在启动服务器时停用虚拟主机的机制。
虚拟主机会使用户无法再访问配置文件中的主服务器。如果想让主服务器成为默认服务器,则必须在虚拟主机区块中先将它列出。
对于每个虚拟主机名称,还需要在DNS中添加相关记录。

=================================================
# /usr/local/apache2/bin/httpd -S    显示虚拟主机的配置

=================================================
ErrorDocument 404 /err.html    这个指令可以让没有打到指定网页的时候,不显示404错误,而是err.html页面。
错误号可以是其它的号码,如403、500等
  
例如:
<VirtualHost *>
    ServerAdmin webmaster@www.kevin.com
    DocumentRoot /www/docs/kevin.com
    ServerName kevin.com
    ErrorLog logs/kevin.com-error_log
    CustomLog logs/kevin.com-access_log combined
    ErrorDocument 404 /err.html
</VirtualHost>
  
根据以上配置,访问kevin.com/index.html时,如果/www/docs/kevin.com目录下没有index.html文件时,
则会显示/www/docs/kevin.com目录下的err.html文件

=================================================
如果是有多个IP的情况下,想在每个地址上支持一个网站:
  
NameVirtualHost 127.0.0.1
<VirtualHost 172.16.50.230>
    ServerAdmin webmaster@www.kevin.com
    DocumentRoot /www/docs/bobo.bobo.com
    ServerName bobo.bobo.com
    ErrorLog logs/bobo.bobo.com-error_log
    CustomLog logs/bobo.bobo.com-access_log combined
</VirtualHost>

<VirtualHost 172.16.50.231>
    ServerAdmin webmaster@www.kevin.com
    DocumentRoot /www/docs/kevin.com
    ServerName kevin.com
    ErrorLog logs/kevin.com-error_log
    CustomLog logs/kevin.com-access_log combined
</VirtualHost>
  
以上配置根据所访问的IP地址不同,会访问不同的虚拟主机。如果服务器上还有其它的IP地址,但是没有在配置文件的虚拟主机区块列出来时,
这时访问这个其它的IP地址,请求会被送至在配置文件主设定区的虚拟主机

=================================================
建立以IP寻址的默认虚拟主机,以配置文件中加入下面代码:
  
<VirtualHost _default_>
    DocumentRoot /www/htdocs
    ErrorDocument 404 /err.html
</VirtualHost>
  
加入以上代码后,如果访问本地的IP,但是该IP确没有在配置文件中配置时,则会访问以上代码指定的页面

=================================================
混用以IP寻址及以名称寻址虚拟主机:
  
ServerName 127.0.0.1
NameVirtualHost 172.16.50.10
NameVirtualHost 172.16.50.230
<VirtualHost 172.16.50.10>                                 #此处不同
    ServerAdmin webmaster@www.kevin.com
    DocumentRoot /www/docs/kevin.com
    ServerName kevin.com                                   #此处不同
    ErrorLog logs/kevin.com-error_log
    CustomLog logs/kevin.com-access_log combined
</VirtualHost>
<VirtualHost 172.16.50.230>                                #此处不同
    ServerAdmin webmaster@www.kevin.com
    DocumentRoot /www/docs/kevin.com
    ServerName kevin.bobo.com                              #此处不同
    ErrorLog logs/kevin.bobo.com-error_log
    CustomLog logs/kevin.bobo.com-access_log combined
</VirtualHost>
<VirtualHost 172.16.50.230>                                #此处不同
    ServerAdmin webmaster@www.kevin.com
    DocumentRoot /www/docs/kevin.com
    ServerName bobo.bobo.com                               #此处不同
    ErrorLog logs/bobo.bobo.com-error_log
    CustomLog logs/bobo.bobo.com-access_log combined
</VirtualHost>

=================================================
mod_vhost_alias   模块可以建立大量的虚拟主机

=================================================
将URL对应至特定目录。比如说:
访问http://172.16.50.10/bobo,如果不想让它访问/usr/local/apache2/htdocs/bobo,
而是让它访问其它的目录中的内容,可以在配置文件中加入如下:
Alias /bobo /home/bobo/apache_bobo
  
然后还要把指定的目录加入到配置文件中,以让apache可以访问,默认情况下apache是不访问DocumentRoot以外的目录的。
<Directory "/home/bobo/apache_bobo">
    Order allow,deny
    Allow from all
</Directory>
  
这种用Alias的目录指定,其实是用Alias的第二个参数去替换第一个参数。
本例中就是用/home/bobo/apache_bobo去替换/bobo
因此,我们访问http://172.16.50.10/bobo
其实上是访问http://172.16.50.10/home/bobo/apache_bobo
  
这种方法对"/"符号要求非常严格,如果上例我们写成Alias /bobo/ /home/bobo/apache_bobo,
而我们在访问http://172.16.50.10/bobo/index.html,其实是访问http://172.16.50.10/home/bobo/apache_boboindex.html,
这是错误的,因为/home/bobo/apache_bobo替换的是/bobo/,
注意,这里把最后的“/”也替换了,所以转换后就是前面所说那样错误的URL。
  
Alias也可以为现有的网页内容创建新的URL,例如要想原来http://172.16.50.10/php/phpinfo.php内容,
通过http://172.16.50.10/newphp/phpinfo.php也可以访问,
只要在配置文件中加入如下一行:
Alias /newphp /usr/local/apache2/htdocs/php
  
Alias只影响本地URI,不会影响URL的主机名部分。

四、域名301跳转
一个站点难免会有多个域名,而多个域名总得有一个主次,比如我的网站可以用两个域名访问:www.kevin.cn 和 www.bobo.cn 但大家发现不管我用哪个域名访问,最终都会跳转到www.bobo.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>

配置为:当访问abc时,跳转到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

4)测试:
# curl -x 192.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/
Content-Type: text/html; charset=iso-8859-1

# curl -x 192.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日志

指定日志记录格式,组合日志格式(combined)或通用日志格式(common),修改配置文件:
CustomLog logs/access_log combined    组合日志格式
CustomLog logs/access_log common      通用日志格式

通用日志格式与组合日志格式的"%h"控制符表示远程请求用户的身份,依据HostNameLookups指令的设定值,
可能是主机名也可能是IP地址。
如果想永远记录IP地址,则使用“%a”控制符。

记录从客户端收到的cookie
CustomLog logs/cookies_in.log "%{UNIQUE_ID}e %{Cookie}i"
CustomLog logs/cookies2_in.log "%{UNIQUE_ID}e %{Cookie2}i"
  
记录由服务器设定并传送给客户端的cookie值:
CustomLog logs/cookies_out.log "%{UNIQUE_ID}e %{Set-Cookie}o"
CustomLog logs/cookies2_out.log "%{UNIQUE_ID}e %{Set-Cookie2}o"

不记录来自本机网页的图像请求:
<FilesMatch \.(jpg|gif|png$)>
SetEnvIfNoCase Referrer "^http://www.kevin.com/" local_referrer=1
</FilesMatch>
Customlog logs/access_log combined env=!local_referrer

按照日或小时来记录请求:
CustomLog "| /usr/local/apache2/bin/rotatelogs /usr/local/apache2/logs/access_log.%Y-%m-%d 86400" combined
  
其中:
rotatelogs的第一个参数是主日志文件名如果有%字符,则表示日志文件名中时间的格式,如果没有指定时间格式,则是以秒为单位,
从1970.1.1日算起的秒数
第二个参数是产生新日志的间隔是多少秒。也可以是大小如果把上例中的86400换成5M,则表时日志达到5M时,就会产生一个新的日志,
日志的名字是access_log.%Y-%m-%d格式的

logresolve 将日志中记录的IP地址解析为主机名
例如:
# logresolve -c < /usr/local/apache2/logs/access_log.raw > access_log.resolved
  
也可以让apache在处理过程中使用IP地址,然后在记录日志时,以管道方式的日志记录进程来解析,修改配置文件:
HostnameLookups off
CustomLog "|/usr/local/apache2/bin/logresolve -c >> /usr/local/apache2/logs/access_log.resolved" combined

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中有定义。

Apache不记录指定文件类型的日志
如果一个网站访问量特别大,那么访问日志就会很多,但有一些访问日志我们其实是可以忽略掉的,比如网站的一些图片,还有js、css等静态对象。而这些文件的访问往往是巨量的,而且即使记录这些日志也没有什么用,那么如何过滤掉(不记录)这些日志呢?

配置日志不记录图片的访问
# 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

3)验证:
# curl -x127.0.0.1:80 'http://www.kevin.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配置防盗链
盗链,全称是盗取链接,假如我们的网站有很多好看的图片,别人可以查看我们网站图片的链接,然后应用在他的网站上,这样的话,去访问他的网站,实际上消耗的是我们的流量(因为实际链接在我们这里),这样我们就不得不去配置防盗链,使得别人不能复制我们图片的链接。

防盗链的实现原理就不得不从HTTP协议说起,在HTTP协议中,有一个表头字段叫referer,采用URL的格式来表示从哪儿链接到当前的网页或文件。换句话说,通过referer,网站可以检测目标网页访问的来源网页,如果是资源文件,则可以跟踪到显示它的网页地址。有了referer跟踪来源就好办了,
这时就可以通过技术手段来进行处理,一旦检测到来源不是本站即进行阻止或者返回指定的页面。

如果想对自己的网站进行防盗链保护,则需要针对不同的情况进行区别对待。如果网站服务器用的是apache,那么使用apache自带的Url Rewrite功能可以很轻松地防止各种盗链,其原理是检查refer,如果refer的信息来自其他网站则重定向到指定图片或网页上。

如果网站有很多漂亮的图片,比如网站域名 www.kevin.com,图片地址为 www.kevin.com/image/111.jpg,那么其它人就可以直接把这个地址放到他
自己的网站上,他的用户可以直接从他网站查看这张图片,而实际图片是从你的网站访问的,所产生的带宽消耗对你没有任何意义,应该对这些图片限制一下,
凡是在第三方站点上,严禁访问你站点的图片,如何配置呢?

# vim /usr/local/apache2/conf/extra/httpd-vhosts.conf

SetEnvIfNoCase Referer "^http://.*\.kevin\.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,其它都拒绝。

Directory表示指定哪个目录,我们设置防盗链肯定是针对本站点,所以直接写站点。
SetEnv开头的是referer的白名单
local_ref    表示空的Refer
filesmatch开头的指的后面这些格式的文件不设置白名单,(就是说针对这些文件做防盗链)
order定义访问控制的,order定义顺序,是先允许还是先拒绝。
allow一行的意思是把上面末尾带有local_ref的白名单referer做一个允许。其他的使用上一行的order给deny掉

然后保存检查错误,然后重启。
# apachectl -t
# apachectl graceful


再看之前用到的一例:
<Directory /data/wwwroot/boke>
        SetEnvIfNoCase Referer "http://kevin.com"; local_ref
        SetEnvIfNoCase Referer "http://xiaobo.com"; local_ref
        SetEnvIfNoCase Referer "^$" local_ref                        
        <filesmatch "\.(txt|doc|mp3|zip|rar|jpg|gif)">
            Order Allow,Deny
            Allow from env=local_ref
        </filesmatch>
 </Directory>


来做一个测试,测试一下http://kevin.com/ai.png浏览器看看能不能打开,或者把它以超链接的形式发到论坛,然后点开。
发现点开后出现"Forbidden"的报错页面,这种情况就是空referer,就是防盗链起了作用!

八、Apache访问控制
其实可以对apache的访问进行控制,可以设置白名单或黑名单(通过allow和deny的规则来配置)。

1)示例一
Order deny,allow
deny from all
allow from 127.0.0.1
 
判断依据是这样的:
看Order后面的,哪个在前,哪个在后
如果deny在前,那么就需要看deny from这句,然后看allow from这句
规则是一条一条匹配的,不管是deny在前还是allow在前,都会生效的。
 
2)示例二
Order allow,deny
deny from all
allow from 127.0.0.1
 
这个就会deny所有了,127.0.0.1也会被deny。因为顺序是先allow然后deny,虽然开始allow了127,但是后面又拒绝了它。
 
3)示例三
Order allow,deny
deny from all
 
上面的规则就表示,全部都不能通过。
 
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语法,表示匹配的意思。
 
验证
# curl -x 192.168.0.8:80 www.kevin.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 -x 127.0.0.1:80 www.kevin.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

7)Apache防盗链主要是防止本网站的链接被别人盗用。可以使用Apache访问控制,禁用来源IP访问
# vim /usr/local/apache2/conf/extra/httpd-vhosts.conf

<VirtualHost *:80>
...........
    <Directory "/data/www">
        AllowOverride None
        Options None
        Order allow,deny
        Allow from all                                               #允许所有访问
        Deny from 127.0.0.1                                     #禁用127.0.0.1访问
    </Directory>
...........
</VirtualHost>

测试
# curl -x 127.0.0.1:80 -I www.kevin.com                 #127.0.0.1被禁止访问
HTTP/1.1 403 Forbidden
Date: Wed, 02 Oct 2018 02:47:23 GMT
Server: Apache/2.2.31 (Unix) PHP/5.4.45
Content-Type: text/html; charset=iso-8859-1

# curl -x 192.168.101.230:80 -I www.kevin.com      #192.168.101.230正常访问
HTTP/1.1 301 Moved Permanently
Date: Wed, 02 Oct 2018 02:47:42 GMT
Server: Apache/2.2.31 (Unix) PHP/5.4.45
X-Powered-By: PHP/5.4.45
location: forum.php
Cache-Control: max-age=0
Expires: Wed, 02 Oct 2018 02:47:42 GMT
Content-Type: text/html

# curl -x 192.168.101.230:80 -I www.kevin.com/forum.php      #正常访问
HTTP/1.1 200 OK


8)如果希望白名单限制管理员登录网页URI:http://www.kevin.com/xiaobo.php,怎么做?)
<VirtualHost *:80>
........
   <filesmatch "(.*)xiaobo(.*)">
        Order deny,allow
         Deny from all                         #禁用所有访问
         Allow from 127.0.0.1              #允许127.0.0.1访问  
         Allow from 192.168.101.230
   </filesmatch>

...........
</VirtualHost>

重启Apache服务后,用PC机器(192.168.101.175)访问http://www.kevin.com/xiaobo.php,报错403Forbidden。
# curl -x 192.168.101.230:80 -I http://www.kevin.com/xiaobo.php
HTTP/1.1 200 OK                    200,但是192.168.101.230可以正常访问

九、禁止解析PHP
某个目录下禁止解析PHP,这个很有作用,我们做网站安全的时候,这个用的很多,比如某些目录可以上传文件,为了避免上传的文件有木马,所以我们禁止这个目录下面的访问解析PHP。

配置禁止解析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.kevin.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} ^.*/shibo/* [NC]
    RewriteRule .* - [F]
</IfModule>

这段配置,会把只要是包含 /shibo/ 字样的请求都限制了。

十二、让Apache服务器的用户都有自己的URL,有自己的网页空间

配置文件里添加下面一行内容:
UserDir public_html    
  
配置文件中有这行指令后,再在用户主目录下创建public_html目录,里面放入网页就可以了。
访问的URL,以kevin这个用户为例:http://192.168.10.10/~kevin/

还要将配置文件中一段注释去掉:
#<Directory /home/*/public_html>
#    AllowOverride FileInfo AuthConfig Limit Indexes
#    Options MultiViews Indexes SymLinksIfOwnerMatch IncludesNoExec
#    <Limit GET POST OPTIONS PROPFIND>
#        Order allow,deny
#        Allow from all
#    </Limit>
#    <LimitExcept GET POST OPTIONS PROPFIND>
#        Order deny,allow
#        Deny from all
#    </LimitExcept>
#</Directory>
  
以配置访问权限。


另一种方式是在配置文件中添加下面一行内容:
UserDir /www/user/*/htdocs

这种方法后的参数是完整的路径名,把用户的页面文件都放在了统一的目录下(/www/usr/下),
后面的*号是用户名命名的目录。访问方法和上面第一种方法一样。

十三、Apache的.htaccess文件配置说明
.htaccess文件是Apache服务器中的一个配置文件,它负责相关目录下的网页配置。通过对.htaccess文件进行设置,可以帮我们实现:网页301重定向、自定义400/403/404/500错误页面、改变文件扩展名、允许/阻止指定IP用户访问、禁止目录列表、配置默认文档等功能,可以说是功能非常强大。

设置网站错误页面
ErrorDocument 400 /error_pages/400.html
ErrorDocument 401 /error_pages/401.html
ErrorDocument 403 /error_pages/403.html
ErrorDocument 404 /error_pages/404.html
ErrorDocument 500 /error_pages/500.html
  
设置网页301重定向
#从 old_dir 目录重定向到 new_dir 目录
Redirect /old_dir/ http://www.yourdomain.com/new_dir/index.html
#把通过二级目录访问的请求301重定向到二级域名
RedirectMatch 301 /dir/(.*) http://dir.yourdomain.com/$1
  
禁止指定IP段用户的访问
#禁止 IP 为 255.0.0.0123.45.6.区段的 IP 访问
order allow,deny
deny from 255.0.0.0
deny from 123.45.6.
allow from all
  
禁止指定来源网页访问
#禁止从 otherdomain.com 和 anotherdomain.com 的来源访问
RewriteEngine on
# Options +FollowSymlinks
RewriteCond %{HTTP_REFERER} otherdomain\.com [NC,OR]
RewriteCond %{HTTP_REFERER} anotherdomain\.com
RewriteRule .* – [F]
  
图片防盗链设置
#从本站以外的域名访问图片,一律显示 feed.jpg
RewriteEngine on
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http://(www\.)?yourdomain.com/.*$ [NC]
RewriteRule \.(gif|jpg|png)$ http://www.yourdomain.com/feed.jpg [R,L]
  
设置文件夹首页
#防止显示文件夹列表,当访问文件夹时,服务器会查找index.html,并将其做为首页文件,如不存在依次向后查找
DirectoryIndex index.html index.cgi index.php
  
设置多媒体文件为可下载而非播放
AddType application/octet-stream .mp3 .mp4
  
自定义HTTP报头
Header set X-Pingback “http://www.yourdomain.com/xmlrpc.php”
Header set article-by “yourdomain.com”
  
设置文件过期时间 Cache Control
# 启用有效期控制
ExpiresActive On
# gif/png/jpg 有效期为1个月
ExpiresByType image/gif “access plus 1 month”
ExpiresByType image/png “access plus 1 month”
ExpiresByType image/jpg “access plus 1 month”
# js/css 有效期为1星期
ExpiresByType text/javascript “access plus 1 week”
ExpiresByType text/css “access plus 1 week”
  
WordPress建站程序伪静态代码
# BEGIN WordPress          #这是一行注释,表示 WordPress 的 htaccess 从这里开始
#如果Apache加载了mod_rewrite.c模块,则运行以下代码
RewriteEngine On             #启用 mod_rewrite 引擎
RewriteBase /                    #设置目录重写的基准URL为 /
RewriteRule ^index\.php$ – [L]              #如果请求路径是 index.php,停止重写操作(避免死循环)
RewriteCond %{REQUEST_FILENAME} !-f               #如果请求的不是一个文件,继续处理
RewriteCond %{REQUEST_FILENAME} !-d              #如果请求的不是一个目录,继续处理
RewriteRule . /index.php [L]                 #把所有的请求指向 /index.php
#结束 IfModule
# END WordPress #WordPress 的 htaccess 到这里结束
  
Discuz x3/x3.1通用伪静态代码
#如果Apache加载了mod_rewrite.c模块,则运行以下代码
RewriteEngine On
RewriteBase /discuz
RewriteCond %{QUERY_STRING} ^(.*)$
RewriteRule ^topic-(.+)\.html$ portal.php?mod=topic&topic=$1&%1
RewriteCond %{QUERY_STRING} ^(.*)$
RewriteRule ^article-([0-9]+)-([0-9]+)\.html$ portal.php?mod=view&aid=$1&page=$2&%1
RewriteCond %{QUERY_STRING} ^(.*)$
RewriteRule ^forum-(\w+)-([0-9]+)\.html$ forum.php?mod=forumdisplay&fid=$1&page=$2&%1
RewriteCond %{QUERY_STRING} ^(.*)$
RewriteRule ^thread-([0-9]+)-([0-9]+)-([0-9]+)\.html$ forum.php?mod=viewthread&tid=$1&extra=page\%3D$3&page=$2&%1
RewriteCond %{QUERY_STRING} ^(.*)$
RewriteRule ^group-([0-9]+)-([0-9]+)\.html$ forum.php?mod=group&fid=$1&page=$2&%1
RewriteCond %{QUERY_STRING} ^(.*)$
RewriteRule ^space-(username|uid)-(.+)\.html$ home.php?mod=space&$1=$2&%1
RewriteCond %{QUERY_STRING} ^(.*)$
RewriteRule ^blog-([0-9]+)-([0-9]+)\.html$ home.php?mod=space&uid=$1&do=blog&id=$2&%1
RewriteCond %{QUERY_STRING} ^(.*)$
RewriteRule ^archiver/(fid|tid)-([0-9]+)\.html$ archiver/index.php?action=$1&value=$2&%1
RewriteCond %{QUERY_STRING} ^(.*)$
RewriteRule ^([a-z]+[a-z0-9_]*)-([a-z0-9_\-]+)\.html$ plugin.php?id=$1:$2&%1

#http强转为https配置
RewriteEngine on         
RewriteBase /            
RewriteCond %{SERVER_PORT} !^443$   
RewriteRule ^.*$ https://%{SERVER_NAME}%{REQUEST_URI} [L,R]   

----------------------------------------------其他注意点---------------------------------------------

AliasMatch指令:可以用正则表达式的方式将多个URL对应至同一个目录。
例如配置如下:
AliasMatch ^/testph(p|ps) /usr/local/apache2/htdocs/php
 
以上配置表示:
可以用
http://www.kevin.com/testphp/phpinfo.php
和
http://www.kevin.com/testphps/phpinfo.php
来访问同一个目录/usr/local/apache2/htdocs/php中的内容
================================
重定向至其他URL:
修改配置文件:
Redirect /xueer http://www.bo.com/yiner
 
以上指令表示访问http:www.kevin.com/xueer时,实际访问的是http://www.bo.com/yiner
   
Redirect指令有几个参数:
temp:表示文件当前不在原来所请求的位置上,可以将来还会在这个位置上,现在只是临时的。这样,客户端会记住原始请求的URL。
permanent:表示被请求的文件不在指定位置上,而是永久在新的位置上。这样,客户端会记住新的URL
gone:表示文件不在此位置,而且以后也不在新的位置上。相当于404错误。但服务器会承认所请求的文件原来在此位置。所以不会被视为错误。
seeother:表示文件不在所请求的位置,而且被不同位置的其它文件取代了(前三个参数都是指同一个文件,这个参数请是不同位置的不同文件取代了原来位置的原来文件)
   
默认情况下是使用temp参数
用RedirectMatch指令可以用正则表达式的方式将多个URL重定向至同一位置。
================================
Apache接受不区分大小写的URL:
1) 安装mod_speling模块
2) 在配置文件中添加:
CheckSpelling On
================================
mod_rewrite模块用途:
可以重写URL请求中的文件,替换成指定的;
可以拒绝访问未被引用的请求;
可以依据查询字符串来重写;
可以将所有请求重定向是单一主机;
将服务器的全部或部分请求重定向至SSL等相关工作
================================
Apache性能测试:
# ab -n 1000 -c 20 http://www.baidu.com/back.html     
其中:
-n  1000 表示请求的数目
-c  20 表示一次送出20 个请求
-h  可以查看帮助
================================
Apache取得网站快照:
修改配置文件:
<Location /server-status>
    SetHandler server-status
#    Order deny,allow
#    Deny from all
#    Allow from .example.com
</Location>
ExtendedStatus On
================================
将经常查看的文件存入高速缓存区:
修改配置文件:
MMapFile /usr/local/apache2/htdocs/index.html           
需要安装mod_file_cache模块
================================
将目录列表存入高速缓存区
修改配置文件:
IndexOptions +TrackModified

==============一个简单的apache跳转页面配置的小示例=================

示例如下:
假设apache的域名(ServerName)为www.kevin.com
 
下面配置表示:
访问http://www.kevin.com/shibo/admin/下匹配的path资源不存在时,页面跳转到 http://www.kevin.com/missing.html 的404错误页面。
要是admin下匹配的path资源存在,则不会跳转!
<IfModule proxy_module>
  ProxyPass /shibo/admin/*  http://www.kevin.com/missing.html
  ProxyPassMatch  /shibo/admin/*  !
</IfModule>
 
下面配置表示:
访问http://www.kevin.com/shibo/admin/下匹配的所有资源时,页面跳转到 http://www.kevin.com/missing.html 的404错误页面。
不管admin下匹配path资源存在还是不存在,都会跳转!
<IfModule proxy_module>
  ProxyPass /shibo/admin/  http://www.kevin.com/missing.html
  ProxyPassMatch  /shibo/admin/  !
</IfModule>

以上的配置:
可以禁止在外网使用域名访问时跳转到missing.html的提示页面。
但是在内网使用ip+port方式访问,不会跳转到missing.html提示页面,会正常访问。

十四、Apache Rewrite重写规则总结

1)介绍
Apached的重写功能,即是mod_rewrite模块功能,它是apache的一个模块。它的功能非常强大,可以操作URL中的所有部分。因此我们就可以改写url,给用户提供一个简介大方的url,当用户访问时可以通过mod_rewrite模块功能转换为真正的资源路径。通过mod_rewrite能实现的功能还有很多,例如隐藏真实地址、实现URL跳转、域名跳转、防盗链、限制访问资源类型等等。

2)工作流程
mod_rewrite模块在运行时会使用两个Hook程序。
a)第一个是从URL到文件名转换的Hook。当有访问到达Apache服务器的时,服务器会确认相应主机(或虚拟主机),这时mod_rewrite模块就开始工作,它将会先处理服务器全局中mod_rewrite模块所提供的指令,然后根据用户提供的指令进行改写。
b)第二个是修正URL的Hook。在此阶段mod_rewrite模块会处理非全局的设置。例如,目录中的.htaccess文件中的设置。但是此时已经完成URL的翻译(由URL转换为文件名),因此是无法在次对目录级别的URL进行改写操作,但是moe_rewrite模块会将已翻译的URL再次转换为URL的状态,继续进行目录级别的URL改写。(mod_rewrite模块将会使用读后请求阶段的回叫函数重新开始一个请求的循环处理)

Rewirte模块规则集的处理
当mod_rewrite在这两个API阶段中开始执行时,它会读取配置结构中配置好的 (或者是在服务启动时建立的服务器级的,或者是在遍历目录采集到的目录级的)规则集,然后,启动URL重写引擎来处理(带有一个或多个条件的)规则集。无论是服务器级的还是目录级的规则集,都是由同一个URL重写引擎处理,只是最终结果处理不同而已。
规则集中规则的顺序是很重要的,因为重写引擎是按一种特殊的顺序处理的:逐个遍历每个规则(RewriteRule指令),如果出现一个匹配条件的规则,则可能回头遍历已有的规则条件(RewriteCond指令)。由于历史的原因,条件规则是前置的,所以控制流程略显冗长,细节见下图-1。

可见,URL首先与每个规则的Pattern匹配,如果匹配失败,mod_rewrite将立即终止此规则的处理,继而处理下一个规则。如果匹配成功,mod_rewrite将寻找相应的规则条件,如果一个条件都没有,则简单地用Substitution构造的新值来替换URL,然后继续处理其他规则;但是如果条件存在,则开始一个内部循环按其列出的顺序逐个处理。对规则条件的处理有所不同:URL并不与模式进行匹配,而是首先通过扩展变量、反向引用、查找映射表等步骤建立一个TestString字符串,然后用它来与CondPattern匹配。如果匹配失败,则整个条件集和对应的规则失败;如果匹配成功,则执行下一个规则直到所有条件执行完毕。如果所有条件得以匹配,则以Substitution替换URL,并且继续处理。(本部分引用译者:金步国)

网络图片:

3)URL重写指令
只需要两步就可以完成了。第一使用RewriteEngine开启mod_rewrite模块功能;第二通过RewriteRule定义URL重写规则。
3.1)URL重写指令套路

RewriteEngine on                 #开启mod_rewrite模块功能
RewriteBase 路径                  #基准URL(使用alias设置别名则需使用这个)
RewriteCond TestString CondPattern [flags]          #重写条件(可以多个)
RewriteRule Pattern Substitution [flags]                 #重写规则

#最后两行可以可以多个
#按顺序一个一个执行RewriteRule([flags不终止情况下])
##以上是常用的指令,还有一些很少见的指令,需要的自己去查资料了解

3.2)RewriteRule Pattern Substitution [flags]

a)pattern是作用于当前URL的perl兼容的正则表达式。当前URL是指该规则生效时刻的URL的值。它可能与被请求时的URL截然不同,因为之前可能被其他RewriteRule或者alias指令修改过。
b)Substitution是当URL与Pattern匹配成功后。用来代替的字符串。
- 可以对pattern反向引用$N(N=0~9),表示正则表达式中第N个括号中的内容
- 对最后匹配的RewriteCond反向引用%N(N=0~9),表示最后匹配的RewriteCond第N对括号中的内容
- 服务器变量%{VARNAME}
- 映射函数调用${mapname:key|default} (通过RewriteMap指令定义映射辅助完成)

c)[flags],标志符,多个则用逗号隔开。

redirect|R [=code] (强制重定向 redirect)
以 http://thishost[:thisport]/(使新的URL成为一个URI) 为前缀的Substitution可以强制性执行一个外部重定向。 如果code没有指定,则产生一个HTTP响应代码302(临时性移动)。如果需要使用在300-400范围内的其他响应代码,只需在此指定这个数值即可, 另外,还可以使用下列符号名称之一: temp (默认的), permanent, seeother. 用它可以把规范化的URL反馈给客户端,如, 重写“/~”为 “/u/”,或对/u/user加上斜杠,等等。

注意: 在使用这个标记时,必须确保该替换字段是一个有效的URL! 否则,它会指向一个无效的位置! 并且要记住,此标记本身只是对URL加上 http://thishost[:thisport]/的前缀,重写操作仍然会继续。通常,你会希望停止重写操作而立即重定向,则还需要使用’L’标记.

forbidden|F (强制URL为被禁止的 forbidden)
强制当前URL为被禁止的,即,立即反馈一个HTTP响应代码403(被禁止的)。使用这个标记,可以链接若干RewriteConds以有条件地阻塞某些URL。

gone|G(强制URL为已废弃的 gone)
强制当前URL为已废弃的,即,立即反馈一个HTTP响应代码410(已废弃的)。使用这个标记,可以标明页面已经被废弃而不存在了.

proxy|P (强制为代理 proxy)
此标记使替换成分被内部地强制为代理请求,并立即(即, 重写规则处理立即中断)把处理移交给代理模块。你必须确保此替换串是一个有效的(比如常见的以 http://hostname开头的)能够为Apache代理模块所处理的URI。使用这个标记,可以把某些远程成分映射到本地服务器名称空间, 从而增强了ProxyPass指令的功能。

注意: 要使用这个功能,代理模块必须编译在Apache服务器中。 如果你不能确定,可以检查“httpd -l”的输出中是否有mod_proxy.c。 如果有,则mod_rewrite可以使用这个功能;如果没有,则必须启用mod_proxy并重新编译“httpd”程序。

last|L (最后一个规则 last)
立即停止重写操作,并不再应用其他重写规则。 它对应于Perl中的last命令或C语言中的break命令。这个标记可以阻止当前已被重写的URL为其后继的规则所重写。 举例,使用它可以重写根路径的URL(’/’)为实际存在的URL, 比如, ‘/e/www/’.

next|N (重新执行 next round)
重新执行重写操作(从第一个规则重新开始). 这时再次进行处理的URL已经不是原始的URL了,而是经最后一个重写规则处理的URL。它对应于Perl中的next命令或C语言中的continue命令。 此标记可以重新开始重写操作,即, 立即回到循环的头部。
但是要小心,不要制造死循环!

chain|C (与下一个规则相链接 chained)
此标记使当前规则与下一个(其本身又可以与其后继规则相链接的, 并可以如此反复的)规则相链接。 它产生这样一个效果: 如果一个规则被匹配,通常会继续处理其后继规则, 即,这个标记不起作用;如果规则不能被匹配,则其后继的链接的规则会被忽略。比如,在执行一个外部重定向时, 对一个目录级规则集,你可能需要删除“.www” (此处不应该出现“.www”的)。

type|T=MIME-type(强制MIME类型 type)
强制目标文件的MIME类型为MIME-type。 比如,它可以用于模拟mod_alias中的ScriptAlias指令,以内部地强制被映射目录中的所有文件的MIME类型为“application/x-httpd-cgi”。

nosubreq|NS (仅用于不对内部子请求进行处理 no internal sub-request)
在当前请求是一个内部子请求时,此标记强制重写引擎跳过该重写规则。比如,在mod_include试图搜索可能的目录默认文件(index.xxx)时, Apache会内部地产生子请求。对子请求,它不一定有用的,而且如果整个规则集都起作用,它甚至可能会引发错误。所以,可以用这个标记来排除某些规则。

根据你的需要遵循以下原则: 如果你使用了有CGI脚本的URL前缀,以强制它们由CGI脚本处理,而对子请求处理的出错率(或者开销)很高,在这种情况下,可以使用这个标记。

nocase|NC (忽略大小写 no case)
它使Pattern忽略大小写,即, 在Pattern与当前URL匹配时,’A-Z’ 和’a-z’没有区别。

qsappend|QSA (追加请求串 query string append)
此标记强制重写引擎在已有的替换串中追加一个请求串,而不是简单的替换。如果需要通过重写规则在请求串中增加信息,就可以使用这个标记。

noescape|NE (在输出中不对URI作转义 no URI escaping)
此标记阻止mod_rewrite对重写结果应用常规的URI转义规则。 一般情况下,特殊字符(如’%’, ‘$’, ‘;’等)会被转义为等值的十六进制编码。 此标记可以阻止这样的转义,以允许百分号等符号出现在输出中,如:
RewriteRule /foo/(.*) /bar?arg=P1=$1 [R,NE] 可以使’/foo/zed’转向到一个安全的请求’/bar?arg=P1=zed’.

passthrough|PT (移交给下一个处理器 pass through)
此标记强制重写引擎将内部结构request_rec中的uri字段设置为 filename字段的值,它只是一个小修改,使之能对来自其他URI到文件名翻译器的 Alias,ScriptAlias, Redirect 等指令的输出进行后续处理。举一个能说明其含义的例子:如果要通过mod_rewrite的重写引擎重写/abc为/def,然后通过mod_alias使/def转变为/ghi,可以这样:
RewriteRule ^/abc(.*) /def$1 [PT]
Alias /def /ghi

如果省略了PT标记,虽然mod_rewrite运作正常, 即, 作为一个使用API的URI到文件名翻译器,它可以重写uri=/abc/…为filename=/def/…,但是,后续的mod_alias在试图作URI到文件名的翻译时,则会失效。

注意: 如果需要混合使用不同的包含URI到文件名翻译器的模块时, 就必须使用这个标记。。混合使用mod_alias和mod_rewrite就是个典型的例子。

For Apache hackers
如果当前Apache API除了URI到文件名hook之外,还有一个文件名到文件名的hook, 就不需要这个标记了! 但是,如果没有这样一个hook,则此标记是唯一的解决方案。 Apache Group讨论过这个问题,并在Apache 2.0 版本中会增加这样一个hook。

skip|S=num (跳过后继的规则 skip)
此标记强制重写引擎跳过当前匹配规则后继的num个规则。 它可以实现一个伪if-then-else的构造: 最后一个规则是then从句,而被跳过的skip=N个规则是else从句. (它和’chain|C’标记是不同的!)

env|E=VAR:VAL (设置环境变量 environment variable)
此标记使环境变量VAR的值为VAL, VAL可以包含可扩展的反向引用的正则表达式$N和%N。 此标记可以多次使用以设置多个变量。这些变量可以在其后许多情况下被间接引用,但通常是在XSSI (via ) or CGI (如 $ENV{’VAR’})中, 也可以在后继的RewriteCond指令的pattern中通过%{ENV:VAR}作引用。使用它可以从URL中剥离并记住一些信息。

cookie|CO=NAME:VAL:domain[:lifetime[:path]] (设置cookie)
它在客户端浏览器上设置一个cookie。 cookie的名称是NAME,其值是VAL。 domain字段是该cookie的域,比如’.apache.org’, 可选的lifetime是cookie生命期的分钟数,可选的path是cookie的路径。

3.3)RewriteCond TestString CondPattern [flags]
Rewritecond指令定义一条规则条件。在一条rewriterule指令前面可能会有一条或者多条rewritecond指令,只有当自身模板匹配成功且这些条件也满足时(即RewriteRule中的pattern匹配成功),规则条件才被应用于当前URL处理。

3.3.1)TestString是一个纯文本的字符串

可以对pattern反向引用$N(N=0~9),紧跟在RewriteCond后面的RewriteRule正则表达式中第N个括号中的内容
反向引用%N(N=0~9),表示RewriteCond中CondPattern中第N对括号中的内容
服务器变量%{VARNAME}

3.3.2)CondPattern是条件pattern,一个应用于当前实例TestString的正则表达式。即TestString与条件pattern条件进行匹配。如果匹配则RewriteCond的值为Rrue,反之为False

可以使用以下特殊变量(可使用'!'实现反转)

'>CondPattern’ (大于) 将condPattern当作一个普通字符串,将它和TestString进行比较,当TestString 的字符大于CondPattern为真。
‘=CondPattern’ (等于) 将condPattern当作一个普通字符串,将它和TestString进行比较,当TestString 与CondPattern完全相同时为真.如果CondPattern只是 “” (两个引号紧挨在一起) 此时需TestString 为空字符串方为真。
‘-d’ (是否为目录) 将testString当作一个目录名,检查它是否存在以及是否是一个目录。
‘-f’ (是否是regular file) 将testString当作一个文件名,检查它是否存在以及是否是一个regular文件。
‘-s’ (是否为长度不为0的regular文件) 将testString当作一个文件名,检查它是否存在以及是否是一个长度大于0的regular文件。
‘-l’ (是否为symbolic link) 将testString当作一个文件名,检查它是否存在以及是否是一个 symbolic link。
‘-F’ (通过subrequest来检查某文件是否可访问) 检查TestString是否是一个合法的文件,而且通过服务器范围内的当前设置的访问控制进行访问。这个检查是通过一个内部subrequest完成的, 因此需要小心使用这个功能以降低服务器的性能。
‘-U’ (通过subrequest来检查某个URL是否存在) 检查TestString是否是一个合法的URL,而且通过服务器范围内的当前设置的访问控制进行访问。这个检查是通过一个内部subrequest完成的, 因此需要小心使用这个功能以降低服务器的性能。

3.3.3)[flags]是第三个参数,多个标志之间用逗号隔开)

’nocase|NC’ (不区分大小写) 在扩展后的TestString和CondPattern中,比较时不区分文本的大小写。注意,这个标志对文件系统和subrequest检查没有影响.
’ornext|OR’ (建立与下一个条件的或的关系) 默认的情况下,二个条件之间是AND的关系,用这个标志将关系改为OR。

4)Rewrite时服务器变量(仅列出少数)

HTTP headers:HTTP_USER_AGENT, HTTP_REFERER, HTTP_COOKIE, HTTP_HOST, HTTP_ACCEPT
connection & request:REMOTE_ADDR, QUERY_STRING
server internals::DOCUMENT_ROOT, SERVER_PORT, SERVER_PROTOCOL
system stuff: TIME_YEAR, TIME_MON, TIME_DAY

5)简单正则表达式规则

. 匹配任何单字符
[chars]   匹配字符串:chars
[^chars]   不匹配字符串:chars
text1|text2   可选择的字符串:text1或text2
?   匹配0到1个字符
*   匹配0到多个字符
+  匹配1到多个字符
^   字符串开始标志
$   字符串结束标志
\n   转义符标志

注意:一代Apache要求URL有斜杠而二代Apache却不允许,因此使用 ^/?

6)Rewirte主要的功能就是实现URL的跳转,它的正则表达式是基于Perl语言。
可基于服务器级的(httpd.conf)和目录级的 (.htaccess)两种方式。如果要想用到rewrite模块,必须先安装或加载rewrite模块,方法有两种:
一种是编译apache的时候就直接 安装rewrite模块。
另一种是编译apache时以DSO模式安装apache,然后再利用源码和apxs来安装rewrite模块。

基于服务器级的(httpd.conf)有两种方法,一种是在httpd.conf的全局下直接利用RewriteEngine on来打开rewrite功能;另一种是在局部里利用RewriteEngine on来打开rewrite功能,下面将会举例说明,需要注意的是,必须在每个virtualhost里用RewriteEngine on来打开rewrite功能。否则virtualhost里没有RewriteEngine on它里面的规则也不会生效。

基于目录级的(.htaccess),要注意一点那就是必须打开此目录的FollowSymLinks属性且在.htaccess里要声明 RewriteEngine on。

rewrite跳转举列说明

示例一:
下面是在一个虚拟主机里定义的规则。功能是把client请求的主机前缀不是www.kevin.cn和192.168.10.20都跳转到主机前缀为http://www.bobo.cn, 避免相同
内容的网页有多个指向的域名,如http://kevin.cn。

配置如下:
NameVirtualHost 192.168.10.20:80
ServerAdmin slj@bobo.cn
DocumentRoot “/web”
ServerName kevin.cn

RewriteEngine on  #打开rewirte功能
RewriteCond %{HTTP_HOST} !^www.kevin.cn [NC]  #声明Client请求的主机中前缀不是www.kevin.cn, 其中 [NC] 的意思是忽略大小写
RewriteCond %{HTTP_HOST} !^192.168.10.20 [NC]    #声明Client请求的主机中前缀不是192.168.10.20,其中 [NC] 的意思是忽略大小写
RewriteCond %{HTTP_HOST} !^$  #声明Client请求的主机中前缀不为空
RewriteRule ^(.*) http://www.bobo.cn/ [L]    

#最后一行含义是如果Client请求的主机中的前缀符合上述条件,则直接进行跳转到http://www.bobo.cn/,[L]意味着立即停止重写操作,并不再应用其他重写规则。
这里的.*是指匹配所有URL中不包含换行字符,()括号的功能是把所有的字符做一个标记,以便于后面的应用.就是引用前面里的 (.*)字符。

=============================================
示例二:将输入 hui.com 的域名时跳转到http://www.kevin.cn

配置如下:
RewriteEngine on
RewriteCond %{HTTP_HOST} ^hui.com [NC]
RewriteRule ^(.*) http://www.kevin.cn/ [L]

=============================================
示例三:
近期更换了域名,新域名为www.grace.com, 更加简短好记。这时需要将原来的域名ss.bobo.cn, 以及论坛所在地址ss.bobo.cn/bbs/定向到新的域名,
以便用户可以找到,并且使原来的论坛URL继续有效而不出现404未找到,比如原来的http://ss.bobo.cn/bbs/tread-60.html, 让它在新的域名下继续
有效,点击后转发到http://bbs.grace.com/tread-60.html,而其他网页,如原先的http: //ss.bobo.cn/purchase不会到二级域名bbs.grace.com/purchase上,
而是到 www.grace.com/purchase按照这样的要求重定向规则应该这样写:

RewriteEngine On
RewriteCond %{REQUEST_URI} ^/bbs/
RewriteRule ^bbs/(.*) http://bbs.grace.com/$1 [R=permanent,L]
RewriteCond %{REQUEST_URI} !^/bbs/
RewriteRule ^(.*) http://www.grace.com/$1 [R=permanent,L]

=============================================
示例四:同时达到下面两个要求:
用http://www.kevin.cn/xxx.php 来访问http://www.kevin.cn/xxx/
用http://xiaoye.kevin.cn 来访问 http://www.kevin.cn/user.php?username=xiaoye的功能

配置如下:
RewriteEngine On
RewriteCond %{HTTP_HOST} ^www.kevin.cn
RewriteCond %{REQUEST_URI} !^user.php$
RewriteCond %{REQUEST_URI} .php$
RewriteRule (.*).php$ http://www.kevin.cn/$1/ [R]
RewriteCond %{HTTP_HOST} !^www.kevin.cn
RewriteRule ^(.+) %{HTTP_HOST} [C]
RewriteRule ^([^.]+).kevin.cn http://www.kevin.cn/user.php?username=$1

=============================================
示例五:实现下面要求:
/type.php?typeid=* –> /type*.html
/type.php?typeid=*&page=* –> /type*page*.html

配置如下:
RewriteRule ^/type([0-9]+).html$ /type.php?typeid=$1 [PT]
RewriteRule ^/type([0-9]+)page([0-9]+).html$ /type.php?typeid=$1&page=$2 [PT]

=============================================
示例六:使用Apache的URL Rewrite配置多用户虚拟服务器

要实现这个功能,首先要在DNS服务器上打开域名的泛域名解析(自己做或者找域名服务商做)。
比如,把 *.bobo.us和 *.bobo.cn全部解析到IP地址为70.40.213.183上。Apache中关于*.bobo.us的虚拟主机的设定如下:

ServerAdmin webmaster@bobo.us
DocumentRoot /home/www/www.bobo.us
ServerName dns.bobo.us
ServerAlias dns.bobo.us bobo.us *.bobo.us
CustomLog /var/log/httpd/osa/access_log.log” common
ErrorLog /var/log/httpd/osa/error_log.log”
AllowOverride None
Order deny,allow

#AddDefaultCharset GB2312
RewriteEngine on
RewriteCond %{HTTP_HOST} ^[^.]+.bobo.(cn|us)$
RewriteRule ^(.+) %{HTTP_HOST}$1 [C]
RewriteRule ^([^.]+).bobo.(cn|us)(.*)$ /home/www/www.bobo.us/sylvan$3?un=$1&%{QUERY_STRING} [L]

配置说明:
在上面这段设定中,把*.bobo.cn和*.bobo.us 的Document Root都设定到了 /home/www/www.bobo.us
继续看下去,这里配置了URL Rewrite规则。
倒数第四行表示:打开URL Rewrite功能
倒数第三行表示:匹配条件,如果用户输入的URL中主机名是类似 xxxx.bobo.us 或者 xxxx.bobo.cn 就执行下面一句
倒数第二行表示:把用户输入完整的地址(GET方式的参数除外)作为参数传给下一个规则,[C]是Chain串联下一个规则的意思
倒数第一行:最关键的是这一句,使用证则表达式解析用户输入的URL地址,把主机名中的用户名信息作为名为un的参数传给/home/www/dev.bobo.us 目录下的脚本,
并在后面跟上用户输入的GET方式的传入参数。并指明这是最后一条规则([L]规则)。注意,在这一句中指明的重写后的地址用的是服务器上 的绝对路径,这是内部跳转。
如果使用http://xxxx这样的URL格式,则被称为外部跳转。使用外部跳转的话,浏览着的浏览器中的URL地址会改变成新的地址,而使用内部跳转则浏览器中的地址不发生
改变,看上去更像实际的二级域名虚拟服务器。

=============================================
示例七:Rewrite 防盗链正则
不允许www.im286.com和www.chinaz.com 这两个网站盗链 , 其它的网站都可以盗链。

配置如下:
RewriteEngine On
RewriteCond %{HTTP_REFERER} chinaz.com [NC]
RewriteCond %{HTTP_REFERER} im286.com [NC]
RewriteRule .*\.(jpg|jpeg|gif|png|rar|zip|txt|ace|torrent|gz|swf)$ http://www.xxx.com/fuck.png [R,NC,L]

=============================================
示例七:关于判断 USER AGENT 。配置如下:

RewriteEngine on
RewriteCond %{HTTP_USER_AGENT} ^MSIE [NC,OR]
RewriteCond %{HTTP_USER_AGENT} ^Opera [NC]
RewriteRule ^.* – [F,L] 

#这里”-”表示没有替换,浏览器为IE和Opera的访客将被禁止访问。 

=============================================
示例八:自动添加.php扩展名及自动换.html到.php扩展名。

配置如下:
RewriteEngine On
RewriteBase /test
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ([^/]+)$ /test/$1.php
#for hui: /test/admin => /test/admin.php

RewriteRule ([^/]+)\.html$ /test/$1.php [L]
#for hui: /test/admin.html => /test/admin.php

=============================================
示例九:限制目录只能显示图片

配置如下:
< IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !^.*\.(gif|jpg|jpeg|png|swf)$
RewriteRule .*$ – [F,L]
< /IfModule> 

7)apache重写规则的示例解析                                                                                                                                                                

在.htaccess里进行规制重写:
RewriteEngine ON
RewriteRule  ^user/(w+)/?$user.php?id=$1
 
配置说明:
^:输入的开头  以user/开头请求的地址
(w+):提取所有的字母,传给$1
/?:可选斜杠
$:结束符
替换为:user.php?id=*
 
注意:
有些apache不兼容简写模式 w+ => [a-zA-Z_-]
 
===============================
禁止IE和Opera浏览器访问
 
RewriteEngine on
RewriteCond %{HTTP_USER_AGENT} ^MSIE [NC,OR]
RewriteCond %{HTTP_USER_AGENT} ^Opera [NC]
RewriteRule ^.* - [F,L]       #'-'表示不替换URL
 
===============================
不合法路径返回首页
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1 [L]
 
==============================
防盗链
 
RewriteEngine On
RewriteCond %{HTTP_REFERER} !^http://(.+.)?mysite.com/ [NC]          #判断请求的是否是自己的域名
RewriteCond %{HTTP_REFERER} !^$                        #{HTTP_REFERER}不为空
RewriteRule .*.(jpe?g|gif|bmp|png)$ /images/nohotlink.jpg [L]         #返回警告图片
 
==============================
改变访问URL目录名),即隐藏真实的目录名字
 
RewriteEngine On
RewriteRule ^/?old_dir/([a-z\.]+)$  new_dir/$1 [R=301,L]
#new_dir为真正目录
 
==============================
创建无文件后缀链接
 
RewriteEngine On
RewriteCond %{REQUEST_FILENAME}.php -f                #判断该后缀文件是否存在
RewriteRule ^/?([a-zA-Z0-9]+)$ $1.php [L]
RewriteCond %{REQUEST_FILENAME}.html -f               #判断该后缀文件是否存在
RewriteRule ^/?([a-zA-Z0-9]+)$ $1.html [L]
 
==============================
限制只能显示图片
 
RewriteEngine on
RewriteCond %{REQUEST_FILENAME}  !^.*\.(gif|jpg|jpeg|png|swf)$
RewriteRule .*$ - [F,L]
 
==============================
文件不存在重定向404
 
RewriteEngine on
RewriteCond  %{REQUEST_FILENAME}  !f
RewriteCond  %{REQUEST_FILENAME}  !d
RewriteRule .? /404.php [L]

====================================其他配置示例====================================
1)去掉域名中的www标记
RewriteCond %{HTTP_HOST} !^jkevin\.net$ [NC]
RewriteRule .? http://jkevin.net%{REQUEST_URI} [R=301,L]
  
2)去掉www标记,但是保存子域名
RewriteCond %{HTTP_HOST} ^www\.(([a-z0-9_]+\.)?jkevin\.net)$ [NC]
RewriteRule .? http://%1%{REQUEST_URI} [R=301,L]
  
这里,当匹配到1%变量以后,子域名才会在%2(内部原子)中抓取到,而我们需要的正是这个%1变量。
  
3)给子域名加www标记
RewriteCond %{HTTP_HOST} ^([a-z.]+)?jkevin\.net$ [NC]
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule .? http://www.%1jkevin.net%{REQUEST_URI} [R=301,L]
  
这个规则抓取二级域名的%1变量,如果不是以www开始,那么就加www,以前的域名以及{REQUEST_URI}会跟在其后。
  
4)防止图片盗链
一些站长不择手段的将你的图片盗链在他们网站上,耗费你的带宽。你可以加一下代码阻止这种行为。
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http://(www\.)?jkevin\.net/ [NC]
RewriteRule \.(gif|jpg|png)$ – [F]
  
如果{HTTP_REFERER}值不为空,或者不是来自你自己的域名,这个规则用[F]FLAG阻止以gif|jpg|png 结尾的URL
如果对这种盗链你是坚决鄙视的,你还可以改变图片,让访问盗链网站的用户知道该网站正在盗用你的图片。
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http://(www\.)?jkevin\.net/.*$ [NC]
RewriteRule \.(gif|jpg|png)$ 你的图片地址 [R=301,L]
  
除了阻止图片盗链链接,以上规则将其盗链的图片全部替换成了你设置的图片。
你还可以阻止特定域名盗链你的图片:
RewriteCond %{HTTP_REFERER} !^http://(www\.)?leech_site\.net/ [NC]
RewriteRule \.(gif|jpg|png)$ – [F,L]
  
这个规则将阻止域名黑名单上所有的图片链接请求。
当然以上这些规则都是以{HTTP_REFERER}获取域名为基础的,如果你想改用成IP地址,用{REMOTE_ADDR}就可以了。
  
5)如果文件不存在重定向到404页面
如果你的主机没有提供404页面重定向服务,那么我们自己创建。
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .? /404.php [L]
  
这里-f匹配的是存在的文件名,-d匹配的存在的路径名。
这段代码在进行404重定向之前,会判断你的文件名以及路径名是否存在。
你还可以在404页面上加一个?url=$1参数:
RewriteRule ^/?(.*)$ /404.php?url=$1 [L]
  
这样,你的404页面就可以做一些其他的事情,例如发一个邮件提醒,加一个搜索等等。
  
6)重命名目录
如果你想在网站上重命名目录,试试这个:
RewriteRule ^/?old_directory/([a-z/.]+)$ new_directory/$1 [R=301,L]
  
在规则里我添加了一个“.”(注意不是代表得所有字符,前面有转义符)来匹配文件的后缀名。
  
7)将.html后缀名转换成.php
前提是.html文件能继续访问的情况下,更新你的网站链接。
RewriteRule ^/?([a-z/]+)\.html$ $1.php [L]
  
这不是一个网页重定向,所以访问者是不可见的。让他作为一个永久重定向(可见的),将FLAG修改[R=301,L]。
  
8)创建无文件后缀名链接
如果你想使你的PHP网站的链接更加简洁易记-或者隐藏文件的后缀名,试试这个:
RewriteRule ^/?([a-z]+)$ $1.php [L]
  
如果网站混有PHP以及HTML文件,你可以用RewriteCond先判断该后缀的文件是否存在,然后进行替换:
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^/?([a-zA-Z0-9]+)$ $1.php [L]
RewriteCond %{REQUEST_FILENAME}.html -f
RewriteRule ^/?([a-zA-Z0-9]+)$ $1.html [L]
  
如果文件是以.php为后缀,这条规则将被执行。
  
9)检查查询变量里的特定参数
如果在URL里面有一个特殊的参数,你可用RewriteCond鉴别其是否存在:
复制代码 代码如下:
RewriteCond %{QUERY_STRING} !uniquekey=
RewriteRule ^/?script_that_requires_uniquekey\.php$ other_script.php [QSA,L]
  
以上规则将检查{QUERY_STRING}里面的uniquekey参数是否存在,如果{REQUEST_URI}值为script_that_requires_uniquekey,将会定向到新的URL。
  
10)删除查询变量
Apache的mod_rewrite模块会自动辨识查询变量,除非你做了以下改动:
a).分配一个新的查询参数(你可以用[QSA,L]FLAG保存最初的查询变量)
b).在文件名后面加一个“?”(比如index.php?)。符号“?”不会在浏览器的地址栏里显示。
  
11)用新的格式展示当前URI
如 果这就是我们当前正在运行的URLs:/index.php?id=nnnn。我们非常希望将其更改成/nnnn并且让搜索引擎以新格式展现。首先,我们 为了让搜索引擎更新成新的,得将旧的URLs重定向到新的格式,但是,我们还得保证以前的index.php照样能够运行。是不是被我搞迷糊了?
实 现以上功能,诀窍就在于在查询变量中加了一个访问者看不到的标记符“marker”。我们只将查询变量中没有出现“marker”标记的链接进行重定向, 然后将原有的链接替换成新的格式,并且通过[QSA]FLAG在已有的参数加一个“marker”标记。
  
以下为实现的方式:
RewriteCond %{QUERY_STRING} !marker
RewriteCond %{QUERY_STRING} id=([-a-zA-Z0-9_+]+)
RewriteRule ^/?index\.php$ %1? [R=301,L]
RewriteRule ^/?([-a-zA-Z0-9_+]+)$ index.php?marker &id=$1 [L]
  
这 里,原先的URL:http://www.jkevin.net/index.php?id=nnnn,不包含marker,所以被第一个规则永久重定向到 http://www.jkevin.net/nnnn
第二个规则将http://www.jkevin.net/nnnn反定向到http: //www.jkevin.net/index.php?marker&id=nnnn,并且加了marker以及id=nnnn两个变量,
最后 mod_rewrite就开始进行处理过程。
第二次匹配,marker被匹配,所以忽略第一条规则,这里有一个“.”字符会出现在http://www.jkevin.net/index.php?marker&id=nnnn中,所以第二条规则也会被忽略,这样我们就完成了。
  
注意,这个解决方案要求Apache的一些扩展功能,所以如果你的网站放于在共享主机中会遇到很多障碍。
  
12)保证安全服务启用
Apache可以用两种方法辨别你是否开启了安全服务,分别引用{HTTPS}和{SERVER_PORT}变量:
RewriteCond %{REQUEST_URI} ^secure_page\.php$
RewriteCond %{HTTPS} !on
RewriteRule ^/?(secure_page\.php)$ https://www.jkevin.net/$1 [R=301,L]
  
以上规则测试{REQUEST_URI}值是否等于我们的安全页代码,并且{HTTPS}不等于on。
如果这两个条件同时满足,请求将被重定向到安全服务URI.另外你可用{SERVER_PORT}做同样的测试,443是常用的安全服务端口
RewriteCond %{REQUEST_URI} ^secure_page\.php$
RewriteCond %{SERVER_PORT} !^443$
RewriteRule ^/?(secure_page\.php)$ https://www.jkevin.net/$1 [R=301,L]
  
13)在特定的页面上强制执行安全服务
遇到同一个服务器根目录下分别有一个安全服务域名和一个非安全服务域名,所以你就需要用RewriteCond 判断安全服务端口是否占用,并且只将以下列表的页面要求为安全服务:
RewriteCond %{SERVER_PORT} !^443$
RewriteRule ^/?(page1|page2|page3|page4|page5)$ https://www.jkevin.net/%1[R=301,L]
  
以下是怎样将没有设置成安全服务的页面返回到80端口:
RewriteCond %{ SERVER_PORT } ^443$
RewriteRule !^/?(page6|page7|page8|page9)$http://www.jkevin.net%{REQUEST_URI} [R=301,L]
其实Rewrite里运用最多的还应该是正则表达式,如果了解点儿正则的话,写起这个规则还是比较简单的。
  
14) ProxyPass规则示例
  
访问http://www.kevin.com/shibo/admin/下匹配的所有资源时,页面跳转到 http://www.kevin.com/missing.html 的404错误页面。
<IfModule proxy_module>
  ProxyPass /shibo/admin/  http://www.kevin.com/missing.html
  ProxyPassMatch  /shibo/admin/  !
</IfModule>

===================其他补充=========================
Apache的URL地址重写的方法:
--------------第一种方法--------------
Apache环境中如果要将URL地址重写,正则表达式是最基本的要求,但对于一般的URL地址来说,基本的匹配就能实现我们大部分要求,因此除非是非常特殊的URL地址,
但这不是我要讨论的范围,简单几招学会Apache中URL地址重写,通过实例展示,轻松学会URL地址重写:
 
URL实例
重写URL:http://www.baidu.com/?p=152
原始URL:http://www.baidu.com/p152.html
 
重写规则:
^p([0-9]+)\.html      /?p=$1     [L]
 
正则基础知识:
^ 匹配行的开始,匹配URL地址的开头部分,对于RewriteRule而言,域名(http://www.biuuu.com)不是URL地址的一部分,如上:?p=152
() 分隔一个被捕获的表达式,如上:([0-9]+)
[] 定义字符类,如上:[0-9] 表示从0-9的数字
+ 说明前面的字符可以被重复匹配1次或数次,如上:[0-9]+,表示任何数字组合
\ 字符转义,如上:转义.
 
其它:
[L] 表示last,停止匹配其它
 
方法如下:
1)打开httpd.conf文件,找到
#LoadModule rewrite_module modules/mod_rewrite.so 注释前面#
2)打开httpd-vhosts.conf文件,在VirtualHost添加重写规则,
RewriteEngine On
RewriteRule ^p([0-9]+)\.html      /?p=$1     [L]
 
基本上就上面这两个步骤,其实总的来说,Apache中URL地址重写还是比较简单的,比看文档学习要快的多,不过要想深入了解还是有必要看看相关文档的,其它规则可以
自定义。记住一点:任何匹配其实就是一个正则表达式的替换过程。
 
创建友好的搜索引擎URL地址对于PHP程序员来说非常重要,因此简单学会Apache中URL地址重写将是一项最基本的要求。
 
--------------第二种方法--------------
1)首先检查是否已安装rewrite模块:
cat httpd.conf | grep rewrite
LoadModule rewrite_module modules/mod_rewrite.so
 
2)生成伪静态html连接:
生成伪静态html
在<VirtualHost>段最后加入
RewriteEngine on
RewriteRule /goods([0-9]+).html /goods.php?id=$1 [PT] 
 
更标准的写法为:
RewriteRule ^(.*)/goods([0-9]+).html$ $1/goods.php?id=$2 [PT]
 
更简洁的写法:
/goods(\d+)\.html /goods\.php\?id=$1
 
第一个(0-9]+)对应参数$1,以此类推第二个对应$2
 
举例:
RewriteRule /forum-([0-9]+)-([0-9]+)\.html /forumdisplay.php?fid=$1&page=$2 [PT]
 
测试http://www.xxx.com/goods1.html 是否与/goods.php?id=1的内容相同。
最后将所有链接换成设置后的伪静态html地址方式。
[PT]:url全局转换,即转换过的goods31.html对应goods.php?id=31 (默认就是这个不加参数)
[R]:    url重定向  即使用goods31.html访问时跳转到goods.php?id=31
 
3)防盗链:
RewriteCrond %{HTTP_HOST} !upkiller.com [R=301,L]
RewriteRule ^(.*)$ http://www.upkiller.com/warning.html [R=301,L]
 
把不是来自upkiller.com的请求重定向到http://www.upkiller.com
 
更好的做法:
RewriteCond %{HTTP_REFERER} !^http://(www\.)?upkiller\.com/.*$ [NC]
RewriteRule \.(mp3|rar|jpe|gif)$ http://www.upkiller.com/warning.jpg [R=301,L]
 
4)防百度爬虫:
RewriteCond %{HTTP_USER_AGENT} ^Baiduspider [OR]
RewriteRule ^(.*)$ http://www.google.com [R=301,L]
 
把来自百度的爬虫转到goole

=====================Apache的ProxyPass使用小结=====================
该指令可以将远程服务器映射到本地服务器的URL空间;本地的服务器并不是扮演传统意义上的代理服务器的角色,而是表现为远程服务器的一个镜像。此本地服务器常被成为反向代理(reversed proxy)或者是网关(gateway)。路径是指本地虚拟路径的名字;url指远程服务器的一个部分URL,不能包含查询字符串。

描述:将远程服务器映射到本地服务器的URL空间
语法:ProxyPass [路径] !|url [键=值 键=值 ...]] [nocanon]
上下文: server config, virtual host, directory
状态:扩展
模块:mod_proxy

apache中的mod_proxy模块主要作用就是进行url的转发,即具有代理的功能。应用此功能,可以很方便的实现同tomcat等应用服务器的整合,甚者可以很方便的实现web集群的功能。httpd.conf配置:

#保证以下模块加载  
LoadModule proxy_module modules/mod_proxy.so  
LoadModule proxy_http_module modules/mod_proxy_http.so  
#配置ProxyPass  
ProxyPass /new/ http://kevincom/  
ProxyPass /new2/ http://192.168.0.169:8080/  

需要注意:
顺序很重要:排除的指令必须在一般的ProxyPass指令之前。上面的配置已经可以实现大部分功能了,要控制细节!

例子:
使用apache作为域名www.kevin.com代理服务器,让其暴露在公网上,即DNS解析到本机器上,真正提供web服务器的是另一台位于同一内网的机器上,假设起IP是172.16.50.40,那么只需要如下配置就可以了。

ProxyPass / http://172.16.50.40/ 
ProxyPassReverse / http://172.16.50.40/

-   ProxyPass 很好理解,就是把所有来自客户端对http://www.kevin.com的请求转发给http://172.16.50.40上进行处理;
-   ProxyPassReverse的配置总是和ProxyPass 一致,但用途很让人费解。似乎去掉它很能很好的工作,事实真的是这样么,其实不然,如果响应中有302重定向,ProxyPassReverse就派上用场。举例说明,假设用户访问http://www.kevin.com/exam.php,通过转发交给http://172.16.50.40 /exam.php处理,假定exam.php处理的结果是实现redirect到login.php(使用相对路径,即省略了域名信息),如果没有配置反向代理,客户端收到的请求响应是重定向操作,并且重定向目的url为http://172.16.50.40/login.php ,而这个地址只是代理服务器能访问到的,可想而知,客户端肯定是打不开的,反之如果配置了反向代理,则会在转交HTTP重定向应答到客户端之前调整它为 http://www.kevin.com/login.php,即是在原请求之后追加上了redirect的路径。当客户端再次请求http: //www.kevin.com/login.php,代理服务器再次工作把其转发到http://172.16.50.40/login.php。
-   客户端到服务器称之为正向代理,那服务器到客户端就叫反向代理。

ProxyPass与ProxyPassReverse及ProxyPassMatch这几个都是Apache的代理指令
1)ProxyPass
语法:ProxyPass [path] !|url
它主要是用作URL前缀匹配,不能有正则表达式,它里面配置的Path实际上是一个虚拟的路径,在反向代理到后端的url后,path是不会带过去的。

示例一
ProxyPass / images/ !

这个示例表示,/images/的请求不被转发。

=======================================
示例二:
ProxyPass /mirror/foo/ http://backend.kevin.com/

假设当前的服务地址是http://kevin.com/,如果做上面的配置,那么访问http://kevin.com/mirror/foo/bar将被转成http://backend.kevin.com/bar
注:配置的时候,不需要被转发的请求,要配置在需要被转发的请求前面。

2)ProxyPassMatch
语法:ProxyPassMatch [regex] !|url
这个实际上是url正则匹配,而不是简单的前缀匹配,匹配上的regex部分是会带到后端的url的,这个是与ProxyPass不同的。

示例一
ProxyPassMatch ^/images !

这个示例表示对/images的请求,都不会被转发。

=======================================
示例二:
ProxyPassMatch ^(/.*.gif)  http://backend.kevin.com

这个示例表示对所有gif图片的请求,都被会转到后端,如此时请求,访问http://kevin.com/foo/bar.gif 那内部将会转换为 http://backend.kevin.com/foo/bar.gif

3)ProxyPassReverse
语法:ProxyPassReverse [路径] url)
它一般和ProxyPass指令配合使用,此指令使Apache调整HTTP重定向应答中Location, Content-Location, URI头里的URL,这样可以避免在Apache作为反向代理使用时。
后端服务器的HTTP重定向造成的绕过反向代理的问题。比如:

80端口的Proxypass跳转
<IfModule proxy_module>
     ProxyPass  /companyNews  http://192.168.10.149:8080/companyNews
     ProxyPassReverse  /companyNews  http://192.168.10.149:8080/companyNews
     ProxyPass  /companyNews/*  http://192.168.10.149:8080/companyNews/*
     ProxyPassReverse  /companyNews/*  http://192.168.10.149:8080/companyNews/*
</IfModule>
  
<IfModule proxy_module>
     ProxyPass  /mlslec  https://hao.kevin.com.com/cgi-bin
     ProxyPassReverse  /mlslec  https://hao.kevin.com.com/cgi-bin
</IfModule>

<IfModule proxy_module>
ProxyPass /kevin http://www.kevin.com/ 
ProxyPassReverse /kevin http://www.kevin.com/
</IfModule>

<IfModule proxy_module>
ProxyPass /bobo http://192.168.1.10:8080/bobo/
ProxyPassReverse /bobo http://192.168.1.10:8080/bobo/
</IfModule>
  
==================================================
443端口的Proxypass跳转
<IfModule proxy_module>
SSLProxyEngine On
  
ProxyPass  /xyy  https://bobo.kevin.com/pay/orderquery
ProxyPassReverse  /xyy  https://bobo.kevin.com/pay/orderquery
  
ProxyPass  /getsignkey   https://bobo.kevin.com/sandbox/pay/getsignkey
ProxyPassReverse  /getsignkey   https://bobo.kevin.com/sandbox/pay/getsignkey
  
ProxyPass  /authorize   https://shibo.kevin.com/connect/oauth2/authorize
ProxyPassReverse  /authorize   https://shibo.kevin.com/connect/oauth2/authorize
</IfModule>

 

   

posted on 2019-09-06 11:15  五光十色  阅读(486)  评论(0编辑  收藏  举报

导航