Skip to content

Nginx · 高频面试题(30+)

涵盖中前端、后端、运维 / SRE 三类岗位的真题。难度从 ⭐ 入门到 ⭐⭐⭐⭐⭐ 专家。每题都给"简短答案 + 展开"两种深度,你可以按场合(电话面 / 现场白板)选用。


🌱 入门题(⭐ — ⭐⭐)

1. Nginx 是什么?为什么比 Apache 快?

简短答:Nginx 是高性能 HTTP / 反向代理服务器;它用事件驱动 + 异步非阻塞模型,单进程靠 epoll 就能 hold 几万连接,而 Apache 默认是"一连接一线程"模型,并发上万就内存爆炸。

展开

  • Nginx:master + N 个 worker(N=CPU 核数),worker 是单线程事件循环
  • Apache:传统 prefork(每连接一个进程,几 MB 一个)或 worker(线程,几百 KB 一个)
  • 现代 Apache 也支持 event MPM,差距比以前小,但 Nginx 仍然是入口层默认选择

比喻:Apache 是"一桌一服务员",Nginx 是"一服务员看 50 桌,谁招手就过去"。


2. Nginx 是单线程还是多线程?

简短答多进程 + 每进程单线程。1 个 master 进程 + N 个 worker 进程(N=CPU 核数),每个 worker 内部是事件循环(单线程)。

展开

  • master:负责读配置、管理 worker(启停)、处理信号
  • worker:处理实际请求;每个 worker 是独立进程,崩了不影响别人
  • 不同 worker 之间通过共享内存 / 文件锁协作

3. 正向代理 vs 反向代理?

简短答

  • 正向代理:代理客户端——你 → VPN → Google。服务器不知道真实客户端是谁。
  • 反向代理:代理服务器——用户 → Nginx → 真正的后端。客户端不知道后端有几台。

记忆口诀:正向代客、反向代服。


4. nginx -s reloadrestart 的区别?

简短答

  • reload:master 进程重新读配置,启新 worker 处理新连接,老 worker 处理完老连接后优雅退出。不断连
  • restart:完全重启 nginx 进程,所有连接都被切断。

最佳实践:改完配置一定 nginx -t 测试语法,再 nginx -s reload


5. 改了 nginx.conf 不 reload 会怎样?

不会生效。Nginx 是启动时读配置加载到内存,不会自动监听文件变化。reload 是显式命令。


6. Nginx 配置文件的层级结构?

:5 层洋葱:

main
 └─ events { ... }
 └─ http {
      └─ server {
           └─ location { ... }
         }
    }

外层指令默认被内层继承;内层重新定义会覆盖外层。


7. worker_processes 应该设几个?

auto(= CPU 核心数)是默认推荐值。

展开

  • CPU 密集型场景(SSL 终止、压缩多):auto
  • I/O 密集型(大量代理 + keepalive):可以 2 × CPU 核数 试试
  • 单核小机器(学习):1 也行

8. 同一个端口能配多个网站吗?

:能,靠 server_name 区分(虚拟主机):

nginx
server { listen 80; server_name a.com; ... }
server { listen 80; server_name b.com; ... }

请求过来时 Nginx 根据 Host 头匹配 server_name。都没匹配上 → 走 default_server(如果声明)或第一个 server 块。


🌿 进阶题(⭐⭐⭐)

9. SPA history 模式刷新页面 404,怎么解决?

nginx
location / {
    try_files $uri $uri/ /index.html;
}

原理:用户在 /about 刷新 → 浏览器真实发 GET /about → Nginx 在硬盘上找 /about 文件,找不到。try_files 让 Nginx 在找不到时回退到 /index.html,浏览器拿到 HTML → JS 跑起来 → 前端路由接管 → 渲染 /about


10. rootalias 的区别?

配置请求 /static/foo.js 实际找的文件
location /static/ { root /var/www; }/var/www/static/foo.js(保留前缀)
location /static/ { alias /var/cdn/; }/var/cdn/foo.js(截掉前缀)

口诀:root = 在这个目录下找原 URLalias = 把 URL 前缀替换成这个目录


11. 怎么让浏览器和 CDN 强缓存静态资源?

:构建工具输出文件名带 hash(app.a3f9.js)+ Nginx 设:

nginx
location ~* \.[a-f0-9]{8,}\.(js|css|png|webp)$ {
    expires 1y;
    add_header Cache-Control "public, immutable";
}

immutable 让浏览器刷新都不再问服务器,是目前最强的缓存指令。


12. proxy_pass 末尾的 / 有什么影响?

配置URL 行为
proxy_pass http://b/;截掉 location 前缀再拼路径
proxy_pass http://b;完整透传 URL

location /api/ proxy_pass http://b/:访问 /api/users/1 → 后端收到 /users/1


