前面我们学了 Nginx 基础架构与性能优化。这次聚焦实战:如何读懂日志排查问题、如何写对 Location 规则、如何从零部署静态和动态站点。这些是日常运维的核心技能,希望读完能让你少踩坑。
1. Nginx 日志篇:看懂日志与自定义配置
1.1 两类核心日志的作用
Nginx 有两个最重要的日志:
access.log(访问日志) 记录所有客户端请求,包括成功和失败的。每一行是一条完整的 HTTP 请求信息——谁访问了、访问什么、返回什么状态码、用了多久。用于排查:用户访问异常、性能瓶颈、恶意爬虫识别。
error.log(错误日志) 记录 Nginx 运行中的异常:配置错误、磁盘满、后端服务不通、权限不足等。用于排查:为什么返回 500、为什么返回 502、为什么请求被拒绝。
简单说:访问日志看”用户层”问题,错误日志看”系统层”问题。两个配合,就能定位 99% 的故障。
1.2 默认访问日志字段逐行解读
默认格式是 combined,一条完整日志长这样:
192.168.1.100 - username [29/Nov/2024:14:23:45 +0800] "GET /api/user HTTP/1.1" 200 1234 "https://example.com" "Mozilla/5.0"逐字段解读:
| 字段 | 示例 | 含义 |
|---|---|---|
$remote_addr | 192.168.1.100 | 客户端 IP(如果经过代理,显示代理 IP,需要用 X-Forwarded-For 获真实 IP) |
$remote_user | username | HTTP 基础认证的用户名,无认证显示 - |
$time_local | 29/Nov/2024:14:23:45 +0800 | 请求时间,服务器本地时区 |
$request | GET /api/user HTTP/1.1 | 完整请求行:方法、URI、协议版本 |
$status | 200 | HTTP 响应状态码 |
$body_bytes_sent | 1234 | 发送给客户端的响应体大小(字节),不含 HTTP 头 |
$http_referer | https://example.com | 请求来源页面(防盗链、流量溯源的关键) |
$http_user_agent | Mozilla/5.0 | 客户端浏览器/爬虫标识 |
这 8 个字段涵盖了 99% 的排查需求。
1.3 自定义日志格式配置
默认格式不够时,可以自定义。比如,我想新增响应时间 $request_time 用于性能排查:
http { # 自定义日志格式,添加响应时间 log_format main_with_time '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" ' 'rt=$request_time urt=$upstream_response_time';
server { listen 80; server_name example.com;
# 引用自定义格式 access_log /var/log/nginx/access.log main_with_time;
location / { proxy_pass http://backend; } }}常用的自定义字段:
$request_time:Nginx 处理请求的总耗时(秒),用于识别慢请求$upstream_response_time:后端响应耗时,如果远大于 request_time,说明网络延迟$pipe:管道连接,值为p表示 HTTP keep-alive$ssl_protocol/$ssl_cipher:HTTPS 协议版本和加密套件,用于安全审计
技巧:定义多个格式,不同 server 块引用不同格式,按业务需求分类记录。
1.4 错误日志级别与生产配置
error.log 有 5 个级别,从低到高:
| 级别 | 记录内容 | 生产建议 |
|---|---|---|
debug | 详细的调试信息,包括变量赋值、函数调用 | 开发环境,生产禁用(日志超大) |
info | 常规信息,启动、重载、关闭 | 可开,有助于监控 Nginx 状态变化 |
notice | 重要的常规信息,worker 进程数变化 | 建议开启 |
warn | 警告,如磁盘满、连接超时 | 默认级别,必须保留 |
error | 真正的错误,配置错误、段错误、请求处理失败 | 最低要求 |
生产推荐:
error_log /var/log/nginx/error.log warn;这样既能捕获严重问题,又不会被日志淹没。
常见错误码对应排查方向:
connection refused:后端服务未启动或绑定地址错误permission denied:站点目录权限不足或 Nginx 运行用户权限不足upstream timed out:后端响应超时,检查网络、后端性能或 proxy_connect_timeouttoo many open files:并发连接数超过系统限制,调整 worker_connections
1.5 日志轮转和切割方案
日志每天都在增长,一个月下来可能几个 G。必须自动切割,否则磁盘爆炸。
最标准的方案:使用系统 logrotate。
创建 /etc/logrotate.d/nginx:
/var/log/nginx/*.log { daily # 每天轮转一次 missingok # 日志文件不存在不报错 rotate 14 # 保留 14 天的备份 compress # gzip 压缩历史日志 delaycompress # 压缩延迟到下一个轮转周期(保证昨天的日志可读) notifempty # 日志为空时不轮转 create 0640 nginx nginx # 新文件权限 sharedscripts # 只在所有日志处理完毕后运行脚本 postrotate # 轮转后钩子:重新打开日志文件 if [ -f /var/run/nginx.pid ]; then kill -USR1 `cat /var/run/nginx.pid` fi endscript}这套配置的效果:
- 每天午夜自动将 access.log 重命名为
access.log-20241129 - 新建空的 access.log,Nginx 继续写入
- 14 天后自动删除旧备份
kill -USR1信号通知 Nginx 重新打开日志文件(无需重启)
手动测试:
logrotate -vf /etc/logrotate.d/nginx加 -f 强制轮转一次,-v 打印详细过程。
2. Location 匹配规则深度解析
Location 是 Nginx 配置的核心难点,正则一写错,就能把线上搞瘫。这节我就讲透它。
2.1 Location 语法与五种匹配符号
完整语法:location [修饰符] /path { ... }
五种修饰符优先级递减:
| 修饰符 | 名称 | 匹配方式 | 优先级 |
|---|---|---|---|
= | 精准匹配 | 完全相同才匹配,必须逐字节相等 | 1(最高) |
^~ | 前缀优先匹配 | 前缀相同且优先于正则 | 2 |
~ | 正则匹配(大小写敏感) | 支持 PCRE 正则表达式,匹配则停止 | 3 |
~* | 正则匹配(不区分大小写) | 同上,但忽略大小写 | 3 |
| (无) | 通用前缀匹配 | 前缀匹配,最后才考虑 | 4(最低) |
实例演示:
server { location = /api/login { # 只匹配 /api/login 这个字符串,不匹配 /api/login/submit proxy_pass http://auth_backend; }
location ^~ /static/ { # 匹配 /static/ 开头的所有请求 # 即使有正则匹配,也优先走这个(因为有 ^~) root /var/www; expires 7d; }
location ~ \.(jpg|png|gif)$ { # 匹配 .jpg/.png/.gif 结尾的文件(区分大小写) root /var/www; expires 30d; }
location ~* \.(jpg|png|gif)$ { # 匹配任何大小写的图片文件 root /var/www; expires 30d; }
location / { # 通用前缀匹配,兜底所有没被上面规则匹配的请求 proxy_pass http://default_backend; }}2.2 匹配优先级顺序与执行逻辑
关键理解:优先级不是”配置文件的顺序”,而是”修饰符的优先级”。
匹配逻辑流程:
- 第一阶段:检查所有精准匹配
=。如果命中,立即返回这个 location 块,完成。 - 第二阶段:检查所有前缀优先
^~和通用前缀/。找到最长的前缀匹配。- 如果最长前缀是
^~,则使用它,完成。 - 如果最长前缀是普通前缀,暂存它,继续第三阶段。
- 如果最长前缀是
- 第三阶段:按配置文件顺序检查所有正则
~和~*。第一个匹配的正则,使用它,完成。 - 第四阶段:如果没有正则匹配,使用第二阶段暂存的最长前缀。如果也没有,返回 404。
实例:请求 /image/photo.JPG,下面 location 如何匹配?
location = /image/photo.jpg { # 规则 1:精准匹配,不符合(大小写不同)}
location ^~ /image/ { # 规则 2:前缀优先,符合 /image/ # 暂存这个}
location ~ \.(jpg|png)$ { # 规则 3:正则匹配,符合 \.jpg$ # 第一个匹配的正则,选这个!}
location / { # 规则 4:通用前缀,符合但优先级最低}结果:选择规则 3(正则匹配)。因为虽然规则 2 是前缀优先,但规则 3 的正则匹配了,在第三阶段被选中。
核心要点:如果你想让某个前缀优先于所有正则,一定要加 ^~。否则正则会抢过去。
2.3 root 与 alias 的核心区别
这是高频踩坑点。两者都是指定文件系统路径,但拼接逻辑完全不同。
root:Nginx 将 root 目录 + location 路径拼接为最终的文件路径。
location /image/ { root /var/www; # 请求 /image/photo.jpg # 最终找的文件:/var/www + /image/ + photo.jpg = /var/www/image/photo.jpg}alias:Nginx 用 alias 目录替换 location 路径。
location /image/ { alias /data/images/; # 请求 /image/photo.jpg # location 部分 /image/ 被替换为 /data/images/ # 最终找的文件:/data/images/ + photo.jpg = /data/images/photo.jpg}关键区别:
| 场景 | root | alias |
|---|---|---|
| location 路径 == 文件系统路径 | ✅ 优先用 root | ✗ 不用 |
| location 路径 != 文件系统路径 | ✗ 容易写错 | ✅ 优先用 alias |
| 目录访问 | 需要加 /,否则 404 | 必须以 / 结尾 |
常见错误示例:
❌ 错误写法:
location /upload { root /var/www/uploads; # 用户访问 /upload/file.pdf # 实际找的:/var/www/uploads/upload/file.pdf # 结果:404}✅ 正确写法 1(用 root):
location /upload { root /var/www; # 文件放在 /var/www/upload/file.pdf # 请求 /upload/file.pdf,找 /var/www + /upload/file.pdf = 正确}✅ 正确写法 2(用 alias):
location /upload { alias /var/www/uploads/; # 文件放在 /var/www/uploads/file.pdf # 请求 /upload/file.pdf,用 /var/www/uploads/ 替换 /upload,找 /var/www/uploads/file.pdf = 正确}规则:能用 root 就用 root,更直观。只有当 location 路径和真实目录路径逻辑不同时,才用 alias。
2.4 生产常用 Location 配置案例
案例 1:静态资源缓存
location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2)$ { root /var/www/html; expires 30d; # 浏览器缓存 30 天 add_header Cache-Control "public, immutable"; access_log off; # 静态文件不记录日志(减少 IO)}案例 2:禁止访问敏感文件
location ~ /\.env$ { deny all; access_log off; error_log off;}
location ~ /\.(git|svn|hg)/ { deny all;}案例 3:PHP 请求转发
location ~ \.php$ { fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params;}案例 4:API 版本路由
location ~ ^/api/v([0-9]+)/(.*) { set $api_version $1; set $api_path $2; proxy_pass http://api_backend_v$api_version/$api_path;}案例 5:目录索引与默认文档
location / { root /var/www/html; index index.html index.htm index.php; # 按顺序尝试 try_files $uri $uri/ /index.html; # 前端路由回源}3. 静态网站完整部署流程
3.1 静态站的特点与适用场景
静态站 = 纯 HTML + CSS + JS,或前后端分离架构中的前端打包产物。特点:
- Nginx 直接从磁盘读文件,返回给浏览器,无需后端计算
- 访问速度快,对服务器性能要求低
- 支持 CDN、浏览器缓存等优化手段
- 适用场景:企业官网、文档站、单页应用(SPA)、博客、落地页
3.2 标准化部署步骤
第 1 步:准备文件和目录
# 在服务器上创建站点目录mkdir -p /var/www/example.comcd /var/www/example.com
# 如果本地已有打包产物(以 React 为例)# 从本地上传 dist/ 目录下的所有文件到服务器scp -r dist/* user@server:/var/www/example.com/第 2 步:编写虚拟主机配置
创建 /etc/nginx/sites-available/example.com.conf:
server { listen 80; server_name example.com www.example.com;
root /var/www/example.com; index index.html;
# 前端路由回源:所有找不到的文件,都返回 index.html,让前端 JS 路由处理 location / { try_files $uri $uri/ /index.html; }
# 静态资源长期缓存 location ~* \.(js|css|jpg|jpeg|png|gif|ico|svg|woff2?)$ { expires 365d; add_header Cache-Control "public, immutable"; }
# 禁止访问敏感文件 location ~ /\. { deny all; }
error_page 404 /404.html;}第 3 步:启用站点配置
# 创建软链接到 sites-enabled(或直接放在 conf.d/)ln -s /etc/nginx/sites-available/example.com.conf /etc/nginx/sites-enabled/
# 检查配置语法nginx -t
# 重新加载配置(不中断连接)nginx -s reload第 4 步:验证权限
# 站点目录所有者必须是 nginx 运行用户chown -R nginx:nginx /var/www/example.com
# 目录权限 755,文件权限 644chmod -R 755 /var/www/example.comfind /var/www/example.com -type f -exec chmod 644 {} \;第 5 步:浏览器验证
# 本地测试(如果没有 DNS)curl -H "Host: example.com" http://server_ip
# 或在浏览器访问# http://example.com3.3 静态资源优化配置
expires 缓存控制:
# 3 种写法,效果等同expires 30d;expires 30d 12h;expires 2592000; # 秒数
# expires off 表示不设置过期时间# 浏览器不会缓存,每次都重新下载(用于测试环境)gzip 压缩:
# 在 http 块启用全局压缩gzip on;gzip_comp_level 6; # 压缩级别 1-9,越高压缩率越好但 CPU 消耗越大gzip_types text/plain text/css text/javascript application/json application/javascript; # 只压缩这些类型gzip_min_length 1000; # 只压缩大于 1KB 的响应
# 在 server 块可以精细控制location ~* \.(js|css)$ { gzip on; gzip_comp_level 9;}etag 与 Last-Modified:
# Nginx 默认开启,用于浏览器判断文件是否变化# 不要关闭,除非有特殊需求etag on;
# 结合 If-Modified-Since,返回 304 Not Modified,减少带宽3.4 常见问题排查
问题 1:403 Forbidden
常见原因:
# 检查 1:站点目录权限ls -ld /var/www/example.com# 预期:drwxr-xr-x nginx:nginx
# 检查 2:Nginx 运行用户是否有读权限ps aux | grep nginx# 预期看到 nginx 用户
# 检查 3:SELinux(如果启用)getenforce# 如果是 Enforcing,需要配置 SELinux 策略问题 2:404 Not Found
常见原因:
# 检查 1:root 路径是否正确grep "root " /etc/nginx/sites-enabled/example.com.conf
# 检查 2:index 文件是否存在ls -l /var/www/example.com/index.html
# 检查 3:location 规则是否正确# 用 try_files 后,如果还是 404,检查 /index.html 是否存在
# 检查 4:查看 error.logtail -20 /var/log/nginx/error.log问题 3:跨域请求失败
解决方案:
add_header Access-Control-Allow-Origin "*";add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS";add_header Access-Control-Allow-Headers "Content-Type";
# 处理 OPTIONS 预检请求if ($request_method = 'OPTIONS') { return 204;}4. 动态网站完整部署流程(以 PHP 为例)
4.1 Nginx 与 PHP-FPM 的通信原理
Nginx 本身不能执行 PHP,必须转发给专门的 PHP 进程。两种通信方式:
TCP 通信(127.0.0.1:9000)
Nginx -> TCP 连接 -> PHP-FPM 进程优点:跨主机通信,可以部署在不同服务器 缺点:网络开销,本机通信也走网络栈
Unix Socket 通信(/var/run/php-fpm.sock)
Nginx -> Unix Socket 文件 -> PHP-FPM 进程优点:同主机通信,更快,无网络开销 缺点:只能本机,socket 文件权限需要配置
生产选择:单服务器用 Socket 更快;分布式架构用 TCP。
4.2 动态站点核心配置讲解
server { listen 80; server_name example.com; root /var/www/example.com;
index index.php index.html index.htm;
# 处理 PHP 请求 location ~ \.php$ { # 转发给 PHP-FPM fastcgi_pass 127.0.0.1:9000; # 或用 Socket # fastcgi_pass unix:/var/run/php-fpm.sock;
fastcgi_index index.php;
# ⚠️ 关键:告诉 PHP-FPM 脚本路径 # 如果缺少这行,PHP-FPM 收不到脚本路径,返回 404 fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
# 导入其他 fastcgi 参数 include fastcgi_params;
# 可选:提升超时时间(如果 PHP 脚本执行慢) fastcgi_connect_timeout 60; fastcgi_send_timeout 60; fastcgi_read_timeout 60; }
# 静态文件直接返回 location ~* \.(jpg|jpeg|png|css|js|gif|ico)$ { expires 7d; access_log off; }
# 禁止访问敏感文件 location ~ /\. { deny all; }}关键参数解释:
fastcgi_pass:PHP-FPM 的地址,TCP 格式IP:PORT,Socket 格式unix:PATHSCRIPT_FILENAME:传给 PHP-FPM 的脚本完整路径,这是 502 的常见原因fastcgi_index:当 URI 是目录时的默认文件,一般都是index.phpfastcgi_params:包含 HTTP 头等其他参数
4.3 标准化部署步骤
第 1 步:安装 PHP-FPM
# Ubuntu/Debianapt-get install php-fpm php-common php-mysql php-gd php-cli
# CentOS/RHELyum install php-fpm php-common php-mysql php-gd php-cli
# 查看版本php -vphp-fpm -v第 2 步:配置 PHP-FPM 监听方式
编辑 /etc/php/*/fpm/pool.d/www.conf(路径因版本而异):
# Socket 方式(推荐单服务器)listen = /var/run/php-fpm.socklisten.owner = nginxlisten.group = nginxlisten.mode = 0660
# 或 TCP 方式(分布式)# listen = 127.0.0.1:9000# listen = 0.0.0.0:9000 # 允许远程连接(生产不推荐)调整进程池大小(根据服务器内存):
pm = dynamic # 动态管理进程数pm.max_children = 50 # 最多 50 个进程pm.start_servers = 10 # 启动时 10 个进程pm.min_spare_servers = 5 # 至少保留 5 个空闲进程pm.max_spare_servers = 20 # 最多保留 20 个空闲进程第 3 步:启动 PHP-FPM
systemctl start php-fpmsystemctl enable php-fpm # 开机自启
# 验证是否运行ps aux | grep php-fpm# 预期看到 master 和若干 worker 进程
# 验证 Socket 文件ls -l /var/run/php-fpm.sock# 预期权限:srw-rw---- nginx nginx第 4 步:编写 Nginx 转发配置
如前所述(第 4.2 节的配置块)。
第 5 步:创建 phpinfo 测试页
cat > /var/www/example.com/info.php << 'EOF'<?phpphpinfo();?>EOF
chmod 644 /var/www/example.com/info.php# 测试curl http://example.com/info.php | grep "PHP Version"# 应该看到 PHP 版本信息第 6 步:部署业务代码
# 上传代码scp -r myapp/* user@server:/var/www/example.com/
# 设置权限chown -R nginx:nginx /var/www/example.comchmod -R 755 /var/www/example.comfind /var/www/example.com -type f -exec chmod 644 {} \;
# 如果有缓存目录,需要写权限chmod 777 /var/www/example.com/storagechmod 777 /var/www/example.com/uploads第 7 步:验证
curl http://example.com/
# 查看日志tail -20 /var/log/nginx/access.logtail -20 /var/log/nginx/error.logtail -20 /var/log/php-fpm.log # 或 /var/log/php*.log4.4 502 Bad Gateway 常见排查思路
502 说明 Nginx 无法连接到 PHP-FPM,按顺序排查:
排查 1:PHP-FPM 是否启动
ps aux | grep php-fpm# 如果看不到进程,PHP-FPM 未启动
systemctl status php-fpm# 查看详细状态和错误
systemctl start php-fpm# 重新启动排查 2:fastcgi_pass 地址是否正确
# 配置中写的是 Socketfastcgi_pass unix:/var/run/php-fpm.sock;
# 验证 Socket 文件是否存在ls -l /var/run/php-fpm.sock# 如果不存在,说明 PHP-FPM 未正确启动
# 或配置是 TCPfastcgi_pass 127.0.0.1:9000;
# 验证端口是否监听netstat -tuln | grep 9000# 应该看到 LISTEN排查 3:Socket 文件权限
# 查看 Socket 权限ls -l /var/run/php-fpm.sock# 预期:srw-rw---- nginx nginx
# Nginx 进程的用户必须是 nginx,必须有读写权限ps aux | grep "nginx: master"
# 如果权限不对,检查 /etc/php/*/fpm/pool.d/www.confgrep "listen.owner\|listen.group\|listen.mode" /etc/php/*/fpm/pool.d/www.conf# 应该是:# listen.owner = nginx# listen.group = nginx# listen.mode = 0660
# 改完后重启 PHP-FPMsystemctl restart php-fpm排查 4:SCRIPT_FILENAME 配置
# 错误配置:fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
# 这里 $document_root 来自 root 指令,$fastcgi_script_name 是请求的 PHP 文件# 必须拼出完整的文件路径,否则 PHP-FPM 找不到文件
# 检查 Nginx 配置grep -A 2 "fastcgi_pass" /etc/nginx/sites-enabled/example.com.conf | grep SCRIPT_FILENAME# 如果找不到这一行,加上去
nginx -t # 检查配置systemctl reload nginx排查 5:查看 PHP-FPM 日志
tail -50 /var/log/php-fpm.log# 或tail -50 /var/log/php*.log
# 常见错误:# "Primary script unknown":SCRIPT_FILENAME 路径错误或文件不存在# "Permission denied":Nginx 用户无读权限# "Connection refused":PHP-FPM 未启动排查 6:临时增加 error.log 级别
# 改为 debug 级别error_log /var/log/nginx/error.log debug;
systemctl reload nginx
# 再次触发 502,查看详细日志tail -100 /var/log/nginx/error.log
# 看完后改回 warnerror_log /var/log/nginx/error.log warn;5. 运维部署最佳实践小结
5.1 配置文件管理规范
规范 1:按域名分文件
# ❌ 不推荐:所有配置堆在 nginx.conf/etc/nginx/nginx.conf (10000+ 行,难以维护)
# ✅ 推荐:逻辑分离/etc/nginx/├── nginx.conf # 全局配置├── conf.d/ # 通用配置片段│ ├── gzip.conf│ └── headers.conf└── sites-available/ # 虚拟主机配置 ├── example.com.conf ├── api.example.com.conf └── static.example.com.conf规范 2:开启配置校验
# 改配置前必须校验nginx -t
# 重载配置nginx -s reload
# 不要直接 kill -9 Nginx,会中断连接规范 3:重要配置备份
# 改配置前备份cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak.$(date +%Y%m%d-%H%M%S)
# 如果改错了,可以快速回滚cp /etc/nginx/nginx.conf.bak.20241129-143000 /etc/nginx/nginx.confnginx -t && nginx -s reload规范 4:注释书写规范
# ✅ 好的注释server { listen 80; # 主域名和 www 子域名 server_name example.com www.example.com;
# 站点根目录 root /var/www/example.com;
# 前端路由,所有找不到的文件返回 index.html location / { try_files $uri $uri/ /index.html; }}
# ❌ 坏的注释# config for exampleserver { listen 80; server_name example.com www.example.com; root /var/www/example.com; location / { try_files $uri $uri/ /index.html; # important!!! }}5.2 权限与安全基线
规范 1:运行用户统一为 nginx
# 检查 Nginx 进程所有者ps aux | grep "nginx: master"# 预期:root nginx 或 nginx
ps aux | grep "nginx: worker"# 预期:nginx
# 如果不对,修改 nginx.confuser nginx;
systemctl reload nginx规范 2:站点目录权限设置
# 所有者:nginx:nginxchown -R nginx:nginx /var/www
# 目录:755(nginx 可读写执行)chmod -R 755 /var/www
# 文件:644(nginx 可读,不可写)find /var/www -type f -exec chmod 644 {} \;
# 特殊目录需要写权限(缓存、上传等)chmod 777 /var/www/example.com/uploadschmod 777 /var/www/example.com/cache规范 3:禁止敏感目录访问
# .git / .svn / .env 等location ~ /\.(git|svn|env|htaccess)$ { deny all; access_log off; error_log off;}
# PHP 配置文件location ~ ^/wp-config\.php$ { deny all;}
# 目录列表autoindex off;规范 4:HTTPS 强制使用
# HTTP 重定向到 HTTPSserver { listen 80; server_name example.com; return 301 https://example.com$request_uri;}
server { listen 443 ssl http2; server_name example.com;
ssl_certificate /etc/ssl/certs/example.com.crt; ssl_certificate_key /etc/ssl/private/example.com.key;
# 强制使用 HTTPS add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;}5.3 排错思路总结
遇到问题时,按这个标准流程排查,不要瞎猜:
第 1 步:查看错误日志
# 最新 20 行tail -20 /var/log/nginx/error.log
# 或 grep 特定错误grep "502" /var/log/nginx/error.loggrep "permission" /var/log/nginx/error.log第 2 步:校验配置语法
nginx -t# 如果报错,按提示修改
# 检查特定文件nginx -t -c /etc/nginx/sites-enabled/example.com.conf第 3 步:检查文件权限
# 站点目录权限ls -ld /var/www/example.com
# 关键文件权限ls -l /var/www/example.com/index.html
# 日志目录权限ls -ld /var/log/nginx第 4 步:追踪请求链路
# 如果是 PHP,追踪 PHP-FPMtail -20 /var/log/php-fpm.log
# 如果是代理,检查后端连通性curl -v http://backend_ip:backend_port/
# 观察访问日志,判断请求是否到达 Nginxtail -20 /var/log/nginx/access.log第 5 步:系统层排查
# 磁盘满?df -h
# 内存足够?free -h
# 文件描述符不足?ulimit -n
# SELinux 干扰?getenforce总结
这篇文章覆盖了 Nginx 运维的核心技能:
- 日志:读懂访问日志和错误日志,自定义日志格式,用 logrotate 自动切割
- Location:掌握五种匹配符、优先级顺序,区分 root 和 alias,写出生产级规则
- 静态部署:从上传文件到配置权限,完整流程无遗漏
- 动态部署:理解 Nginx 和 PHP-FPM 的通信原理,系统化排查 502 问题
- 最佳实践:规范配置管理、权限控制、标准化排错流程
希望这些实战经验能帮你少踩坑、提升运维效率。