Nginx(发音 "engine-x")是由 Igor Sysoev 于 2004 年发布的高性能 HTTP 和反向代理服务器,同时也是 IMAP/POP3 代理服务器。它以事件驱动(event-driven)的异步非阻塞架构闻名,能以极低的内存占用处理数万并发连接。
根据 W3Techs 统计,Nginx 是全球使用量最大的 Web 服务器,为超过 30% 的网站提供服务,包括 Netflix、Airbnb、Dropbox 等知名企业。2019 年 F5 Networks 收购了 Nginx Inc.,但开源版本仍然活跃维护。
| 项目信息 | 详情 |
|---|---|
| 开发团队 | F5 / Nginx Inc.(原作者 Igor Sysoev) |
| GitHub Stars | 26,000+ |
| 官方网站 | nginx.org |
| 开源协议 | BSD-2-Clause License |
| 技术栈 | C 语言 |
| 架构模型 | 事件驱动(Event-Driven)、异步非阻塞 |
| 主要用途 | Web 服务器 / 反向代理 / 负载均衡 / HTTP 缓存 |
| 对比维度 | Nginx | Apache | Caddy | Traefik |
|---|---|---|---|---|
| 架构模型 | 事件驱动、异步非阻塞 | 进程/线程模型(MPM) | Go 协程 | Go 协程 |
| 高并发性能 | 极强(C10K+) | 较弱(重线程) | 良好 | 良好 |
| 内存占用 | 极低 | 较高 | 中等 | 中等 |
| 配置方式 | 自定义配置文件 | httpd.conf / .htaccess | Caddyfile(极简) | 自动发现(Docker 标签) |
| HTTPS 自动化 | 需手动配置 Certbot | 需手动配置 | 全自动 HTTPS | 全自动 HTTPS |
| 模块/插件 | 丰富(编译时加载) | 最丰富(运行时加载) | Go 插件系统 | 中间件 |
| 容器编排支持 | 需手动配置 | 需手动配置 | 一般 | 原生 Docker/K8s |
| 学习曲线 | 中等 | 中等 | 简单 | 中等 |
| 适用场景 | 高并发生产环境 | 传统 PHP 托管 | 小型项目/快速部署 | 微服务/容器化部署 |
# Ubuntu / Debian sudo apt update sudo apt install nginx -y # CentOS / RHEL / Rocky Linux sudo yum install epel-release -y sudo yum install nginx -y # Arch Linux sudo pacman -S nginx # macOS (Homebrew) brew install nginx安装后常用命令:
# 启动 sudo systemctl start nginx # 开机自启 sudo systemctl enable nginx # 查看状态 sudo systemctl status nginx # 测试配置文件语法 sudo nginx -t # 重新加载配置(不中断服务) sudo nginx -s reload
# 安装编译依赖 sudo apt install build-essential libpcre3 libpcre3-dev zlib1g-dev libssl-dev libgeoip-dev -y # 下载源码 wget https://nginx.org/download/nginx-1.26.2.tar.gz tar -xzf nginx-1.26.2.tar.gz cd nginx-1.26.2 # 配置(带常用模块) ./configure \ --prefix=/etc/nginx \ --sbin-path=/usr/sbin/nginx \ --conf-path=/etc/nginx/nginx.conf \ --error-log-path=/var/log/nginx/error.log \ --http-log-path=/var/log/nginx/access.log \ --pid-path=/var/run/nginx.pid \ --with-http_ssl_module \ --with-http_v2_module \ --with-http_realip_module \ --with-http_gzip_static_module \ --with-http_stub_status_module # 编译 & 安装 make && sudo make install
# 快速启动 docker run -d --name nginx \ -p 80:80 -p 443:443 \ -v /path/to/nginx.conf:/etc/nginx/nginx.conf:ro \ -v /path/to/html:/usr/share/nginx/html:ro \ nginx:alpineDocker Compose(推荐):
nginx:alpine 镜像体积仅约 40MB,比默认镜像小 3 倍以上。/etc/nginx/nginx.conf:
/etc/nginx/conf.d/ 目录下,而不是直接修改 nginx.conf 主文件。X-Real-IP 和 X-Forwarded-For 头部让后端应用能获取到客户端的真实 IP,而非 Nginx 的 IP。rate=10r/s 表示每秒 10 个请求,burst=20 允许突发 20 个请求排队,nodelay 表示突发请求不延迟立即处理。max_fails=3 表示连续失败 3 次后标记为不可用,fail_timeout=30s 表示 30 秒后重新尝试。主动健康检查需要 Nginx Plus 或使用第三方模块 nginx_upstream_check_module。# 安装 Certbot sudo apt install certbot python3-certbot-nginx -y # 自动配置 Nginx + 获取证书 sudo certbot --nginx -d example.com -d www.example.com # 测试自动续期 sudo certbot renew --dry-run # Certbot 会自动设置 cron/timer 续期
ulimit -n 值足够大。gzip_static on; 可以直接发送预压缩的 .gz 文件,避免每次请求都实时压缩,适合构建工具已生成 .gz 文件的场景。client_max_body_size;如果后端响应较慢(如 AI 推理),需要增大 proxy_read_timeout。systemctl status your-app
proxy_pass 的地址和端口是否正确
ls -la /var/run/php/
proxy_connect_timeout 300s; proxy_send_timeout 300s; proxy_read_timeout 300s;
request_terminate_timeout
client_max_body_size 100m;
upload_max_filesize = 100M post_max_size = 100M
ls -la /var/www/html/
nginx 或 www-data)有读取权限
getenforce,如果为 Enforcing 可能阻止访问
deny all; 或缺少 index 指令
root 指令指向的目录是否正确
ls -la /var/www/html/path/to/file
try_files $uri $uri/ /index.html;
location 匹配规则是否正确
proxy_ignore_client_abort on; 让后端继续处理
$http_x_forwarded_proto 而非 $scheme 判断:
if ($http_x_forwarded_proto = "http") {
return 301 https://$host$request_uri;
}
client_header_buffer_size 4k; large_client_header_buffers 4 32k;
client_body_timeout 60s; client_header_timeout 60s;
rate 或 burst 值
geo $limit {
default 1;
10.0.0.0/8 0; # 内网不限流
}
map $limit $limit_key {
0 "";
1 $binary_remote_addr;
}
limit_req_zone $limit_key zone=api:10m rate=10r/s;
sudo lsof -i :80 或 sudo ss -tlnp | grep :80
sudo systemctl stop apache2
sudo killall nginx 后重启
nginx -V
--with-http_ssl_module、--with-http_v2_module
nginx -T 查看实际加载的配置
nginx -t 确认没有语法错误
# 正确结构
http {
server { ... }
}
# 错误:server 在 http 外面
server { ... }
http { ... }
grep -r "server_name example.com" /etc/nginx/
which nginx 和 nginx -V
nginx -c /path/to/nginx.conf
sudo setenforce 0
sudo setsebool -P httpd_can_network_connect 1
sudo semanage port -a -t http_port_t -p tcp 3000
worker_connections:
events {
worker_connections 4096;
}
# /etc/security/limits.conf nginx soft nofile 65535 nginx hard nofile 65535
worker_rlimit_nofile 65535;
proxy_buffer_size 128k; proxy_buffers 4 256k; proxy_busy_buffers_size 256k;
fastcgi_buffer_size 128k; fastcgi_buffers 4 256k; fastcgi_busy_buffers_size 256k;
ssl_session_cache 缓存会话
perf top -p $(pgrep nginx) 分析热点
ssl_certificate 使用 fullchain.pem(包含中间证书)
openssl x509 -in cert.pem -noout -dates
proxy_pass 使用 http:// 还是 https://
ssl_protocols 是否与客户端兼容
/.well-known/acme-challenge/ 路径可访问:
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
/var/log/letsencrypt/letsencrypt.log
//example.com/...)
add_header Content-Security-Policy "upgrade-insecure-requests" always;
X-Forwarded-Proto 头部让后端知道使用 HTTPS
ssl_session_cache shared:SSL:10m; ssl_session_timeout 1d;
ssl_stapling on; ssl_stapling_verify on;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_certificate /path/to/fullchain.pem; ssl_certificate_key /path/to/privkey.pem;
ssl 关键字
ssl_certificate 文件包含完整证书链(服务器证书 + 中间证书)
fullchain.pem 而非 cert.pem
openssl s_client -connect example.com:443 -servername example.com
server_name 正确
server {
listen 443 ssl default_server;
server_name _;
ssl_certificate /path/to/default.pem;
return 444; # 拒绝未知域名
}
-----BEGIN CERTIFICATE----- 开头)
openssl x509 -in cert.der -inform DER -out cert.pem -outform PEM
# Certbot DNS 验证(以 Cloudflare 为例) sudo certbot certonly \ --dns-cloudflare \ --dns-cloudflare-credentials ~/.secrets/cloudflare.ini \ -d example.com \ -d "*.example.com"配置中可以在多个 server 块中复用同一张证书:
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
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;后端应用读取
X-Real-IP 或 X-Forwarded-For 头部获取真实 IP。如果有多层代理,需要配置 set_real_ip_from 和 real_ip_header。
proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade";
proxy_read_timeout 86400s;
proxy_pass 末尾有无斜杠行为完全不同:
# 请求: /api/users
# 带斜杠 — 去掉匹配的前缀
location /api/ {
proxy_pass http://backend/; # → backend 收到 /users
}
# 不带斜杠 — 保留完整路径
location /api/ {
proxy_pass http://backend; # → backend 收到 /api/users
}
proxy_redirect 改写后端返回的 Location 头:
proxy_redirect http://127.0.0.1:3000/ /; # 或自动改写 proxy_redirect default;同时确保设置了 Host 头:
proxy_set_header Host $host;
proxy_cookie_path 和 proxy_cookie_domain 改写 Cookie:
# 改写 Cookie 路径 proxy_cookie_path /internal-app/ /; # 改写 Cookie 域名 proxy_cookie_domain backend.internal example.com;如果使用子路径代理,确保后端应用的 Cookie 路径设置兼容。
curl -v http://127.0.0.1:3000
proxy_connect_timeout 60s;
# 关闭代理缓冲 proxy_buffering off; # 或者使用临时文件缓冲 proxy_max_temp_file_size 1024m; proxy_temp_path /var/cache/nginx/temp;对于视频流或大文件下载场景,建议关闭缓冲。
ip_hash 策略可能导致分配不均 — 改用 least_conn
weight 参数按性能分配:
upstream backend {
least_conn;
server 10.0.0.1:3000 weight=3; # 高性能机器
server 10.0.0.2:3000 weight=1; # 低性能机器
}
keepalive 值
server {
listen 80;
server_name app.example.com;
root /var/www/app/dist;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
# API 代理
location /api/ {
proxy_pass http://127.0.0.1:3000;
}
}
try_files 会先查找实际文件,找不到则回退到 index.html 让前端路由处理。
location /api/ {
# CORS 头部
add_header Access-Control-Allow-Origin $http_origin always;
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
add_header Access-Control-Allow-Headers "Authorization, Content-Type" always;
add_header Access-Control-Allow-Credentials true always;
# 预检请求直接返回
if ($request_method = OPTIONS) {
return 204;
}
proxy_pass http://backend;
}
* 作为 Allow-Origin,应该明确指定允许的域名。# /etc/logrotate.d/nginx
/var/log/nginx/*.log {
daily
missingok
rotate 14
compress
delaycompress
notifempty
create 0640 nginx adm
sharedscripts
postrotate
[ -f /var/run/nginx.pid ] && kill -USR1 `cat /var/run/nginx.pid`
endscript
}
access_log off;
access_log /var/log/nginx/access.log main buffer=32k flush=5s;
# 1. 备份旧二进制 sudo cp /usr/sbin/nginx /usr/sbin/nginx.old # 2. 替换新二进制(编译安装后) sudo cp objs/nginx /usr/sbin/nginx # 3. 发送 USR2 信号启动新进程 sudo kill -USR2 `cat /var/run/nginx.pid` # 4. 优雅关闭旧 worker sudo kill -WINCH `cat /var/run/nginx.pid.oldbin` # 5. 确认新版本正常后关闭旧主进程 sudo kill -QUIT `cat /var/run/nginx.pid.oldbin`
apt upgrade nginx 即可,systemd 会处理重启。# 添加状态页面
server {
listen 127.0.0.1:8080;
location /nginx_status {
stub_status;
allow 127.0.0.1;
deny all;
}
}
访问后输出如下:
Active connections: 291 server accepts handled requests 16630948 16630948 31070465 Reading: 6 Writing: 179 Waiting: 106可以配合 Prometheus + nginx-exporter + Grafana 做可视化监控。
proxy_buffers 和 proxy_buffer_size
proxy_cache 相关配置
worker_shutdown_timeout 10s;
worker_rlimit_core 限制 core dump 大小
# 1. 屏蔽常见扫描路径
location ~* /(wp-admin|wp-login|phpmyadmin|\.env|\.git) {
return 444;
}
# 2. 屏蔽恶意 User-Agent
if ($http_user_agent ~* (scrapy|curl|wget|python-requests|Go-http-client)) {
return 403;
}
# 3. 限制请求速率
limit_req_zone $binary_remote_addr zone=scan:10m rate=2r/s;
location / {
limit_req zone=scan burst=5 nodelay;
}
# nginx.conf 全局块 worker_rlimit_nofile 65535;
# /etc/security/limits.conf nginx soft nofile 65535 nginx hard nofile 65535 # /etc/sysctl.conf fs.file-max = 2097152
LimitNOFILE=65535
# nginx.conf(与 http 块同级)
stream {
upstream mysql_backend {
server 10.0.0.1:3306;
server 10.0.0.2:3306 backup;
}
server {
listen 3306;
proxy_pass mysql_backend;
proxy_connect_timeout 10s;
proxy_timeout 300s;
}
}
--with-stream。包管理器安装的 Nginx 通常已包含。# proxy_pass 使用服务名而非 localhost proxy_pass http://app:3000;
host.docker.internal 访问宿主机服务
resolver 127.0.0.11 valid=30s; # Docker 内置 DNS