13. 怎么让后端拿到客户端真实 IP?

:配 5 个 header:

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;
proxy_set_header X-Forwarded-Host  $host;

后端读 X-Real-IPX-Forwarded-For 第一个 IP。


14. X-Forwarded-For 能被伪造吗?怎么防?

能伪造。这是请求头,客户端能任意写。

防御

  1. 入口的 Nginx 应该重写这个头,而不是拼接:
    nginx
    proxy_set_header X-Forwarded-For $remote_addr;   # 重写!别用 $proxy_add_x_forwarded_for
  2. 后端只信任来自已知代理 IP的 X-Forwarded-For
  3. 业务上做"真实 IP + 行为"的多维度风控

15. Nginx 代理 WebSocket 要注意什么?

:4 件事:

nginx
location /ws/ {
    proxy_pass http://ws_backend/;
    proxy_http_version 1.1;                       # 必须
    proxy_set_header Upgrade    $http_upgrade;    # 透传
    proxy_set_header Connection "upgrade";        # 改写
    proxy_read_timeout 3600s;                     # 拉长超时
}

少任何一个 → WS 第一时间断开。


16. Nginx 有哪些负载均衡算法?

算法关键字场景
轮询(默认)(无)通用
加权轮询weight=N机器配置异构
IP 哈希ip_hash;老式会话粘性
最少连接least_conn;处理时长波动大
一致性哈希hash $key consistent缓存命中(需 Plus 或 OpenResty)

17. ip_hash 解决会话粘性还有什么问题?

  1. 移动用户 IP 频繁切换 → 频繁丢 session
  2. 公司 / 学校 / 家庭出口 IP 共享 → 多人挤一台后端,负载不均
  3. 后端节点变动会导致大量重哈希(不像一致性哈希那样温和)

现代做法:把 session 放 Redis,用任何算法都行。


18. Nginx 怎么剔除挂掉的后端?

  • 被动健康检查(开源版自带):

    nginx
    upstream backend {
        server 10.0.0.1 max_fails=3 fail_timeout=30s;
    }
  • 主动健康检查(开源版没有!需要 Nginx Plus / Tengine / OpenResty):

    nginx
    upstream backend {
        server 10.0.0.1;
        health_check uri=/healthz interval=5s;
    }

大厂生产一般用 Tengine 或 APISIX 替代开源版 Nginx,就为了主动健康检查。


19. 怎么让 Nginx 与上游用长连接?

:3 件事配齐:

nginx
upstream backend {
    keepalive 64;            # ① 保持 64 条空闲长连接
}

location /api/ {
    proxy_pass http://backend/;
    proxy_http_version 1.1;  # ② 必须 HTTP/1.1
    proxy_set_header Connection "";   # ③ 清空 Connection 头
}

20. location 5 种修饰符的优先级是?

必背):

=  >  ^~ + 最长前缀  >  ~ / ~*(按文件顺序)  >  普通最长前缀  >  /

精确 → 前缀阻断 → 正则按顺序 → 长前缀 → / 兜底。


21. ^~~ 的区别?

  • ^~前缀匹配(不是正则!)匹配上后不再尝试任何正则规则。
  • ~正则匹配(区分大小写),按配置顺序找第一个。

22. if 在 location 里为啥被官方说"evil"?

  1. 行为反直觉:if (x = 1) 在 location 里和在 server 里语义不同
  2. 容易写出死循环(rewrite 后再次匹配 if)
  3. 嵌套 if + rewrite 几乎无法预测

替代:能用 try_files / map 解决就别用 ifif 仅在配 return / rewrite 时算"可用"。


🌳 高级题(⭐⭐⭐⭐)

23. HTTPS 比 HTTP 慢吗?

:握手会慢 1-2 个 RTT(TLS 1.3 是 1-RTT),但:

  • HTTP/2 多路复用 → 实际加载更快
  • OCSP Stapling → 减一次外联
  • TLS 1.3 0-RTT → 能"零握手"复用会话

结论:现代 HTTPS 不是性能负担,反而整体更快


24. HSTS 的作用?怎么部署?

:HTTP Strict Transport Security——让浏览器记住"必须用 HTTPS 访问"。即使用户输 http://,浏览器也自动改成 https://

nginx
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;

注意:是单向的——一旦设了 1 年,未来 1 年内你不能降级回 HTTP。新手谨慎,先 max-age=300 试试。


25. Let's Encrypt 证书怎么自动续签?

bash
# certbot 自带定时任务(apt 装的会自动 enable systemd timer)
sudo systemctl list-timers | grep certbot

# 或者 cron:每天凌晨检查
0 2 * * * certbot renew --quiet && nginx -s reload

证书 90 天有效期,certbot 在剩 30 天时才真签。


