nginx虚拟主机配置的核心答案很简单:通过server块区分不同域名或端口,实现一台服务器托管多个网站。 你只需要在配置文件中定义多个server,分别指定server_name和root,再执行nginx -t校验和reload重载即可生效。

nginx的灵活性和高性能让它占据了Web服务器市场的相当大份额,对于站长和运维人员来说,虚拟主机配置是必会的基本功,也是很多朋友遇到困惑较多的地方,今天咱们就抛开那些绕口的官方文档,用大白话把这件事彻底捋清楚,让你看完就能动手操作。
nginx虚拟主机配置逻辑:先理解配置文件在忙什么
想要配置得心应手,你得先知道nginx是怎么“思考”的。本质上,nginx虚拟主机配置就是定义“当用户访问特定域名时,应该把请求交给哪个目录或服务处理”的规则集合。
配置文件的骨架结构
nginx的主配置文件通常是/etc/nginx/nginx.conf(CentOS/RHEL系)或/etc/nginx/sites-available/(Ubuntu/Debian系),主配置文件里有一行关键指令:
http {
include /etc/nginx/conf.d/.conf;
# 或者
# include /etc/nginx/sites-enabled/;
}
这行include就是“收纳盒”,它会把conf.d目录下所有以.conf结尾的文件都加载进来。行业共识认为,把每个虚拟主机的配置单独放在一个文件里,是维护效率最高的方式。
server块的三个核心要素
每个虚拟主机配置的核心就是server块,一个server块就是一个虚拟主机,一个最小的server块长这样:
server {
listen 80;
server_name example.com www.example.com;
root /var/www/example;
index index.html;
}
这里面的listen和server_name,就是nginx用来区分不同虚拟主机的“身份证”,当请求到达时,nginx会根据端口和域名,匹配到对应的server块。
实战指南:手把手配置基于域名的虚拟主机
基于域名的虚拟主机是最常用的场景,也就是一个IP地址上挂多个域名,下面用一个具体场景来演示。
假设你现在有两台“网站”,都跑在同一台服务器上:
- 站点A:
blog.example.com,代码放在/var/www/blog - 站点B:
shop.example.com,代码放在/var/www/shop
第一步:创建目录结构和测试文件
先在服务器上执行命令:
mkdir -p /var/www/blog /var/www/shop echo "<h1>这是博客</h1>" > /var/www/blog/index.html echo "<h1>这是商城</h1>" > /var/www/shop/index.html
第二步:编写虚拟主机配置文件
在/etc/nginx/conf.d/目录下创建两个配置文件,命名要见名知意,比如blog.conf和shop.conf。
blog.conf
server {
listen 80;
server_name blog.example.com;
root /var/www/blog;
index index.html;
}
shop.conf
server {
listen 80;
server_name shop.example.com;
root /var/www/shop;
index index.html;
}
第三步:校验并重载配置
这一步非常关键,很多配置“不生效”的故障就是跳过了校验步骤。
nginx -t
如果输出syntax is ok和test is successful,说明配置格式没问题,然后执行:
nginx -s reload
reload是平滑重载,不会中断现有连接,这一点比Apache的restart要体贴得多。
第四步:验证结果
在你本地的/etc/hosts文件里临时加上解析记录(或者直接用已经解析好的域名),然后访问blog.example.com和shop.example.com,能看到各自不同的页面,就代表虚拟主机配置成功了。

破解默认虚拟主机与server_name匹配规则
在实际运维中,nginx服务器往往面临大量不同来源的访问请求,这些请求的Host头五花八门,理解nginx的匹配优先级能帮你避免不少坑。
当访问的域名没配置时会发生什么?
如果你访问的域名在服务器上没有对应的server块,nginx会使用默认虚拟主机来处理,默认虚拟主机就是listen配置了default_server参数的server块。
server {
listen 80 default_server;
server_name _;
return 444;
}
配置了default_server的server块,会接住所有没有匹配到任何server_name的请求,返回444是一种常见的做法,表示直接断开连接,不给任何响应,可以有效减少恶意扫描。
server_name的精准匹配顺序
nginx处理server_name时,有严格的顺序:
- 精确匹配:
server_name blog.example.com - 通配符前匹配:
server_name .example.com - 通配符后匹配:
server_name www.example. - 正则匹配:
server_name ~^(www\.)?example\.com$
nginx会按这个顺序依次查找,找到第一个匹配的规则就会停止。
泛解析配置:运用通配符
有时候你需要把某个域名下的所有子域名都指向同一个网站,比如用户个人主页,此时可以用通配符虚拟主机:
server {
listen 80;
server_name .user.example.com;
root /var/www/userpages/$subdomain;
}
这里有个技巧,你可以配合$host变量来动态指定目录,比如用root /var/www/userpages/$host;,这样abc.user.example.com就会自动映射到/var/www/userpages/abc.user.example.com目录下,不过需要你确保目录存在,或者用正则重写来处理。
进阶场景:基于端口和IP的虚拟主机配置
域名虚拟主机足够应对绝大多数场景,但还有两种特殊情况。
基于端口的配置:用途特定服务
比如你有一个管理后台,不想让用户通过常规80端口访问,想换个冷门端口提高隐蔽性。
server {
listen 8080;
server_name admin.example.com;
root /var/www/admin;
access_log /var/log/nginx/admin.access.log;
}
访问http://admin.example.com:8080才能打开,要注意的是,使用非80端口时,需要在云服务器安全组和防火墙里放行对应端口。
基于IP的配置:多IP服务器
如果你的服务器绑定了多个IP地址,想让不同IP访问不同的站点,只需修改listen:
server {
listen 203.0.113.10:80;
server_name example.com;
root /var/www/site1;
}
server {
listen 203.0.113.11:80;
server_name example.com;
root /var/www/site2;
}
这种场景现在用得少了,但在某些政企内网环境中还是会遇到。
location匹配规则:虚拟主机内部的详细路由
正确配置location,可以更精细地控制URL映射,这是nginx虚拟主机配置中提升访问精准度的关键环节,很多人只关注域名匹配,却忽视了location的优先级,导致图片加载失败或者伪静态规则失效,这一块尤其值得留意。
location匹配优先级排序
nginx的location匹配有严格优先级顺序,从上到下先匹配优先级别高的规则:
- 精确匹配 :
location = /logo.png - 前缀匹配
^~:location ^~ /static/ - 正则匹配 或 `~location ~ .php$`
- 普通前缀匹配:
location /api/
nginx会先检查精确匹配和前缀匹配,再按顺序检查正则,找到第一个匹配的规则后,如果它是^~或,就直接使用,不进行正则匹配,如果找到普通前缀匹配,则继续找正则,正则匹配到了就覆盖前缀匹配。
一个常用的静态资源配置块
比如对于常见站点,可以配置:

