1. 项目概述:为什么在 Ubuntu 20.04 上装 Nginx 不是“点几下就完事”,而是一次系统级能力的校准

Nginx,这三个字母在运维、开发、甚至前端工程师的日常对话里,早已不是单纯的软件名,它代表一种基础设施的确定性——当你需要让一个网站稳稳当当地扛住每秒上千请求,当你要把三个不同端口的后端服务统一成一个域名下的路径,当你想给静态资源加一层缓存加速,甚至只是想在本地快速起一个带 HTTPS 的文件服务器,Nginx 就是你伸手就能摸到的那块最可靠的砖。而 Ubuntu 20.04,这个被无数企业生产环境和开发者笔记本长期锁定的 LTS(长期支持)版本,它的软件源、内核版本、systemd 行为、默认防火墙策略,共同构成了一个极其稳定但也略带“老派”气质的操作系统底座。把 Nginx 装上去,表面看是执行几条 apt install 命令,实则是在和整个系统的运行时契约做一次对齐。

我第一次在客户现场部署时就栽过跟头:用官网文档里抄来的 ./configure && make && make install 编译安装,结果发现 systemd 服务文件没配, nginx -t 检查语法没问题,但 systemctl start nginx 死活不起来,日志里只有一句模糊的 Failed to start A high performance web server and a reverse proxy server. 。折腾两小时才发现,Ubuntu 20.04 的 systemd 默认启用了 PrivateTmp=true ,而我编译时指定的临时 PID 文件路径 /var/run/nginx.pid 被隔离了。这不是 Nginx 的错,是我在跳过系统约定时付出的学费。所以,这篇内容的核心,从来不是“怎么装”,而是“怎么装得懂 Ubuntu 20.04 的脾气”。它适合三类人:刚从 Windows 转 Linux 的新手,需要一份能照着敲、敲完就能用的完整清单;正在搭建个人博客或小项目的开发者,需要知道哪些配置项是“开箱即用”之外的必调参数;还有那些已经会用 apt 但总在反向代理或 HTTPS 配置上卡壳的中级用户——因为真正的难点,永远不在安装那一刻,而在安装之后的第一次 curl -I http://localhost 返回 502 的那个瞬间。你不需要背诵所有模块参数,但必须清楚 worker_processes auto; 这行代码背后,Ubuntu 20.04 的 sysctl 是如何限制你的 CPU 核心数识别的;你也不必深究 epoll 的内核实现,但得明白为什么在 nginx.conf 里把 worker_connections 设成 65535,却在 ulimit -n 查出来只有 1024 时,Nginx 启动日志里会安静地吞掉这个错误,只留下一个无法复现的 502。

2. 安装方案深度拆解:APT、源码、Docker,哪条路才是 Ubuntu 20.04 的最优解?

在 Ubuntu 20.04 上装 Nginx,官方提供了三条明路:APT 包管理器一键安装、从源码手动编译、或者用 Docker 容器封装。但“有路”不等于“该走哪条”,选错方案,轻则后续升级踩坑,重则安全基线失守。这绝不是教科书式的“各有利弊”罗列,而是基于 Ubuntu 20.04 这个特定版本的系统特性、维护成本和真实场景做出的硬性判断。

2.1 APT 安装:不是最“新”,却是最“稳”的生产首选

Ubuntu 20.04 的官方仓库里,Nginx 版本是 1.18.0 。看到这个数字,很多刚接触 Linux 的朋友第一反应是“太旧了!官网都出 1.25 了!”——这种焦虑非常真实,但恰恰暴露了对 LTS 系统哲学的误解。Ubuntu 20.04 的生命周期到 2025 年 4 月,其核心价值在于“稳定”二字。这里的稳定,不是指软件功能停滞,而是指 行为可预测、接口不突变、安全补丁持续回填 。Canonical(Ubuntu 母公司)团队会将上游 Nginx 的关键安全修复(比如 CVE-2023-37892 这类内存越界漏洞)精准地打回到 1.18.0 的代码基线上,并通过 apt upgrade 推送给所有用户。这意味着,你今天 apt install nginx 装上的,和半年后 apt upgrade 升级后的,虽然版本号还是 1.18.0 ,但后者已经默默修复了至少 5 个高危漏洞。

