Nginx Url Rewrite

Nginx Rewrite规则相关指令
Nginx Rewrite规则相关指令有if、rewrite、set、return、break等,其中rewrite是最关键的指令。一个简单的Nginx Rewrite规则语法如下:

rewrite ^/b/(.*).html /play.php?video=$1 break;

如果加上if语句,示例如下:

if (!-f $request_filename)
rewrite ^/img/(.*)$ /site/$host/images/$1 last;

Nginx与Apache的Rewrite规则实例对比

简单的Nginx和Apache 重写规则区别不大,基本上能够完全兼容。例如:

Apache Rewrite 规则:

RewriteRule ^/(mianshi|xianjing)/$ /zl/index.php?name=$1 [L]
RewriteRule ^/ceshi/$ /zl/ceshi.php [L]
RewriteRule ^/(mianshi)_([a-zA-Z]+)/$ /zl/index.php?name=$1_$2 [L]
RewriteRule ^/pingce([0-9]*)/$ /zl/pingce.php?id=$1 [L]

Nginx Rewrite 规则:

rewrite ^/(mianshi|xianjing)/$ /zl/index.php?name=$1 last;
rewrite ^/ceshi/$ /zl/ceshi.php last;
rewrite ^/(mianshi)_([a-zA-Z]+)/$ /zl/index.php?name=$1_$2 last;
rewrite ^/pingce([0-9]*)/$ /zl/pingce.php?id=$1 last;

由以上示例可以看出,Apache的Rewrite规则改为Nginx的Rewrite规则,其实很简单:Apache的RewriteRule指令换成Nginx的rewrite指令,Apache的[L]标记换成Nginx的last标记,中间的内容不变。

如果Apache的Rewrite规则改为Nginx的Rewrite规则后,使用nginx -t命令检查发现nginx.conf配置文件有语法错误,那么可以尝试给条件加上引号。例如一下的Nginx Rewrite规则会报语法错误:

rewrite ^/([0-9]{5}).html$ /x.jsp?id=$1 last;

加上引号就正确了:

rewrite “^/([0-9]{5}).html$” /x.jsp?id=$1 last;

Apache与Nginx的Rewrite规则在URL跳转时有细微的区别:

Apache Rewrite 规则:

RewriteRule ^/html/tagindex/([a-zA-Z]+)/.*$ /$1/ [R=301,L]

Nginx Rewrite 规则:

rewrite ^/html/tagindex/([a-zA-Z]+)/.*$ http://$host/$1/ permanent;

以上示例中,我们注意到,Nginx Rewrite 规则的置换串中增加了“http://$host”,这是在Nginx中要求的。

另外,Apache与Nginx的Rewrite规则在变量名称方面也有区别,例如:

Apache Rewrite 规则:

RewriteRule ^/user/login/$ /user/login.php?login=1&forward=http://%{HTTP_HOST} [L]

Nginx Rewrite 规则:

rewrite ^/user/login/$ /user/login.php?login=1&forward=http://$host last;

Apache与Nginx Rewrite 规则的一些功能相同或类似的指令、标记对应关系:

Apache的RewriteCond指令对应Nginx的if指令;
Apache的RewriteRule指令对应Nginx的rewrite指令;
Apache的[R]标记对应Nginx的redirect标记;
Apache的[P]标记对应Nginx的last标记;
Apache的[R,L]标记对应Nginx的redirect标记;
Apache的[P,L]标记对应Nginx的last标记;
Apache的[PT,L]标记对应Nginx的last标记;

允许指定的域名访问本站,其他域名一律跳转到http://www.aaa.com

Apache Rewrite 规则:

RewriteCond %{HTTP_HOST} ^(.*?).xiaokyun.com$
RewriteCond %{HTTP_HOST} !^qita.xiaokyun.com$
RewriteCond %{DOCUMENT_ROOT}/market/%1/index.htm -f
RewriteRule ^/wu/$ /market/%1/index.htm [L]

