Nginx 到底是什么

一句话:Nginx 是一个高性能的 HTTP 服务器和反向代理。但它远不止”托管静态网站”这么简单。

它同时干三件事:

  1. Web 服务器:把硬盘上的 HTML/CSS/JS 文件通过 HTTP 对外提供
  2. 反向代理:把外部请求转发给后端的真实服务(比如 Node.js、Python、PHP),对外隐藏后端
  3. 负载均衡:把流量分发给多台后端服务器,扛住大并发

这三个能力让它成了互联网的中流砥柱——全球流量最高的网站(Netflix、百度、淘宝),背后几乎都有 Nginx 的身影。

为什么不用 Apache

老一代用的是 Apache。Nginx 出现后大量取代它,核心原因就一个:并发模型不同

  • Apache:一个请求开一个线程/进程(或 worker),连接多了内存和上下文切换就扛不住
  • Nginx事件驱动、异步非阻塞,一个 worker 进程能同时处理几千上万个连接,内存占用极低

打个比方:Apache 像银行开一个窗口派一个柜员,客户多了柜员就累瘫;Nginx 像一个柜员同时招呼几十个客户,谁 ready 了就处理谁,效率天差地别。

所以高并发场景下 Nginx 完胜。这也是它成为”反向代理首选”的根本原因。

Nginx 的核心功能

1. 静态文件托管

这是最基础的用法。把文件放目录里,Nginx 对外提供访问:

1
2
3
4
5
6
server {
listen 80;
server_name example.com;
root /var/www/html;
index index.html;
}

Nginx 处理静态文件比任何应用服务器都快——直接 sendfile 零拷贝,CPU 几乎不参与。

2. 反向代理

外部请求 → Nginx → 后端服务。后端不需要暴露在公网,Nginx 帮它挡在前面:

1
2
3
4
5
location /api/ {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}

好处很多:后端服务只监听 127.0.0.1,外面摸不到;Nginx 还能做缓冲、限速、缓存。

3. 负载均衡

有多台后端时,Nginx 在前面分发:

1
2
3
4
5
6
7
8
9
10
11
upstream backend {
server 192.168.1.10:3000;
server 192.168.1.11:3000;
server 192.168.1.12:3000;
}

server {
location / {
proxy_pass http://backend;
}
}

策略可选:轮询(默认)、加权、IP 哈希(同一用户固定到一台后端)、最少连接数。

4. HTTPS / SSL 终端

Nginx 处理 TLS 加解密,后端服务只管明文逻辑。证书在 Nginx 这一层统一管理:

1
2
3
4
5
6
7
server {
listen 443 ssl;
http2 on;
ssl_certificate /etc/ssl/fullchain.cer;
ssl_certificate_key /etc/ssl/private.key;
ssl_protocols TLSv1.2 TLSv1.3;
}

5. 缓存

Nginx 能把后端返回的内容缓存到磁盘/内存,相同请求直接返回缓存,不打到后端。这对静态站和 API 缓存都极有价值。

Nginx 的好处

优点 说明
高并发 单机几万并发连接毫无压力,内存占用极低
稳定 跑几个月不重启是常态,内存泄漏几乎不存在
配置灵活 模块化设计,按 location 做不同策略,精细到 URL 级别
生态成熟 几乎所有运维场景都有现成方案,社区文档丰富
资源省 1 核 1G 的小服务器跑起来毫无压力
安全 作为反向代理天然隔离后端,配合限流/封 IP 能挡大量攻击

Nginx 的坏处

客观说也有局限:

缺点 说明
动态内容弱 Nginx 本身不能执行 PHP/Python,得配合后端或 FastCGI
配置有门槛 指令多、继承规则复杂,新手容易踩坑(比如 location 优先级)
模块需编译 标准版装第三方模块要重新编译,虽然动态模块缓解了这点
不是银弹 挡不住超大流量 DDoS(几十 Gbps),那种得靠云厂商的清洗
默认不安全 开箱即用的配置抗攻击能力为零,必须手动加固

部署:最小可用配置

以 CentOS / RHEL / 阿里云 Linux 为例:

1
2
3
4
5
6
7
# 安装
yum install -y nginx
systemctl enable --now nginx

# 验证
curl -I http://127.0.0.1
# HTTP/1.1 200 OK 说明跑起来了

配置文件结构:

1
2
3
4
/etc/nginx/
├── nginx.conf # 主配置(http 块、全局参数)
├── conf.d/ # 各站点配置(include 进主配置)
└── mime.types

主配置 nginx.conf 的核心部分:

1
2
3
4
5
6
7
http {
# --- 限流区域定义(防御 CC 的基础)---
limit_req_zone $binary_remote_addr zone=reqperip:10m rate=10r/s;
limit_conn_zone $binary_remote_addr zone=perip:10m;

include /etc/nginx/conf.d/*.conf;
}

单个站点配置 conf.d/blog.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
server {
listen 443 ssl;
http2 on;
server_name blog.example.com;

ssl_certificate /etc/ssl/fullchain.cer;
ssl_certificate_key /etc/ssl/private.key;

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

# 启用限流(防 CC)
limit_req zone=reqperip burst=20 nodelay;
limit_conn perip 10;

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

改完先测语法再重载——这条铁律必须记

1
2
nginx -t          # 测试配置语法
nginx -s reload # 语法 OK 才重载,不中断服务

策略:location 匹配优先级

Nginx 最容易踩的坑就是 location 优先级。记住这个顺序:

  1. = 精确匹配(最高)
  2. ^~ 前缀匹配(不再走正则)
  3. ~ / ~* 正则匹配(按出现顺序)
  4. 普通前缀匹配(最长匹配)
1
2
3
4
location = / { ... }              # 只匹配首页,最高优先
location ^~ /static/ { ... } # /static/ 开头的,不走正则
location ~* \.(jpg|png)$ { ... } # 图片走这里
location / { ... } # 兜底,最低

搞混优先级会导致请求打到错误的 location,比如静态资源被反代规则截获——这是最常见的新手 bug。

重点:网络安全与防 CC/DDoS

Nginx 作为网站的第一道防线,默认配置几乎是裸奔的。下面这套是生产级的防护方案,逐层加固。

第一层:请求频率限制(挡 CC)

CC 攻击的本质是高频请求打垮服务器。Nginx 的 limit_req 是最直接的武器:

1
2
# http 块:定义限流区域,单 IP 每秒 10 个请求
limit_req_zone $binary_remote_addr zone=reqperip:10m rate=10r/s;
1
2
# server/location 块:启用
limit_req zone=reqperip burst=20 nodelay;
  • rate=10r/s:每秒允许 10 个请求
  • burst=20:突发允许排 20 个队
  • nodelay:排队的不延迟,超过就立即拒绝(返回 503)
  • 正常用户一秒点不了 10 次,只拦攻击者,不影响真人

第二层:并发连接限制

限制单 IP 同时开的连接数,防一个 IP 开几百个连接耗尽资源:

1
2
# http 块定义
limit_conn_zone $binary_remote_addr zone=perip:10m;
1
2
# server 块启用
limit_conn perip 10;

单 IP 最多 10 个并发连接,超出直接拒绝。

第三层:空 User-Agent 拦截

扫描器、CC 工具经常不带 UA(或带古董 UA)。直接拦:

1
2
3
4
# 空 UA 拒绝
if ($http_user_agent = "") {
return 403;
}

进阶:拦截常见的恶意 UA 关键词:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 常见扫描器/爬虫黑名单
map $http_user_agent $bad_agent {
default 0;
~*sqlmap 1;
~*nikto 1;
~*nmap 1;
~*masscan 1;
~*acunetix 1;
~*netsparker 1;
~*libwww 1;
~*python-requests 1;
}

# server 块
if ($bad_agent) {
return 403;
}

第四层:IP 黑名单

手动封禁确认的恶意 IP:

1
2
3
# /etc/nginx/conf.d/blockip.conf
deny 1.2.3.4; # 单点 CC 攻击者
deny 5.6.7.0/24; # 封整个网段
1
2
# nginx.conf 的 http 块引入
include /etc/nginx/conf.d/blockip.conf;

被封的 IP 访问直接返回 403。

第五层:隐藏敏感信息

默认 Nginx 会在响应头和错误页暴露版本号,给攻击者信息:

1
2
# nginx.conf 的 http 块
server_tokens off; # 不显示版本号(默认是 on,必须关)

第六层:禁止危险路径

扫描器会扫各种后门路径(.env.gitphpinfo),直接拦死:

1
2
3
4
5
6
7
8
9
10
11
# 禁止访问隐藏文件(.git/.env/.htaccess 等)
location ~ /\.(?!well-known) {
deny all;
return 404; # 返回 404 而非 403,不暴露存在性
}

# 禁止访问敏感文件
location ~* \.(env|ini|conf|sql|bak|log|swp)$ {
deny all;
return 404;
}

第七层:自动封禁脚本(主动防御)

光靠上面这些是被动的。加一个定时脚本,每分钟扫描日志,自动封禁高频恶意 IP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#!/bin/bash
# cc-guard.sh — 每分钟由 cron 执行
LOG="/var/log/nginx/access.log"
BLOCK="/etc/nginx/conf.d/blockip.conf"
THRESHOLD=300 # 5分钟内超过300次 = 异常

CUTOFF=$(($(date +%s) - 300))

tail -8000 "$LOG" | awk -v cutoff="$CUTOFF" -v thr="$THRESHOLD" '
{
ip = $1
if (match($0, /\[([0-9]+)\/([A-Za-z]+)\/([0-9]+):([0-9]+):([0-9]+)/, m)) {
mon = (index("JanFebMarAprMayJunJulAugSepOctNovDec", m[2]) + 2) / 3
ts = mktime(m[3] " " int(mon) " " m[1] " " m[4] " " m[5] " 0 0")
if (ts > cutoff) count[ip]++
}
}
END {
for (i in count) if (count[i] > thr) printf "%d %s\n", count[i], i
}' | while read cnt ip; do
grep -qw "$ip" "$BLOCK" 2>/dev/null && continue
echo "deny $ip;" >> "$BLOCK"
logger -t cc-guard "AUTO-BANNED $ip ($cnt req/5min)"
done

nginx -t 2>/dev/null && nginx -s reload
1
2
# crontab — 每分钟检查
* * * * * /bin/bash /root/scripts/cc-guard.sh

关于 DDoS:Nginx 能挡到什么程度

CC 攻击(应用层、高频请求)——Nginx 的 limit_req + limit_conn + 自动封禁能挡住,因为攻击请求量在服务器能处理的量级。

大流量 DDoS(几十 Gbps 的流量洪流)——Nginx 挡不住。因为请求还没到 Nginx,带宽就被打满了,服务器根本收不到正常请求。这种情况必须靠:

  1. 云厂商的 DDoS 高防(阿里云 DDoS 防护、AWS Shield)——在流量到服务器之前清洗
  2. CDN 套一层(Cloudflare、阿里云 CDN)——隐藏源站 IP,攻击打到 CDN 边缘节点

⚠️ 重要认知:Nginx 防的是”应用层攻击”(CC、扫描、爬虫滥用),不是”流量层攻击”(大流量 DDoS)。两者性质不同,防御手段也不同。别指望一台 Nginx 挡住 T 级 DDoS。

完整的生产级安全配置模板

把上面所有层级整合成一个可直接用的模板:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# ===== nginx.conf 主配置 =====
http {
# 隐藏版本号
server_tokens off;

# 限流区域定义
limit_req_zone $binary_remote_addr zone=reqperip:10m rate=10r/s;
limit_conn_zone $binary_remote_addr zone=perip:10m;

# 恶意 UA 黑名单
map $http_user_agent $bad_agent {
default 0;
~*sqlmap 1; ~*nikto 1; ~*nmap 1; ~*masscan 1;
~*acunetix 1; ~*netsparker 1; ~*python-requests 1;
"" 1; # 空 UA
}

# IP 黑名单
include /etc/nginx/conf.d/blockip.conf;

include /etc/nginx/conf.d/*.conf;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# ===== 单站点配置 =====
server {
listen 443 ssl;
http2 on;
server_name example.com;

ssl_certificate /etc/ssl/fullchain.cer;
ssl_certificate_key /etc/ssl/private.key;
ssl_protocols TLSv1.2 TLSv1.3;

# 防护三件套
limit_req zone=reqperip burst=20 nodelay;
limit_conn perip 10;

# 恶意 UA 拦截
if ($bad_agent) { return 403; }

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

# 禁止隐藏文件
location ~ /\.(?!well-known) { deny all; return 404; }

# 禁止敏感文件
location ~* \.(env|ini|conf|sql|bak)$ { deny all; return 404; }

# 正常路由
location / {
try_files $uri $uri/ =404;
}
}

日常运维要点

  1. 改配置必先 nginx -t:测语法再重载,避免配置错误导致全站挂
  2. 看日志定位问题/var/log/nginx/access.log 看谁在访问,error.log 看报错
  3. 监控 503 数量:503 突然飙升 = 可能在被 CC,去看 access.log 的高频 IP
  4. 定期清黑名单:封太多 IP 会拖慢配置解析,过段时间清理已失效的
  5. 证书自动续期:用 acme.sh 或 certbot,别手动续

写在最后

Nginx 的价值不只是”能跑网站”,更在于它天然站在攻击者和后端服务之间。把它配置好,等于给网站穿了一层防弹衣——绝大多数 CC 攻击、漏洞扫描、恶意爬虫,在 Nginx 这一层就被挡掉了,根本碰不到后端。

但记住:Nginx 是第一道防线,不是唯一防线。真遇到大流量 DDoS,还得靠云厂商的高防服务。分层防御、各司其职,才是正确的安全姿势。

把本文的配置抄过去、加上自动封禁脚本,你的服务器抗攻击能力就能上一个台阶——这些都是我实测在真实攻击中验证过、确实有效的配置,不是纸上谈兵。