nginx配置虚拟主机的核心逻辑就一句话:Nginx通过server块区分不同域名的请求,你只需要在配置目录里写好server配置并加载include即可,无需修改主配置文件。

很多新手第一次接触Nginx虚拟主机时,都会被五花八门的教程绕晕,其实抛开那些花哨的术语,虚拟主机就是在一台服务器上,让多个不同域名各自独立运行网站,你按自己的业务需求,为每个域名写一个单独的配置文件,Nginx会根据用户访问的域名自动匹配对应配置,这套机制比Apache的.htaccess规则更直观,也比直接在nginx.conf里堆代码更好维护,下面我用实际操作路径拆解一遍,从基本配置到排查报错,再到和宝塔面板的对比,一步一步说透。
nginx配置虚拟主机的完整步骤
第一步:先搞清楚配置文件目录结构
不同系统、不同安装方式的目录略有差异,但主流发行版基本遵循同一个逻辑,以Ubuntu和CentOS为例,Nginx的虚拟主机配置通常放在以下路径之一:
/etc/nginx/conf.d/最常见的目录,所有.conf文件都会自动加载/etc/nginx/sites-available/Ubuntu倾向使用此目录,需要手动软链到sites-enabled/etc/nginx/nginx.conf主配置文件,其中http块里默认包含include /etc/nginx/conf.d/.conf
行业共识认为:不要把虚拟主机配置直接写进nginx.conf主文件,主文件管全局调度,频繁改动容易写坏语法,也让后期维护变得痛苦,正确做法是在conf.d目录下新建独立的.conf文件,每份文件对应一个域名或一个站点,命名清晰即可。
第二步:编写一个标准的server配置块
虚拟主机的核心就是server块,一个最简单的静态站点配置长这样:
server {
listen 80;
server_name example.com www.example.com;
root /var/www/example;
index index.html;
access_log /var/log/nginx/example_access.log;
error_log /var/log/nginx/example_error.log;
}
这份配置的意思很明确:当用户访问example.com或www.example.com时,Nginx会读取/var/www/example目录下的index.html文件返回给用户,这个目录就是网站的根目录,改成你自己的网站路径即可。
如果你想在一个Nginx上跑多个虚拟主机,就再新建一份.conf文件,重复上述结构,换掉server_name和root即可,注意Nginx的多站点并发运行没有数量限制,只要服务器性能扛得住。
第三步:检测语法并重载生效
修改完配置不要急着重启服务,先检查语法,这一步每年能帮无数运维省下大半夜的排查时间:
nginx -t
看到syntax is ok和test is successful提示后,执行重载:
systemctl reload nginx
如果需要Nginx开机自启,顺手执行:
systemctl enable nginx
至此,一个完整的虚拟主机配置流程就走完了,整个过程不超过5分钟,却能让一台轻量服务器轻松托管多个网站。
nginx配置虚拟主机不生效的排查思路
很多用户照着教程配置完后,发现域名依然打不开,或者打开的是默认页面,这里有个高频误区值得单独拎出来讲:配置语法正确不等于配置生效,Nginx的server_name匹配优先级很可能帮你拦截了请求。
检查域名解析是否指向服务器IP
用一条命令实测当前服务器IP,再去云控制台检查A记录:
curl ifconfig.me dig +short example.com
如果解析结果不是服务器真实IP,说明DNS还没生效或记录写错,国内云服务商的控制台里,解析生效通常需要几分钟到几小时不等,耐心等待即可。
server_name匹配规则需要铭记
Nginx在选择server块时,有一套严格的优先级顺序:

