// Linux · 2025-05-16

Apache 虚拟主机配置指南:从单站点到多站点

一、什么是虚拟主机

虚拟主机(Virtual Host)是 Apache 的核心功能之一,允许在一台物理服务器上托管多个网站。每个网站拥有独立的域名、文档根目录和配置,互不干扰。

Apache 支持三种虚拟主机方式:

类型 区分依据 适用场景
基于域名(Name-based) HTTP 请求头中的 Host 字段 最常用,共享同一个 IP 地址
基于 IP(IP-based) 不同的 IP 地址 需要独立 IP 的场景
基于端口(Port-based) 不同的端口号 内部测试、特殊应用

本文重点介绍基于域名的虚拟主机,这是目前最主流、最实用的方案。

二、核心原理:基于域名的虚拟主机

2.1 工作原理

Apache 通过 HTTP 请求头中的 Host 字段来区分不同的网站。当浏览器访问 http://set.charitize.dsz 时,会在请求头中携带 Host: set.charitize.dsz,Apache 根据这个字段匹配对应的 <VirtualHost> 块。

sequenceDiagram
    participant 用户 as 浏览器
    participant DNS as DNS 解析
    participant Apache as Apache 服务器
    participant 站点A as 默认站点 /var/www/localhost/htdocs
    participant 站点B as 隐藏子域名 /var/www/set

    用户->>DNS: 查询 set.charitize.dsz
    DNS-->>用户: 返回服务器 IP
    用户->>Apache: GET / HTTP/1.1<br/>Host: set.charitize.dsz
    Apache->>站点B: 匹配 ServerName<br/>返回 /var/www/set 内容
    站点B-->>Apache: index.html
    Apache-->>用户: 200 OK + 页面内容

    用户->>Apache: GET / HTTP/1.1<br/>Host: localhost
    Apache->>站点A: 未精确匹配<br/>走第一个 VirtualHost(默认)
    站点A-->>Apache: index.html
    Apache-->>用户: 200 OK + 页面内容

2.2 与单站点的核心区别

方面 初始配置(单站点) 修改后配置(虚拟主机)
站点数量 只有 1 个站点(全局 DocumentRoot) 多个虚拟主机(默认 + 隐藏子域名)
匹配方式 所有请求都去同一个目录 根据 Host 请求头分发到不同目录
配置结构 全局 DocumentRoot + Directory 多个 <VirtualHost> 块
关键指令 DocumentRoot "/var/www/localhost/htdocs" NameVirtualHost *:80 + <VirtualHost *:80>

三、配置步骤详解

3.1 启用虚拟主机功能

在 Apache 2.2 中,需要显式启用 NameVirtualHost 指令:

NameVirtualHost *:80

作用:告诉 Apache 启用基于域名的虚拟主机功能,监听所有 IP 的 80 端口。如果没有这个指令,Apache 会将所有请求交给第一个 VirtualHost 处理。

在 Apache 2.4 中,NameVirtualHost 已被废弃,默认自动启用基于域名的虚拟主机。

3.2 配置默认虚拟主机

当使用虚拟主机时,全局的 DocumentRoot 会被忽略,必须将站点配置放在 VirtualHost 块中。

<VirtualHost *:80>
    ServerName localhost
    ServerAlias default
    DocumentRoot "/var/www/localhost/htdocs"
    
    <Directory "/var/www/localhost/htdocs">
        Options Indexes FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>
    
    ErrorLog ${APACHE_LOG_DIR}/localhost_error.log
    CustomLog ${APACHE_LOG_DIR}/localhost_access.log combined
</VirtualHost>

作用:

  • 处理访问 localhost 的请求
  • 作为默认站点,处理所有未匹配到的域名请求(包括直接 IP 访问、未知域名)

3.3 配置隐藏子域名虚拟主机

<VirtualHost *:80>
    ServerName set.charitize.dsz
    DocumentRoot "/var/www/set"
    
    <Directory "/var/www/set">
        Options Indexes FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>
    
    ErrorLog ${APACHE_LOG_DIR}/set_error.log
    CustomLog ${APACHE_LOG_DIR}/set_access.log combined
</VirtualHost>

作用:只处理 Host: set.charitize.dsz 的请求,访问其他域名不会看到这个站点。

