web学习笔记编程技术学习与分享

Apache 虚拟主机与 .htaccess 的几个坑

2026 年 09 月 08 日约 3 分钟阅读 运维与部署

Apache 的虚拟主机机制灵活,但几个细节不注意,症状会非常诡异:全站 500、配置不生效、访问到另一个站点。

VirtualHost 的匹配规则

Apache 按顺序匹配 <VirtualHost>:先精确匹配 ServerName 与 ServerAlias,都不匹配时用第一个定义的虚拟主机。所以第一个 VHost 通常是默认站点或 404 引导。

<VirtualHost *:80>
    ServerName example.com
    ServerAlias www.example.com
    DocumentRoot /www/example/public
</VirtualHost>

改完 apachectl -t(或 httpd -t)做语法检查再 reload,能拦掉一半事故。

.htaccess 与 AllowOverride

.htaccess 支持目录级配置,是它最大的优点和最大的问题:

  • 性能:开启 AllowOverride All 后,每个请求 Apache 都要沿目录树向上逐级查找并解析 .htaccess。文件越深,查找越多。可以的话把规则写到 vhost 里,AllowOverride None;
  • 语法兼容:FPM/CGI 模式下部分指令不可用(如 php_flag),写了直接整目录 500。这是从 mod_php 迁移到 FPM 时最典型的坑;
  • 错误面大:一条非法指令会让整个目录 500,而不是只影响那一行。

排查方法:先临时 AllowOverride None 看是否恢复,确认是 .htaccess 的问题后逐行注释定位。

Files / Directory 的合并顺序

Apache 配置段有固定合并顺序:<Directory>(从短路径到长路径)→ .htaccess → <DirectoryMatch> → <Files> → <Location>。后合并的覆盖先合并的。理解为「越具体的越后生效」不如记顺序,遇到冲突时用日志验证:

LogLevel alert rewrite:trace3   # 重写规则调试

两个高频错误

重写循环:RewriteRule . index.php [L] 配合了错误条件,规则反复命中自己。所有 rewrite 都应带「目标不是文件」的前置条件:

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

权限段顺序:Require 指令新旧混用(Order/Deny 与 Require)会互相干扰,统一用 Apache 2.4 的 Require 语法。

目录结构建议

配置全部收敛到 vhost 文件,.htaccess 只在确需用户级控制时使用;每个站点一个 conf 文件;变更走 Git 管理——Apache 出问题时,第一反应应该是 diff 上一次正常工作的配置。

Apache配置部署