Apache 的配置 VirtualHost 配置里,一个 ServerName 后面跟多个 DocumentRoot 入口,文件这事听起来简单,单域实际踩坑的名多人不少。上周帮朋友迁移一个老项目,入口就遇到这个问题:域名是配置
app.example.com,但用户访问/要进前台页面,文件访问/admin要进后台管理系统,单域两个目录完全独立,名多代码也不在一起。入口最直接的配置想法是在 Apache 里配两个 VirtualHost,都绑定同一个域名。文件但 Apache 对同名 ServerName 的单域处理方式是——谁先匹配到谁生效,后面的名多直接忽略。所以这条路走不通。入口
Alias 是最省事的做法
如果两个入口的物理路径不同,Alias 指令几乎是最快能跑通的方式。比如前台在
/var/www/frontend,后台在/var/www/adminpanel:<VirtualHost *:80> ServerName app.example.com DocumentRoot /var/www/frontend Alias /admin /var/www/adminpanel <Directory /var/www/adminpanel> Options Indexes FollowSymLinks AllowOverride All Require all granted </Directory> <Directory /var/www/frontend> Options Indexes FollowSymLinks AllowOverride All Require all granted </Directory> </VirtualHost>
这样
app.example.com/走前台,app.example.com/admin走后台。配置改完apachectl configtest检查一下语法,没问题就 reload。但这里有个细节容易被忽略:Alias 是路径前缀匹配,
/admin会匹配到/admin、/admin/、/adminanything。如果后台程序内部有自己的一套路由,比如它期望的入口是/admin/index.php,那 Alias 到目录层面通常没问题。但如果后台代码里写死了$_SERVER['DOCUMENT_ROOT']来做文件包含,Alias 不会改变 DOCUMENT_ROOT 的值,程序可能找不到文件。这种情况就得靠RewriteBase或者干脆上反向代理。RewriteRule 更灵活,但别写太绕
另一个常见场景是两个入口在同一个 DocumentRoot 下,只是入口文件不同。比如 Laravel 项目里前台走
index.php,后台走admin.php。这种用 mod_rewrite 更自然:RewriteEngine On RewriteBase / RewriteRule ^admin(/.*)?$ admin.php [L,QSA] RewriteRule ^(?!admin).*$ index.php [L,QSA]
注意第二条规则里的负向断言
(?!admin),不加的话/admin会被第二条规则也匹配到,虽然[L]标记会阻止继续处理,但规则顺序和标记配合不好就容易出现 500 或者无限循环。我见过有人在规则里写RewriteCond %{ REQUEST_URI} !^/admin来做条件判断,效果一样,但可读性差一些。RewriteRule 的好处是路径可以完全重写,不依赖物理目录结构。坏处是调试麻烦,
LogLevel alert rewrite:trace3打开日志才能看清每一步怎么跳的。ProxyPass 适合前后端分离的架构
现在很多项目前台是静态站或者 Node 服务,后台是 PHP 或者 Java。这种异构入口用 Alias 和 Rewrite 都别扭,反向代理最干净:
ProxyPreserveHost On ProxyPass /api http://127.0.0.1:3000/ ProxyPassReverse /api http://127.0.0.1:3000/ ProxyPass /admin http://127.0.0.1:8080/ ProxyPassReverse /admin http://127.0.0.1:8080/
这样
/api转发到本地 3000 端口的 Node 服务,/admin转发到 8080 端口的后台应用。Apache 只做入口网关,具体业务逻辑由后端服务处理。这种配置在容器化部署里特别常见,因为每个服务可以独立扩缩容,Apache 层几乎不用改。有个坑要注意:
ProxyPass的路径末尾有没有斜杠,行为不一样。ProxyPass /admin http://127.0.0.1:8080/会把/admin/foo映射成http://127.0.0.1:8080/foo,而ProxyPass /admin http://127.0.0.1:8080会映射成http://127.0.0.1:8080/admin/foo。差一个字符,后端收到的路径完全不同。选哪种取决于入口之间的关系
我的判断标准很简单:如果两个入口共享同一个物理目录树,RewriteRule 最合适;如果目录完全独立但还在同一台机器上,Alias 够用;如果入口背后是不同的服务进程,直接上 ProxyPass。别为了“统一配置风格”硬用一种方案,Apache 提供了这些指令就是让它们各司其职的。
最后提一句,改完配置记得用
顶: 689踩: 563curl -I分别测两个入口的响应头,确认状态码和 Content-Type 都符合预期。浏览器缓存有时候会骗你,命令行更可靠。






评论专区