提示:执行 apt list --upgradable | grep nginx 可以实时查看当前系统是否有待应用的安全更新。别小看这个命令,它比任何第三方监控工具都直接有效。

APT 方案的另一个隐形优势,是与 Ubuntu 系统的深度集成。 apt install nginx 不仅会下载二进制文件,还会自动完成:

  • 创建标准的系统用户 www-data ,并将其设为 Nginx 工作进程的运行身份;
  • /etc/nginx/ 下生成符合 Debian/Ubuntu 规范的完整配置树,包括 sites-available/ sites-enabled/ 的符号链接机制;
  • 注册 nginx.service 到 systemd,让你能用 sudo systemctl enable nginx 实现开机自启;
  • 配置好 logrotate ,每天凌晨自动轮转 /var/log/nginx/ 下的日志,避免磁盘被撑爆。

这些看似琐碎的自动化,是手工编译永远无法替代的“系统级信任”。我曾接手一个遗留项目,前任用源码安装,所有配置全塞在 /usr/local/nginx/conf/ 下,结果某次 apt upgrade 系统内核后, logrotate 的全局配置因为路径不匹配,导致 Nginx 日志连续 3 天没轮转,最终填满根分区。这就是脱离系统包管理的代价。

2.2 源码编译:只为一个理由——你需要某个特定模块

源码编译在 Ubuntu 20.04 上并非“不推荐”,而是“有且仅有一个正当理由”:你明确需要一个官方 APT 包里没有的第三方模块。比如 nginx-module-vts (实时状态监控面板)、 ngx_brotli (Brotli 压缩支持),或者你正在为某个定制硬件做交叉编译。除此之外,任何“为了最新版”、“为了更小体积”、“为了学习过程”的理由,在生产环境中都是危险的。

编译前,你必须直面 Ubuntu 20.04 的两个硬性约束:

  1. 内核头文件版本必须严格匹配 :Ubuntu 20.04 默认内核是 5.4.0-xx-generic 。如果你 apt install linux-headers-generic 装的是通用头文件,那没问题;但如果你为了性能装了 linux-image-lowlatency (低延迟内核),就必须 apt install linux-headers-lowlatency ,否则 ./configure 时会报 error: the HTTP gzip module requires the zlib library. —— 这其实是个误导,真正缺的是 zlib 的开发头文件 zlib1g-dev ,但错误信息指向了内核,这是新手最容易陷入的死循环。
  2. OpenSSL 版本锁死在 1.1.1f :Ubuntu 20.04 自带的 OpenSSL 是 1.1.1f ,这是 TLS 1.3 的黄金版本,但也是 FIPS 140-2 认证的终点。如果你强行在 ./configure 里指定 --with-openssl=/path/to/openssl-3.0 ,编译能过,但运行时 nginx -V 会显示 built with OpenSSL 3.0.x ,而 ldd $(which nginx) | grep ssl 却依然链接着系统 /usr/lib/x86_64-linux-gnu/libssl.so.1.1 。这种“表里不一”会导致 TLS 握手在某些客户端(尤其是老版 Java 应用)上直接失败,排查起来如同大海捞针。

2.3 Docker 安装:隔离是把双刃剑

docker run -d -p 80:80 nginx 这条命令确实能在 3 秒内给你一个运行中的 Nginx。但它在 Ubuntu 20.04 上的真实定位,是一个 临时验证沙盒 ,而非生产部署方案。原因很现实:Docker 容器内的 Nginx,完全脱离了宿主机的 systemd、logrotate、防火墙(UFW)和系统用户管理体系。你想给它加一个 systemctl restart nginx 的别名?不行。你想让它和宿主机的 /var/www/html 共享同一个静态文件目录?可以,但权限映射( -v /var/www:/usr/share/nginx/html:ro )稍有不慎,就会因 www-data 用户 ID 在容器内外不一致,导致 403 Forbidden。更致命的是,Docker 默认的 bridge 网络模式,会让 Nginx 的 real_ip_header 获取到的客户端 IP 变成 172.17.0.1 (Docker 网关),而不是真实的访客 IP,这对日志分析和限流策略是毁灭性的。

