服务器运维

Nginx 是什么意思:能做什么、和 Apache 怎么选

Nginx(读作 engine x)是一款开源的 Web 服务器,同时承担反向代理、负载均衡、HTTPS 终结和缓存。它通常放在网站最前面:静态文件自己返回,动态请求转给后端程序。事件驱动的架构让它用很少的进程维持大量连接,高并发下比传统的 Apache 省内存。

作者 顶联产品团队发布于 6 分钟阅读

Nginx 是什么意思?Nginx 读作“engine x”,是一款开源的 Web 服务器,同时也是反向代理、负载均衡器和 HTTP 缓存。它由 Igor Sysoev 开发,2004 年公开发布,最初就是为了解决单台服务器同时处理上万个连接的问题。今天它最常见的位置是网站的最前面:图片、CSS、JS 这些静态文件由它直接返回,PHP、Java、Node.js、Python 写的动态请求由它转给后端程序,HTTPS 证书也在它这里处理。与 Apache 相比,它用事件驱动模型处理连接,少数几个进程就能维持成千上万个连接,所以高并发场景下更省内存。

Nginx 能做什么:五种常见用法

用法 做什么 关键配置指令
静态网站与文件服务 直接返回 HTML、图片、CSS、JS 和下载文件 root、index、try_files、expires
反向代理 接收客户端请求,转给后端程序,客户端看不到后端地址 proxy_pass、proxy_set_header
负载均衡 把请求分给多台后端,连续失败的后端暂时摘除 upstream、least_conn、max_fails
HTTPS 终结 在 Nginx 上完成 TLS 握手,后端只跑普通 HTTP ssl_certificate、ssl_protocols
缓存 把后端的响应存到本地,重复请求不再打到后端 proxy_cache_path、proxy_cache

此外还能做 TCP/UDP 四层转发(stream 模块,例如转发 MySQL 的 3306 端口)、gzip 压缩和按 IP 限流。

下面一份配置把五种用法放在一起:一个商城站点,静态文件由 Nginx 返回,接口转给 3 台应用服务器,商品列表接口缓存 10 分钟。放在 /etc/nginx/conf.d/shop.conf,这个目录里的文件会被包含进主配置的 http 块:

# 缓存目录:1 MB 的 keys_zone 大约能存 8000 个缓存键
proxy_cache_path /var/cache/nginx/shop levels=1:2 keys_zone=shop_cache:50m
                 max_size=2g inactive=60m use_temp_path=off;

# 负载均衡:请求优先给当前连接数最少的后端,30 秒内失败 3 次就暂停使用 30 秒
upstream shop_app {
    least_conn;
    server 10.0.0.11:8080 max_fails=3 fail_timeout=30s;
    server 10.0.0.12:8080 max_fails=3 fail_timeout=30s;
    server 10.0.0.13:8080 backup;    # 前两台都不可用时才启用
}