Nginx的if指令不支持嵌套,也不支持AND、OR等多条件匹配,相比于Apache的RewriteCond,显得麻烦一些,但是,我们可以通过下一页的Nginx配置写法来实现这个示例:

Nginx Rewrite 规则:

if ($host ~* ^(.*?).xiaokyun.com$) set $var_wupin_city $1;
set $var_wupin ‘1′;

if ($host ~* ^qita.xiaokyun.com$)
set $var_wupin ‘0′;

if (!-f $document_root/market/$var_wupin_city/index.htm)
set $var_wupin ‘0′;

if ($var_wupin ~ ‘1′)
rewrite ^/wu/$ /market/$var_wupin_city/index.htm last;
}

rewrite 的语法

语法: rewrite regex replacement flag

默认: none

作用域: server, location, if

This directive changes URI in accordance with the regular expression and the replacement string. Directives are carried out in order of appearance in the configuration file.

这个指令根据表达式来更改URI,或者修改字符串。指令根据配置文件中的顺序来执行。

Be aware that the rewrite regex only matches the relative path instead of the absolute URL. If you want to match the hostname, you should use an if condition, like so:

注意重写表达式只对相对路径有效。如果你想配对主机名,你应该使用if语句。

rewrite只是会改写路径部分的东东,不会改动用户的输入参数,因此这里的if规则里面,你无需关心用户在浏览器里输入的参数,rewrite后会自动添加的,因此,我们只是加上了一个?号和后面我们想要的一个小小的参数 ***https=1就可以了。

nginx的rewrite规则参考:

~ 为区分大小写匹配
~* 为不区分大小写匹配
!~和!~*分别为区分大小写不匹配及不区分大小写不匹

-f和!-f用来判断是否存在文件
-d和!-d用来判断是否存在目录
-e和!-e用来判断是否存在文件或目录
-x和!-x用来判断文件是否可执行

last 相当于Apache里的[L]标记,表示完成rewrite,呵呵这应该是最常用的
break 终止匹配, 不再匹配后面的规则
redirect 返回302临时重定向 地址栏会显示跳转后的地址
permanent 返回301永久重定向 地址栏会显示跳转后的地址

$args
$content_length
$content_type
$document_root
$document_uri
$host
$http_user_agent
$http_cookie
$limit_rate
$request_body_file
$request_method
$remote_addr
$remote_port
$remote_user
$request_filename
$request_uri
$query_string
$scheme
$server_protocol
$server_addr
$server_name
$server_port
$uri

结合QeePHP的例子

