必须为每个站点配置独立虚拟主机,因Apache中DocumentRoot仅支持“服务器配置”或“虚拟主机”上下文,单个VirtualHost内无法定义多个DocumentRoot,共享根目录会导致路径混淆、权限越界及安全风险。
在 apache 虚拟主机中为每个站点配置独立的 documentroot,是实现物理路径安全隔离最直接、最可靠的方式。关键不在于“多个 documentroot 共存于一个虚拟主机”,而在于每个站点独占一个 virtualhost,并各自声明专属 documentroot。这样,不同网站的文件系统根完全分离,互不可见、互不干扰,天然规避了跨目录访问、路径混淆和权限越界风险。
为什么必须用独立 VirtualHost 实现隔离
Apache 的 DocumentRoot 指令上下文仅限于“服务器配置”或“虚拟主机”层级,不能嵌套在 或 中,也不支持单个 内定义多个根目录。若强行把多个网站放在同一 DocumentRoot 下(如 /var/www/html/test 和 /var/www/html/prod),即使通过 URL 路由区分,PHP 的 include_once '/config.php' 仍会从 /var/www/html/ 开始查找——这不仅逻辑混乱,更可能因错误的相对路径或开放的目录遍历导致敏感文件泄露。
- 一个
只能有一个DocumentRoot,这是 Apache 架构决定的硬性限制 - 共享 DocumentRoot 下的子目录不具备独立的“Web 根语义”,无法真正隔离运行时路径上下文
- SELinux、文件系统 ACL、chroot 等安全机制都依赖明确且唯一的文档根路径进行策略绑定
配置步骤:从路径到权限的完整闭环
以两个站点为例:site-a.example 对应 /srv/site-a/public,site-b.example 对应 /srv/site-b/public。所有操作需在启用的虚拟主机配置文件中(如 /etc/apache2/sites-enabled/site-a.conf)完成:
-
明确声明 DocumentRoot:指向实际 Web 可访问目录(如 CI4 必须是
public/,非项目根) -
同步配置
块:路径必须与 DocumentRoot 完全一致,并包含Require all granted(2.4+)或等效权限指令 -
确保父级路径可执行:Apache 用户(如
www-data)需对/srv、/srv/site-a、/srv/site-a/public均有x权限,否则 403 报错 -
SELinux 上下文校准(RHEL/CentOS):运行
sudo semanage fcontext -a -t httpd_sys_content_t "/srv/site-a(/.*)?"后执行sudo restorecon -Rv /srv/site-a
避免常见陷阱:路径、加载与权限三重校验
配置后页面空白或 403,往往不是 DocumentRoot 写错了,而是环境链断裂:
Apache Superset 是一个广泛采用的开源 BI 平台,用于 SQL 探索、图表构建和仪表板交付。当代理需要查询仓库数据、组装仪表板或使用成熟的分析界面解释指标而不是临时笔记本代码时,此技能非常有用。
- 用
apachectl -t -D DUMP_INCLUDES确认你修改的配置文件确实在加载列表中,且无其他同名DocumentRoot覆盖 - 检查是否启用了
sites-enabled符号链接(Ubuntu/Debian)或conf.d/*.conf(RHEL),而非只改了sites-available未启用 - 禁止在
.htaccess中尝试“覆盖”DocumentRoot——它根本不被支持,只会引发解析异常 - 若使用符号链接作为 DocumentRoot 目标,需在
块中添加Options +FollowSymLinks并确认 Apache 有权限解析目标路径
进阶建议:强化隔离边界的辅助手段
独立 DocumentRoot 是基础,配合以下措施可进一步加固:
- 为每个站点分配独立系统用户(如
sitea-user),用mpm_itk或php-fpm pool隔离 PHP 进程,防止文件读写越权 - 禁用危险模块(如
mod_userdir),避免通过~username暴露用户主目录 - 在
中显式限制AllowOverride None(除非必需 .htaccess),减少运行时解析开销与规则注入面 - 使用
mod_security规则集拦截对/../类路径遍历请求,作为最后一道防线