# HTTP 统一跳转到 HTTPS
server {
    listen 80;
    server_name shop.example.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    http2 on;                        # 1.25.1 起的写法,旧版本改为 listen 443 ssl http2;
    server_name shop.example.com;

    ssl_certificate     /etc/nginx/ssl/shop.example.com.fullchain.pem;
    ssl_certificate_key /etc/nginx/ssl/shop.example.com.key;
    ssl_protocols       TLSv1.2 TLSv1.3;

    # 静态文件:由 Nginx 直接读磁盘返回,浏览器缓存 7 天
    location /static/ {
        root /var/www/shop;          # 实际读取 /var/www/shop/static/...
        expires 7d;
    }

    # 商品列表接口:缓存 10 分钟,后端出错时先返回旧缓存
    location /api/products/ {
        proxy_cache shop_cache;
        proxy_cache_valid 200 10m;
        proxy_cache_use_stale error timeout updating http_500 http_502 http_503;
        add_header X-Cache-Status $upstream_cache_status;
        proxy_pass http://shop_app;
        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;
    }

    # 其余请求:反向代理到应用服务器
    location / {
        proxy_pass http://shop_app;
        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_set_header 不能省。不传 Host,后端拿到的是 upstream 名称而不是域名;不传 X-Forwarded-For 和 X-Real-IP,后端日志里所有访客的 IP 都是 Nginx 自己;不传 X-Forwarded-Proto,后端以为用户走的是 HTTP,可能反复跳转到 HTTPS。
  • 开源版只有被动健康检查。max_fails 和 fail_timeout 靠真实请求失败来判断后端是否可用;定时主动探测后端属于商业版 NGINX Plus 的功能,开源版需要第三方模块或在后端前面另加检测。
  • 验证缓存是否生效。连续请求两次 curl -sI https://shop.example.com/api/products/ | grep -i x-cache-status,第一次是 MISS,第二次是 HIT(走 HTTP/2 时响应头名称是小写,所以 grep 要加 -i)。如果一直是 MISS,先看后端响应是否带了 Set-Cookie 或禁止缓存的 Cache-Control,默认情况下 Nginx 不缓存这类响应。
  • PHP 程序走 FastCGI。Nginx 不执行 PHP,要把 .php 请求交给 PHP-FPM:在 location ~ \.php$ 里写 include fastcgi.conf; 和 fastcgi_pass unix:/run/php/php8.3-fpm.sock;。注意 fastcgi.conf 比 fastcgi_params 多一行 SCRIPT_FILENAME,只 include 后者又没补这一行,PHP-FPM 会找不到脚本;Debian、Ubuntu 上也可以直接用 include snippets/fastcgi-php.conf;。socket 路径以服务器上实际安装的 PHP 版本为准。

为什么 Nginx 在高并发下更省资源

Nginx 启动后是一个 master 进程加若干 worker 进程。master 只负责读配置、管理 worker;真正处理请求的是 worker,数量通常设为 worker_processes auto;,即与 CPU 核数相同。每个 worker 是单线程的事件循环:它把几千个连接都交给内核的 epoll(BSD 上是 kqueue)监视,哪个连接有数据可读、可写,内核就通知它去处理哪个,处理完立刻转向下一个,从不停下来等某一个慢客户端。

传统的 Apache prefork 模式则是一个连接占一个进程。用户的浏览器开着 keep-alive 什么也不发,这个进程也只能干等。两种模型面对 1 万个并发连接时的差别:

对比 Nginx Apache prefork
处理 1 万个连接需要 4 核服务器上 4 个 worker,每个维持约 2500 个连接(worker_connections 要相应调高) 理论上 1 万个进程;默认 MaxRequestWorkers 只有 256,超出的连接排队等待
空闲 keep-alive 连接的开销 很小:Nginx 官网的说法是 1 万个空闲 keep-alive 连接约占 2.5 MB 内存 每个连接占一个完整进程,加载了 mod_php 时每个进程常有几十 MB
慢客户端的影响 只占一个连接的少量内存 长时间占住一个进程

Nginx 能维持的连接上限大约是 worker_processes × worker_connections。发行版自带的配置里 worker_connections 常见 768 或 1024,做反向代理时每个请求要占用客户端和后端两个连接,实际能服务的并发约为上限的一半;要调高时,同时用 worker_rlimit_nofile 提高每个进程能打开的文件数。

事件驱动也有代价:如果某个操作阻塞了 worker(例如在很慢的磁盘上读大文件,或者第三方模块里有同步调用),这个 worker 上的所有连接都会跟着卡住。Nginx 为此提供了线程池(aio threads),把读磁盘这类阻塞操作交给后台线程。另外,Apache 2.4 的 event 模式也把空闲的 keep-alive 连接交给专门的监听线程管理,差距已经比 prefork 时代小,但每个正在处理的请求仍然要占用一个线程。

在服务器上可以直接看到这两种结构:

ps -o pid,ppid,user,rss,cmd -C nginx     # 1 个 master(root)加若干 worker,RSS 单位是 KB
grep -E 'worker_processes|worker_connections' /etc/nginx/nginx.conf
nproc                                    # CPU 核数,worker_processes auto 时与它相同
apachectl -V | grep -i mpm               # Apache 当前用的 MPM:prefork、worker 或 event

Nginx 和 Apache 的区别

对比项 Nginx Apache httpd
连接处理模型 事件驱动,少数 worker 进程各自处理大量连接 由 MPM 决定:prefork 一连接一进程,worker 和 event 为多进程多线程
静态文件、高并发 内存占用低,适合做前端入口 并发上去后进程或线程数随之增长
运行 PHP 交给 PHP-FPM 可以用 mod_php 内嵌执行,也可以接 PHP-FPM
目录级配置 不支持 .htaccess,规则写在主配置里,改完要 reload 支持 .htaccess,网站目录里放文件即可生效
伪静态规则 rewrite、try_files mod_rewrite,很多 PHP 程序自带 .htaccess 规则
模块 多数编译进程序;动态模块要和 Nginx 版本匹配 模块动态加载,Debian、Ubuntu 上用 a2enmod 一条命令启用
反向代理与负载均衡 核心功能,配置简洁 用 mod_proxy、mod_proxy_balancer 实现
许可证 BSD 类许可证 Apache License 2.0
典型位置 网站入口、反向代理、静态资源、负载均衡 共享虚拟主机、依赖 .htaccess 的老程序

两者的分界其实就在两点:要不要 .htaccess、并发有多高。共享虚拟主机让每个用户在自己目录里改规则,离不开 .htaccess,所以多用 Apache 或兼容它的 LiteSpeed;自己有整台服务器、能改主配置的,用 Nginx 的限制就不存在了。

还有一种常见的混合方案:Nginx 在前面处理 HTTPS、静态文件和连接,Apache 在后面跑依赖 .htaccess 的老程序。这时 Apache 看到的来源 IP 全是 Nginx 的地址,要启用 mod_remoteip 并信任 Nginx 传来的 X-Forwarded-For,日志和程序里才能拿到访客的真实 IP。

租服务器建站,什么情况选 Nginx

场景 选择 理由
1–2 GB 内存的云服务器或 VPS 跑 WordPress 等 PHP 网站 Nginx 加 PHP-FPM 静态文件和空闲连接不占 PHP 进程,内存更够用
Node.js、Java、Python、Go 写的应用 Nginx 做反向代理 应用只监听 127.0.0.1,由 Nginx 对外处理 80、443 和证书
多台后端服务器 Nginx 的 upstream 负载均衡和故障摘除开箱即用
图片站、下载站、纯静态网站 Nginx 静态文件吞吐高,配置简单
程序大量依赖 .htaccess,且不想改写规则 Apache,或前 Nginx 后 Apache 免去把规则逐条翻译成 Nginx 写法
用宝塔等面板建站 两者都可以 面板里切换,按上面的规则选

小内存服务器上,Nginx 的优势可以算出来。假设一台 2 GB 内存的服务器,系统和 MySQL 占去约 1 GB,剩下约 1000 MB 给 PHP,用下面的命令实测每个 PHP 进程平均占 40 MB:

ps -o rss= -C php-fpm8.3 | awk '{s+=$1; n++} END {printf "%d 个进程,平均 %.1f MB\n", n, s/n/1024}'

那么 PHP 最多开 1000 ÷ 40 = 25 个进程,PHP-FPM 的 pm.max_children 就设为 25。区别在于这 25 个进程被谁占用:用 Apache prefork 加 mod_php 时,每个连接都占一个带 PHP 的进程,包括下载一张图片、甚至什么都不发的 keep-alive 连接,一个页面带 30 个静态资源,几个访客同时打开就可能把 25 个进程占满,后来的人只能排队;用 Nginx 时,静态文件和空闲连接由 Nginx 处理,25 个 PHP-FPM 进程只服务真正需要执行 PHP 的请求。

装好 Nginx 后,记得放行 80 和 443 端口,Ubuntu 上用 ufw:

sudo ufw allow 22/tcp          # 先放行 SSH,否则启用防火墙后可能再也连不上
sudo ufw allow 80,443/tcp
sudo ufw enable
sudo ufw status

第一行最容易忘:启用 ufw 前没有放行 22 端口,当前会话可能还连着,退出后就再也登录不上 SSH。真遇到这种情况,用服务商控制面板里的 VNC 控制台登录修改,例如基于 Toplink DCIM 的 客户自助端 就能直接在浏览器里打开服务器控制台,不依赖 SSH。云服务器还要在安全组里放行同样的端口。

常用命令与配置文件位置

项目 Debian、Ubuntu 软件源 RHEL、Rocky、AlmaLinux 及 nginx.org 官方包
安装 apt install nginx dnf install nginx
主配置 /etc/nginx/nginx.conf /etc/nginx/nginx.conf
站点配置 /etc/nginx/sites-available/,软链接到 sites-enabled/ 生效;也读取 conf.d/ /etc/nginx/conf.d/*.conf
默认网站目录 /var/www/html /usr/share/nginx/html
日志 /var/log/nginx/access.log、error.log 同左
worker 运行用户 www-data nginx
nginx -v                         # 版本号:偶数小版本(如 1.26)是 stable,奇数是 mainline
nginx -V 2>&1 | tr ' ' '\n' | grep -E '^--with'   # 编译了哪些模块
sudo nginx -t                    # 检查配置语法,改完配置先执行它
sudo nginx -T | less             # 打印合并后的完整配置,排查“改了不生效”
sudo systemctl reload nginx      # 平滑加载新配置
sudo tail -f /var/log/nginx/error.log

改配置的固定顺序是:编辑 → nginx -t → systemctl reload nginx → 看 error.log。改配置不需要 restart:reload 时 master 进程用新配置启动新的 worker,旧 worker 处理完手头的请求再退出,访客不会断开;新配置有错时 reload 不会生效,线上仍按旧配置运行。跳过检查直接 restart,配置一错 Nginx 就起不来了。

常见问题

Nginx 和 Tomcat 有什么区别?

Tomcat 是运行 Java Web 应用的容器,负责执行 Servlet 和 JSP;Nginx 不执行 Java 代码。常见搭配是 Nginx 在前面处理 HTTPS、静态文件和负载均衡,把动态请求用 proxy_pass 转给后面的一台或多台 Tomcat。

Nginx 免费吗?可以商用吗?

开源版 Nginx 以 BSD 类许可证发布,免费使用,包括商业用途。F5 另外提供商业版 NGINX Plus,增加主动健康检查、动态配置接口和官方支持。国内常见的 OpenResty、Tengine 是基于 Nginx 的衍生版本。

Nginx 报 502 和 504 是什么原因?

502 Bad Gateway 表示 Nginx 连不上后端,或后端返回了无效响应,常见于后端程序没启动、proxy_pass 或 fastcgi_pass 的地址写错、PHP-FPM 进程崩溃;504 Gateway Timeout 表示后端在超时时间内没有响应,proxy_read_timeout 默认 60 秒。先看 error.log 里带 upstream 字样的报错,再去查后端。

想看看在你的机房里怎么用?

从一次产品演示开始,梳理你的业务链路。

查看价格
服务热线 400-112-2951

让我们聊聊你的 IDC 业务

扫码添加企业微信,预约产品演示或申请试用。

Toplink 企业微信二维码

长按保存或使用企业微信 / 微信扫描

也可致电
400-112-2951
Telegram
@TopLink88