做了这些年站点被问得最多的问题之一就是“我想用 NGINX 搭个网站第一步到底该干什么”。问这话的人里有刚学完几条基础命令的新手也有从别的服务器软件迁移过来的老手——新手卡在配置写不对、首页打不开老手卡在迁移之后一堆说不清的行为差异。我自己第一次正经搭站的时候一个首页出不来折腾了整整两天最后发现是目录权限和防火墙规则两个问题叠在一起改完一个还有一个每次以为找到了真凶刷新页面还是那副样子。所以这篇不打算按“安装—配置—启动”的教科书顺序念一遍而是按我实际从零搭一个站会走的路径写把每一步背后的“为什么”讲透把容易翻车的地方提前标出来。NGINX 是一个事件驱动模型的高性能 HTTP 服务器与反向代理用它搭 web 网站图的无非三件事内存占用低、扛并发稳、配置结构清晰到基本可以当文档读。下面聊的内容以静态站点为主线顺带覆盖反向代理和动静分离这类常见组合环境是常见的 Linux 发行版命令和配置在主流版本上基本通用。适合手上有台机器、想把自己的页面真正挂上去的人看也适合已经在用但总觉得配置“抄来的、不敢改”的人回头补一遍地基。1. 先弄明白NGINX在一个请求里到底做了哪几件事1.1 从浏览器敲下回车到文件被读出来的完整链路很多人配置写不顺根源不在语法在于脑子里没有一条完整的请求链路。补上这条链路后面所有的 server、location、try_files 你都能自己推出来该写在哪一层。浏览器发起请求之后先做域名解析拿到服务器地址然后和服务器建立 TCP 连接现在多数还叠了一层 TLS 握手。连接建立后NGINX 的 master 进程并不直接干活它负责读配置、管理端口、派生 worker 进程真正接活的是 worker每个 worker 用事件驱动的方式同时盯着成千上万个连接哪个连接有数据可读就去处理哪个这就是它能用很少的内存扛住很高并发的原因。请求进来之后NGINX 先根据 Host 头和监听端口挑出匹配的 server 块再在选中的 server 块里按规则匹配 location最后决定这个请求是交给本地磁盘上的文件、转给后端应用还是直接返回一个错误码。这条链路里有两个环节最容易被忽略。第一个是 Host 匹配如果你只配了一个 server 块那不管别人用什么域名指过来、甚至直接用 IP 访问都会落到这个块里看起来“能访问”实际上埋着一个隐患——等哪天你加了第二个站点第一个站点的流量可能会被莫名其妙地接走。第二个是 location 匹配的顺序它不是简单的“从上往下第一个命中就停”前缀匹配和正则匹配有各自的优先级规则配错了会出现“我明明写了这条规则却没生效”的情况第 4 节会专门拆。有一句话我建议每个刚开始配 NGINX 的人都记一下NGINX 的所有行为都可以归结为“选哪个 server、选哪个 location、然后怎么处理”三个问题。配置写不下去的时候就问自己卡在这三步的哪一步比漫无目的地翻文档高效得多。1.2 静态站、反向代理站、动静混合站三种形态的取舍搭站之前先想清楚你要的是哪一种形态因为它们的配置重心完全不同。站点形态典型场景配置重心容易踩的坑纯静态站展示页、文档站、博客root 目录、缓存头、gzip目录权限、缓存过期策略反向代理站后端有应用服务NGINX 只做入口proxy_pass、真实 IP、超时路径斜杠、后端超时动静混合站页面静态化接口走后端location 分流规则分流前缀写重叠纯静态站是最简单也最容易被低估的形态。很多人觉得“静态文件嘛扔进去就行”结果上线之后发现首页加载慢、更新后用户看到旧版本、大文件下载经常断。这些问题几乎都能靠缓存头、压缩和连接配置解决第 5 节会具体讲。反向代理站的关键在于“边界要划清楚”哪些请求原样透传哪些需要改写路径哪些头必须补上。做得好后端应用完全不用关心外网这一层做得不好后端拿到的全是代理机的 IP做限流、做日志分析全废。动静混合站最容易出的问题是 location 规则重叠。比如你用/api/分流到后端又用~ \.(js|css)$匹配静态资源某个请求既符合前缀又符合正则最后落到哪一条取决于优先级而不是你写的顺序。这类问题在测试环境往往看不出来因为前后端在同一个域下随便怎么配都能通一上线就暴露。2. 装之前先把目录约定和权限模型理清楚2.1 用包管理器装还是自己编译看你要什么包管理器安装和源码编译安装差别不在“高级不高级”而在“你要不要那个可控性”。包管理器安装的好处是省事一条命令搞定systemd 的服务单元、日志轮转、默认配置目录全都给你配好了升级也是顺手一条命令。缺点是版本和模块受发行版仓库限制某些第三方模块要么没有要么得额外装包。对绝大多数搭站需求来说这条路足够我自己的生产机器基本都是走包管理器除非确实需要某个仓库里没有的模块。源码编译的好处是能精确控制编译参数比如关掉用不上的模块减小体积、打开某个需要额外依赖的模块、指定安装路径。代价是升级要自己来服务单元要自己写出了依赖问题得自己排查。我一般只在两种情况下编译一是需要某个特定模块二是要在同一台机器上隔离跑多个不同版本的实例。无论哪种方式装完之后先做一件事确认配置文件的实际加载路径。同一个命令nginx -t在不同发行版上读的可能是/etc/nginx/nginx.conf也可能是别的位置。用nginx -V看编译参数里的--conf-path比猜要靠谱。我曾经在一台机器上改了半天配置不生效最后发现改的是备份文件真正加载的是另一个目录下的同名文件这种低级错误在着急的时候特别容易犯。2.2 配置目录怎么组织才不会半年后自己都看不懂默认的nginx.conf里通常有一行include把conf.d/或sites-enabled/下的文件都拉进来。这个机制一定要用起来别把所有站点的配置全堆在主文件里。我的习惯是每个站点一个独立文件文件名带上域名放在conf.d/下主配置文件只保留全局设置worker 数量、日志格式、连接数上限这类。这样做的直接好处是加一个站就是加一个文件删一个站就是删一个文件不用担心误删别人的配置出问题的时候可以单独把某个文件临时改名排除定位速度差好几倍。另一个细节是先把默认站点处理掉。多数发行版装完会自带一个默认 server 块监听 80 端口并返回一个欢迎页。如果你新加的站点没有明确写server_name或者请求的 Host 谁都不匹配流量就会落到这个默认块上。表现形式就是“我明明配了新站访问却还是那个欢迎页”。处理方式有两种删掉默认配置或者把它留作兜底但明确写default_server并返回 444 直接断连。我倾向后者因为直接断连可以挡掉一大批扫描流量也不会让人误以为站点没配好。权限这块单独提一句。NGINX 的 worker 进程通常以nginx或www-data这类低权限用户运行而你的站点目录如果是用 root 建的默认权限往往是 755看起来能读。但如果中间某一级父目录的权限是 700worker 就进不去报 403。这不是 NGINX 的问题是文件系统权限的问题但错误信息只会告诉你“禁止访问”很容易往配置方向查。第 8 节会把这类排查链路完整走一遍。3. 一个能真正打开的server块长什么样3.1 从最小配置开始逐行加东西别一上来就抄一份几百行的“生产级配置”先写一个最小的、能打开首页的版本跑通了再往上加。最小可用配置大概是这样server { listen 80; server_name www.example.com; root /var/www/mysite; index index.html; location / { try_files $uri $uri/ 404; } }逐行拆一下。listen 80声明监听端口server_name是域名匹配的依据写多个用空格隔开root指定站点根目录注意这是目录前缀不是“首页文件”index指定目录请求时默认找哪个文件location /兜住所有路径try_files按顺序尝试先找同名文件再找同名目录都没有就返回 404。这里有个特别常见的误解有人以为root写的是首页路径于是写成/var/www/mysite/index.html结果所有资源全 404。因为 NGINX 会把请求路径拼在 root 后面/css/style.css拼出来就成了/var/www/mysite/index.html/css/style.css显然不存在。记住 root 是“目录”请求路径是“相对这个目录的子路径”。配置改完不要直接 reload先测nginx -t这条命令会做语法检查并尝试加载配置报错会指出文件和第几行。养成习惯-t通过再nginx -s reload能省掉大量“网站突然挂了”的时刻。reload 是平滑的老连接处理完才退出不会断开正在进行的请求这一点比直接 restart 友好得多。3.2 域名、端口、防火墙三道关一道都不能少配置写对了却访问不了百分之九十卡在这三道关里的某一道。第一道是域名解析。域名要指向服务器地址解析生效需要时间本地缓存也可能拖后腿。测试阶段可以先不改解析直接改本地 hosts 文件把域名指过去验证配置是否正确确认没问题再动真正的解析记录。这个顺序很重要否则你会同时怀疑解析和配置排查效率减半。第二道是端口监听。确认listen写的端口和实际访问的端口一致确认 NGINX 真的起来了ss -lntp看端口有没有被监听确认没有别的进程抢占同一个端口。端口被占这种问题在装了两个服务器软件、或者之前跑过测试实例的机器上很常见启动会失败但错误信息不一定显眼。第三道是防火墙。系统自带防火墙和上层网络策略都可能拦。测试时可以先临时放开端口验证确认能通之后再收回到最小开放范围。这一步我踩过最蠢的坑在云主机上折腾了四十分钟配置最后发现是控制台里的安全组没放行——机器内部的防火墙我查了三遍压根没想到外面还有一层。三道关全过之后用一个最简单的请求验证curl -I http://www.example.com/看返回的状态码和Server头。200 说明通了403 查权限404 查 root 路径502 说明你配了反向代理但后端没起来连不上说明卡在前三道关。用curl而不是浏览器是因为它不会缓存、不会自动跳转、能直接看到响应头定位问题干净得多。4. location匹配规则URL怎么落到具体的文件和目录上4.1 前缀、正则、精确匹配的优先级不是按书写顺序这是 NGINX 配置里最容易出错的一块值得单独花时间搞清楚。location 的匹配分几类是精确匹配路径必须完全一致^~是前缀匹配且命中后不再尝试正则普通前缀匹配不带修饰符会记住最长的那条~是区分大小写的正则~*是不区分大小写的正则。匹配顺序大致是先找精确匹配命中就结束没命中就找最长前缀匹配如果这条前缀带^~直接用不再看正则否则按配置文件里出现的顺序依次尝试正则第一个命中的就用它正则全没命中才回到刚才记住的那条最长前缀。举个实际会遇到的例子。你写了location /static/ { ... } location ~ \.(js|css)$ { ... }一个请求/static/app.css前缀匹配命中了/static/但因为它没带^~NGINX 还会去试正则结果被第二条抢走。如果你本意是让/static/下的东西全走第一条就该写成location ^~ /static/。我一般建议能用前缀匹配就别用正则。前缀匹配是字符串比较快且行为可预测正则灵活但优先级容易绕晕而且写错了很难一眼看出来。4.2 try_files 与单页应用的路径回退现在不少前端项目是单页应用路由由前端接管。用户直接访问/user/profile这种路径时服务器上并没有对应文件如果按常规逻辑就 404 了。正确做法是把所有未命中的路径回退到入口文件location / { try_files $uri $uri/ /index.html; }含义是先找同名文件再找同名目录都没有就内部转发到/index.html由前端路由处理。注意最后这个是内部转发浏览器地址栏不变所以前端拿到的仍是原始路径路由才能正常工作。这里有个副作用要留意因为任何路径都会返回index.html且状态码是 200搜索引擎可能会把一堆无效路径都当成有效页面。如果站点在意这个可以在入口文件里做判断或者在服务端对明显的无效路径单独返回 404。另外接口路径一定要在这条规则之前用更具体的前缀拦掉否则前端请求/api/xxx也会拿到一个 HTML前端解析 JSON 直接报错而这个错误信息往往会误导你去查前端。4.3 root 和 alias 的分水岭一个字之差结果完全不同这两个指令经常被混用但行为差别很大。root是把请求路径拼在指定目录后面。alias是把匹配到的那部分路径替换成指定目录。location /img/ { root /data/assets; } # 请求 /img/a.png → /data/assets/img/a.png location /img/ { alias /data/assets/; } # 请求 /img/a.png → /data/assets/a.png看出区别了吗用 root 时/img/这段还留在路径里用 alias 时被替换掉了。所以什么时候用哪个取决于你的磁盘目录结构是不是和 URL 结构一致。一致就用 root不一致比如你想把/download/映射到一个完全无关的目录就用 alias。alias 有个经典坑结尾的斜杠。location 以斜杠结尾alias 也必须以斜杠结尾否则拼出来的路径会少一层或者多一层表现为 404。这个问题不会报配置错误只能靠访问验证发现所以在写完 alias 之后一定要实际请求一个文件确认。5. 静态资源的三个性能开关压缩、缓存、连接5.1 gzip 该开多大什么时候该用预压缩文本类资源HTML、CSS、JS、JSON、SVG压缩比很高开 gzip 通常能省掉六七成的传输体积。配置大概是这样gzip on; gzip_comp_level 5; gzip_min_length 1024; gzip_types text/plain text/css application/javascript application/json image/svgxml; gzip_vary on;gzip_comp_level从 1 到 9越高压缩率越好但 CPU 消耗越大。实测下来 5 左右是性价比拐点再往上压缩率提升很有限CPU 却明显上涨。gzip_min_length设个下限太小的文件压缩后可能反而更大还白白消耗 CPU。gzip_vary on会加上Vary: Accept-Encoding响应头告诉中间缓存同一资源有压缩和未压缩两个版本避免缓存串味。图片、视频这类本身已经压缩过的格式不要再 gzip压不动还费 CPU所以gzip_types里不要放它们。如果你的静态资源是构建产物、内容不常变更好的做法是构建时预压缩提前生成.gz文件放在旁边然后用gzip_static on;让 NGINX 直接发预压缩好的文件。这样运行时零压缩开销效果比动态压缩好代价是需要构建流程配合。5.2 缓存头给多长取决于文件名的变化规律缓存是静态站性能的核心也是最容易让用户“看到旧版本”的地方。关键思路是内容会变的文件靠文件名变化来失效文件名不变的入口文件不要长缓存。现代前端构建工具输出的资源文件名通常带内容哈希比如app.3f9a2b.js内容一变文件名就变。这类文件可以给很长的缓存location ~* \.(js|css|png|jpg|jpeg|gif|svg|woff2?)$ { expires 1y; add_header Cache-Control public, immutable; }immutable是告诉浏览器“这个资源在有效期内绝对不变不用再发请求验证”能省掉大量条件请求。但入口 HTML 千万不能这么配。index.html名字是固定的内容却随每次发布变化如果给它一年缓存用户可能几个月都看不到新版本。入口文件应该用短缓存或者协商缓存location /index.html { add_header Cache-Control no-cache; }no-cache不是不缓存而是“每次使用前都要向服务器确认”。配合 ETag 或 Last-Modified内容没变时服务器返回 304只传几个头开销很小。这套“长缓存 文件名哈希 入口不缓存”的组合我用了几年基本没再遇到用户反馈“改了但看不到”的问题。之前不做区分的时候每次发布都得让用户手动清缓存非常难受。5.3 sendfile、keepalive 和文件描述符上限这几个是底层的开关配好了对吞吐和延迟有实际帮助。sendfile on;让文件发送在内核态直接完成省掉从内核缓冲区到用户缓冲区的拷贝。传静态文件时这个开关收益明显。配合tcp_nopush on;可以把响应头和文件内容攒在一起发减少小包数量。注意tcp_nopush和tcp_nodelay在某些场景下会互相影响一般静态文件为主的站点开tcp_nopush反向代理场景更看重tcp_nodelay。keepalive_timeout控制长连接保持多久。设太短频繁建连开销大设太长空闲连接占资源。一般 30 到 65 秒之间看实际流量特征调。还有一个经常被忽略的文件描述符上限。每个连接占一个描述符并发一高就容易撞上限表现是日志里出现大量“too many open files”。除了系统层面的限制NGINX 自己的worker_connections也要跟着调而且要注意worker_connections是每个 worker 的连接数总容量还要乘 worker 数量。6. 反向代理让NGINX站在应用前面该注意什么6.1 proxy_pass 结尾有没有斜杠路径完全不同这是反向代理里最经典的坑没有之一。location /api/ { proxy_pass http://127.0.0.1:8080/; }结尾带斜杠请求/api/user转发到后端会变成/user/api这段被剥掉了。location /api/ { proxy_pass http://127.0.0.1:8080; }结尾不带斜杠转发后路径保持/api/user。后端到底期望哪种取决于它的路由是怎么注册的。前端调/api/user后端路由也写成/api/user那就不能剥后端路由写的是/user那就得剥。这个一定要和后端对齐别靠猜。我曾经因为这个问题查了一下午前端说“我请求发出去了”后端说“我没收到这个路由”最后发现请求确实到了后端只是路径被改写了。6.2 真实IP、超时和缓冲区三个必须补的配置真实 IP。经过代理之后后端拿到的客户端地址全是代理机的。标准做法是让 NGINX 把原始信息放进请求头proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme;后端要读这些头才能拿到真实来源。X-Forwarded-For是个列表多级代理时会不断往后追加后端取的时候要注意取哪个位置。另外这些头是客户端可以伪造的如果前面还有一层可信代理要配合real_ip模块做可信来源校验不能无条件相信。超时。默认的超时时间对某些慢接口来说太短会导致偶发的 504。可以分开调proxy_connect_timeout 5s; proxy_send_timeout 30s; proxy_read_timeout 60s;连接超时设短一点没关系那是建连阶段建不上就是有问题读超时要根据后端最慢的接口来定别一刀切设成很大否则后端真卡住时前端会一直干等。缓冲区。后端返回的头特别大比如带了很多 Cookie 或者超长跳转地址时可能触发“upstream sent too big header”这类错误。这时候需要调proxy_buffer_size专门管响应头和proxy_buffers管响应体。我遇到过接口返回的头部超过默认大小导致 502 的情况排查时看后端日志一切正常最后是靠 NGINX 的错误日志里那句话定位到的。还有一个实用的小配置proxy_http_version 1.1;加上清空Connection头可以让 NGINX 和后端之间也用长连接减少建连开销。默认走 1.0每次请求都要重新建连QPS 高的时候差别很明显。7. HTTPS 配置里那些不会报错但会出事的细节7.1 证书文件的配置和权限拿到证书之后配置大致是这样server { listen 443 ssl; server_name www.example.com; ssl_certificate /etc/nginx/certs/fullchain.pem; ssl_certificate_key /etc/nginx/certs/privkey.pem; ssl_protocols TLSv1.2 TLSv1.3; ssl_prefer_server_ciphers off; ssl_session_cache shared:SSL:10m; ssl_session_timeout 1d; }几个要点。fullchain.pem必须包含完整的证书链只放服务器证书的话某些客户端会因为找不到中间证书而握手失败而这种失败在桌面浏览器上可能看不出来浏览器会自己补链在移动端或者命令行工具上就暴露了。私钥文件的权限要收紧属主设成 root权限 600 或 640确保只有必要进程能读。ssl_protocols里把老旧协议关掉只留 1.2 和 1.3这是现在的通行做法。ssl_prefer_server_ciphers off在现代客户端上是推荐值让客户端根据自己的能力选握手更快。会话缓存这块ssl_session_cache shared:SSL:10m大概能放四万个会话对多数站点足够。握手是 HTTPS 里开销最大的环节缓存能显著减少重复握手。7.2 强制跳转与证书续期别让站“突然挂了”配好 HTTPS 之后通常还要把 HTTP 请求导过去server { listen 80; server_name www.example.com; return 301 https://$host$request_uri; }用 301 是永久跳转浏览器会记住后续直接走 HTTPS省一次往返。但要注意如果哪天你想关掉 HTTPS这个 301 会因为被浏览器缓存而很难撤销。测试阶段建议先用 302确认整套流程没问题再换成 301。证书续期是另一个高频事故点。免费证书通常有效期不长靠自动任务定期续。这里有两个坑一是续期任务执行成功但 NGINX 没有 reload新证书没被加载到期那天照样报错二是续期任务本身失败了但没人知道因为它是静默跑的。我的做法是续期任务里明确加一步 reload并且加一个到期前若干天的检查快到期还没续上就主动告警。听起来麻烦但比起某天早上发现站点打不开这点配置成本完全可以接受。另外如果你的站点同时提供 HTTP 和 HTTPS注意 Cookie 的Secure属性、页面上引用的资源是否也走 HTTPS。混用内容会被浏览器拦控制台里一堆红色报错用户看到的就是样式全乱。8. 排错实录403、404、502、413这几个高频报错怎么定位8.1 403 的三种来路从权限查到索引403 表示服务器理解了请求但拒绝执行。在静态站场景下绝大多数是权限或索引问题按下面顺序查效率最高。第一种目录或文件权限不足。worker 进程的用户对目标路径没有读权限或者中间某一级父目录没有执行权限进不去。检查方式是逐级看权限从站点根目录一直到目标文件。这里有个容易漏的点父目录的执行权限。文件本身 644 看起来没问题但它的上级目录是 700 且属主不是 worker 用户一样进不去。第二种缺少索引文件。请求的是一个目录但该目录下没有index指令指定的默认文件同时autoindex又是关闭的NGINX 就会拒绝列出目录内容。这种情况下返回 403 而不是 404很多人会觉得奇怪其实逻辑上是“我知道这个目录存在但我不给你看”。第三种访问控制规则拦截。配置里有deny规则或者.htaccess之类的隐藏文件被规则挡住了。这类情况查配置里有没有deny all、allow相关的段落就行。排查时最有效的手段是看错误日志。错误日志的路径在全局配置里由error_log指定默认通常在/var/log/nginx/下。把日志级别临时调到error甚至warn复现一次请求日志里通常会直接告诉你“权限被拒绝”或者“目录索引被禁止”比盲猜快得多。记住改完级别要 reload很多人改完配置没 reload 就去看日志然后说日志里什么都没有。8.2 502 和 413一个查后端一个查大小限制502 表示 NGINX 作为代理时后端返回了无效响应或者根本连不上。定位顺序是先确认后端进程在跑、端口在听再用curl直接打后端地址绕过 NGINX 看是否正常如果后端正常而经过 NGINX 就 502那就是代理配置的问题——可能是路径改写出错、可能是超时太短、可能是响应头太大。我之前遇到过一次很隐蔽的 502后端接口在返回大量数据时偶尔失败日志里写的是“upstream prematurely closed connection”。查下来是后端在处理长请求时自己设了超时比 NGINX 的超时还短于是后端先断开NGINX 收到一个不完整的响应。这类问题不看两边的日志对不上只看一边永远想不明白。413 是请求体太大被拒。默认的client_max_body_size只有 1MB上传图片稍微大一点就撞上。改法很简单client_max_body_size 20m;放在 http、server 或 location 层都行按需要控制粒度。注意这个值不要无脑设很大它是防止超大请求打满内存的一道闸门按业务实际需要给就行。另外有些后端框架自己也有请求体大小限制NGINX 放开了但后端还是拒那就得两头一起改。还有一类不那么起眼的问题配置改了但不生效。除了前面说的改错文件、忘记 reload还有一种情况是浏览器或者中间缓存住了旧响应。排查时用curl加-H Cache-Control: no-cache或者直接换个查询串绕过缓存能排除掉这一层干扰。9. 上线前我会过一遍的那张清单搭完能访问只是及格线真正上线前我一般会按下面这张表过一遍很多问题都是在这一步提前发现的。检查项具体动作不做的后果配置语法nginx -t通过改错一个字整站起不来默认站点确认兜底 server 块行为未匹配域名落到奇怪页面目录权限用 worker 用户身份试读文件随机出现 403缓存策略入口文件短缓存、带哈希资源长缓存用户长期看到旧版本压缩文本资源已开 gzip 或预压缩首屏体积翻倍日志访问日志和错误日志路径确认、有轮转磁盘被日志写满上传限制client_max_body_size符合业务上传功能偶发失败证书链完整、到期时间确认、续期任务有 reload到期当天站点不可用健康检查用 curl 走一遍主要路径上线后才发现某类请求挂了日志这一项特别值得单独说。默认的日志格式只记了 IP、时间、请求行、状态码够用但不够查。我一般会在格式里加上 upstream 响应时间和请求总耗时这样排查慢请求时能直接看出时间花在哪一段log_format main $remote_addr - $remote_user [$time_local] $request $status $body_bytes_sent $http_referer $http_user_agent rt$request_time urt$upstream_response_time;$request_time是整个请求耗时$upstream_response_time是后端处理耗时两个一减就是 NGINX 自己的开销。如果差值很大说明问题在代理层或者网络如果urt本身就很大那要去查后端。这一条在我排查性能问题时救过好几次场。日志轮转也别忘了配。访问日志涨得比想象中快一个中等流量的站日志文件几个月就能到几个 G。用系统自带的日志轮转工具配一份规则按天切分、保留一定天数、切完给 NGINX 发信号让它重新打开文件句柄——最后这一步不做的话切走的文件其实还在被占用磁盘空间不会释放。最后说个我自己的习惯每次改完配置先在测试环境用同样的配置跑一遍再上生产。听起来是老生常谈但真到了赶时间的时候人最容易跳过这一步而事故往往就发生在那次“就改一行不用测了”的时候。踩过几次之后我现在改配置之前会先把原文件备份一份改完nginx -t通过再 reloadreload 之后立刻 curl 一下主要路径确认状态码正常。这三步加起来不到一分钟能挡掉绝大多数自己给自己制造的事故。