5121 字
26 分钟
Nginx 运维实战(下):日志分析、Location 规则与站点部署全流程

前面我们学了 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_addr192.168.1.100客户端 IP(如果经过代理,显示代理 IP,需要用 X-Forwarded-For 获真实 IP)
$remote_userusernameHTTP 基础认证的用户名,无认证显示 -
$time_local29/Nov/2024:14:23:45 +0800请求时间,服务器本地时区
$requestGET /api/user HTTP/1.1完整请求行:方法、URI、协议版本
$status200HTTP 响应状态码
$body_bytes_sent1234发送给客户端的响应体大小(字节),不含 HTTP 头
$http_refererhttps://example.com请求来源页面(防盗链、流量溯源的关键)
$http_user_agentMozilla/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_timeout
  • too many open files:并发连接数超过系统限制,调整 worker_connections

1.5 日志轮转和切割方案#

日志每天都在增长,一个月下来可能几个 G。必须自动切割,否则磁盘爆炸。

最标准的方案:使用系统 logrotate。

创建 /etc/logrotate.d/nginx:

Terminal window
/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 重新打开日志文件(无需重启)

手动测试:

Terminal window
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 匹配优先级顺序与执行逻辑#

关键理解:优先级不是”配置文件的顺序”,而是”修饰符的优先级”。

匹配逻辑流程:

  1. 第一阶段:检查所有精准匹配 =。如果命中,立即返回这个 location 块,完成。
  2. 第二阶段:检查所有前缀优先 ^~ 和通用前缀 /。找到最长的前缀匹配。
    • 如果最长前缀是 ^~,则使用它,完成。
    • 如果最长前缀是普通前缀,暂存它,继续第三阶段。
  3. 第三阶段:按配置文件顺序检查所有正则 ~ 和 ~*。第一个匹配的正则,使用它,完成。
  4. 第四阶段:如果没有正则匹配,使用第二阶段暂存的最长前缀。如果也没有,返回 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
}

关键区别:

场景rootalias
location 路径 == 文件系统路径✅ 优先用 root✗ 不用
location 路径 != 文件系统路径✗ 容易写错✅ 优先用 alias
目录访问需要加 /,否则 404必须以 / 结尾

常见错误示例:

❌ 错误写法:

/var/www/uploads/file.pdf
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 步:准备文件和目录

Terminal window
# 在服务器上创建站点目录
mkdir -p /var/www/example.com
cd /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 步:启用站点配置

Terminal window
# 创建软链接到 sites-enabled(或直接放在 conf.d/)
ln -s /etc/nginx/sites-available/example.com.conf /etc/nginx/sites-enabled/
# 检查配置语法
nginx -t
# 重新加载配置(不中断连接)
nginx -s reload

第 4 步:验证权限

Terminal window
# 站点目录所有者必须是 nginx 运行用户
chown -R nginx:nginx /var/www/example.com
# 目录权限 755,文件权限 644
chmod -R 755 /var/www/example.com
find /var/www/example.com -type f -exec chmod 644 {} \;

第 5 步:浏览器验证

Terminal window
# 本地测试(如果没有 DNS)
curl -H "Host: example.com" http://server_ip
# 或在浏览器访问
# http://example.com

3.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

常见原因:

Terminal window
# 检查 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

常见原因:

Terminal window
# 检查 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.log
tail -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:PATH
  • SCRIPT_FILENAME:传给 PHP-FPM 的脚本完整路径,这是 502 的常见原因
  • fastcgi_index:当 URI 是目录时的默认文件,一般都是 index.php
  • fastcgi_params:包含 HTTP 头等其他参数

4.3 标准化部署步骤#

第 1 步:安装 PHP-FPM

Terminal window
# Ubuntu/Debian
apt-get install php-fpm php-common php-mysql php-gd php-cli
# CentOS/RHEL
yum install php-fpm php-common php-mysql php-gd php-cli
# 查看版本
php -v
php-fpm -v

第 2 步:配置 PHP-FPM 监听方式

