
Nginx 是那种你用着用着就会喜欢上的软件。对于搞 Web 开发、后端运维、甚至本地调试的人来说Nginx 几乎无处不在正式环境用它在前面顶着开发环境用它在同一台机器上切出多个站点哪怕只是临时起一个静态文件服务它也常常是首选。我这份笔记是边学边记整理出来的从怎么装一个干净的环境开始一路写到 location 匹配机制、反向代理、多站点自定义域名、安全加固、性能排查最后还聊了容器里的 Nginx 长什么样。适合两类人一类是刚接触 Nginx、想知道它到底在干嘛的初学者另一类是已经在用、但遇到报错只能搜到零散答案的进阶用户。我会尽量把“为什么这么做”也写清楚而不只是给命令。1. 先把环境装明白不同场景下的 Nginx 安装与目录结构1.1 Linux 下最快装好 Nginx 的两条路线绝大多数 Linux 服务器上装 Nginx我推荐直接走系统自带的软件仓库。在 Debian/Ubuntu 上就是sudo apt update sudo apt install nginx -y sudo systemctl enable --now nginx curl http://127.0.0.1/在 CentOS/RHEL 9 上用 dnfCentOS 7 上用 yumsudo dnf install nginx -y sudo systemctl enable --now nginx装完以后浏览器打开服务器 IP看到 Welcome to nginx 页面说明基础服务已经起来了。这种方式最大的好处是依赖帮你处理好了配置目录、日志目录、systemd 服务脚本都放在规范位置后续排查问题时会轻松很多。还有一种场景是源码编译安装。以前我总觉得源码编译很酷后来发现维护成本太高如果只是常规使用没必要折腾。除非你需要定制模块、裁剪体积或者系统仓库里的版本太老。编译的典型步骤是sudo apt install libpcre3-dev zlib1g-dev libssl-dev wget https://nginx.org/download/nginx-1.26.2.tar.gz tar -xf nginx-1.26.2.tar.gz cd nginx-1.26.2 ./configure --prefix/usr/local/nginx --with-http_ssl_module make -j$(nproc) sudo make install注意编译前要确认依赖库齐全缺 openssl 的话后面配 HTTPS 就会很被动。另外编译安装出来的二进制版本是固定的后续升级要重新编译生产环境慎用。1.2 装完先认清这几个关键目录无论哪种安装方式最需要记住的其实是几个目录。用系统包安装的 Nginx核心配置在/etc/nginx/nginx.conf子配置可以放到/etc/nginx/conf.d/或者 Debian 系特有的/etc/nginx/sites-enabled/。静态文件默认放在/usr/share/nginx/html/日志默认在/var/log/nginx/access.log和/var/log/nginx/error.log。源码编译安装的话默认前缀是/usr/local/nginx配置和 html 目录都在它下面路径会不一样。这也解释了为什么网上很多教程写的路径和你机器上对不上——先分清楚你是哪种安装方式再去套命令。我自己的习惯是在笔记里记清楚每个路径是“默认值”还是“发行版专用”这样换一台服务器排查时不会一头雾水。1.3 下载教程之类的话题很多时间其实花在选源上网上经常搜到“nginx 下载教程”多数是教你去官网拿源码包。但对于大部分业务场景一条 apt 命令就能解决反而比从官网下载更靠谱。唯二需要主动“下载”的场景是一是离线内网环境去官网或镜像站拿到.rpm/.deb包二是你要在容器里用指定版本的基础镜像比如nginx:1.27-alpine。这两个场景才值得手动下载。还有一个经验如果你所在地区的官方源慢不要随便改源先试试系统自带源是不是已经满足需求。Nginx 本身是免费软件用发行版仓库里的签名包比第三方源安全得多。想验证装的版本用nginx -v看一下再配合nginx -V看编译参数后续排查模块缺失时特别有用。2. 配置文件的骨架server 块、events 与 location 的工作流2.1 先搞清楚 nginx.conf 的主结构第一次打开 nginx.conf 时很多人会被注释和格式吓到。剥掉注释后主干其实只有三层main全局、events、http。main 里常驻的指令有worker_processes它决定 Nginx 启动多少个 worker 进程events 块里出现频率最高的是worker_connections它表示每个 worker 进程能同时打开的最大连接数http 块里才是真正的服务器行为定义比如include引入的子配置、日志格式、gzip、upstream 等等。一个值得背下来的结构示例user nginx; worker_processes auto; events { worker_connections 1024; } http { include /etc/nginx/mime.types; default_type application/octet-stream; access_log /var/log/nginx/access.log; sendfile on; keepalive_timeout 65; server { listen 80; server_name example.com; location / { root /usr/share/nginx/html; } } }注意server是定义“虚拟主机”的最小单位。一个 Nginx 可以在同一个端口上通过不同的server_name区分多个站点也可以在不同端口上各挂一套 server。理解这一点后面配置多站点就会顺很多。2.2 location 的匹配顺序nginx 最容易让人困惑的地方location 是 Nginx 配置里最常用也最容易写错的核心。不少人写location /api/时以为它一定比location /优先结果发现请求全部落到别处去原因就是没搞懂匹配顺序。Nginx 官方定义的 location 匹配可以概括成这么几步前缀是精确匹配命中之后立即跳出去不再做任何后续匹配。比如location /health只匹配/health这个请求。^~前缀是普通前缀匹配但如果这个前缀命中就直接用它不再检查正则。它比普通前缀多了一层“优先且终止”的含义。~或~*开头的是正则匹配前者区分大小写后者不区分。正则按配置文件中出现的顺序依次匹配一旦命中就用这个正则。不带任何前缀的普通前缀匹配是最常见的那种比如location /。它会记录一个“最长匹配的普通前缀”然后继续去检查正则。如果正则都没有命中才使用之前记录的那个最长前缀。所以完整的工作流是先看所有精确匹配再看所有普通前缀和^~如果命中了^~就定案否则把最长前缀记下来然后从配置文件的第一个正则开始逐个试只要有一个正则命中就用正则所有正则都试完都没命中就用刚才记下的最长前缀。举个实际例子location /ping { return 200 pong; } location ^~ /static/ { alias /srv/static/; } location ~ \.php$ { proxy_pass http://php-fpm; } location / { proxy_pass http://app; }请求/ping走精确匹配/static/js/app.js命中^~不会落到\.php$正则/index.php会先匹配普通前缀/然后被正则\.php$抓走/home最终落到/。把这个优先级刻在脑子里配接口转发时就不会出现“我明明写了 /api 为什么没生效”的谜之问题。2.3 root 和 alias 的区别一个斜杠就让人翻车和 location 紧密相关的还有root和alias。很多人把location /images/ { root /data/files; }写下去期望访问/images/a.png对应/data/files/a.png但实际上会去找/data/files/images/a.png。因为 root 的语义是“把请求的完整 URI 拼在 root 后面”。而 alias 的语义才是“把 location 匹配到的部分替换为 alias 指定的路径”。正确写法是location /images/ { alias /data/files/; }访问/images/a.png时Nginx 会找到/data/files/a.png。但 alias 有个坑如果 location 里用了正则alias 后面的路径必须能对应到正则捕获的那一部分否则容易 404。日常开发时我建议在配置完成后用curl -I http://localhost/images/a.png先看一眼实际返回的是 200 还是 404再判断是不是路径拼接的问题。3. 反向代理把 Nginx 从静态服务器升级成流量网关3.1 反代基础proxy_pass 并不只是填个地址Nginx 最常见的用途不是什么“高并发神器”而是反向代理。所谓反向代理就是客户端只认识 NginxNginx 再把请求转给内部的其他服务。典型的配置是这样location /api/ { proxy_pass http://127.0.0.1:8080/; 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; }这里的proxy_pass http://127.0.0.1:8080/;最后的斜杠非常关键。带斜杠时location 中匹配到的/api/前缀会被“消耗掉”后端收到的是干净的/users/1不带斜杠时Nginx 会把完整的 URI 原样传给后端后端就要接/api/users/1。具体用哪种取决于后端的接口是否知道自己被加了前缀。这个细节能解释很多“为什么我代理之后接口 404”的问题。加Host头也是必须的。很多后端 Web 框架根据 Host 来生成跳转链接或校验域名如果 Nginx 不给它传递真实的 Host后端的重定向 URL 就会变成127.0.0.1前端拿到以后一脸懵。X-Forwarded-For则是为了让后端能拿到客户端真实 IP做风控或日志分析时会用到。3.2 用 Nginx 代理 Ollama顺便把 API Key 的校验做在网关层大模型本地服务火起来之后很多团队会在内网部署 Ollama再让 Cherry Studio 之类的客户端去连。默认 Ollama 监听 11434 端口没有鉴权如果直接暴露到局域网别人很容易扫到并滥用。一个很干净的方案是让 Nginx 做代理同时在 Nginx 这一层校验 API Key。假设客户端把 Ollama 地址填成https://ollama.local.exampleAPI Key 填成sk-123456那 Nginx 配置可以这么做server { listen 443 ssl; server_name ollama.local.example; ssl_certificate /etc/nginx/ssl/fullchain.pem; ssl_certificate_key /etc/nginx/ssl/privkey.pem; location / { if ($http_authorization ! Bearer sk-123456) { return 401; } proxy_pass http://127.0.0.1:11434; proxy_set_header Host $host; proxy_set_header Authorization $http_authorization; } }这里最关键的一点是“把校验放在网关层”。Ollama 本身不是业务系统改它的鉴权逻辑既不方便也不安全而在 Nginx 上做一层只属于“前置网关”的校验后面就算再套几层反向代理也不会失守。如果希望密钥不出现在明文配置里可以用变量配合环境变量注入或者用map做简单的 token 表。不过要注意if指令在 Nginx 里的行为比较特殊简单业务还好复杂逻辑尽量少用。3.3 HTTPS 转发与证书错误ERR_CERT_COMMON_NAME_INVALID 的前因后果现在访问站点基本都要上 HTTPS。一个标准的 443 端口 server 块长这样server { listen 443 ssl; server_name www.example.com; ssl_certificate /etc/nginx/ssl/www.example.com.pem; ssl_certificate_key /etc/nginx/ssl/www.example.com.key; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; location / { proxy_pass http://127.0.0.1:8080; } }前端最常遇到的一个报错是net::ERR_CERT_COMMON_NAME_INVALID意思是浏览器检查证书上的 Common Name现在主要是 SAN 域名和你访问的域名对不上。常见原因有三种证书里只有example.com但你用www.example.com访问自签证书生成时 CN 写错了或者你用了.localhost这类特殊域名访问而证书里没有这个域名。排查时先看证书内容openssl x509 -in cert.pem -noout -text | grep DNS。然后确认访问域名和 server_name 是否一致。如果是本地开发建议用 mkcert 生成包含localhost和127.0.0.1的证书而不是把浏览器的证书校验关掉。还有一个小坑是反代到后端时如果后端证书也是自签的Nginx 本身也会报502或upstream SSL certificate verify failed这时需要设置proxy_ssl_server_name on;并把proxy_ssl_verify off;仅限内网信任环境或者在 upstream 块里指定正确的证书。4. 本地开发环境虚拟机、多端口、自定义域名一次配齐4.1 为什么要折腾多站点自定义域名在日常开发里我经常需要在本地同时跑好几个项目。它们可能分别要对接微信登录、Cookie、跨域资源共享如果全用http://localhost:端口访问不仅域名混在一起Cookie 还会互相串。比较好的办法是在 hosts 文件里给每个项目一个独立的域名比如site1.local、site2.local然后让虚拟机里的 Nginx 根据server_name把请求分给不同项目。这就是 Nginx 虚拟主机功能的日常化应用。开发环境的架构可能是这样本机装一个虚拟机虚拟机里运行 Nginx 和多个 Web 服务宿主机通过http://site1.local:8080访问。要做到这点关键就两步宿主机 hosts 把域名指到虚拟机 IPNginx 用listen 8080和server_name site1.local做分发。4.2 hosts 与 Nginx 的 server_name 配合先在宿主机上用管理员权限编辑 hosts 文件Windows 是C:\Windows\System32\drivers\etc\hostsLinux/macOS 是/etc/hosts加一行192.168.56.101 site1.local site2.local然后进入虚拟机的 Nginx新建一个站点配置server { listen 8080; server_name site1.local; root /var/www/site1; index index.html; } server { listen 8081; server_name site2.local; root /var/www/site2; index index.html; }这里最容易被忽略的是“同一个 server_name 多个 listen 端口”和“同一个端口多个 server_name”都能工作但浏览器访问时端口决定连接域名决定 server 块匹配。如果我访问http://site1.local:8081虽然域名匹配到了第二个 server 的 server_name但端口 8081 只对应第二个 server所以打不开 site1。所以约定好“每个项目绑定一个独立端口”或者“所有站点统一用 80 端口但靠域名区分”。开发期最简单的是每个项目一个端口这样 hosts 和 Nginx 都不容易踩坑。4.3 端口转发、防火墙这些开发环境细节用虚拟机时宿主机要能访问到虚拟机的端口还需要注意两点。第一虚拟机网络模式如果是 NAT需要在 VirtualBox 或 VMware 里做端口转发比如把宿主机的 8080 转发到虚拟机的 8080如果是桥接或者 host-only 网络宿主机直接看虚拟机 IP 就能通。第二虚拟机内防火墙常常是默认拒绝外部的非 22 端口需要放行sudo firewall-cmd --permanent --add-port8080/tcp sudo firewall-cmd --reload或者用 ufwsudo ufw allow 8080/tcp。我经历过很多次“明明 Nginx 在虚拟机里 curl 正常宿主机却打不开”的情况排查到最后基本都是防火墙或端口转发没弄。建议把“curl 本地验证 ok - 检查虚拟机防火墙 - 检查宿主机端口转发”当作固定排查顺序能省下很多时间。5. 安全加固与运维监控从 CTF 题到 Zabbix 75.1 从 CTF 安全加固题看 Nginx 常见风险CTF 里经常有 Nginx 配置相关的安全加固题表面上考的是某个漏洞实际上考察的是对配置指令的敏感度。见过不少题目后我总结出几个 Nginx 最容易暴露的风险点。第一是版本泄露。默认配置下Nginx 错误页会带版本号攻击者可以用来匹配已知漏洞。加固方式是全局加server_tokens off;同时不要随意在自定义错误页里写版本号。第二是目录遍历。如果开启了autoindex on;且没有做好访问控制整个目录结构就会暴露。生产环境默认应该保持autoindex off;只有在明确用作文件下载服务时才开启并且要配合allow/deny限制来源 IP。第三是允许危险请求方法。比如TRACE、DELETE、PUT如果不被业务使用可以在 location 里用limit_except GET POST {}拒绝掉。第四是没有限制请求体大小client_max_body_size不设置的话恶意上传超大请求体会把磁盘和内存打满。常规建议设置 1m 到 10m 之间按业务需求来。还有一个很容易忽略的问题是路径穿越。使用alias时如果 location 的匹配路径没有兼顾到斜杠可能通过构造../泄露服务端文件。加固思路是尽量用 root 而不是 alias确需 alias 时要在配置后做路径穿越测试。安全加固没有一劳永逸的配置但至少要做到“最小暴露、默认拒绝、及时更新”。高防现场还会配合限制请求速率比如limit_req_zone $binary_remote_addr zonereq_limit:10m rate5r/s; server { location /login/ { limit_req zonereq_limit burst10; proxy_pass http://127.0.0.1:8080; } }这样做不是让你能防住所有攻击而是把各种扫描器的效率大大降低给后续的安全检测争取时间。5.2 用 Zabbix 7 监控 Nginx 状态监控 Nginx 最基础的手段是启用它的stub_status模块。先确认 Nginx 编译参数里带--with-http_stub_status_module一般发行版已经带了。然后在配置里加一个只允许本机或内网访问的 status 端点server { listen 127.0.0.1:8080; location /nginx_status { stub_status; allow 127.0.0.1; deny all; } }重载后访问curl http://127.0.0.1:8080/nginx_status会看到类似Active connections: 2 server accepts handled requests 100 100 200 Reading: 0 Writing: 1 Waiting: 1Zabbix 7 自带的 agent2 支持通过 Nginx 插件采集这些指标。配置时需要在 agent2 的配置文件里填上Plugins.Nginx.Status.Default.Urlhttp://127.0.0.1:8080/nginx_status然后在 Zabbix Server 端为这台主机关联 Nginx by Zabbix agent 2 模板就能自动创建监控项比如活动连接数、请求总数、握手数、当前读写等待状态。核心指标里我比较关注Active connections和Waiting的比例如果 Waiting 居高不下说明大量请求在空闲等待可能 keepalive 超时设置太长如果 Reading/Writing 一直很高说明并发读写压力大要小心了。5.3 Windows 下查看 Nginx 访问日志的几个小工具有些团队开发机是 Windows却要临时观察 Nginx 访问日志。最直接的办法是用 PowerShellGet-Content -Path C:\nginx\logs\access.log -Wait -Tail 50这会像 Linux 的tail -f一样实时滚动输出。缺点是颜色和过滤都不够方便日志量一上来容易刷屏。想要稍微强一点的分析可以用 GoAccess 的 Windows 版它能直接解析 access.log 生成终端仪表盘统计来源 IP、URL、状态码、响应时间。如果公司已经部署了日志收集系统比如 ELK那把 access.log 接到 Filebeat 里最省心。如果只是本地临时排查某个 5xx 请求我更喜欢用 WSL 里的tail -f /mnt/c/nginx/logs/access.log配合 grep 过滤关键词比 PowerShell 顺手得多。Windows 自带的 LogParser 也能做 SQL 式查询但上手门槛略高不推荐作为日常工具。6. 性能调优与高频坑位并发、Alpine 挂载、Welcome to nginx6.1 最大并发连接数老是用超先从这几点找原因很多运维同学第一次被问“Nginx 最大并发链接数老是用超”时就会想到调大worker_connections。这方向没错但不完整。Nginx 能达到的最大并发连接数可以近似为一个公式最大并发连接数 ≈ worker_processes × worker_connections比如worker_processes 4、worker_connections 1024理论上最大支持 4096 个并发连接。但别高兴得太早操作系统对进程的文件描述符数量做了限制如果ulimit -n是 1024那即使 Nginx 配置成 4096 也没用超过 1024 后新连接会报Too many open files。所以调参要同步看这几个地方grep worker_processes /etc/nginx/nginx.conf grep worker_connections /etc/nginx/nginx.conf ulimit -n在 systemd 下Nginx 的 LimitNOFILE 可能和 shell 里的 ulimit 不一致需要查看systemctl cat nginx。确认没有隐藏限制后再调整内核参数sysctl -w net.core.somaxconn65535 sysctl -w net.ipv4.ip_conntrack_max65535至于应用层超时如果你的反向代理经常报connect() failed或者upstream timed out通常不是连接数的问题而是proxy_connect_timeout和proxy_read_timeout设得太短改为 5s/30s 会稳妥很多。我踩过一次高并发事故所有 worker 都被数据库连接池占住了Nginx 本身没满但请求全部卡等最后定位到是上游应用线程池太小。所以说“并发老是用超”不一定真的是 Nginx 资源不够要顺着请求链路一层层查。6.2 Alpine 容器里挂载 conf.d 报错权限和路径的坑在 Docker 里跑 Nginx 很常见nginx:alpine镜像体积小很多人喜欢用。但把宿主机配置目录挂载进去时偶尔会看到一个经典报错nginx: [emerg] open() /etc/nginx/conf.d/default.conf failed (13: Permission denied)最常见的原因是宿主机目录权限过严。Alpine 镜像里的 nginx worker 进程默认以nginx用户运行UID 是 101。宿主机挂载进去的目录如果 owner 是 root 且权限是 700容器里的 nginx 用户读不了。解决办法是把宿主机对应目录权限放宽chmod -R 755 /your/nginx/conf.d或者更精确一点把目录 owner 改成 101chown -R 101:101 /your/nginx/conf.d。还有一个不那么明显的原因官方 nginx 镜像的入口脚本会查找/etc/nginx/conf.d/default.conf并尝试做 envsubst 之类的处理如果你的挂载目录里没有这个文件或者挂载时覆盖了整个 conf.d也会报错。解决方式是只挂载单个配置文件到 conf.d 里或者在命令里禁用默认配置。总之遇到容器内 Nginx 挂载报错第一件事就是docker exec 容器 ls -l /etc/nginx/conf.d看看容器内用户视角下文件到底可不可读。这一步能筛掉一大半问题。6.3 第一次打开显示 Welcome to nginx 该怎么办这个页面几乎是所有人的“第一个 Nginx 页面”。它出现本身说明 Nginx 服务是正常的只是还没有任何站点配置指向你的项目。如果你已经写了 server 块却还是看到 Welcome可能是访问的 IP 命中了默认 server 块。Ubuntu 默认安装会在/etc/nginx/sites-enabled/default里定义一个默认站点监听 80 的 default_serverroot 指向/usr/share/nginx/html里面放的正是欢迎页。想让自己的项目接管最常见做法是删掉或禁用默认站点sudo rm /etc/nginx/sites-enabled/default或直接修改它的 root。建一个自己的站点配置比如/etc/nginx/conf.d/my-site.conf。配置一个 server 块把server_name指向你的域名或 IProot指向项目目录。nginx -t systemctl reload nginx后刷新浏览器。如果刷新还是看到欢迎页确认浏览器是否有缓存或者服务器上是不是多块网卡导致访问的端口不是你想的那个。还有一个低级错误是项目文件放到了/usr/share/nginx/html之外但权限不对nginx 用户读不了结果 403。这时可以去查 error.log里面会写明权限拒绝的具体路径。7. 容器化是绕不开的下一步Nginx 在 Kubernetes 里的部署形态7.1 用 Deployment Service 部署 NginxKubernetes 里部署 Nginx最常见的是把它当作一个普通的 Web 服务跑起来。一个最小可用的例子是写一个 Deployment使用nginx:1.27-alpine镜像通过 ConfigMap 把自定义站点配置放进去然后暴露成 Service。apiVersion: apps/v1 kind: Deployment metadata: name: nginx-demo spec: replicas: 2 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.27-alpine ports: - containerPort: 80 volumeMounts: - name: conf mountPath: /etc/nginx/conf.d - name: html mountPath: /usr/share/nginx/html volumes: - name: conf configMap: name: nginx-conf - name: html configMap: name: nginx-html --- apiVersion: v1 kind: Service metadata: name: nginx-demo-svc spec: type: NodePort selector: app: nginx ports: - port: 80 targetPort: 80 nodePort: 30080配置变更后可以直接重建 ConfigMap 并触发滚动重启kubectl rollout restart deployment/nginx-demo。注意 ConfigMap 挂载是只读的Nginx 运行时如果尝试写目录会报权限问题所以日志目录尽量用 emptyDir 或改到 stdout。这也是容器化 Nginx 和宿主机 Nginx 最大的思维差异容器里一切文件都是临时的别把状态留在文件系统里。7.2 Ingress 和 Nginx 不是一回事很多人说“在 K8s 里部署 Nginx”以为是起一个 Nginx Pod 就完事了。其实对外流量入口通常会用 Ingress Controller而最流行的 ingress-nginx 就是基于 Nginx 开发的控制器。Ingress 资源提供的域名、路径规则会被 Controller 编译成一份 Nginx 配置然后写进一个 Running 的 Nginx Pod 里。用起来时最省心的方式是把 Ingress 当作“声明式 Nginx”apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: demo-ingress spec: ingressClassName: nginx rules: - host: demo.example.com http: paths: - path: / pathType: Prefix backend: service: name: nginx-demo-svc port: number: 80和直接管理 Nginx 配置相比Ingress 的好处是能让开发者声明意图Controller 负责把它转化成底层配置并且支持证书挂载、限流、重写等注解。但注解过多时排查难度会上升所以我建议团队里至少有一两个人能看懂 Controller 生成的 nginx.conf否则流量异常时会陷入“只能重启”的被动局面。写在最后的个人体会我自己的经验是Nginx 的配置语法并不复杂真正复杂的是搞清楚一个请求进入后在配置文件里经过了多少个阶段的判断。把所有知识点串起来的方式其实很朴素就是“一个请求从浏览器到后端的完整路径”客户端先和 Nginx 建立 TCP 连接Nginx 根据端口、server_name 选择合适的 server再根据 URI 找到合适的 location被选中 location 里的 root、proxy_pass、重写规则依次执行然后把响应原路返回。把这条链路走通再遇到任何 Nginx 报错都不会慌因为你知道它卡在哪一段。最后分享一个让我少背了很多锅的小习惯每次改完配置先nginx -t接着systemctl reload nginx或nginx -s reload然后立刻看一眼 error.log。生产环境变更前一定备份原配置变更后做一次 curl 验证再离开。这套习惯值这个笔记里的所有知识点。