if (!-d $request_filename) {
rewrite ^/([a-z-A-Z]+)/([a-z-A-Z]+)/?(.*)$ /index.php?namespace=user&controller=$1&action=$2&$3 last;
rewrite ^/([a-z-A-Z]+)/?$ /index.php?namespace=user&controller=$1 last;
break;

多目录转成参数
abc.xiaokyun.com/sort/2 => abc.xiaokyun.com/index.php?act=sort&name=abc&id=2

if ($host ~* (.*).xiaokyun.com) {
set $sub_name $1;
rewrite ^/sort/(d+)/?$ /index.php?act=sort&cid=$sub_name&id=$1 last;
}

目录对换
/123456/xxxx -> /xxxx?id=123456

rewrite ^/(d+)/(.+)/ /$2?id=$1 last;

例如下面设定nginx在用户使用ie的使用重定向到/nginx-ie目录下:

if ($http_user_agent ~ MSIE) {
rewrite ^(.*)$ /nginx-ie/$1 break;
}

目录自动加“/”

if (-d $request_filename){
rewrite ^/(.*)([^/])$ http://$host/$1$2/ permanent;
}

禁止htaccess

location ~/.ht {
deny all;
}

禁止多个目录

location ~ ^/(cron|templates)/ {
deny all;
break;
}

禁止以/data开头的文件
可以禁止/data/下多级目录下.log.txt等请求;

location ~ ^/data {
deny all;
}

禁止单个目录
不能禁止.log.txt能请求

location /searchword/cron/ {
deny all;
}

禁止单个文件

location ~ /data/sql/data.sql {
deny all;
}

给favicon.ico和robots.txt设置过期时间;
这里为favicon.ico为99天,robots.txt为7天并不记录404错误日志

location ~(favicon.ico) {
log_not_found off;
expires 99d;
break;
}

location ~(robots.txt) {
log_not_found off;
expires 7d;
break;
}

设定某个文件的过期时间;这里为600秒,并不记录访问日志

location ^~ /html/scripts/loadhead_1.js {
access_log off;
root /opt/lampp/htdocs/web;
expires 600;
break;
}

文件反盗链并设置过期时间
这里的return 412 为自定义的http状态码,默认为403,方便找出正确的盗链的请求
“rewrite ^/ http://leech.xiaokyun.com/leech.gif;”显示一张防盗链图片
“access_log off;”不记录访问日志,减轻压力
“expires 3d”所有文件3天的浏览器缓存

location ~* ^.+.(jpg|jpeg|gif|png|swf|rar|zip|css|js)$ {
valid_referers none blocked *.test.xiaokyun.com *.app.xiaokyun.com localhost 208.97.167.194;
if ($invalid_referer) {
rewrite ^/ http://leech.xiaokyun.com/leech.gif;
return 412;
break;
}
access_log off;
root /opt/lampp/htdocs/web;
expires 3d;
break;
}

只充许固定ip访问网站,并加上密码

root /opt/htdocs/www;
allow 208.97.167.194;
allow 222.33.1.2;
allow 231.152.49.4;
deny all;
auth_basic “C1G_ADMIN”;
auth_basic_user_file htpasswd;

将多级目录下的文件转成一个文件,增强seo效果
/job-123-456-789.html 指向/job/123/456/789.html

rewrite ^/job-([0-9]+)-([0-9]+)-([0-9]+).html$ /job/$1/$2/jobshow_$3.html last;

将根目录下某个文件夹指向2级目录
如/shanghaijob/ 指向 /area/shanghai/
如果你将last改成permanent,那么浏览器地址栏显是/location/shanghai/

rewrite ^/([0-9a-z]+)job/(.*)$ /area/$1/$2 last;

上面例子有个问题是访问/shanghai 时将不会匹配

rewrite ^/([0-9a-z]+)job$ /area/$1/ last;
rewrite ^/([0-9a-z]+)job/(.*)$ /area/$1/$2 last;

这样/shanghai 也可以访问了,但页面中的相对链接无法使用,
如./list_1.html真实地址是/area/shanghia/list_1.html会变成/list_1.html,导至无法访问。

那我加上自动跳转也是不行咯
(-d $request_filename)它有个条件是必需为真实目录,而我的rewrite不是的,所以没有效果

if (-d $request_filename){
rewrite ^/(.*)([^/])$ http://$host/$1$2/ permanent;
}

知道原因后就好办了,让我手动跳转吧

rewrite ^/([0-9a-z]+)job$ /$1job/ permanent;
rewrite ^/([0-9a-z]+)job/(.*)$ /area/$1/$2 last;

文件和目录不存在的时候重定向:

if (!-e $request_filename) {
proxy_pass http://127.0.0.1;
}

域名跳转

server
{
listen 80;
server_name jump.xiaokyun.com;
index index.html index.htm index.php;
root /opt/lampp/htdocs/www;
rewrite ^/ http://www.xiaokyun.com/;
access_log off;
}

多域名转向

server_name www.test.xiaokyun.com/ www.xiaokyun.com/;
index index.html index.htm index.php;
root /opt/lampp/htdocs;
if ($host ~ “c1gstudio.net”) {
rewrite ^(.*) http://www.test.xiaokyun.com$1/ permanent;
}

三级域名跳转

if ($http_host ~* “^(.*).i.xiaokyun.com$”) {
rewrite ^(.*) http://top.xiaokyun.com$1/;
break;
}

域名镜向

server
{
listen 80;
server_name mirror.test.xiaokyun.com;
index index.html index.htm index.php;
root /opt/lampp/htdocs/www;
rewrite ^/(.*) http://www.xiaokyun.com/$1 last;
access_log off;
}

某个子目录作镜向

location ^~ /zhaopinhui {
rewrite ^.+ http://zph.xiaokyun.com/ last;
break;
}

discuz ucenter home (uchome) rewrite

rewrite ^/(space|network)-(.+).html$ /$1.php?rewrite=$2 last;
rewrite ^/(space|network).html$ /$1.php last;
rewrite ^/([0-9]+)$ /space.php?uid=$1 last;

discuz 7 rewrite

rewrite ^(.*)/archiver/((fid|tid)-[w-]+.html)$ $1/archiver/index.php?$2 last;
rewrite ^(.*)/forum-([0-9]+)-([0-9]+).html$ $1/forumdisplay.php?fid=$2&page=$3 last;
rewrite ^(.*)/thread-([0-9]+)-([0-9]+)-([0-9]+).html$ $1/viewthread.php?tid=$2&extra=page%3D$4&page=$3 last;
rewrite ^(.*)/profile-(username|uid)-(.+).html$ $1/viewpro.php?$2=$3 last;
rewrite ^(.*)/space-(username|uid)-(.+).html$ $1/space.php?$2=$3 last;
rewrite ^(.*)/tag-(.+).html$ $1/tag.php?name=$2 last;

给discuz某版块单独配置域名

server_name bbs.test.xiaokyun.com news.test.xiaokyun.com;

location = / {
if ($http_host ~ news.xiaokyun.com$) {
rewrite ^.+ http://news.xiaokyun.com/forum-831-1.html last;
break;
}
}

discuz ucenter 头像 rewrite 优化

location ^~ /ucenter {
location ~ .*.php?$
{
#fastcgi_pass unix:/tmp/php-cgi.sock;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fcgi.conf;
}

location /ucenter/data/avatar {
log_not_found off;
access_log off;
location ~ /(.*)_big.jpg$ {
error_page 404 /ucenter/images/noavatar_big.gif;
}
location ~ /(.*)_middle.jpg$ {
error_page 404 /ucenter/images/noavatar_middle.gif;
}
location ~ /(.*)_small.jpg$ {
error_page 404 /ucenter/images/noavatar_small.gif;
}
expires 300;
break;
}
}

jspace rewrite

location ~ .*.php?$
{
#fastcgi_pass unix:/tmp/php-cgi.sock;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fcgi.conf;
}

location ~* ^/index.php/
{
rewrite ^/index.php/(.*) /index.php?$1 break;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fcgi.conf;
}

apache-nginx-url-rewrite-convert

Apache(.htaccess):

RewriteEngine On
RewriteBase /
RewriteRule ^()$ index.php [NC,L]
Rewritecond %{REQUEST_URI} !(^/?.*..*$) [NC]
RewriteRule (.*)$ $1.php [NC]

nginx:

location / {
root /htdocs/;
index index.php index.html index.htm;
rewrite ^/()$ /index.php last;
rewrite /(.*)$ /$1.php;
}

使用Apache作为Nginx的PHP处理后台

Nginx本身不自带PHP处理模块,因此需要配置反向代理,将php请求交给其他的PHP解析器执行,然后返回结果给Nginx。
目前流行的方式是使用fast-cgi的方式配置PHP处理服务。其优点是比较简洁,服务器负载轻。但是缺点也是很明显的:无法查看php处理状态。
比如有时候网站因为负荷过高,php处理线程已经全部阻塞,就会造成网站无法再响应php服务。使用fastcgi方式,无法查看是哪些脚本处理时间过长,阻塞了php处理线程。
而Apache的有点就在于,可以很好的查看哪些php脚本处理时间过长,阻塞了有效进程数。

下面的方式是使用Apache最为Nginx的php处理后台:

1,先安装apache

apt-get install apache

并配置好apache正确运行在8001端口。

2,修改nginx的虚拟主机配置,其他php脚本交由apache解析

location ~ .php$ {
proxy_pass http://127.0.0.1:8001;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_connect_timeout 30;
proxy_send_timeout 30;
proxy_read_timeout 30;

client_max_body_size 10m;
client_body_buffer_size 128k;
proxy_buffer_size 4k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
}

重启nginx和apache就好了。

注意,如果要查看php的处理状态,安装使用apache的监控模块就可以了。

linux 多账户下实现Apache虚拟主机之间的相互隔离设置

合租了linux服务器,作为管理员以及和合租者都希望将自己的虚拟主机目录和别人的隔离(因为每个用户都有linux登录账户),这个问题起初也烦恼我很久,不过很快我就有了解决办法。

1.假设 有两个站点 siteA 和 siteB(假设这两个站点的目录在/var/www/下)
2.使用root账户登录终端建立两个帐号 userA 和 userB, 要满足使用userA登录时候只能有权限进入siteA目录,登录siteB只能进入siteB目录

useradd userA
useradd userB

3.linux 在新建账户的时候如果没有为此帐号分配组,则默认会建立以该帐号同名的组,于是上面就自动产生了userA 和 userB组
4.然后将siteA 和 siteB这两个目录的所属

cd /var/www
chgrp userA siteA/ #注意这里的userA是同名的组名非帐户
chgrp userB siteB/

5.然后修改两个目录的访问权限,只能同一个组可有访问和修改

chmod 755 siteA/ #755的权限就是文件的创建者和所属组可有读取,写入
chmod 755 siteB/

6.此时我们就实现了不同的用户组账户进入对应的目录的权限,但是此时Apache没有读取这两个目录的权限,因为Apache不属于上述任何组
7.启动Apache的默认账户一般是 apache (如果没有建立一个)
8.如果将Apache账户 分别加入 userA 和 userB组,那么apache 就有权限可有访问到这两个目录了

gpasswd -a apache userA #将apache账户分别加入 userA组和 userB组
gpasswd -a apache userB
service httpd restart

原文:http://blog.css-js.com/linux/linux-centos-apache-dirset.html

Windows下配置Apache + OpenSSL测试

1. 下载包含OpenSSL的Apache Http Server,如httpd-2.2.17-win32-x86-openssl-0.9.8o.msi
2. 安装Apache,例如:d:Apache. 安装时制定一个域名,因为是本机测试,在hosts文件中加入了127.0.0.1 www.xiaokyun.com;
3. 在d:Apacheconfhttpd.conf,去掉下面两行的注释:

LoadModule ssl_module modules/mod_ssl.so
Include conf/extra/httpd-ssl.conf

4. 命令行切换到目录d:Apachebin。运行下面三行命令(执行第一个命令时,Common Name项的值输入www.xiaokyun.com):

openssl req -new -out www.xiaokyun.com.csr -config ..confopenssl.cnf
openssl rsa -in privkey.pem -out www.xiaokyun.com.key
openssl x509 -in www.xiaokyun.com.csr -out www.xiaokyun.com.crt -req -signkey www.xiaokyun.com.key -days 3650

5. 完成之后,将目录中的www.xiaokyun.com.key和www.xiaokyun.com.crt拷贝到d:Apacheconf目录中。
6. d:Apacheconfhttpd.conf中取消Include conf/extra/httpd-ssl.conf前的注释。
7. d:Apacheconfhttpd.confextrahttpd-ssl.conf中设置:

SSLCertificateFile “d:/apache/conf/www.xiaokyun.com.crt”
SSLCertificateKeyFile “d:/apache/conf/www.xiaokyun.com.key”

6. 重启Apache Http Server服务。
7. 测试访问http://www.xiaokyun.com/.自己颁发浏览器不信任的SSL证书成功!
免费SSL证书可参考StartSSL.