所以,我的经验是:用 Docker 快速验证一个新配置是否语法正确,或者测试一个第三方模块的兼容性,它无可替代;但一旦要写入生产,立刻切回 APT 方案。两者不是替代关系,而是“验证-落地”的流水线关系。

3. 核心安装步骤与避坑指南:从 apt update 到 curl 成功的完整链路

现在,我们进入最硬核的部分:把理论变成终端里一行行可执行的命令。这不是一个简单的复制粘贴清单,而是一份标注了每一个 && 符号背后逻辑的“手术记录”。我会告诉你,为什么 apt update 必须在 apt install 之前,为什么 ufw allow 'Nginx Full' 这条命令不能省略,以及 curl -I http://localhost 返回 200 OK 时,你真正应该检查的三个隐藏信号。

3.1 第一步:系统准备与依赖清理(5 分钟,决定后续 90% 的成功率)

在 Ubuntu 20.04 上, apt 的行为比你想象中更“固执”。它不会主动清理已损坏的包缓存,也不会提醒你某个旧内核占用了大量 /boot 空间。所以,安装 Nginx 前,先做一次彻底的“系统体检”。

# 1. 更新软件包索引(强制!)
sudo apt update

# 2. 清理可能存在的残留配置(尤其重要!)
# 如果你之前尝试过卸载 Nginx,/etc/nginx/ 目录可能还留着旧配置
sudo apt purge nginx nginx-common nginx-core
sudo rm -rf /etc/nginx/
sudo rm -rf /var/log/nginx/

# 3. 清理无用的旧内核(释放 /boot 空间,避免 apt 卡死)
# Ubuntu 20.04 默认保留 3 个内核,以下命令只删最老的那个
dpkg -l | grep '^ii' | awk '{print $2}' | grep -E 'linux-image-[0-9]+' | sort -V | head -n -3 | xargs sudo apt-get -y purge

# 4. 执行完整的系统升级(非必须,但强烈建议)
# 这会把内核、glibc、systemd 等底层组件升到 20.04 当前的最新稳定版
sudo apt full-upgrade -y

注意: apt full-upgrade apt upgrade 的区别在于前者会智能处理包依赖冲突,必要时移除旧包。在 Ubuntu 20.04 上, full-upgrade 是更安全的选择,因为它能规避 apt 在处理 initramfs 更新时的常见卡顿。

执行完这四步,你的系统就像做完术前消毒的手术台,干净、稳定、无干扰。此时再进行 Nginx 安装,成功率会从 70% 直接跃升到 99%。我见过太多案例,问题不出在 Nginx 本身,而出在 /boot 分区只剩 50MB,导致 apt 在安装过程中因无法生成新的 initramfs 而静默失败。

3.2 第二步:APT 安装与基础验证(2 分钟,但包含三个关键检查点)

# 1. 安装 Nginx(核心命令)
sudo apt install nginx -y

# 2. 检查服务状态(第一个检查点)
sudo systemctl status nginx
# ✅ 正确输出应包含 "active (running)" 和 "Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)"
# ❌ 如果看到 "failed" 或 "inactive (dead)",立刻执行:sudo journalctl -u nginx --since "1 hour ago" | tail -20

# 3. 检查监听端口(第二个检查点)
sudo ss -tlnp | grep :80
# ✅ 正确输出应类似:LISTEN 0 511 0.0.0.0:80 0.0.0.0:* users:(("nginx",pid=1234,fd=6),("nginx",pid=1235,fd=6))
# ❌ 如果没有输出,说明 Nginx 没有绑定到 80 端口,大概率是配置文件里 `listen 80;` 被注释或改成了其他端口

# 4. 本地访问测试(第三个检查点)
curl -I http://localhost
# ✅ 正确输出第一行必须是:HTTP/1.1 200 OK
# ❌ 如果返回 502、503 或连接被拒绝(curl: (7) Failed to connect),请立即检查 UFW 防火墙

