刚工作的时候,"Nginx"对我来说就是一个黑盒------运维配好我就用,出了问题只会重启。直到有一次线上 HTTPS 证书过期,整个排查过程我插不上手,才下决心自己学了一遍。
Nginx 是干什么的
简单说就三件事:
- 静态文件服务:直接返回 HTML/CSS/JS/图片
- 反向代理:把请求转发给后端服务(Tomcat、Node、Go 等)
- 负载均衡:多个后端实例,Nginx 帮你分发请求
大部分项目里,Nginx 同时干这三件事。
核心配置文件结构
nginx
# nginx.conf 主配置
worker_processes auto; # 工作进程数,auto = CPU 核数
events {
worker_connections 1024; # 每个进程最大连接数
}
http {
include mime.types;
sendfile on; # 零拷贝传输,静态文件必开
keepalive_timeout 65;
# 虚拟主机 1
server {
listen 80;
server_name example.com;
location / {
root /var/www/html;
index index.html;
}
}
# 虚拟主机 2(反向代理)
server {
listen 80;
server_name api.example.com;
location / {
proxy_pass http://127.0.0.1:8080;
}
}
}
http → server → location 三层嵌套,每一层都可以有独立的配置。
反向代理配置
最基本的一条:
nginx
server {
listen 80;
server_name api.example.com;
location / {
proxy_pass http://127.0.0.1:8080;
# 传递真实客户端信息给后端
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 这四行基本是固定写法,不加的话后端拿到的 IP 全是 Nginx 的 127.0.0.1。
按路径转发到不同后端
nginx
server {
listen 80;
server_name example.com;
# API 请求 → Java 后端
location /api/ {
proxy_pass http://127.0.0.1:8080;
}
# WebSocket → Node 服务
location /ws/ {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
# 静态文件 → 直接返回
location / {
root /var/www/frontend/dist;
try_files $uri $uri/ /index.html; # SPA 路由兜底
}
}
try_files 那行是 SPA 标配------前端用 Vue Router / React Router 的 history 模式时,所有路径都要返回 index.html,否则刷新就 404。
HTTPS 配置
nginx
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /etc/nginx/ssl/example.com.pem;
ssl_certificate_key /etc/nginx/ssl/example.com.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
location / {
proxy_pass http://127.0.0.1:8080;
}
}
# HTTP 自动跳转 HTTPS
server {
listen 80;
server_name example.com;
return 301 https://$host$request_uri;
}
证书用 Let's Encrypt 免费申请,certbot 一行命令搞定续期。
负载均衡
nginx
upstream backend {
# 默认轮询
server 192.168.1.10:8080 weight=3; # 权重高的分更多请求
server 192.168.1.11:8080 weight=1;
server 192.168.1.12:8080 backup; # 备用,前两台挂了才用
# 也可以用 ip_hash(同一 IP 始终打到同一台,解决 session 问题)
# ip_hash;
# 或者 least_conn(请求最少的优先)
# least_conn;
}
server {
listen 80;
server_name api.example.com;
location / {
proxy_pass http://backend;
}
}
| 策略 | 说明 | 适用场景 |
|---|---|---|
| 轮询 (默认) | 按顺序依次分发 | 后端实例性能一致 |
| weight | 按权重比例分发 | 后端性能不一致 |
| ip_hash | 同一 IP 固定到同一台 | 有 session 依赖 |
| least_conn | 优先分给连接数最少的 | 请求处理时间差异大 |
常用运维命令
bash
# 测试配置文件语法
nginx -t
# 重新加载配置(不中断服务)
nginx -s reload
# 查看 Nginx 进程
ps aux | grep nginx
# 查看当前连接数
netstat -nlp | grep nginx
改完配置一定要先 nginx -t 测一下语法,再 nginx -s reload。直接 restart 会短暂中断连接。
踩坑:proxy_pass 末尾的斜杠
nginx
# 有斜杠:/api/users → http://backend/users(去掉了 /api)
location /api/ {
proxy_pass http://backend/;
}
# 没斜杠:/api/users → http://backend/api/users(保留 /api)
location /api/ {
proxy_pass http://backend;
}
这个坑我见过不下三次,前后端联调的时候路径对不上,排查半天发现是斜杠的问题。记住:proxy_pass 后面有路径(哪怕只是一个 /),就会替换掉 location 的匹配部分。
总结
Nginx 日常用到的就是:反向代理(proxy_pass)、静态文件(root + try_files)、HTTPS(ssl_certificate)、负载均衡(upstream)。配完记得 nginx -t 测语法,proxy_pass 注意斜杠。