26. 强缓存 vs 协商缓存?

  • 强缓存Cache-Control: max-age=N / Expires。命中后不发请求,浏览器直接用本地。
  • 协商缓存ETag / Last-Modified。每次都发请求,服务器对比后返 200(变了)或 304 Not Modified(不变)。
状态码含义
200 (cache)强缓存命中(DevTools 显示 from disk/memory cache)
304协商缓存命中(不传 body)

27. proxy_cache 缓存了登录态怎么办?

:用 proxy_cache_bypass 排除带敏感头的请求:

nginx
proxy_cache_bypass $http_authorization $cookie_session;
proxy_no_cache     $http_authorization $cookie_session;

带 Authorization 头或 session cookie → 不命中缓存、也不写入缓存。


28. 怎么对接口做灰度发布(用 Nginx)?

:用 split_clients + 多 upstream:

nginx
split_clients "${remote_addr}${http_user_agent}" $version {
    5%   "v2";
    *    "v1";
}

upstream v1 { server 10.0.0.1; }
upstream v2 { server 10.0.0.2; }

server {
    location / {
        proxy_pass http://$version;
    }
}

5% 用户去 v2,95% 还是 v1。也可按 cookie / 用户 ID hash 路由。


29. Nginx 怎么做限流?

:两种限流:

nginx
# 1. 限请求数(滑动窗口)
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=20r/s;

server {
    location /api/ {
        limit_req zone=mylimit burst=40 nodelay;   # 平时 20rps,可突发 40
    }
}

# 2. 限连接数
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;

server {
    location /api/ {
        limit_conn conn_limit 10;     # 同一 IP 最多 10 条并发
    }
}

burst + nodelay 含义:把超出 rate 的请求放队列里,最多 burst 个;nodelay 让队列里的请求立刻发,不延迟(这个组合最常用)。


30. Nginx 的 if (...)mapsplit_clients 各适合什么?

指令适合场景一句话
if单一条件 + return / rewrite简单判断
map把变量映射成另一个变量(KV 表)UA / Host / Path 多分支
split_clients按比例分流(A/B / 灰度)流量切分

map 例子:

nginx
map $http_user_agent $is_mobile {
    default 0;
    ~*Mobile|Android|iPhone 1;
}

server {
    location / {
        if ($is_mobile) {
            rewrite ^ /m$uri last;
        }
    }
}

31. Nginx 怎么实现 CORS 跨域?

:在 location 加响应头 + 处理 OPTIONS 预检:

nginx
location /api/ {
    if ($request_method = OPTIONS) {
        add_header Access-Control-Allow-Origin "*";
        add_header Access-Control-Allow-Methods "GET, POST, OPTIONS, PUT, DELETE";
        add_header Access-Control-Allow-Headers "Content-Type, Authorization";
        add_header Access-Control-Max-Age 1728000;
        add_header Content-Length 0;
        return 204;
    }
    add_header Access-Control-Allow-Origin "*" always;
    proxy_pass http://backend/;
}

现代项目更推荐不要让前端跨域——同一个 Nginx 既挂前端又反代 /api,前端调 /api 就是同源,没有跨域问题(参见第 5 章)。


32. Nginx 默认进程数 auto 怎么算的?

:取逻辑 CPU 核数(包括超线程的虚拟核)。在容器里有时会拿到宿主机的核数(比容器实际限制多),需要手动设:

nginx
worker_processes 4;      # 或者读 /proc/self/cgroup

33. Nginx 怎么排查"请求慢"?

:3 步:

  1. $request_time / $upstream_response_time 到 access_log

    nginx
    log_format main '... rt=$request_time urt=$upstream_response_time';
  2. 看慢请求 Top

    bash
    awk '{print $NF, $7}' access.log | sort -rn | head
  3. 判断瓶颈

    • request_time 大、upstream_response_time 小 → 客户端网络慢、SSL 握手慢
    • 两个都大 → 后端慢,去查后端
    • urt 远大于 request_time → ……不可能(urt ≤ rt)

🎓 专家题(⭐⭐⭐⭐⭐)

34. Nginx 的事件驱动模型,为什么 epoll 比 select 快?

  • select:每次都把整个 fd 数组从用户态拷到内核,O(n) 遍历找就绪
  • poll:同上,但用链表无 1024 限制
  • epoll:内核维护红黑树 + 就绪链表,仅返回有事件的 fd,O(1)

epoll 还支持边缘触发(ET):只有 fd 状态变化时通知一次,配合非阻塞 I/O 性能极高。


35. 一个 Nginx worker 能扛多少连接?瓶颈在哪?

:理论上 = worker_connections(默认 512,调大到 10240)。实际瓶颈:

  1. 文件描述符上限ulimit -nworker_rlimit_nofile
  2. 内存:每个连接约 1~10KB(含读写缓冲)
  3. CPU:上下文切换、TLS 握手算力
  4. 网络:网卡带宽 / 包率
  5. 后端:upstream 响应慢,连接堆积