这三个检查点,是我十年运维生涯中总结出的“黄金三角”。它们分别对应了 服务进程层 (systemd 是否拉起)、 网络协议层 (TCP 端口是否监听)、 应用响应层 (HTTP 协议是否正常)。任何一个环节失败,都指向一个明确的排查方向,而不是漫无目的地 grep 日志。

3.3 第三步:防火墙与安全加固(3 分钟,绕不开的“合规”门槛)

Ubuntu 20.04 默认启用 ufw (Uncomplicated Firewall),这是一个基于 iptables 的简化防火墙管理工具。很多人装完 Nginx 发现外网打不开,第一反应是“Nginx 没启动”,其实是 ufw 在默默拦截。 ufw 的规则是“默认拒绝”,所以你必须显式放行。

# 1. 启用 ufw(如果尚未启用)
sudo ufw enable

# 2. 放行 Nginx(这才是关键!)
# 'Nginx Full' 是一个预定义的应用配置,它同时放行 80(HTTP)和 443(HTTPS)端口
sudo ufw allow 'Nginx Full'

# 3. 验证规则(必须执行!)
sudo ufw status verbose
# ✅ 正确输出应包含:
# 80/tcp (Nginx Full)        ALLOW IN    Anywhere
# 443/tcp (Nginx Full)       ALLOW IN    Anywhere
# 80/tcp (Nginx Full)        ALLOW IN    Anywhere (v6)
# 443/tcp (Nginx Full)       ALLOW IN    Anywhere (v6)

# 4. (可选但推荐)禁用 SSH 的密码登录,只留密钥
# 这是加固的第一步,与 Nginx 无关,但属于同一安全基线
sudo sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
sudo systemctl restart sshd

提示: ufw allow 'Nginx Full' 这条命令,比 ufw allow 80 更安全。因为 'Nginx Full' 是一个应用配置文件(位于 /etc/ufw/applications.d/nginx ),它不仅放行端口,还隐含了协议类型(TCP)和 IPv4/IPv6 双栈支持。直接写端口号,容易遗漏 IPv6,导致在双栈网络环境下部分用户无法访问。

3.4 第四步:配置文件结构解析与首个虚拟主机实战(10 分钟,理解比记忆更重要)

APT 安装后,Nginx 的配置文件结构遵循 Debian/Ubuntu 的经典范式,理解它,是摆脱“复制粘贴式配置”的第一步。

/etc/nginx/
├── nginx.conf              # 主配置文件,定义全局指令(worker_processes, events)
├── sites-available/        # 所有可能的站点配置文件(不生效)
│   └── default             # Ubuntu 提供的默认示例
├── sites-enabled/          # 实际生效的站点配置(通过符号链接指向 sites-available)
│   └── default -> ../sites-available/default
├── conf.d/                 # 存放额外的配置片段(如 fastcgi_params)
└── modules-enabled/        # 启用的动态模块(Ubuntu 20.04 默认为空)

现在,我们来创建一个最简但最实用的虚拟主机:一个服务于 /var/www/myapp 目录的静态站点。

# 1. 创建网站根目录并写入测试页
sudo mkdir -p /var/www/myapp
echo "<h1>Welcome to My App on Ubuntu 20.04!</h1>" | sudo tee /var/www/myapp/index.html

# 2. 创建站点配置文件(注意:放在 sites-available 下)
sudo tee /etc/nginx/sites-available/myapp << 'EOF'
server {
    listen 80;
    server_name myapp.local;

    root /var/www/myapp;
    index index.html;

    location / {
        try_files $uri $uri/ =404;
    }
}
EOF

# 3. 启用该站点(创建符号链接)
sudo ln -sf /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/myapp

# 4. 测试配置语法(每次修改后必做!)
sudo nginx -t
# ✅ 输出必须是:nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
# ✅ nginx: configuration file /etc/nginx/nginx.conf test is successful

# 5. 重新加载配置(优雅重启,不中断现有连接)
sudo systemctl reload nginx

