标签归档:Apache

.htaccess的RewriteRule不生效

由于网站链接改版,需要对一些旧的已经被收录的内容进行301跳转。规则如下

Old: http://blog.zivers.com/post/666
New: http://blog.zivers.com/post/666.html

规则很简单,就是添加一个.html后缀。于是我在.htaccess中写入了一条RewriteRule:

RewriteRule ^post/(\d+)$ /post/$1.html [R=301,L]

但是,实际访问/post/123时,并没有按预期跳转,而是返回了一个404页面。由于我其他RewriteRule生效正常,所以排除了例如没有开启Rewrite Mod这一类的问题。焦点放在了这条规则上。然而这条规则太简单,以至于一眼就能明白肯定正确。在网上查了许久也没找到答案,于是我还是去看Apache的官方文档怎么说吧。果然,问题找到了,RewriteRule是顺序生效的,这点和Nginx一样,当第一条规则匹配生效后,第二条匹配到相同规则的URL就不会使用这条规则了。而我的.htaccess规则如下:

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
RewriteRule ^post/(\d+)$ /post/$1.html [R=301,L]
</IfModule>
# END WordPress

显然,上面的RewriteCond已经匹配到了我想要跳转的URL,然后执行了这条规则:

RewriteRule . /index.php [L]

所以,问题迎刃而解,把我所需要执行的规则上移即可:

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^post/(\d+)$ /post/$1.html [R=301,L]
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress

修改Apache2的Access日志格式

这是一个由实际需求引发的问题。公司服务器上原来有一个防止恶意抓取脚本,基本思路是从Apache2的access.log中获取到访问的来源ip,然后对ip进行分析,提取出其中的可疑ip加入Apache2的block ip中。

但是,由于Apache版本的升级还是其他不知道的什么缘故,脚本无法使用了。查到原因发现是因为类似以下的记录引起的:

记录1:

crawl-66-249-75-174.googlebot.com - - [27/Apr/2016:06:32:25 +0000] "GET /es/hipercor-vestidos/all/9/ HTTP/1.1" 302 584 "-" "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5X Build/MMB29P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.96 Mobile Safari/537.36 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"

记录2:

::1 - - [27/Apr/2016:00:35:12 +0000] "OPTIONS * HTTP/1.0" 200 125 "-" "Apache/2.4.7 (Ubuntu) (internal dummy connection)"

这是两条非常典型的非典型记录,主要问题处在第一个字段(Hostname)。默认的access.log中记录的第一个字段为来访的主机名,一般情况下是ip地址,但是在记录1中,显示的是一个完整的主机名。这是一个来自Google的bot,主机名为crawl-66-249-75-174.googlebot.com,ip地址被放在了中间。于是脚本识别就出现了问题。所以,我需要修改access日志,将第一个字段修改为ip而不是hostname。

网上查到apache2.conf中有一个字段是控制显示ip还是hostname,我找到了这个字段。却发现这个字段默认为off,即显示ip。

#
# HostnameLookups: Log the names of clients or just their IP addresses
# e.g., www.apache.org (on) or 204.62.129.132 (off).
# The default is off because it'd be overall better for the net if people
# had to knowingly turn this feature on, since enabling it means that
# each client request will result in AT LEAST one lookup request to the
# nameserver.
#
HostnameLookups Off

那么,问题肯定不出在这。所以我还是去查看官方文档。在mod_log_config模块中,定义了Access Log的格式。这段配置也在Apache2.conf文件中:

#
# The following directives define some format nicknames for use with
# a CustomLog directive.
#
# These deviate from the Common Log Format definitions in that they use %O
# (the actual bytes sent including headers) instead of %b (the size of the
# requested file), because the latter makes it impossible to detect partial
# requests.
#
# Note that the use of %{X-Forwarded-For}i instead of %h is not recommended.
# Use mod_remoteip instead.
#
LogFormat "%v:%p %h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" vhost_combined
LogFormat "%h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %l %u %t \"%r\" %>s %O" common
LogFormat "%{Referer}i -> %U" referer
LogFormat "%{User-agent}i" agent

我的日志格式是采用的combine方式,所以看这行:

LogFormat "%h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined

我们关注第一个参数,%h。在官方文档中是这样描述这个字段的:

%h: Remote hostname. Will log the IP address if HostnameLookups is set to Off, which is the default. If it logs the hostname for only a few hosts, you probably have access control directives mentioning them by name. See the Require host documentation.

