前两篇把 Linux 命令和权限打底打完,从这一篇起进入 Nginx 主战场。
第一次接触 Nginx 的人,最容易卡在「装好了不知道改哪个文件」「改完不知道怎么生效」「配错了不知道哪里看错误」。这一篇按真实部署流程走一遍:装上去 → 看目录结构 → 写第一个站点配置 → 验证生效 → 看日志。10 分钟跑起来一个能访问的静态站点,对 Nginx 的整体结构也就有了感觉。
一、Nginx 三种安装姿势对比
| | | |
|---|
| 偏老(如 Ubuntu 22.04 默认 1.18) | | |
| | | |
| | | |
| | | |
新人推荐路径:本地学习用发行版仓库(最简单);生产用官方仓库(最新稳定版);需要 Lua / brotli 时上 OpenResty 或 nginx + 模块编译。
Ubuntu / Debian 安装(发行版仓库)
sudo apt updatesudo apt install nginx -y# 验证nginx -v# nginx version: nginx/1.18.0 (Ubuntu)sudo systemctl status nginx
Ubuntu 装官方最新版
# 1. 装必要工具sudo apt install curl gnupg2 ca-certificates lsb-release ubuntu-keyring -y# 2. 加 Nginx 官方签名 keycurl https://nginx.org/keys/nginx_signing.key | gpg --dearmor \ | sudotee /usr/share/keyrings/nginx-archive-keyring.gpg > /dev/null# 3. 加仓库(mainline 是最新主线、stable 是稳定)echo"deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \http://nginx.org/packages/mainline/ubuntu $(lsb_release -cs) nginx" \ | sudotee /etc/apt/sources.list.d/nginx.list# 4. 安装sudo apt updatesudo apt install nginx -ynginx -v# nginx version: nginx/1.27.x
CentOS / Rocky / RHEL 安装
# 系统自带 dnf 仓库版本一般稳定但偏老sudo dnf install nginx -y# 装官方最新(推荐)sudotee /etc/yum.repos.d/nginx.repo <<'EOF'[nginx-stable]name=nginx stable repobaseurl=http://nginx.org/packages/centos/$releasever/$basearch/gpgcheck=1enabled=1gpgkey=https://nginx.org/keys/nginx_signing.keyEOFsudo dnf install nginx -y
Docker 起一个(最快验证)
docker run -d --name nginx-demo \ -p 8080:80 \ -v $(pwd)/html:/usr/share/nginx/html:ro \ nginx:1.27-alpinecurl http://localhost:8080
容器化最大的好处:测完 docker rm -f nginx-demo 一键清,本机零污染。
二、安装后的目录结构地图
装完后第一件事是搞清楚配置、日志、文档都在哪儿。Ubuntu/Debian 系和 CentOS/RHEL 系结构不完全一样:
Ubuntu / Debian(apt 装的)
/etc/nginx/├── nginx.conf # 主配置入口├── conf.d/ # 通用配置片段(推荐自己加文件在这)├── sites-available/ # **Debian 特有**:所有站点配置原始文件├── sites-enabled/ # **Debian 特有**:通过软链启用的站点├── snippets/ # 复用片段(fastcgi-php.conf 等)├── mime.types # MIME 类型映射├── modules-available/├── modules-enabled/└── proxy_params # 反代常用 header 片段/var/log/nginx/├── access.log # 访问日志└── error.log # 错误日志(**最先看的文件**)/var/www/html/ # 默认站点根目录/usr/sbin/nginx # 二进制/usr/share/doc/nginx/ # 文档
sites-available + sites-enabled 的逻辑:站点配置写在 sites-available/ 下,要启用就 ln -s 软链到 sites-enabled/。这是 Apache 时代留下的习惯,新人很容易在 sites-available 里改了配但忘了软链,发现配置不生效。
CentOS / RHEL / Rocky(dnf 装的)
/etc/nginx/├── nginx.conf├── conf.d/ # **CentOS 没有 sites-* 目录,统一放 conf.d**├── default.d/├── mime.types└── fastcgi.conf/var/log/nginx//usr/share/nginx/html/ # 默认站点根(**注意路径不同**)
Nginx 官方仓库装的(不论发行版)
/etc/nginx/├── nginx.conf├── conf.d/ # 只有 conf.d,没有 sites-*└── default.d//var/log/nginx//usr/share/nginx/html/
这是 Nginx 圈最高频的迷惑点:你查到的教程说 sites-enabled,你在 CentOS 上找不到——因为根本没有。新人记一条:
官方仓库 + CentOS 系 = 走 conf.d/,Debian 系 = 走 sites-enabled/。
三、nginx.conf 五大块结构
打开 /etc/nginx/nginx.conf,看到的不是一坨平铺配置,是有嵌套层级的:
# === main 上下文(全局)===user www-data;worker_processes auto;pid /run/nginx.pid;error_log /var/log/nginx/error.log warn;# === events 上下文(连接处理)===events {worker_connections1024;useepoll;}# === http 上下文(HTTP 协议层)===http {include /etc/nginx/mime.types;default_type application/octet-stream;sendfileon;keepalive_timeout65;log_format main '$remote_addr - $remote_user [$time_local] ''"$request" $status$body_bytes_sent ''"$http_referer" "$http_user_agent"';access_log /var/log/nginx/access.log main;# === include 进来的所有站点配置 ===include /etc/nginx/conf.d/*.conf;include /etc/nginx/sites-enabled/*;# === server 上下文(虚拟主机)===server {listen80 default_server;server_name _;root /var/www/html;# === location 上下文(URL 路径)===location / {try_files$uri$uri/ =404; } }}
五层嵌套关系:
main ├── events └── http └── server └── location
核心心智模型:
- main / events:全局基础设置,一般不动
- http:全站默认行为(日志格式、压缩、超时、SSL 默认),改这里影响所有站点
- server:一个虚拟主机(一个域名 / 一组域名)
写自己站点 99% 的时间是在 server + location 里改,main / events / http 几乎只在调优时碰。
四、写第一个站点:3 分钟可用
新人第一次自己写一个 Nginx 站点,先在 conf.d/ 下加文件,不要直接改 nginx.conf(升级时会被覆盖)。
# 1. 准备静态文件sudomkdir -p /var/www/my-sitesudotee /var/www/my-site/index.html <<'EOF'<!doctype html><html><body> <h1>Hello from Nginx</h1> <p>First site is live.</p></body></html>EOF# 2. 改属主,让 nginx 用户能读sudochown -R www-data:www-data /var/www/my-site # Ubuntu/Debian# sudo chown -R nginx:nginx /var/www/my-site # CentOS# 3. 写一份最小可用 site 配置sudotee /etc/nginx/conf.d/my-site.conf <<'EOF'server { listen 80; server_name my-site.local; root /var/www/my-site; index index.html; access_log /var/log/nginx/my-site.access.log; error_log /var/log/nginx/my-site.error.log warn; location / { try_files $uri$uri/ =404; }}EOF
Debian 系用 sites-enabled 的话:
sudocp /etc/nginx/conf.d/my-site.conf /etc/nginx/sites-available/my-sitesudoln -s /etc/nginx/sites-available/my-site /etc/nginx/sites-enabled/sudorm /etc/nginx/conf.d/my-site.conf # 避免重复 include
五、验证三件套:test → reload → curl
永远按这个顺序,缺一不可:
# 1. 语法检查sudo nginx -t# nginx: the configuration file /etc/nginx/nginx.conf syntax is ok# nginx: configuration file /etc/nginx/nginx.conf test is successful# 2. 平滑重载(不断连)sudo nginx -s reload# 或者sudo systemctl reload nginx# 3. 访问验证curl -H "Host: my-site.local" http://127.0.0.1/# <!doctype html># <html><body># <h1>Hello from Nginx</h1># ...curl -I -H "Host: my-site.local" http://127.0.0.1/# HTTP/1.1 200 OK# Server: nginx/1.27.x# ...
铁律:永远先 nginx -t 再 nginx -s reload。Nginx master 收到 SIGHUP 后会先解析新配置:
- 语法错误:master 会在 error.log 里报错并回滚到旧配置,老 worker 继续工作——这一类不会断
- 语法对但语义错(监听端口被占、SSL 证书路径不存在、upstream DNS 解析失败等):新 worker 起不来,老 worker 还在跑,但部分场景(如 listen 改了端口、证书过期被拒)会导致新连接无人接、老连接慢慢断
nginx -t 能拦下语法错误,但拦不下「语法对、语义错」的问题。真正稳的姿势是:测试环境 reload 一遍、prod 改完再 nginx -t、配上 reload 后的探活脚本(curl /healthz 校验回 200)。
nginx 信号速查表
sudo nginx -s reload # SIGHUP:平滑重载配置(**不断连**)sudo nginx -s reopen # SIGUSR1:重新打开日志文件(logrotate 用)sudo nginx -s stop # SIGTERM:快速停止(**会断连**)sudo nginx -s quit # SIGQUIT:优雅关闭(**等存量请求处理完**)
| | | |
|---|
nginx -s reload | | 不断 | |
nginx -s reopen | | | |
nginx -s quit | | | |
nginx -s stop | | 断 | |
systemctl restart nginx | | 断 | |
核心区别:reload 不断连,restart 会断连。日常改配置 reload 就够,只有升级 nginx 二进制本身才需要 restart。
六、Master + Worker 进程模型
启动后看一眼进程:
ps auxf | grep nginx# root 1234 ... nginx: master process /usr/sbin/nginx# www-data 1235 ... \_ nginx: worker process# www-data 1236 ... \_ nginx: worker process
- Master 进程:root 跑(读 80/443 端口需要 root 权限),不处理请求,只管 worker 的启停 / 信号转发 / 配置 reload
- Worker 进程:普通用户(www-data / nginx)跑,实际处理请求的就是它,默认
worker_processes auto 会启动等于 CPU 核数的 worker
reload 时具体发生了什么:
1. master 收到 SIGHUP2. master 解析新配置,校验失败 → 不做任何事,原 worker 继续干活3. master 启动一批新 worker(用新配置)4. master 向老 worker 发 SIGQUIT5. 老 worker 处理完手头请求后自己退出
整个过程没有任何请求被中断——这就是为什么 nginx 改配置生产可以随便 reload。
七、日志怎么看
Nginx 日志分两类,新人遇到任何问题先看 error.log,再看 access.log。
access.log(每个请求一条)
默认的 combined 格式:
127.0.0.1 - - [25/Jun/2026:14:23:45 +0800] "GET /index.html HTTP/1.1" 200 89 "-" "curl/8.0.1" │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └─ User-Agent │ │ │ │ │ │ │ └─ Referer │ │ │ │ │ │ └─ 响应体字节数 │ │ │ │ │ └─ 状态码 │ │ │ │ └─ 请求行(方法 + URI + 协议) │ │ │ └─ 时间 │ │ └─ 远程用户(HTTP 基本认证才有) │ └─ identd(基本永远是 -) └─ 客户端 IP
定位问题的实战 awk:
# Top 10 访问 IPawk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -10# 所有 5xx 错误请求awk '$9 >= 500 {print $0}' /var/log/nginx/access.log# 各状态码分布awk '{print $9}' /var/log/nginx/access.log | sort | uniq -c | sort -rn
error.log(五级日志)
debug → info → notice → warn → error → crit → alert → emerg
默认是 warn 级别(从 warn 起记录)。调试时改 error_log /var/log/nginx/error.log debug; 能看到非常详细的处理路径,但生产环境千万别开 debug——量大到爆磁盘。
最常见的几条 error 长这样:
# 后端连不通*123 connect() failed (111: Connection refused) while connecting to upstream# 权限不够(Nginx 用户读不到文件)*456 open() "/var/www/my-site/index.html" failed (13: Permission denied)# 路径不存在*789 "/var/www/my-site/" is not found (2: No such file or directory)
八、第一次踩坑清单
新人搭完发现「装好了访问不到」,按这个清单顺序排:
1. nginx 进程没启动
sudo systemctl status nginx# 看 Active 状态、Main PID
2. 80 端口被别人占了
sudo ss -lntp | grep ':80'# 如果是 Apache / 其他东西占了,要么停掉,要么 nginx 改听别的端口
3. 防火墙拦截
# Ubuntu ufwsudo ufw statussudo ufw allow 80/tcp# CentOS firewalldsudo firewall-cmd --list-allsudo firewall-cmd --permanent --add-service=httpsudo firewall-cmd --reload# 云上别忘了「安全组」也要放行(云防火墙在 OS 防火墙之前生效)
4. SELinux 拦截(CentOS 高频)
# 看一眼是不是 enforcinggetenforce# Enforcing# 临时关(仅排查用)sudo setenforce 0# 如果确认是 SELinux 拦截了 nginx 读 /var/www/my-site,正确做法是改上下文:sudochcon -Rt httpd_sys_content_t /var/www/my-sitesudo restorecon -Rv /var/www/my-site
Ubuntu 默认没装 SELinux,CentOS 默认 enforcing,这条是 CentOS 新人栽得最深的坑之一。
5. 文件权限不对
# nginx worker 用什么用户跑?ps aux | grep "nginx: worker"# www-data ... nginx: worker process# 这个用户能不能读到你的文件?sudo -u www-data ls /var/www/my-site/index.html# 如果 Permission denied,就是权限或属主问题
常见解法:
sudochown -R www-data:www-data /var/www/my-sitesudochmod -R 755 /var/www/my-site
6. server_name 没匹配上
# 你的 server_name my-site.local,但 curl 直接打 http://127.0.0.1/# 没设 Host 头,Nginx 会用 default_server 处理(不是你的 my-site)# 测试时要么改 hosts 让域名指向 127.0.0.1,要么 curl 带 -H "Host: my-site.local"
写在最后
- 装 Nginx 生产用官方仓库,开发用发行版仓库 / Docker 都行
- Debian 系走 sites-enabled、CentOS / 官方包统一走 conf.d
- nginx.conf 五大块嵌套:main / events / http / server / location,自己改 99% 在最后两层
- 改完永远
nginx -t 再 nginx -s reload - reload 不断连、restart 才断连
- 访问不到先按「进程 → 端口 → 防火墙 → SELinux → 权限 → server_name」六步排查,比瞎试快十倍
- error.log 是诊断金矿,permission denied / connect refused / not found 三大常客