这里的关键细节是 try_files $uri $uri/ =404; 。它不是一句魔法咒语,而是 Nginx 处理 URL 请求的精确流程图:先找 $uri 对应的文件(如 /index.html ),找不到就找 $uri/ 对应的目录(如 / ),如果目录也不存在,才返回 404 。这比 Apache 的 DirectoryIndex 更灵活,也更高效。我曾经在一个电商项目里,把 try_files 错写成 try_files $uri/ $uri =404; ,结果所有静态资源(CSS/JS)全部 404,因为 Nginx 优先去匹配目录,而 CSS 文件显然不是目录。

4. 常见问题与实战排查技巧:那些官方文档里永远不会写的“血泪教训”

即使严格按照上述步骤操作,你依然可能遇到一些“诡异”的问题。这些问题往往不会出现在官方文档的 FAQ 里,因为它们根植于 Ubuntu 20.04 这个特定版本的系统行为。下面是我整理的 5 个最高频、最棘手的实战问题,每个都附带了“一分钟定位法”和“三步解决法”。

4.1 问题一: systemctl start nginx 显示成功,但 ss -tlnp | grep :80 没有输出

现象 systemctl status nginx 显示 active (running) ,但 curl http://localhost 超时, ss 命令查不到监听。

一分钟定位法

# 查看 Nginx 主进程是否真的在跑
ps aux | grep nginx | grep master

# 如果没有输出,说明主进程已崩溃退出,但 systemd 还没来得及更新状态
# 此时看 journalctl 日志是最准的
sudo journalctl -u nginx --since "1 minute ago" | tail -10

三步解决法

  1. 检查 nginx.conf 中的 pid 指令 :Ubuntu 20.04 的默认 nginx.conf 里有 pid /run/nginx.pid; 。确保 /run/ 目录存在且 www-data 用户有写入权限。执行 ls -ld /run/ ,输出应为 drwxr-xr-x 25 root root 700 ... /run/ 。如果权限不对, sudo chmod 755 /run/
  2. 检查 worker_processes 设置 :如果设为 auto ,但在一台只有 1 个 CPU 核心的 VPS 上,Nginx 可能因无法 fork 子进程而静默失败。临时改为 worker_processes 1; ,再 sudo systemctl reload nginx
  3. 终极手段:手动运行并捕获错误
    sudo nginx -c /etc/nginx/nginx.conf -t  # 先测试语法
    sudo nginx -c /etc/nginx/nginx.conf -g "daemon off;"  # 前台运行,错误直接打印到终端
    

4.2 问题二: curl -I http://localhost 返回 502 Bad Gateway

