Nginx和Apache有什么区别?网站服务器如何选择

搭建网站时几乎每个人都会碰到这个选择题:Web 服务器用 Nginx 还是 Apache?网上的说法往往两极分化,一边说"Apache 早就过时了",另一边说"Nginx 不支持 .htaccess 太麻烦"。这两种说法都不算错,但都不完整——真正决定选择的不是谁更先进,而是两者的架构模型差异在特定场景下的表现。

这篇文章从架构模型出发,把内存占用、并发表现、配置方式、模块生态、rewrite 写法这些关键差异讲清楚,并给出可以直接落地的选型结论。文中命令区分 RHEL、CentOS、Rocky 系(dnf 或 yum,主机名下的服务名是 httpd,防火墙是 firewalld)和 Debian、Ubuntu 系(apt,服务名是 apache2,防火墙是 ufw)。

架构模型:这是所有差异的根源

两者的根本区别在于如何处理并发连接。

Nginx 采用事件驱动、异步非阻塞模型。 启动后有一个 master 进程负责读取配置、管理 worker,若干个 worker 进程负责实际处理请求。每个 worker 内部通过事件循环(底层是 epoll、kqueue 这类 I/O 多路复用机制)同时监视成千上万个连接,哪个连接有数据可读就处理哪个,处理过程中遇到需要等待的操作(读磁盘、等待后端响应)就挂起转去处理别的连接,不阻塞整个进程。配置里的 worker_connections 直接决定了单个 worker 能同时维持多少连接。

Apache 采用进程或线程模型,具体行为由 MPM(多处理模块)决定。 每个连接需要占用一个执行单元,这带来了一个直接后果:并发能力受限于进程或线程数量,而进程和线程是有内存成本、有调度开销的。

Apache 提供了三种 MPM:

MPM 工作方式 内存与并发特点 适用场景
prefork 一个父进程派生多个子进程,每个子进程一次只处理一个请求 内存占用最高,并发能力最弱,但进程间完全隔离 需要搭配线程不安全的模块时才用,比如老式的 mod_php
worker 多进程,每个进程内有多个线程,一个线程处理一个请求 内存占用明显低于 prefork 通用场景,但对线程安全有要求
event 在 worker 基础上把 keep-alive 空闲连接交给专用监听线程 解决了长连接长期占用工作线程的问题,高并发下表现好得多 Apache 2.4 上的首选,是绝大多数情况下的正确默认值

这里有一个关键背景:很多关于 Apache 并发差的印象来自 prefork 时代。Apache 2.4 的 event MPM 在处理 keep-alive 连接上已经做了专门优化,实际表现和网上流传的老结论差距不小。但这不改变一个大方向——在同等硬件下处理大量并发长连接,Nginx 的资源开销依然更可控。

值得一提的是,Apache 现在的推荐做法已经不是用 mod_php 在 Web 服务内部执行 PHP,而是通过 PHP-FPM 配合 mod_proxy_fcgi。一旦这么用,就没有必要坚守 prefork 了,event MPM 是更好的选择。

关键差异对照表

对比维度 Nginx Apache
架构 master + worker,事件驱动、异步非阻塞 进程/线程模型,由 MPM 决定行为
内存占用 稳定且有上限,主要随 worker 数量增长 随并发连接数增长,每个连接占用一个线程或进程
高并发长连接 优势明显,一个 worker 可维持成千上万连接 event MPM 下有改善,但每连接成本仍高于 Nginx
分布式配置 .htaccess 不支持,所有规则必须写在集中配置里 原生支持,目录级配置可即时生效
修改配置生效方式 需 nginx -s reload 或有权限者重载 .htaccess 即时生效,主配置需重载
动态模块 支持动态模块,但很多模块仍建议编译进二进制 DSO 机制成熟,LoadModule 开关模块非常方便
静态文件 原生设计目标之一,sendfile、缓存头配置直观 同样支持,但在高并发下资源成本更高
反向代理与负载均衡 一等公民,upstream、proxy_pass 简洁强大 通过 mod_proxy 等模块实现,功能齐全但配置相对啰嗦
rewrite 写法 rewrite 指令,推荐用 try_files 替代大量重写 mod_rewrite 生态庞大,社区规则资源极多
典型部署角色 边缘/前端:终结 TLS、服务静态资源、反向代理、缓存 后端应用服务器,或需要分布式配置托管的场景