- 先做精确匹配,比如访问www.example.com时会优先选中server_name包含该域名的server块
- 最长前缀匹配,支持
.example.com通配符 - 最后才按listen端口匹配第一个server块作为兜底
这意味着,如果你启动了默认站点(default_server)并且它排在前面,不带域名的IP访问会被它吃掉,建议把无匹配请求统一重定向到指定站点:
server {
listen 80 default_server;
server_name _;
return 301 http://example.com$request_uri;
}
这段配置会让所有无法匹配的请求直接跳转到你的主站点。
配置文件的权限和目录权限同样关键
Nginx工作进程通常以nginx用户运行,如果网站根目录的权限设为root且只读,Nginx虽然有读取能力但依然会出现403,执行以下命令能解决绝大多数权限问题:
chown -R nginx:nginx /var/www/example chmod 755 /var/www/example
另外别忘了查看错误日志,这是一切故障的唯一真相来源:
tail -f /var/log/nginx/error.log
nginx虚拟主机和宝塔面板哪个更省心
这是宝塔生态在国内流行后,几乎每场群聊里都会出现的对比,两者不在同一层面:Nginx是底层Web服务器,宝塔是管理面板,宝塔底层默认驱动就是Nginx,真正该比较的是“手工配置Nginx虚拟主机”和“宝塔可视化配置”哪个适合你。
| 对比维度 | 手工配置Nginx | 宝塔面板建站 |
|---|---|---|
| 配置方式 | 手写conf文件 | 表单填写,自动生成配置 |
| 学习成本 | 对新手有门槛 | 可视化,简单直观 |
| 灵活性 | 完全掌控,随意定制 | 受面板模板限制 |
| 服务器性能 | 无多余进程,资源占用最低 | 面板常驻进程,占用额外内存 |
| 适合场景 | 生产环境、高并发业务 | 个人博客、中小站点 |
这里给个比较务实的建议:如果是构建正式的线上业务系统,建议手工配置Nginx虚拟主机,这样可以精确掌握每一条location规则和性能参数,并且便于接入CI/CD自动化流程,如果是快速搭建个人网站、测试环境,或者你刚接触服务器,宝塔可以帮你免去大量命令行操作,业内专家指出,宝塔近几年在安全补丁和兼容性上改善明显,低配置服务器上的性能损耗基本可以接受。
nginx虚拟主机location规则怎么选
一个server块确定后,真正决定网站行为的是内部location块,很多初学者问nginx配置虚拟主机时location到底怎么配才合理,这里给出最常用的几种匹配场景。
精确匹配用于优先处理关键路径
location = /favicon.ico {
log_not_found off;
access_log off;
}
等号提供精确匹配,优先于所有其他规则,小图标请求无需记日志,这样可以减少无意义的磁盘I/O,在高并发场景下收益明显。
前缀匹配处理静态资源分离
location ^~ /static/ {
alias /data/static/;
expires 30d;
}
^~的意思是匹配到这个前缀后立刻停止正则匹配,把图片、CSS、JS文件放到独立目录,并开启expires缓存,能显著减少Nginx对后端服务的压力,据统计,一个典型的PHP站点中静态资源请求占比可达总流量的半数以上,做好这一步体验提升非常明显。
正则匹配灵活应对文件类型
location ~ \.(js|css|png|jpg|jpeg|gif|ico)$ {
expires 7d;
add_header Cache-Control "public, no-transform";
}
表示不区分大小写的正则匹配,适合统一处理多类型静态文件,使用时要考虑与前述^~的优先级区别,Nginx官方文档明确说明:普通前缀匹配点优先级低于正则,但^~前缀匹配会直接忽略后续正则。
反向代理场景下的常用写法
如果你的Nginx虚拟主机用于接口网关、前后端分离项目,location块里的proxy_pass是核心:
location /api/ {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
这种写法常见于国内云服务器上的微服务部署,Nginx承担流量入口角色,后端用Java、Go或Node容器接收转发请求,需要注意proxy_pass末尾是否带会影响路径拼接规则,混淆这两者也是配置虚拟主机时的经典报错来源。
高级技巧:给虚拟主机做单项性能调优
既然已经独立配置了server块,性能优化就显得有的放矢,在http块里做全局调优固然简单,但如果某个虚拟主机流量特别大或特别小,也可以只针对它做单独配置。
- 开启keepalive复用长连接
keepalive_timeout 65; keepalive_requests 1000;
长连接能减少TCP握手次数,对HTTPS网站尤其重要,因为握手开销更大。

- 调整静态文件读取效率
sendfile on; tcp_nopush on;
sendfile让Nginx直接在文件系统层面传输数据,无需拷贝到用户态,tcp_nopush则由内核合并包再发送,减少小包数量,对视频站和大文件下载效果显著。
- 多虚拟主机共享连接池
upstream backend_pool {
keepalive 32;
server 127.0.0.1:8080;
}
如果服务器上多个虚拟机服务同一个后端,共享连接池可以大幅减少后端服务的并发连接数压力,这类技巧在秒杀、抢购等突发流量场景时用处极大。
- 为单个虚拟主机单独设置worker进程数
大部分场景建议采用默认的worker_processes auto,让Nginx根据核数自动分配,但部分共享主机、低配置云服务器场景下,手工限制单个虚拟机的worker连接数可以防止一个站点拖垮整机:
worker_connections 512;
这条指令放在events块中,生效于全部虚拟主机,如果你想区分站点间的并发上限,更精细的手段是靠limit_req模块按域名做流量限制,反向限制某些盗链域名或爬虫源。
结尾思考
Nginx虚拟主机配置的本质,其实就是一套基于域名路由的规则引擎,当你掌握server块的组合方式、理解include加载机制、并能用location和rewrite自由构建访问规则后,一台单机部署几十个站点完全可行,建议在本地用Docker起一个Nginx镜像,花半天时间模拟不同server_name和location组合的实际效果,比带着担心在生产环境实验安心得多,配置文件多备份、版本化托管,才是长期运维的类基础能力。
Q&A:nginx配置虚拟主机常见问题
问:配置完nginx虚拟主机后访问域名返回Nginx默认页,是什么原因?
多半是default_server兜底规则在起作用,如果你没有重新声明默认站点,Nginx会使用安装时自带的初始配置来匹配任何未命中的域名,检查一下conf.d目录下有没有遗留的default.conf,在配置里确认你的域名拼写无错,并确保每份配置文件末尾都有正确闭合,最简单的方法是把默认文件移走,再执行nginx -t && systemctl reload nginx。
问:一个IP上能配置多少个虚拟主机?
理论上仅受服务器资源限制,nginx配置文件中的server块数量没有硬性上限,一台2核4G的国内云服务器,托管几十个纯静态虚拟主机完全没问题;如果每个虚拟主机都要跑独立PHP-FPM进程,建议控制在十个以内。
问:上级域名的子域名如何配置不同虚拟主机?
可以直接在server_name里写.example.com通配符,然后把子域名信息作为变量传给项目:
server {
listen 80;
server_name ~^(?<sub>.)\.example\.com$;
root /var/www/$sub;
}
但要注意,这种正则匹配方式在生产环境不建议大面积使用,原因在于它的可读性较差,更规范的做法是每个重要子域名独立书写server块,通过include同一份通用配置片段来减少重复。