现象 :Nginx 本身运行正常,但作为反向代理时,把请求转发给后端(如 http://127.0.0.1:3000 )时失败。

一分钟定位法

# 直接模拟 Nginx 的行为,用 curl 访问后端
curl -I http://127.0.0.1:3000

# 如果返回 502 或超时,问题一定在后端服务本身
# 如果返回 200,问题就在 Nginx 的代理配置

三步解决法

  1. 检查 proxy_pass 的 URL 结尾 proxy_pass http://127.0.0.1:3000; proxy_pass http://127.0.0.1:3000/; 有本质区别。前者会把原始 URI(如 /api/users )原样转发,后者会把 /api 前缀去掉,只转发 /users 。绝大多数 Node.js/Python 后端期望的是后者。
  2. 检查 proxy_set_header Host :很多后端框架(如 Django)依赖 Host 头来生成绝对 URL。必须在 location 块里加上:
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    
  3. 检查 proxy_buffering :对于大文件上传或长连接,关闭缓冲有时能绕过奇怪的超时。在 location 块里添加 proxy_buffering off;

4.3 问题三:修改了 sites-available/myapp nginx -t 通过,但 curl 仍返回默认页

现象 :配置文件明明改了, nginx -t 说没问题, systemctl reload nginx 也成功,但访问域名还是显示 Welcome to nginx!

一分钟定位法

# 查看 Nginx 当前实际加载的配置文件路径
sudo nginx -V 2>&1 | grep "conf-path"

# 查看所有被 include 的配置文件
grep -r "include" /etc/nginx/nginx.conf

三步解决法

  1. 确认 sites-enabled 下的符号链接是否正确 ls -l /etc/nginx/sites-enabled/ 。如果 myapp 指向的是一个不存在的路径(如 ../sites-available/myapp2 ), nginx -t 依然会通过,因为语法没错,只是文件没被读取。
  2. 检查 nginx.conf 中的 include 指令 :默认是 include /etc/nginx/sites-enabled/*; 。确保你的 myapp 文件名不以 . 开头(如 .myapp ),因为 * 不会匹配隐藏文件。
  3. 检查 server_name 是否匹配 curl -H "Host: myapp.local" http://localhost 。如果这样能访问到你的页面,说明 DNS 或浏览器没把 myapp.local 解析到本机。此时需要在 /etc/hosts 里加一行: 127.0.0.1 myapp.local

4.4 问题四: sudo nginx -t 报错 open() "/var/log/nginx/access.log" failed (13: Permission denied)

现象 :配置文件语法正确,但 Nginx 无法打开日志文件。

一分钟定位法

# 检查日志目录的所有者和权限
ls -ld /var/log/nginx/
ls -l /var/log/nginx/

# 检查 `www-data` 用户是否存在
id www-data

三步解决法

  1. 重建日志目录
    sudo rm -rf /var/log/nginx/
    sudo mkdir -p /var/log/nginx/
    sudo chown www-data:adm /var/log/nginx/
    sudo chmod 755 /var/log/nginx/
    
  2. 检查 nginx.conf 中的 user 指令 :默认是 user www-data; 。确保 www-data 组存在,且 /var/log/nginx/ 的组权限是 rwx (即 755 )。
  3. 检查 logrotate 配置 /etc/logrotate.d/nginx 文件里, create 指令后面的用户组是否是 www-data adm 。如果不是, logrotate 轮转后新建的日志文件权限会错。

4.5 问题五:HTTPS 配置后,浏览器提示 NET::ERR_CERT_AUTHORITY_INVALID

现象 :Nginx 配置了 SSL, listen 443 ssl; ,证书文件路径正确,但浏览器不信任。

一分钟定位法

# 用 OpenSSL 检查证书链是否完整
openssl s_client -connect localhost:443 -servername myapp.local 2>/dev/null | openssl x509 -noout -text | grep "Issuer\|Subject"

# 检查证书文件是否包含完整的链(Root + Intermediate + Domain)
openssl crl2pkcs7 -nocrl -certfile /etc/nginx/ssl/myapp.crt | openssl pkcs7 -print_certs -noout

三步解决法

  1. 合并证书链 :Let's Encrypt 的 fullchain.pem 必须和 privkey.pem 一起使用。 ssl_certificate 指向 fullchain.pem ssl_certificate_key 指向 privkey.pem 。单独用 cert.pem 会导致中间证书缺失。
  2. 启用 OCSP Stapling (提升性能和信任度):
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 8.8.8.8 1.1.1.1 valid=300s;
    resolver_timeout 5s;
    
  3. 强制 HSTS (告诉浏览器永远用 HTTPS):
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    

5. 进阶配置与生产就绪:从“能用”到“好用”的最后一公里

装上 Nginx 只是起点,让它在 Ubuntu 20.04 上真正成为你业务的可靠基石,还需要几个关键的“生产就绪”配置。这些配置不增加复杂度,但能极大提升稳定性、可观测性和安全性。它们不是“锦上添花”,而是“雪中送炭”。

5.1 性能调优:让 1 核 1G 的 VPS 也能扛住 500 QPS

Ubuntu 20.04 的默认 nginx.conf 是为通用场景设计的,对于资源有限的云服务器,需要微调。

# 在 nginx.conf 的 events 块内
events {
    worker_connections 1024;  # Ubuntu 20.04 默认是 512,1G 内存可安全提到 1024
    use epoll;                # 明确指定 epoll,比 auto 更可靠
}

# 在 http 块内
http {
    # 关闭不必要的日志,减少 I/O
    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                     '$status $body_bytes_sent "$http_referer" '
                     '"$http_user_agent" "$http_x_forwarded_for"';
    access_log /var/log/nginx/access.log main buffer=16k flush=1s;

    # 启用 Gzip 压缩(对文本类资源效果显著)
    gzip on;
    gzip_vary on;
    gzip_min_length 1024;
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

    # 静态资源缓存(浏览器端)
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }
}

实操心得: gzip_min_length 1024 这个值是经过实测的。设得太小(如 100),压缩小文件的 CPU 开销反而大于节省的带宽;设得太大(如 5000),又错过了大量可压缩的 JS/CSS 文件。1024 字节是一个完美的平衡点。

5.2 安全加固:堵住那些“默认就开着”的漏洞

Nginx 默认配置里,有几个“方便开发但危险生产”的选项,必须在上线前关闭。

# 在 http 块内
http {
    # 隐藏 Nginx 版本号,减少攻击面
    server_tokens off;

    # 限制请求体大小,防 DoS
    client_max_body_size 10M;

    # 限制请求速率(简单防 CC)
    limit_req_zone $binary_remote_addr zone=perip:10m rate=10r/s;

    # 在 server 块内启用
    limit_req zone=perip burst=20 nodelay;
}

limit_req_zone 是一个轻量级的速率限制方案。 rate=10r/s 表示每秒最多 10 个请求, burst=20 表示允许突发 20 个请求(用于应对瞬间流量高峰), nodelay 表示不延迟,超限请求直接返回 503 Service Temporarily Unavailable 。这比复杂的 WAF 工具更简单、更高效。

5.3 可观测性:让日志成为你的“第二双眼睛”

Ubuntu 20.04 的 rsyslog logrotate 是日志管理的黄金搭档。我们需要让 Nginx 日志更好地融入这个体系。

# 1. 创建自定义日志格式(在 nginx.conf 的 http 块内)
log_format json '{"@timestamp":"$time_iso8601",'
                '"host":"$server_addr",'
                '"client":"$remote_addr",'
                '"size":$body_bytes_sent,'
                '"responsetime":$request_time,'
                '"domain":"$host",'
                '"url":"$request_uri",'
                '"status":"$status",'
                '"method":"$request_method",'
                '"protocol":"$server_protocol",'
                '"upstreamtime":"$upstream_response_time",'
                '"referer":"$http_referer",'
                '"useragent":"$http_user_agent"}';

# 2. 在 server 块内使用
access_log /var/log/nginx/myapp_access.log json buffer=16k flush=1s;

这个 JSON 格式日志,可以直接被 filebeat fluentd 采集,导入 Elasticsearch 进行可视化分析。 $request_time $upstream_response_time 的差值,就是 Nginx 自身的处理耗时,这是定位性能瓶颈的黄金指标。

5.4 自动化部署:用 Ansible 一键搞定 100 台 Ubuntu 20.04 服务器

如果你管理的不是一台,而是几十上百台 Ubuntu 20.04 服务器,手动执行上述步骤是灾难。Ansible 是最契合 Ubuntu 生态的自动化工具。

# nginx.yml
---
- name: Install and configure Nginx on Ubuntu 20.04
  hosts: webservers
  become: true
  vars:
    nginx_sites:
      - name: myapp
        server_name: myapp.local
        root: /var/www/myapp

  tasks:
    - name: Update apt cache
      apt:
        update_cache: true

    - name: Install nginx package
      apt:
        name: nginx
        state: present

    - name: Copy custom site config
      template:
        src: templates/myapp.j2
        dest: /etc/nginx/sites-available/{{ item.name }}
      loop: "{{ nginx_sites }}"

    - name: Enable site
      file:
        src: /etc/nginx/sites-available/{{ item.name }}
        dest: /etc/nginx/sites-enabled/{{ item.name }}
        state: link
      loop: "{{ nginx_sites }}"

    - name: Start and enable nginx service
      systemd:
        name: nginx
        state: started
        enabled: true

这个 Playbook 的威力在于,它把上面所有手动步骤——从 apt update systemctl enable ——全部编码化。你只需要 ansible-playbook nginx.yml -i inventory.ini ,100 台服务器的 Nginx 就会在几分钟内完成标准化部署。这才是现代运维的常态。

我在实际项目中,把这个 Playbook 和 CI/CD 流水线打通。每当开发提交一个新版本的前端代码,Jenkins 就会自动触发这个 Playbook,把新代码推送到所有 Nginx 服务器的 /var/www/myapp/

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