Linux小课堂: Apache虚拟主机配置之基于IP与域名的服务器部署指南
服务器主机分类与特性
1 ) 独立服务器
- 整台服务器资源由单一用户独占,采用租用或托管方式
- 用户对硬件配置拥有完全控制权,需自行维护硬件设备(如故障修理),适用于大中型网站
2 ) 虚拟主机(Virtual Host)
- 单台服务器划分磁盘空间存放网站数据,仅提供基础访问、存储与传输功能
- 资源共享导致成本较低,无需用户维护网站外服务,适合小型网站
3 ) VPS(Virtual Private Server)
- 虚拟化技术模拟多台独立主机,每台具备独立IP、操作系统、隔离的磁盘/内存/CPU资源
- 用户自由分配资源,需一定系统维护能力,适合小型企业官网
4 ) ECS(Elastic Compute Service)
- 云服务器整合计算、存储、网络,支持弹性伸缩
- 分布式架构跨越多台物理服务器,主机镜像备份保障高安全性与稳定性,扩展灵活,适合大中小型网站
选型建议:
- 个人静态网站:虚拟主机或免费服务(如 GitHub Pages)
- 小型企业官网:VPS
- 高访问量/可扩展网站:ECS云服务器(如阿里云)
技术类比:
- 虚拟主机 ≈ 单套房分隔的共享房间(资源相互影响)
- VPS ≈ 单套房分隔的独立公寓(可自定义环境)
- 云服务器 ≈ 整栋大楼(按需扩展空间)
Apache虚拟主机核心机制
- 功能定义:基于请求的IP地址、主机域名或端口号,单台服务器提供多个独立网站访问
- 基于不同IP地址、主机域名或端口号响应请求,实现多网站并行服务,不同请求返回不同内容
- 用户访问不同标识时,获取的网页内容独立隔离
基于IP地址的虚拟主机配置
前提条件:服务器需绑定多个IP地址(本例以 192.168.0.106、192.168.0.10、192.168.0.20 为例)。
配置步骤
1 ) 绑定静态IP地址
编辑网络配置文件(CentOS)
sudo vi /etc/sysconfig/network-scripts/ifcfg-ens33
修改以下参数
BOOTPROTO=static
IPADDR=192.168.0.106
NETMASK=255.255.255.0
# 使用 nmtui 添加新IP
sudo nmtui # 选择 "Edit a connection" → "Edit" → "IPv4 CONFIGURATION"
# 添加新地址:192.168.0.10/24 和 192.168.0.20/24
sudo systemctl restart network # 重启网络服务
2 ) 创建网站目录与内容
mkdir -p /home/web/{10,20}
echo "IP 192.168.0.10" > /home/web/10/index.html
echo "IP 192.168.0.20" > /home/web/20/index.html
3 ) 修改Apache主配置文件 (/etc/httpd/conf/httpd.conf)
<VirtualHost 192.168.0.10:80>DocumentRoot "/home/web/10"ServerName www.linuxcoreapp.com <Directory "/home/web/10">AllowOverride None Require all granted </Directory>
</VirtualHost><VirtualHost 192.168.0.20:80>DocumentRoot "/home/web/20"ServerName bbs.linuxcoreapp.com <Directory "/home/web/20">AllowOverride None Require all granted </Directory>
</VirtualHost>
4 ) SELinux安全上下文配置
sudo semanage fcontext -a -t httpd_sys_content_t "/home/web(/.*)?"
sudo restorecon -Rv /home/web # 应用配置
5 ) 重启Apache服务
sudo systemctl restart httpd
验证访问:浏览器输入 http://192.168.0.10 或 http://192.168.0.20 分别显示对应IP的页面内容
基于主机域名的虚拟主机配置
前提条件:单IP绑定多域名(本例以 192.168.0.10 解析 www.linuxcoreapp.com 和 bbs.linuxcoreapp.com 为例)
配置步骤
1 ) 客户端域名解析配置
- 修改客户端
/etc/hosts文件:192.168.0.10 www.linuxcoreapp.com 192.168.0.10 bbs.linuxcoreapp.com # 或这样写 192.168.0.10 www.linuxcoreapp.com bbs.linuxcoreapp.com
2 ) 创建域名对应目录与内容
mkdir -p /home/web/{www,bbs}
echo "www.linuxcoreapp.com" > /home/web/www/index.html
echo "BBS.linuxcoreapp.com" > /home/web/bbs/index.html
3 ) 修改Apache配置 (/etc/httpd/conf/httpd.conf)
<VirtualHost 192.168.0.10:80>DocumentRoot "/home/web/www"ServerName www.linuxcoreapp.com <Directory "/home/web/www">AllowOverride None Require all granted </Directory>
</VirtualHost><VirtualHost 192.168.0.10:80>DocumentRoot "/home/web/bbs"ServerName bbs.linuxcoreapp.com <Directory "/home/web/bbs">AllowOverride None Require all granted </Directory>
</VirtualHost>
4 ) 重启Apache服务,清理冲突配置
rm -rf /home/web/{10,20} # 删除旧IP目录
systemctl restart httpd # 重启Apache生效
验证访问:
http://www.linuxcoreapp.com→ 显示 “www.linuxcoreapp.com”http://bbs.linuxcoreapp.com→ 显示 “BBS.linuxcoreapp.com”
NestJS工程实践
1 ) 方案1
实现虚拟主机逻辑
import { Controller, Get, HostParam } from '@nestjs/common';
import { Response } from 'express';@Controller({ host: ':domain' }) // 动态捕获域名
export class VirtualHostController {@Get()serveContent(@HostParam('domain') domain: string, res: Response) {const contentMap = {'www.linuxcoreapp.com': 'Welcome to www.linuxcoreapp.com','bbs.linuxcoreapp.com': 'BBS.linuxcoreapp.com Forum'};if (contentMap[domain]) {res.send(contentMap[domain]);} else {res.status(404).send('Virtual Host Not Found');}}
}// 多IP支持(需多网卡或IP别名)
@Controller({ host: '192.168.0.10' })
export class IpBasedController {@Get()handleIpRequest() {return 'Response from IP 192.168.0.10';}
}
关键配置说明:
@Controller({ host: ':domain' })动态捕获域名参数contentMap实现域名与内容的映射逻辑- 多IP需结合服务器网络配置(如IP别名
ifconfig eth0:0 192.168.0.10)
2 )方案2
NestJS域名路由实现
// domain-routing.module.ts
import { Module, MiddlewareConsumer } from '@nestjs/common';
import { DomainMiddleware } from './domain.middleware';
import { WebsiteController } from './website.controller';
import { BBSController } from './bbs.controller';@Module({controllers: [WebsiteController, BBSController],
})
export class DomainRoutingModule {configure(consumer: MiddlewareConsumer) {consumer .apply(DomainMiddleware).forRoutes('*');}
}// domain.middleware.ts
import { Request, Response, NextFunction } from 'express';export function DomainMiddleware(req: Request, res: Response, next: NextFunction) {const host = req.headers.host;// 重写请求路径以匹配不同控制器if (host === 'www.linuxcoreapp.com') {req.url = '/website' + req.url;} else if (host === 'bbs.linuxcoreapp.com') {req.url = '/bbs' + req.url;}next();
}// website.controller.ts
import { Controller, Get } from '@nestjs/common';@Controller('website')
export class WebsiteController {@Get()serveWebsite() {return { content: 'Welcome to www.linuxcoreapp.com' };}
}// bbs.controller.ts
import { Controller, Get } from '@nestjs/common';@Controller('bbs')
export class BBSController {@Get()serveBBS() {return { content: 'Welcome to BBS.linuxcoreapp.com' };}
}
实现逻辑:
- 中间件动态路由:根据
Host请求头重写URL路径 - 控制器分离:独立控制器处理不同域名业务逻辑
- 扩展性:可结合反向代理(Nginx)实现域名分流与负载均衡
3 ) 方案3
import { Controller, Get, HostParam } from '@nestjs/common'; @Controller({ host: ':domain' }) // 动态域名捕获
export class VirtualHostController { @Get() serveContent(@HostParam('domain') domain: string): string { if (domain === 'www.linuxcoreapp.com') { return 'www.linuxcoreapp.com content'; } else if (domain === 'bbs.linuxcoreapp.com') { return 'BBS.LINUXCOREAPP.COM content'; } return 'Default host content'; }
}
技术要点总结
- IP与域名解析隔离:
- 基于IP:每个网站需独立IP,适用于IP资源充足的场景
- 基于域名:单IP多域名,依赖
ServerName字段区分请求
- SELinux安全机制:
必须通过semanage与restorecon命令设置httpd_sys_content_t上下文类型,否则文件不可访问 - 配置优先级:
Apache优先匹配<VirtualHost>区块,未匹配的请求由默认主机处理 - 虚拟主机核心
Apache通过<VirtualHost>指令块 隔离不同网站,依赖 DocumentRoot 指定资源路径 - 配置文件逻辑:
DocumentRoot指定资源路径<Directory>定义目录访问权限ServerName声明域名标识
- 配置冲突规避:删除旧目录/配置块(如
/home/web/10)避免残留规则干扰