编辑 /etc/php/*/fpm/pool.d/www.conf(路径因版本而异):

# Socket 方式(推荐单服务器)
listen = /var/run/php-fpm.sock
listen.owner = nginx
listen.group = nginx
listen.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

Terminal window
systemctl start php-fpm
systemctl 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 测试页

Terminal window
cat > /var/www/example.com/info.php << 'EOF'
<?php
phpinfo();
?>
EOF
chmod 644 /var/www/example.com/info.php
Terminal window
# 测试
curl http://example.com/info.php | grep "PHP Version"
# 应该看到 PHP 版本信息

第 6 步:部署业务代码

Terminal window
# 上传代码
scp -r myapp/* user@server:/var/www/example.com/
# 设置权限
chown -R nginx:nginx /var/www/example.com
chmod -R 755 /var/www/example.com
find /var/www/example.com -type f -exec chmod 644 {} \;
# 如果有缓存目录,需要写权限
chmod 777 /var/www/example.com/storage
chmod 777 /var/www/example.com/uploads

第 7 步:验证

Terminal window
curl http://example.com/
# 查看日志
tail -20 /var/log/nginx/access.log
tail -20 /var/log/nginx/error.log
tail -20 /var/log/php-fpm.log # 或 /var/log/php*.log

4.4 502 Bad Gateway 常见排查思路#

502 说明 Nginx 无法连接到 PHP-FPM,按顺序排查:

排查 1:PHP-FPM 是否启动

Terminal window
ps aux | grep php-fpm
# 如果看不到进程,PHP-FPM 未启动
systemctl status php-fpm
# 查看详细状态和错误
systemctl start php-fpm
# 重新启动

排查 2:fastcgi_pass 地址是否正确

Terminal window
# 配置中写的是 Socket
fastcgi_pass unix:/var/run/php-fpm.sock;
# 验证 Socket 文件是否存在
ls -l /var/run/php-fpm.sock
# 如果不存在,说明 PHP-FPM 未正确启动
# 或配置是 TCP
fastcgi_pass 127.0.0.1:9000;
# 验证端口是否监听
netstat -tuln | grep 9000
# 应该看到 LISTEN

排查 3:Socket 文件权限

Terminal window
# 查看 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.conf
grep "listen.owner\|listen.group\|listen.mode" /etc/php/*/fpm/pool.d/www.conf
# 应该是:
# listen.owner = nginx
# listen.group = nginx
# listen.mode = 0660
# 改完后重启 PHP-FPM
systemctl restart php-fpm

排查 4:SCRIPT_FILENAME 配置

Terminal window
# 错误配置:
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 日志

Terminal window
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 级别

Terminal window
# 改为 debug 级别
error_log /var/log/nginx/error.log debug;
systemctl reload nginx
# 再次触发 502,查看详细日志
tail -100 /var/log/nginx/error.log
# 看完后改回 warn
error_log /var/log/nginx/error.log warn;

5. 运维部署最佳实践小结#

5.1 配置文件管理规范#

规范 1:按域名分文件

Terminal window
# ❌ 不推荐:所有配置堆在 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:开启配置校验

Terminal window
# 改配置前必须校验
nginx -t
# 重载配置
nginx -s reload
# 不要直接 kill -9 Nginx,会中断连接

规范 3:重要配置备份

Terminal window
# 改配置前备份
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.conf
nginx -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 example
server {
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

Terminal window
# 检查 Nginx 进程所有者
ps aux | grep "nginx: master"
# 预期:root nginx 或 nginx
ps aux | grep "nginx: worker"
# 预期:nginx
# 如果不对,修改 nginx.conf
user nginx;
systemctl reload nginx

规范 2:站点目录权限设置

Terminal window
# 所有者:nginx:nginx
chown -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/uploads
chmod 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 重定向到 HTTPS
server {
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 步:查看错误日志

Terminal window
# 最新 20 行
tail -20 /var/log/nginx/error.log
# 或 grep 特定错误
grep "502" /var/log/nginx/error.log
grep "permission" /var/log/nginx/error.log

第 2 步:校验配置语法

Terminal window
nginx -t
# 如果报错,按提示修改
# 检查特定文件
nginx -t -c /etc/nginx/sites-enabled/example.com.conf

第 3 步:检查文件权限

Terminal window
# 站点目录权限
ls -ld /var/www/example.com
# 关键文件权限
ls -l /var/www/example.com/index.html
# 日志目录权限
ls -ld /var/log/nginx

第 4 步:追踪请求链路

Terminal window
# 如果是 PHP,追踪 PHP-FPM
tail -20 /var/log/php-fpm.log
# 如果是代理,检查后端连通性
curl -v http://backend_ip:backend_port/
# 观察访问日志,判断请求是否到达 Nginx
tail -20 /var/log/nginx/access.log

第 5 步:系统层排查

Terminal window
# 磁盘满?
df -h
# 内存足够?
free -h
# 文件描述符不足?
ulimit -n
# SELinux 干扰?
getenforce

总结#

这篇文章覆盖了 Nginx 运维的核心技能:

  1. 日志:读懂访问日志和错误日志,自定义日志格式,用 logrotate 自动切割
  2. Location:掌握五种匹配符、优先级顺序,区分 root 和 alias,写出生产级规则
  3. 静态部署:从上传文件到配置权限,完整流程无遗漏
  4. 动态部署:理解 Nginx 和 PHP-FPM 的通信原理,系统化排查 502 问题
  5. 最佳实践:规范配置管理、权限控制、标准化排错流程

希望这些实战经验能帮你少踩坑、提升运维效率。

Nginx 运维实战(下):日志分析、Location 规则与站点部署全流程
https://www.6ixblog.site/posts/nginx-2/
作者
Licwic
发布于
2025-04-30
许可协议
CC BY-NC-SA 4.0