3.4 完整配置示例

# 启用基于域名的虚拟主机(Apache 2.2 需要)
NameVirtualHost *:80

# 默认虚拟主机(必须放在第一位,作为 fallback)
<VirtualHost *:80>
    ServerName localhost
    ServerAlias default
    DocumentRoot "/var/www/localhost/htdocs"
    
    <Directory "/var/www/localhost/htdocs">
        Options Indexes FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>
    
    ErrorLog ${APACHE_LOG_DIR}/localhost_error.log
    CustomLog ${APACHE_LOG_DIR}/localhost_access.log combined
</VirtualHost>

# 隐藏子域名虚拟主机
<VirtualHost *:80>
    ServerName set.charitize.dsz
    DocumentRoot "/var/www/set"
    
    <Directory "/var/www/set">
        Options Indexes FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>
    
    ErrorLog ${APACHE_LOG_DIR}/set_error.log
    CustomLog ${APACHE_LOG_DIR}/set_access.log combined
</VirtualHost>

四、请求处理流程

flowchart LR
    A[浏览器/客户端] -->|HTTP 请求| B[Apache Web 服务器]
    B -->|Host: set.charitize.dsz| C[隐藏子域名站点<br/>DocumentRoot: /var/www/set]
    B -->|Host: localhost / IP| D[默认站点<br/>DocumentRoot: /var/www/localhost/htdocs]
    B -->|Host: 其他未知域名| D
    
    style C fill:#e8f5e9
    style D fill:#e1f5fe

匹配规则:

  1. Apache 收到请求后,读取 HTTP 头中的 Host 字段
  2. 精确匹配 ServerName → 返回对应站点内容
  3. 未精确匹配 → 走第一个 VirtualHost(默认站点)

五、常见问题与解决

5.1 为什么配置了 VirtualHost 后原来的站点无法访问?

原因:配置 VirtualHost 后,Apache 进入“虚拟主机模式”。在这个模式下:

  1. 全局的 DocumentRoot 被忽略
  2. 只有 VirtualHost 块中定义的站点才能被访问
  3. 如果没有定义处理原来域名(如 localhost 或直接 IP 访问)的 VirtualHost,原来的内容就无法访问

解决:添加一个默认 VirtualHost,将原来的配置移入其中。

5.2 如何验证虚拟主机配置?

# 列出所有虚拟主机
sudo apachectl -S

输出示例:

VirtualHost configuration:
*:80                   localhost (/etc/apache2/httpd.conf:162)
*:80                   set.charitize.dsz (/etc/apache2/httpd.conf:175)

5.3 如何添加更多站点?

只需增加新的 <VirtualHost *:80> 块,指定不同的 ServerName 和 DocumentRoot:

<VirtualHost *:80>
    ServerName blog.example.com
    DocumentRoot "/var/www/blog"
    ...
</VirtualHost>

5.4 403 Forbidden 错误?

可能原因:

  • 目录权限不正确:sudo chmod -R 755 /var/www
  • 配置中缺少 Require all granted
  • SELinux 未关闭(CentOS):sudo setenforce 0

六、关键指令速查表

指令 作用
NameVirtualHost *:80 启用基于域名的虚拟主机(Apache 2.2)
<VirtualHost *:80> 定义一个虚拟主机块
ServerName 设置虚拟主机的主域名
ServerAlias 设置虚拟主机的别名域名
DocumentRoot 设置站点的文档根目录
ErrorLog 设置错误日志路径
CustomLog 设置访问日志路径

七、总结

问题 答案
为什么要加默认虚拟主机? 让原来直接访问 IP/localhost 的用户还能看到原来的网站
为什么隐藏子域名生效? Apache 根据 Host 请求头精确匹配 ServerName
访问顺序是什么? 精确匹配 ServerName → 匹配不到的走第一个 VirtualHost(默认站点)
如何添加更多隐藏站点? 增加新的 <VirtualHost *:80> 块,指定不同的 ServerName 和 DocumentRoot

虚拟主机是 Apache 最实用的功能之一,通过基于域名的方式,可以在一台服务器上高效托管多个独立站点,既节省资源又便于管理。

原文 https://blog.csdn.net/2301_79518550/article/details/148019877