单 Nginx 抗 10 万 - 100 万并发是常规水平(Cloudflare 单机更高)。


36. accept_mutex 是什么?现代要不要开?

:早期 Linux 内核多 worker 同时 accept() 会有"惊群"问题——所有 worker 被唤醒,但只有一个能拿到连接。accept_mutex on 让 worker 排队 accept。

现代:Linux 3.9+ 支持 SO_REUSEPORT、Nginx 1.9.1+ 自动启用,没有惊群问题了 → accept_mutex off 性能更好。


37. Nginx 如何热升级(不停服务换二进制)?

:6 步:

bash
# 1. 替换二进制(备份旧的)
cp /usr/sbin/nginx /usr/sbin/nginx.old
cp /path/to/new/nginx /usr/sbin/nginx

# 2. 给 master 发 USR2 信号 → 启动一个新 master + 新 worker(带 .oldbin pid 文件)
kill -USR2 $(cat /run/nginx.pid)

# 3. 让老 worker 优雅退出(处理完老连接)
kill -WINCH $(cat /run/nginx.pid.oldbin)

# 4. 验证新版本无问题后,让老 master 也退出
kill -QUIT $(cat /run/nginx.pid.oldbin)

# 5. 如果新版本有 bug,回滚:
kill -HUP $(cat /run/nginx.pid.oldbin)        # 老 master 拉起新 worker
kill -QUIT $(cat /run/nginx.pid)              # 干掉新 master

原理:USR2 让老 master fork+exec 新 master,socket 文件描述符通过环境变量传递给新进程,所以新老版本可以同时监听 80 端口而不冲突。


38. Nginx Plus / Tengine / OpenResty / APISIX 的区别?

产品出身关键差异
Nginx 开源版官方基础
Nginx Plus商业(F5)主动 health_check、动态 upstream、监控
Tengine阿里主动 health_check、动态共享、双 11 抗住
OpenResty章亦春Nginx + LuaJIT,可在 Nginx 里写业务
APISIXApache基于 OpenResty,云原生 API 网关、有控制台

选型

  • 个人 / 小项目 → 开源 Nginx
  • 大流量、要主动健康检查 → Tengine
  • 要在边缘写业务(限流、鉴权、WAF)→ OpenResty
  • 现代 API 网关 → APISIX

39. 怎么让 Nginx 支持 HTTP/3 (QUIC)?

:Nginx 1.25+ 默认编译支持 QUIC:

nginx
listen 443 ssl http2;
listen 443 quic reuseport;          # ← QUIC 监听
add_header Alt-Svc 'h3=":443"; ma=86400';     # 通告浏览器升级到 H3

ssl_protocols TLSv1.3;              # QUIC 仅支持 TLS 1.3

QUIC 基于 UDP,握手更快、抗丢包更强(0-RTT 复用)。移动网络下提升明显


40. Nginx 一次完整请求的生命周期?

(11 阶段,经典面试题):

1. POST_READ            读完请求头
2. SERVER_REWRITE       server 块的 rewrite
3. FIND_CONFIG          找 location
4. REWRITE              location 内的 rewrite
5. POST_REWRITE         检查 rewrite 后是否要重新找 location
6. PREACCESS            限流 / 限连接(limit_req / limit_conn)
7. ACCESS               鉴权 / IP 黑白名单(auth_basic / allow / deny)
8. POST_ACCESS          检查 access 阶段结果
9. PRECONTENT           try_files
10. CONTENT             生成响应(static / proxy_pass / fastcgi)
11. LOG                 写 access log

OpenResty 的强大就在于:可以在每个阶段插入 Lua 代码(access_by_lua / content_by_lua 等)。


🎯 终极题(白板手写题)

41. 白板:写一份生产级 Nginx 配置,要求支持

  • HTTPS + HTTP/2 + HSTS
  • 80 → 443 跳转
  • SPA history fallback
  • API 反向代理 + 负载均衡(3 后端,least_conn)
  • WebSocket
  • 静态资源 1 年强缓存
  • 5xx 跳到自定义 50x.html

答案:见 10 章 · 实战default.conf,能默写出来 = 拿到 Offer 的"决心证明"。


总结 · 学完这 41 题你会变成什么样

入门  ⭐ ─────► 知道 Nginx 是干嘛的
进阶  ⭐⭐⭐ ──► 能独立部署一个项目,看懂 nginx.conf
高级  ⭐⭐⭐⭐ ─► 能改大厂的网关配置,定位 5xx
专家  ⭐⭐⭐⭐⭐ ► 能讲事件模型 / 热升级 / 11 阶段,进 SRE / 架构组

祝你拿 Offer! 🚀

回到入口 → 0 · README