Nginx以url前缀作为虚拟主机

需求

仅通过IP或者单一域名访问的情况下,根据不同的url前缀,指向不同的根目录。给用户的感觉是访问了不同的站点。

例如http://localhost/aaa则访问站点a,http://localhost/bbb则访问站点b,http://localhost/aaa/ccc则访问站点c

真正的Vhost

真正意义上Vhost,是使用域名作为区分。也就是server_name字段。这类配置方式广为人知。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
server {
listen 80;
server_name www.aaa.com;
charset utf-8;
access_log /var/log/nginx/log/aaa.access.log main;
location / {
root /www/aaa;
index index.html index.htm;
}
}
server {
listen 80;
server_name www.bbb.com;
charset utf-8;
access_log /var/log/nginx/log/bbb.access.log main;
location / {
root /www/bbb;
index index.html index.htm;
}
}

URL前缀区分

要通过url前缀区来区分站点,本质上还是通过配置多级location来实现,顶层使用location ^~作为区分,里面有独立的access_log策略,有嵌套的location作为动态静态控制。

不过笔者在实践的时候,还是遇到了一些小坑。

root还是alias

根据官方讲义
http://nginx.org/en/docs/http/ngx_http_core_module.html#alias

1
2
3
4
5
6
7
8
9
location /images/ {
alias /data/w3/images/;
}
# or
location /images/ {
root /data/w3;
}

使用两个配置,在访问lcoalhost/images/a.jpg时,最终读取的都是/data/w3/images/a.jpg
使用rootlocation后的URI也会一并包含在访问路径中,/data/w3/+images/a.jpg
使用aliaslocation后的URI不回包含在访问路径中,/data/w3/images/+a.jpg

alias还可以实现如下的高级用法,不过alias的路径一定要有/结尾,不然就妥妥的404吧。

1
2
3
location ~ ^/users/(.+\.(?:gif|jpe?g|png))$ {
alias /data/w3/images/$1;
}

不带斜杠的情况

访问http://localhost/aaahttp://localhost/aaa/的时候,都应该视为访问站点a。这里针对/aaa做了跳转的处理方式

1
2
3
location = /aaa {
rewrite /aaa /aaa/ permanent;
}

嵌套路径

针对http://localhost/aaa/ccc指向站点c的情况。需要使用location ^~前缀匹配的方式,因为nginx在进行location匹配的时候,会寻找尽可能匹配的情况,这于先后顺序无关。
比如,访问http://localhost/aaa/ccc会匹配到下一条。

1
2
3
4
5
6
7
location ^~ /aaa/ {
...
}
location ^~ /aaa/ccc {
...
}

PHP

通过fastcgi访问php时。$fastcgi_script_name将被赋值成URI,或者是URI+/index.php
在访问http://localhost/aaa/时,$fastcgi_script_name/aaa/index.php,但aaa是不应出现在变量中,否则会导致路径错误。

我们使用fastcgi_split_path_info对URI进行处理,略去aaa前缀部分,并设置正确的SCRIPT_FILENAME

1
2
3
4
5
6
7
8
location ~ ^/aaa/(.+\.php)(.*)$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_split_path_info ^/aaa/(.+\.php)(.*)$;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
include fastcgi_params;
}

这样,对于SCRIPT_FILENAMESCRIPT_NAME,都可以将其设置为正确值。

参考讲义
http://nginx.org/en/docs/http/ngx_http_fastcgi_module.html#variables
http://nginx.org/en/docs/http/ngx_http_fastcgi_module.html#fastcgi_split_path_info

成品

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
server {
listen 80;
server_name localhost;
charset utf-8;
access_log off;
error_log off;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
#============================================================
# aaa
#============================================================
location = /aaa {
rewrite /aaa /aaa/ permanent;
}
location ^~ /aaa/ {
alias /www/aaa/;
index index.php;
access_log /var/log/nginx/log/aaa.access.log main;
error_log /var/log/nginx/log/aaa.error.log;
if (!-e $request_filename){
rewrite ^/(.*) /aaa/index.php last;
}
location ~ ^/aaa/(.+\.php)(.*)$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_split_path_info ^/aaa/(.+\.php)(.*)$;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
include fastcgi_params;
}
}
#============================================================
# bbb
#============================================================
location = /bbb {
rewrite /bbb /bbb/ permanent;
}
location ^~ /bbb/ {
alias /www/bbb/;
index index.php;
access_log /var/log/nginx/log/bbb.access.log main;
error_log /var/log/nginx/log/bbb.error.log;
location ~ ^/bbb/(.+\.php)(.*)$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_split_path_info ^/bbb/(.+\.php)(.*)$;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
include fastcgi_params;
}
}
#============================================================
# ccc
#============================================================
location = /aaa/ccc {
rewrite /aaa/ccc /aaa/ccc/ permanent;
}
location ^~ /aaa/ccc/ {
alias /www/ccc/;
index index.php;
access_log /var/log/nginx/log/ccc.access.log main;
error_log /var/log/nginx/log/ccc.error.log;
if (!-e $request_filename){
rewrite ^/(.*) /aaa/ccc/index.php last;
}
location ~ ^/aaa/ccc/(.+\.php)(.*)$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_split_path_info ^/aaa/ccc/(.+\.php)(.*)$;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
include fastcgi_params;
}
}
}