配置文件的实际差异

知道文件在哪,是能自己排错的前提。

Nginx 在 Debian、Ubuntu 上的站点配置是 /etc/nginx/sites-available/ 存放、/etc/nginx/sites-enabled/ 通过符号链接启用,主配置 /etc/nginx/nginx.conf;在 Rocky、RHEL、CentOS 上一般直接写到 /etc/nginx/conf.d/*.conf。日志默认在 /var/log/nginx/。

Apache 在 Debian、Ubuntu 上服务名是 apache2,主配置 /etc/apache2/apache2.conf,站点在 sites-available/ 与 sites-enabled/,模块启用用 a2enmod;在 Rocky、RHEL、CentOS 上服务名是 httpd,主配置 /etc/httpd/conf/httpd.conf,附加配置在 /etc/httpd/conf.d/,模块加载在 /etc/httpd/conf.modules.d/。

安装命令:

# Rocky、RHEL、CentOS
sudo dnf install -y nginx          # 安装 Nginx
sudo dnf install -y httpd          # 安装 Apache(包名叫 httpd)

# Debian、Ubuntu
sudo apt install -y nginx          # 安装 Nginx
sudo apt install -y apache2        # 安装 Apache(包名叫 apache2)

查看当前 Apache 使用的 MPM:

# Debian、Ubuntu
sudo apachectl -V | grep -i mpm
sudo apache2ctl -M | grep mpm

# Rocky、RHEL、CentOS
sudo httpd -V | grep -i mpm
sudo httpd -M | grep mpm

如果输出显示 prefork,而你已经改用 PHP-FPM 处理 PHP,就应该切到 event。风险提示:切换 MPM 会影响所有站点,操作前备份配置文件,并在低峰期进行。

Debian、Ubuntu 切换方式:

sudo a2dismod mpm_prefork
sudo a2enmod mpm_event
sudo a2enmod proxy_fcgi setenvif
sudo a2enconf php*-fpm
sudo apachectl configtest
sudo systemctl restart apache2

Rocky、RHEL、CentOS 需要编辑 /etc/httpd/conf.modules.d/00-mpm.conf,注释掉 prefork 行、启用 event 行,然后:

sudo httpd -t
sudo systemctl restart httpd

两者的配置语法检查命令分别是 nginx -t 和 apachectl configtest(等价于 httpd -t)。这是每次改配置之后必须执行的动作,语法错误时不要重载或重启服务。

.htaccess:既是优势也是代价

这是选型时最实际的考量点,值得单独讲。

.htaccess 是 Apache 的目录级配置文件,放在网站目录下就能覆盖部分服务器配置,不需要重启服务,也不需要服务器管理权限。这对虚拟主机用户和需要频繁调伪静态规则的站长极其方便,也是大量开源 PHP 程序默认提供 .htaccess 文件的原因。

代价是性能与安全的双重成本:Apache 处理每个请求时,需要从请求文件所在目录一路向上遍历到站点根目录,逐级查找并解析 .htaccess 文件。目录层级深、规则文件多时,这部分开销无法忽略。官方文档也明确说明,如果拥有主配置文件的访问权限,应当把规则写进主配置并把 AllowOverride 设为 None 来关闭查找。

Nginx 完全没有这个机制,所有规则集中写在配置里。好处是消除了逐目录查找的开销,规则位置统一便于审计;代价是每次改规则都要重载服务,而且需要服务器控制权——共享虚拟主机用户没法自己改。

所以这里有一条清晰的判断线:如果你的业务重度依赖 .htaccess(老程序的伪静态规则、共享主机上无法改主配置、客户需要自助改规则),Apache 能省掉大量沟通成本;如果你完全掌控服务器并且追求性能与配置统一,Nginx 更合适。

迁移时把 Apache 规则转成 Nginx 是常见需求,比如最常见的入口重写:

# Apache mod_rewrite 的典型写法

  RewriteEngine On
  RewriteBase /
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteRule . /index.php [L]

对应到 Nginx,不宜照抄 rewrite 加条件判断,更合适的是用 try_files:

location / {
    try_files $uri $uri/ /index.php?$query_string;
}

try_files 按顺序检查文件或目录是否存在,都不存在则内部跳转到入口。它比 if 加 rewrite 的组合更清晰,也避开了 Nginx 里 if 在 location 上下文中的各种陷阱。

性能与资源的经验量级

不给绝对数字,因为硬件、场景、配置变量太多,但可以给相对的比较结论。

内存方面,Nginx 的内存占用相对稳定,主要由 worker 进程数决定,一个 worker 处理静态请求时通常只需几兆到十几兆字节的常驻内存(内含大量共享内存,实际增量更小)。Apache 在 prefork 下,每个并发连接对应一个进程,若单进程常驻几十兆字节,几百并发就会吃下数 GB 内存。event MPM 下线程成本远低于进程,但依然高于 Nginx 的事件模型。这就是为什么 1 GB 或 2 GB 内存的小机器跑 LNMP(Nginx 方案)比跑 LAMP(Apache 方案)更容易稳定。

静态资源吞吐方面,两者在单连接大文件传输上差距不大,瓶颈通常是磁盘和网络。差距体现在大量小文件、大量短连接、大量 keep-alive 空闲连接并存的场景,也就是真实互联网流量的典型形态,此时 Nginx 的资源曲线明显更平缓。

CPU 方面,动态内容的 CPU 消耗主要在 PHP、Java、数据库这些后端,Web 服务本身占比不高。所以"换 Nginx 网站变快"往往不是因为 Nginx 计算更快,而是因为它不再抢占内存,让数据库缓存和 PHP 进程有了更多空间。

TLS 握手方面,Nginx 在 TLS 终止上的实现成熟、配置直观,常作为统一入口承接 HTTPS 再转发到后端 HTTP 服务,这种架构叫 TLS 终结,能简化后端证书管理。

怎么选:落到具体场景

场景 推荐 理由
静态站点、文档站、前端 SPA Nginx 静态处理是强项,配缓存头和压缩直观
WordPress、Discuz 等 PHP CMS(自管服务器) Nginx + PHP-FPM 资源占用低,伪静态规则用 try_files 已足够
同一台机器跑多个不同语言的服务 Nginx 做前端反代 upstream 配置清晰,统一入口和证书管理
高并发 API 网关、反向代理、负载均衡 Nginx 这是它的设计目标场景
共享虚拟主机、客户需自助改伪静态 Apache .htaccess 的分布式配置不可替代
依赖特定 Apache 模块的遗留系统 Apache 部分模块在 Nginx 上没有等价物
老旧 PHP 程序必须用 mod_php 且不便改动 Apache + prefork 兼容优先,但要接受内存代价
已有 Apache 环境但流量上涨 Nginx 前置 + Apache 后端 渐进改造,风险低于一次性替换

最后一行值得展开,这是生产环境里最常见的组合架构:

用户 → Nginx(443/80) → ├─ 静态资源:直接本地返回
                      ├─ /api/ → 后端 Node/Java 服务
                      └─ PHP 请求 → PHP-FPM 或后端 Apache

在这个架构里,Nginx 负责 TLS 终结、静态资源、压缩、缓存、限流和反向代理,把动态请求转发给后端。Apache 若仍在其中,通常承担的是那些依赖自身模块的项目。这样做的好处是改动可以逐步进行:先让 Nginx 监听公网并处理静态与证书,验证稳定后再逐步把动态请求也接管过来,全程 Apache 还在,随时可回退。

具体做法是在 Nginx 里把请求代理给后端 Apache:

upstream backend_apache {
    server 127.0.0.1:8080 max_fails=3 fail_timeout=10s;
}

server {
    listen 80;
    server_name example.com;

    # 静态资源 Nginx 自己处理,不再转发给后端
    location ~* \.(jpg|jpeg|png|gif|css|js|ico|svg|woff2)$ {
        root /var/www/example.com/public;
        expires 30d;
        access_log off;
    }

    location / {
        proxy_pass http://backend_apache;
        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;
    }
}

对应地把 Apache 改到 8080 监听。风险提示:改端口前先确认新端口在安全组与主机防火墙层面不需要对公网开放,8080 只是本机回环或内网转发使用,不应暴露公网。改完先 apachectl configtest 再重启。

防火墙放行外网访问的仍应是 80 和 443:

# Rocky、RHEL、CentOS
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload

# Debian、Ubuntu
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw reload

迁移与替换的注意事项

如果决定从 Apache 切到 Nginx,有几件事务必提前处理。

先做规则清单。 把站点里所有的 .htaccess 文件找出来,逐个转换为 Nginx 配置。遗漏会导致某些目录的访问控制、密码保护或重写规则失效,而且这类问题往往在上线后才被发现。

sudo find /var/www -name '.htaccess' -print

注意 index 和目录索引行为差异。 Apache 默认可能开启目录列表,Nginx 默认关闭(通过 autoindex 控制)。如果之前依赖目录列表,需要显式开启,但从安全角度建议保持关闭。

注意访问控制写法。 Apache 的 Order deny,allow、Require all denied 在 Nginx 里对应 deny、allow 指令,语法不同且匹配顺序规则不同,不能直接粘贴。

两边不要同时监听 80。 迁移调试阶段让 Nginx 占 80,Apache 占 8080,避免端口抢占导致服务起不来。

最后一定要做全量回归。 首页能打开不代表迁移成功。至少验证:二级页面伪静态是否正常、后台登录是否有 Cookie 或路径问题、上传功能是否受请求体大小限制(client_max_body_size)、下载文件是否正常、HTTPS 跳转是否正确、日志格式里的时间与 IP 是否正常。

常见问题

新手应该先学哪个?

如果只选一个,建议 Nginx。它的配置语法更简洁,反向代理和 HTTPS 配置在实战中遇到的频率很高,而且目前新项目采用率更高。但学会 Nginx 之后遇到 Apache 环境,理解 MPM 和虚拟主机两块内容就能上手。

Apache 真的不如 Nginx 快吗?

取决于场景。静态资源和高并发长连接场景,Nginx 的资源曲线更好;如果站点本身瓶颈在数据库或 PHP 代码,换 Web 服务器带来的差异远小于优化一条慢查询。先测出真正的瓶颈,再谈换哪个。

已经有 mod_php 的 Apache 站点能改成 PHP-FPM 吗?

通常可以,而且推荐这么做。改完之后就能用 event MPM,内存占用会明显下降。改动前备份配置,修改后逐个站点回归测试,注意 SetHandler 与相关环境变量的配置是否需要同步调整。

.htaccess 完全不能用 Nginx 替代吗?

规则本身基本都能翻译成 Nginx 配置,只是失去了"用户自助即时生效"这个特性。如果你管控服务器,这不是问题;如果你卖虚拟主机给用户,用户无法重载你的 Nginx,那 Apache 的分布式配置才有实际意义。

可以两个都不用吗?

可以。静态站点用对象存储加 CDN、容器环境用专门的边缘网关、Node 项目用进程管理器直接对外等都是常见做法。但在一台常规 VPS 上,Nginx 或 Apache 仍是最省心的 Web 层选择。

总结

  • 选择的核心是架构差异:Nginx 的事件驱动异步非阻塞在大量并发连接下资源更可控,Apache 的进程线程模型配合 event MPM 也能胜任常规负载,但对内存的线性消耗更高。
  • .htaccess 是最实际的决策点:需要用户自助改规则或依赖大量现成的 mod_rewrite 规则就选 Apache;拥有服务器完全控制权且追求性能与配置统一就选 Nginx。
  • Apache 上如果用 PHP,优先改用 PHP-FPM 加 mod_proxy_fcgi 并把 MPM 切到 event,这是成本最低的一档性能提升,改前务必 apachectl configtest 并备份配置。
  • 不必二选一,Nginx 前置做 TLS 终结、静态资源和反向代理,Apache 保留承载遗留应用,是风险最低的渐进式改造路线。
  • 每次改配置都要先跑 nginx -t 或 httpd -t,迁移到 Nginx 后要逐个转换 .htaccess 规则,并完成伪静态、上传、后台登录、HTTPS 跳转的全量回归验证。