Appearance
Nginx 入门与部署
Nginx 是一个事件驱动的 Web 服务——一个 master 进程负责管理配置和控制 worker,多个 worker 进程负责接收连接、读取请求、匹配配置、返回响应或转发给后端。
text
nginx: master process /usr/sbin/nginx
├── nginx: worker process
├── nginx: worker process
└── nginx: worker process一、几个核心概念
Nginx 的配置是分层的,每个层次有不同的职责:
| 概念 | 做什么 | 在配置的哪一层 |
|---|---|---|
| master 进程 | 管理进程,读取配置、控制 worker 的启停和 reload | 不由配置控制,Nginx 自身架构 |
| worker 进程 | 工作进程,实际处理客户端连接和请求 | worker_processes |
| server | 一个虚拟主机,按监听端口和域名区分 | server {} |
| location | 一个 URI 匹配规则,决定匹配后怎么处理 | location {} |
| upstream | 一组后端服务,反向代理和负载均衡时引用 | upstream {} |
Nginx 最常见的三种形态:
| 形态 | 处理方式 | 例子 |
|---|---|---|
| 静态 Web 服务 | 直接读取本机文件返回 | HTML、CSS、JS、图片、下载文件 |
| 反向代理入口 | 把请求转发给后端应用 | Java、Go、Node.js、PHP-FPM |
| 混合入口 | 静态资源本机返回,API 转发后端 | /static/ 走文件,/api/ 走代理 |
混合形态在生产环境最常见:前端静态文件由 Nginx 直接返回(快),接口请求转发给后端(灵活)。排查时先确认请求进了哪个 server,命中了哪个 location,然后看它是在读文件还是转发。
二、安装
测试和普通生产环境用系统包最省事:
bash
# RHEL / Rocky / CentOS
yum install -y nginx
systemctl enable --now nginx
nginx -v
# Debian / Ubuntu
apt update
apt install -y nginx
systemctl enable --now nginx
nginx -v常见路径(不同发行版可能有差异,用 rpm -ql nginx 或 dpkg -L nginx 确认):
| 路径 | 用途 |
|---|---|
/etc/nginx/nginx.conf | 主配置文件 |
/etc/nginx/conf.d/*.conf | 虚拟主机配置目录,主配置通过 include 引入 |
/usr/share/nginx/html | 包安装的默认静态文件目录 |
/var/log/nginx/access.log | 访问日志 |
/var/log/nginx/error.log | 错误日志 |
/usr/sbin/nginx | Nginx 主程序 |
三、配置文件结构
主配置 /etc/nginx/nginx.conf:
nginx
user nginx;
worker_processes auto; # 通常设为 CPU 核数,auto 自动检测
error_log /var/log/nginx/error.log warn;
pid /run/nginx.pid;
events {
worker_connections 1024; # 单个 worker 最多并发处理的连接数
}
http {
include /etc/nginx/mime.types; # MIME 类型映射,决定 Content-Type
default_type application/octet-stream;
access_log /var/log/nginx/access.log;
sendfile on; # 静态文件传输优化:直接内核态复制,不经过用户态
keepalive_timeout 65;
include /etc/nginx/conf.d/*.conf; # 引入虚拟主机配置
}配置上下文的层级关系:
| 上下文 | 位置 | 放什么 |
|---|---|---|
| main | 最外层 | 用户、worker 数、错误日志、pid |
| events | events {} | worker 连接数等事件模型参数 |
| http | http {} | HTTP 全局:日志格式、gzip、mime、include |
| server | server {} | 虚拟主机:监听端口、域名、根目录 |
| location | location {} | URI 匹配后的行为:读文件、返回状态、转发代理 |
改完配置先检查语法:
bash
nginx -t # 检查语法和引用文件是否存在通过后 reload(不中断现有连接,旧 worker 处理完手中请求后退出,新 worker 用新配置):
bash
systemctl reload nginxnginx -t 只看语法,不看逻辑——root 目录不存在它不会报错。还有一个常见的坑:主配置语法正确,但 conf.d 里某个 include 文件写错了,nginx -t 一样失败。
四、第一个静态站点
创建站点目录和测试文件:
bash
mkdir -p /data/www/example
echo 'hello nginx' > /data/www/example/index.html
chown -R nginx:nginx /data/www/example # RHEL 系运行用户
# Debian/Ubuntu 运行用户是 www-data:
# chown -R www-data:www-data /data/www/example虚拟主机配置 /etc/nginx/conf.d/example.conf:
nginx
server {
listen 80;
server_name example.local;
root /data/www/example;
index index.html;
location / {
try_files $uri $uri/ =404; # 依次尝试文件、目录,都不存在返回 404
}
access_log /var/log/nginx/example.access.log;
error_log /var/log/nginx/example.error.log warn;
}加载并验证:
bash
nginx -t && systemctl reload nginx
curl -H 'Host: example.local' http://127.0.0.1/返回 hello nginx 说明请求命中了这个 server。curl -H 'Host:' 是模拟浏览器带 Host 头的请求——Nginx 靠 Host 头匹配 server_name。
五、静态资源和 API 混合
前后端分离应用最常见的配置:前端静态文件本机返回,接口请求转发给后端:
nginx
upstream app_api {
server 127.0.0.1:8080;
}
server {
listen 80;
server_name app.example.local;
root /data/www/app;
index index.html;
location / {
try_files $uri $uri/ /index.html; # SPA 路由:找不到文件时返回入口 HTML
}
location /static/ {
expires 7d; # 静态资源让浏览器缓存 7 天
try_files $uri =404;
}
location /api/ {
proxy_pass http://app_api; # 接口请求转给后端
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}try_files $uri $uri/ /index.html 是 SPA(单页应用)的标准写法——用户访问 /user/profile 时,服务器上没有这个文件,但前端路由需要 index.html 来接管这个路径。如果只是普通多页站点,用 try_files $uri $uri/ =404 就够了。
排查时的思路:静态资源 404 多半是目录路径和权限问题,API 502/504 多半是后端连接或响应问题。
六、虚拟主机
同一台 Nginx 可以跑多个站点,按 listen 端口和 Host 头区分:
nginx
server {
listen 80;
server_name app.example.local;
root /data/www/app;
location / {
try_files $uri $uri/ =404;
}
}
server {
listen 80;
server_name admin.example.local;
root /data/www/admin;
location / {
try_files $uri $uri/ =404;
}
}验证不同域名:
bash
curl -H 'Host: app.example.local' http://127.0.0.1/
curl -H 'Host: admin.example.local' http://127.0.0.1/没有匹配到 server_name 的请求会落到默认虚拟主机(第一个定义的 server,或显式标记 default_server 的那个)。建议显式写一个默认的拒绝站点,避免未知域名的探测请求打到真实业务:
nginx
server {
listen 80 default_server;
server_name _;
return 444; # Nginx 特有的状态码——直接关闭连接,不返回任何内容
}七、location 匹配规则
location 决定一个 URI 怎么被处理。几种写法的优先级:
| 写法 | 含义 | 优先级 |
|---|---|---|
location = /health | 精确匹配,只有 /health 命中 | 最高 |
location ^~ /static/ | 前缀匹配,命中后不再检查正则 | 高于正则 |
location ~ \.php$ | 区分大小写的正则匹配 | 按配置顺序 |
location ~* \.(jpg|png)$ | 不区分大小写的正则匹配 | 按配置顺序 |
location /api/ | 普通前缀匹配 | 最低,但选最长匹配 |
示例:
nginx
server {
listen 80;
server_name example.local;
root /data/www/example;
location = /health {
return 200 "ok\n"; # 健康检查,直接返回文本
}
location ^~ /static/ {
expires 7d;
try_files $uri =404;
}
location / {
try_files $uri $uri/ =404;
}
}root 和 alias 的差别:
nginx
location /static/ {
root /data/www/example; # /static/a.png → /data/www/example/static/a.png
}
location /assets/ {
alias /data/cdn/; # /assets/a.png → /data/cdn/a.png (location 前缀被替换)
}root 是把 location 路径拼接在 root 目录后面;alias 是把 location 路径替换成 alias 目录。静态文件 404 时,先看 error_log 里 Nginx 实际去找的文件路径是什么——根据真实路径反推配置比猜要准。
八、常用命令
bash
nginx -t # 检查配置语法
nginx -T # 打印完整合并后的配置(include 展开后)
systemctl start nginx # 启动
systemctl reload nginx # 平滑重载配置(不中断连接)
systemctl restart nginx # 重启(连接会断开)
systemctl stop nginx # 停止
journalctl -u nginx -n 100 --no-pager
tail -f /var/log/nginx/access.log
tail -f /var/log/nginx/error.lognginx -T 比 nginx -t 多一步——它不仅检查语法,还把 include 后的完整配置打印出来。排查"配置明明改了但好像没用"时,nginx -T 能发现是改错了文件还是被其他 include 覆盖了。
reload 和 restart 的区别:reload 是平滑的——master 重新读配置,fork 新 worker,旧 worker 处理完手头请求后优雅退出,整个过程不掉连接。restart 是暴力的——直接停掉所有进程再启动,连接全断。改 LimitNOFILE 这类 systemd 级别的参数需要 restart,其他绝大多数情况用 reload。
九、常见启动问题
| 现象 | 可能原因 | 排查入口 |
|---|---|---|
nginx -t 失败 | 配置语法错误、include 的文件不存在 | 错误输出、nginx -T |
| 端口被占用 | 80/443 已被其他进程监听 | ss -lntp | grep ':80' |
| 403 Forbidden | 目录权限不足、缺少 index 文件、被 deny 指令拦截 | error.log 会写具体原因 |
| 404 Not Found | root/alias 路径不对、URI 匹配不对 | error.log 里的实际文件路径 |
| 访问到了默认站点 | Host 头没匹配到目标 server_name | curl -H 'Host:' 验证 |
| reload 后配置没变 | reload 失败,旧 worker 仍在跑 | nginx -t 看新配置是否通过 |
排查思路顺着请求链路走:请求是否到达机器 → 是否命中正确的 server → 是否命中正确的 location → 最终是读文件还是转发。沿着这条线,比直接翻一堆配置更有效。