按照这段说明,既然我设置的HostnameLookups为Off,所以应当显示IP才对,但不不知道为什么没有生效。于是,我看到文档中的另一个字段:%a,描述如下:

%a: Client IP address of the request (see the mod_remoteip module).

记录请求IP,这应该就是我要的了。于是,修改配置如下:

LogFormat "%a %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined

现在,记录1的情况就已经解决了。下面来解决记录2的问题。

“::1”这个记录是IPv6的回环地址,相当于IPv4的127.0.0.1。而我们网站并不需要IPv6的支持,那么问题就简单了,只需要关闭Apache2对IPv6的支持即可。

在ports.conf中修改下面字段即可:

Listen 0.0.0.0:80

重新运行脚本,可以正常使用了。

在Ubuntu服务器上部署一个网站(Apache2)

服务器环境:Ubuntu 15.04 x64    权限:root

1、安装Apache2

~# apt-get install apache2

安装完成后,得到一下几个文件夹:

网站默认目录:

/var/www/    #如果部署多个网站则在此目录下新建子目录
/var/www/html/    #网站默认根目录

Apache2配置目录:

/etc/apache2/
/etc/apache2/mods-available
/etc/apache2/mods-enable
/etc/apache2/sites-available
/etc/apache2/sites-enable

此时访问localhost(或者直接在外部用IP访问)可以看到It Works!的提示页面

2、网站部署(tool.zivers.com)

在解析商处添加A解析到服务器IP地址

在网站默认目录www/下新建文件夹,例如tool.zivers.com

~# cd /var/www/
~# mkdir tool.zivers.com

在Apache的配置目录下的sites-available目录下加入新网站的配置信息,此处可以借鉴Apache2的默认配置:

~# cd /etc/apache2/sites-available
~# cp 000-default.conf tool.zivers.com.conf

修改conf:

~# vi tool.zivers.com.conf

将网站信息改为新网站信息:

ServerName tool.zivers.com
DocumentRoot /var/www/tool.zivers.com

切换到sites-enabled目录,创建软链接启用网站

~# cd ../sites-enabled
~# ln -s ../sites-available/tool.zivers.com.conf tool.zivers.com.conf

重启Apache2

~# service apache2 restart

此时tool.zivers.com已经可以访问

3、开启rewrite-mod和AllowOverride

部分网站系统,例如Wordpress,需要开启rewrite功能,这里一并描述

进入mods-enabled目录,创建软链接启用rewrite-mod

~# cd /etc/apache2/mods-enabled
~# ln -s ../mods-available/rewrite.load rewrite.load

在需要开启AllowOverride的网站中写入配置信息

~# vi /etc/apache2/sites-available/tool.zivers.com

加入AllowOverride属性

<Directory /var/www/tool.zivers.com>
    Options Indexes FollowSymLinks MultiViews
    AllowOverride All
    Order allow,deny
    allow from all
</Directory>

使用.htaccess实现网站的301重定向

为什么要使用301重定向?

301转向是用户或蜘蛛向网站服务器发出访问请求时,服务器返回的HTTP数据流中头信息(header)部分状态码的一种,表示本网址永久性转移到另一个地址。

网页A用301重定向转到网页B,搜索引擎可以肯定网页A永久性改变地址,或者说实际上不存在了,搜索引擎就会把网页B当做唯一有效的目标。这是搜索引擎唯一推荐的不会产生怀疑的转向方法,最重要的是,网页A累积的页面权重被传到网页B。

做301转向目前Google会传递大部分网址权重,但不是百分之百权重。百度会传递所有权重。Google对301的识别、反应、完成权重传递,需要1-3个月的时间。百度对301处理则比较保守,新旧URL会同时存在于数据库很长的时间,经常看到做了301转向一年的URL还出现在百度结果中。

下面是利用Apache的.htaccess实现301重定向的方法:

首先需要开启Apache的RewriteMod,具体在《在Ubuntu服务器上部署一个网站(Apache2)》这篇文章里有介绍。

然后在.htaccess文件中添加以下内容

RewriteEngin on
#开启RewriteMod
RewriteCond %{HTTP_HOST} ^zivers.com [NC]
RewriteRule ^(.*)$ http://www.zivers.com/$1 [L,R=301]
#将所有不带www的访问重定向到带www的访问

重启服务器即可。