server {
listen 80;
server_name example.com;
root /var/www/html;
index index.php index.html;
# 静态文件缓存
location ~ \.(jpg|jpeg|png|gif|ico|css|js)$ {
expires 30d;
add_header Cache-Control "public, immutable";
}
# PHP请求转发
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
# 拒绝访问隐藏文件
location ~ /\. {
deny all;
}
}
用rewrite规则美化URL
如果想让用户访问/article/123实际转发给/index.php?id=123,可以在server块里加上:
location / {
rewrite ^/article/(\d+)$ /index.php?id=$1 last;
}
last标记表示停止当前规则的匹配,重新发起一轮location匹配。
常见故障:配置不生效与404排查思路
新配置完虚拟主机,最容易在处理关于‘配置未生效’的问题时踩坑,我用经验帮你快速定位,直接给出可验证的排查路径。
排查业务流程
- 运行
nginx -t检查语法: 语法错误是最低级的错误,但经常发生,检查缺少分号、大括号不配对、变量名拼写错误。 - 查看错误日志: 日志文件在
/var/log/nginx/error.log,大多数格式问题、路径问题在日志里一目了然,通常带有具体的行号提示。 - 确认是否使用了正确配置文件: 检查主配置文件的include路径是否覆盖了你编辑的文件,有的朋友编辑了
sites-available下的文件,却忘了创建软链接到sites-enabled,导致配置载入失败,尤其以Debian/Ubuntu系统居多。 - 检查文件权限: nginx运行用户通常是
nginx或www-data,需要保证该用户对网站目录有读权限,否则页面结果是403,而非404。
处理404问题
404通常是root路径设置错误或location匹配不当,先看root路径下是否真的存在对应文件,如果在location中使用了alias,也要检查alias路径拼接是否正确,它是替换而不是拼接。
安全加固与性能建议
虚拟主机配置的最终目的是稳定、安全地对外提供服务,作为线上生产环境,有几个配置细节值得关注。
隐藏版本号降低被针对性攻击风险
在http块中添加:
server_tokens off;
这样nginx报错页面就不会显示版本号,能避开针对特定版本漏洞的扫描。
启用gzip压缩流量
大部分场景下,文本类内容启用gzip能显著降低带宽消耗:
gzip on; gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
设置超时与连接限制
对虚拟主机做基本的资源隔离,避免单个站点耗尽连接:
server {
listen 80;
server_name example.com;
client_max_body_size 10m;
keepalive_timeout 65;
}
client_max_body_size可根据业务上传需求调整大小,这是防止大文件上传拖垮服务器的常用手段。
常见nginx虚拟主机相关疑问与解答
nginx的虚拟主机配置和Apache的虚拟主机配置差别在哪里?
两者核心逻辑都是配置基于域名或IP的多个站点,但存在三点明显差异。nginx没有独立的<VirtualHost>标签,统一用server块实现,配置语法更简洁紧凑,nginx的.htaccess机制不完全等同于Apache,通常在server块或location块中直接写规则,建议关闭Apache风格的分布式配置,以降低性能开销,nginx的高并发能力和低内存占用,让它在同等硬件条件下能支撑更多虚拟主机。
虚拟主机配置中server_name可以同时匹配多个域名吗?
可以。server_name支持一个块内并列多个域名,用空格分隔即可。 这是很常见的做法,比如使用server_name example.com www.example.com;就能实现访问主域和www子域都指向相同站点内容,这种方式适用于需要配置大量域名的虚拟主机,建议配合通配符和正则规则使用,总体匹配效率更高,运维目标也更明确,结合泛解析和default_server机制,可以构建覆盖不同需求的虚拟主机体系。
nginx修改了虚拟主机配置后为什么清理浏览器缓存才能生效?
这不是nginx本身的问题,是浏览器层级的响应机制和你的客户端本地缓存。nginx在reload之后,新生效规则已经不会影响已经建立的TCP连接和缓存响应。 而浏览器可能对静态资源启用了强缓存,本地保存了过期响应头,导致页面看起来还是旧状态,通常等待缓存自然过期即可,也可以用Ctrl+F5强制刷新,问题就会消失,属于正常现象,清理的是客户端缓存,不是服务器缓存。
结尾收束与建议
nginx虚拟主机配置的核心就是server块、server_name、root和location之间的协同工作,只要掌握了匹配优先级,并且熟悉nginx -t和nginx -s reload这套安全操作流程,你就能轻松管理一台服务器上的多个站点,千万不要图省事把所有站点都塞进一个server块里,给每个虚拟主机独立配置文件,才是长期维护的上策。
