nginx虚拟主机依赖三个硬性条件:server块必须嵌套在http块内、listen指令必须显式声明端口、server_name必须与请求host头精确匹配;缺一即导致404或落入默认站。

直接结论:Nginx 虚拟主机不是“开个开关”就能用,它依赖三个硬性条件——server块必须嵌套在http块内、listen指令必须显式声明端口、server_name必须与请求头的Host字段精确匹配。漏掉任一环,访问就 404 或落到默认站。
server 块写在哪才不报 unknown directive "server"
错误现象:nginx -t 报 unknown directive "server",哪怕配置内容完全正确。
-
server块绝不能放在events块里,也不能顶格写在nginx.conf开头 - 必须确保它位于
http { ... }大括号内部——常见位置是/etc/nginx/nginx.conf底部的http段,或被include /etc/nginx/conf.d/*.conf;加载的独立文件中 - 推荐做法:新建
/etc/nginx/conf.d/example.com.conf,只放一个server块,避免污染主配置 - 验证是否加载成功:运行
nginx -T | grep -A5 "server_name example.com",看到实际生效的完整配置才算到位
listen 80 但外网打不开?检查监听地址和防火墙
现象:本地 curl http://localhost 成功,但从另一台机器访问 http://192.168.1.100 超时或拒绝连接。
-
listen 80;等价于listen *:80;,可被所有 IP 访问;而listen 127.0.0.1:80;只响应本机回环,外部不可达 - CentOS/RHEL 默认启用
firewalld,Ubuntu 默认启用ufw,必须手动放行:sudo firewall-cmd --add-port=80/tcp --permanent && sudo firewall-cmd --reload(CentOS)或sudo ufw allow 80(Ubuntu) - 如果服务器在云上(如阿里云、AWS),还要检查安全组规则,80 端口必须显式开放
server_name 匹配失败的三种典型场景
现象:浏览器输入 http://example.com 却返回默认站点首页或 404,access_log 显示请求进了别的 server 块。
- 用户访问
http://192.168.1.100,但配置是server_name example.com;→ 不匹配,进第一个没带default_server的块,或 fallback 到全局默认 - 配置
server_name www.example.com;,但用户输的是example.com→ 必须显式列出:server_name example.com www.example.com; - 想匹配所有子域却写成
server_name *.example.com;→ 它只匹配一级子域(如api.example.com),不匹配dev.api.example.com;多级需正则:server_name ~^([^.]+\.)*example\.com$;
root 和 alias 路径行为差异导致静态文件 404
现象:配置了 location /static/ { root /var/www; },访问 /static/js/app.js 却报 404;换成 alias 后又提示目录无权限或路径错乱。
-
root是“拼接”:请求/static/js/app.js→ 实际查找/var/www/static/js/app.js(注意自动补全/static/) -
alias是“替换”:请求/static/js/app.js→ 实际查找/var/www/static/js/app.js,但前提是alias /var/www/static/;结尾必须有斜杠;写成alias /var/www/static;(缺斜杠)会导致路径错位 - 别混用:一个
location里不要同时出现root和alias,Nginx 会忽略后者并报错 - 调试建议:临时加
error_log /var/log/nginx/error.log notice;,403/404 错误日志里会明确写出 Nginx 实际尝试打开的绝对路径
最常被忽略的一点:改完配置后只跑 nginx -t 是不够的。nginx -t 不校验 include 的文件是否存在、路径是否拼错、软链接是否断开;它只检查语法。真正要确认生效,得用 nginx -T 输出全部合并后的配置,再人工核对目标 server 块是否出现在其中、root 路径是否是你期望的绝对路径、server_name 是否包含你正在测试的值。











