Nginx
安装 Nginx
- Ubuntu / Debian
shell
sudo apt update
sudo apt install -y nginx
sudo systemctl enable --now nginx
nginx -v- CentOS / Rocky / Alma (dnf/yum)
shell
sudo dnf install -y nginx # 或 yum install -y nginx
sudo systemctl enable --now nginx
nginx -v基本目录与配置结构
常见路径:
- 主配置:
/etc/nginx/nginx.conf - 站点配置:
- Debian/Ubuntu:
/etc/nginx/sites-available/+sites-enabled/ - CentOS系:
/etc/nginx/conf.d/*.conf
- Debian/Ubuntu:
- 日志:
/var/log/nginx/access.log、/var/log/nginx/error.log - 默认站点目录:
/usr/share/nginx/html或/var/www/html
- 主配置:
nginx.conf
nginx
user nginx;
worker_processes auto;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent"';
access_log /var/log/nginx/access.log main;
sendfile on;
keepalive_timeout 65;
include /etc/nginx/conf.d/*.conf; # 或 include sites-enabled/*
}基本配置:静态站点 / 反向代理
静态站点(前端 dist)
nginx
server {
listen 80;
server_name example.com;
root /var/www/myapp/dist;
index index.html;
location / {
try_files $uri $uri/ /index.html; # SPA 必备
}
}反向代理(把 80 转到后端服务)
nginx
server {
listen 80;
server_name api.example.com;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
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;
# WebSocket 需要
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}负载均衡配置(upstream)
最常用:轮询(默认)
nginx
upstream backend_pool {
server 10.0.0.11:3000;
server 10.0.0.12:3000;
server 10.0.0.13:3000;
}
server {
listen 80;
server_name app.example.com;
location / {
proxy_pass http://backend_pool;
}
}加权:
nginx
upstream backend_pool {
server 10.0.0.11:3000 weight=5;
server 10.0.0.12:3000 weight=3;
server 10.0.0.13:3000 weight=1;
}IP 哈希(同一用户尽量命中同一台:会话粘性的一种简易方式)
nginx
upstream backend_pool {
ip_hash;
server 10.0.0.11:3000;
server 10.0.0.12:3000;
}最少连接(适合耗时请求更均匀)
nginx
upstream backend_pool {
least_conn;
server 10.0.0.11:3000;
server 10.0.0.12:3000;
}健康/失败参数(常见写法)
nginx
upstream backend_pool {
server 10.0.0.11:3000 max_fails=3 fail_timeout=10s;
server 10.0.0.12:3000 max_fails=3 fail_timeout=10s;
}max_fails:连续失败多少次认为不可用fail_timeout:失败统计窗口 + 暂时剔除的时间
配置说明
server {}:一个虚拟主机listen 80;:监听端口server_name:域名匹配(可多个)location /path {}:路径匹配块(前缀/正则)root vs alias:root /a; location /img/ {}→ 实际路径/a/img/...alias /a/img/; location /img/ {}→ 实际路径/a/img/...(注意结尾/影响很大)
try_files:文件存在就直接返回,否则兜底(SPA 常用)proxy_pass:转发到上游include:拆分配置
SSL 配置(HTTPS)
基础 HTTPS(证书已准备好)
nginx
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /etc/nginx/certs/fullchain.pem;
ssl_certificate_key /etc/nginx/certs/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
location / {
root /var/www/myapp/dist;
try_files $uri $uri/ /index.html;
}
}
# HTTP 自动跳转 HTTPS
server {
listen 80;
server_name example.com;
return 301 https://$host$request_uri;
}Let’s Encrypt(自动签证书)
- DNS 必须有 A 记录
shell
dig example.com +short
dig www.example.com +short- 防火墙(如启用 ufw):
shell
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw reload- 用 conf.d 写一个“可验证的 HTTP 站点”
Certbot nginx 插件要能找到匹配
server_name的server {}才好自动改配置 - 创建配置文件:
shell
sudo nano /etc/nginx/conf.d/example.com.conf- 写入(先只配 HTTP):
nginx
# /etc/nginx/conf.d/example.com.conf
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
# 方式 1:静态站点
root /var/www/example.com;
index index.html;
# Let’s Encrypt 验证文件目录(可选但推荐显式写)
location ^~ /.well-known/acme-challenge/ {
root /var/www/example.com;
default_type "text/plain";
try_files $uri =404;
}
location / {
try_files $uri $uri/ =404;
}
}- 创建站点目录与测试页:
shell
sudo mkdir -p /var/www/example.com/.well-known/acme-challenge
echo "ok" | sudo tee /var/www/example.com/index.html >/dev/null
sudo chown -R www-data:www-data /var/www/example.com- 检查并重载:
shell
sudo nginx -t
sudo systemctl reload nginx- 验证 HTTP 是否能访问:
shell
curl -I http://example.com- 安装 Certbot(建议 snap,避免 Python 依赖冲突)
shell
sudo apt remove -y certbot python3-certbot-nginx
sudo apt autoremove -y
sudo apt update
sudo apt install -y snapd
sudo snap install core
sudo snap refresh core
sudo snap install --classic certbot
sudo ln -sf /snap/bin/certbot /usr/bin/certbot- 签发证书(自动修改 conf.d 里的 server 块)
shell
sudo certbot --nginx -d example.com -d www.example.com会自动改 Nginx 配置并设置续期任务(系统里一般有 timer/cron)。
模板
shell
# /etc/nginx/conf.d/example.com.conf
# 1) HTTP:只负责 acme 验证 + 跳转 HTTPS
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
# acme 验证
location ^~ /.well-known/acme-challenge/ {
root /var/www/example.com;
default_type "text/plain";
try_files $uri =404;
}
# 其余都跳转到 https
location / {
return 301 https://$host$request_uri;
}
}
# 2) HTTPS:真实业务
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com www.example.com;
# certbot 自动生成/维护的证书路径
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# (可选)TLS 强化
ssl_protocols TLSv1.2 TLSv1.3;
root /var/www/example.com;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}- 自动续期确认 + 手动测试
- 查看 timer(snap/系统版都可能有)
shell
systemctl list-timers | grep -i certbot || true- 模拟续期
shell
sudo certbot renew --dry-runGzip 压缩 + 常用优化配置
- 放在
http {}里更合适:
Gzip
nginx
http {
##
## ===== Gzip 压缩配置 =====
##
gzip on; # 开启 gzip 压缩(默认 off)
gzip_min_length 1024; # 响应内容大于 1KB 才压缩(太小没必要)
gzip_comp_level 5; # 压缩等级 1~9(5 性能/压缩率平衡,最常用)
gzip_vary on; # 给响应头加 Vary: Accept-Encoding
# 解决代理/CDN 缓存问题
gzip_proxied any; # 代理请求也启用 gzip
# any = 所有代理情况
# 指定哪些 MIME 类型参与压缩
gzip_types
text/plain # 普通文本
text/css # CSS
application/json # JSON 接口
application/javascript # JS
text/xml
application/xml
application/xml+rss
image/svg+xml; # SVG(文本格式,适合压缩)
# ⚠️ 不建议压缩图片(jpg/png/webp 已经是压缩格式)
# gzip_types image/jpeg image/png; ❌
##
## ===== 传输 & 性能优化 =====
##
sendfile on; # 内核级文件传输(静态文件性能提升)
tcp_nopush on; # 配合 sendfile,减少包数量
tcp_nodelay on; # 保证实时性(对小包/长连接友好)
keepalive_timeout 65; # HTTP 长连接超时时间(秒)
keepalive_requests 1000; # 单连接最多处理请求数
##
## ===== 上传 & 请求限制 =====
##
client_max_body_size 20m; # 单次请求最大 body(文件上传)
# 超过返回 413 Request Entity Too Large
##
## ===== 安全相关 Header(基础版)=====
##
add_header X-Frame-Options SAMEORIGIN always; # 防止 iframe 劫持
add_header X-Content-Type-Options nosniff always; # 禁止 MIME 嗅探
add_header Referrer-Policy strict-origin-when-cross-origin always;
}静态资源缓存
nginx
location ~* \.(js|css|png|jpg|jpeg|gif|svg|ico|webp)$ {
expires 30d;
add_header Cache-Control "public, max-age=2592000, immutable";
}上传大小限制
nginx
client_max_body_size 20m;基本安全头(按需)
nginx
add_header X-Frame-Options SAMEORIGIN always;
add_header X-Content-Type-Options nosniff always;
add_header Referrer-Policy strict-origin-when-cross-origin always;跨域(CORS)
nginx
# CORS 允许的前端域名白名单
# key:浏览器请求的 Origin
# value:返回给浏览器的 Access-Control-Allow-Origin
map $http_origin $cors_origin {
# 默认不允许(返回空字符串)
default "";
# ===== 允许的前端域名 =====
"https://www.example.com" $http_origin;
"https://admin.example.com" $http_origin;
# 本地开发环境
"http://localhost:3000" $http_origin;
"http://127.0.0.1:3000" $http_origin;
}
location /api/ {
##
## ===== 1️⃣ 处理预检请求(OPTIONS)=====
## 浏览器在复杂跨域请求前自动发送
##
if ($request_method = OPTIONS) {
# 允许的跨域来源(只对白名单生效)
add_header Access-Control-Allow-Origin $cors_origin;
# 是否允许携带 Cookie / Authorization
add_header Access-Control-Allow-Credentials true;
# 允许的 HTTP 方法
add_header Access-Control-Allow-Methods
"GET,POST,PUT,DELETE,PATCH,OPTIONS";
# 允许的请求头(要包含前端真实使用的)
add_header Access-Control-Allow-Headers
"Content-Type,Authorization,X-Requested-With";
# 预检结果缓存时间(秒)
# 在此时间内浏览器不会重复发 OPTIONS
add_header Access-Control-Max-Age 86400;
# 预检请求不需要返回内容
return 204;
}
##
## ===== 2️⃣ 实际请求(GET / POST / PUT ...)=====
##
# 允许跨域访问的来源
# always:即使返回 4xx / 5xx 也携带 CORS 头
add_header Access-Control-Allow-Origin $cors_origin always;
# 允许浏览器携带 Cookie
add_header Access-Control-Allow-Credentials true always;
##
## ===== 3️⃣ 反向代理到后端服务 =====
##
proxy_pass http://backend_pool;
# 传递真实客户端信息
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;
}DANGER
❌ 错误写法(浏览器会直接拦)
nginx
Access-Control-Allow-Origin: *;
Access-Control-Allow-Credentials: true;TIP
✅ 正确写法
nginx
Access-Control-Allow-Origin: https://www.example.com;
Access-Control-Allow-Credentials: true;常用命令列表
shell
# 查看版本
nginx -v
# 检查配置语法(改完配置第一步)
sudo nginx -t
# 查看最终生效配置(排查 include/覆盖很有用)
sudo nginx -T
# 启动 / 停止 / 重启
sudo systemctl start nginx
sudo systemctl stop nginx
sudo systemctl restart nginx
# 平滑重载(推荐:不中断连接)
sudo systemctl reload nginx
# 或:sudo nginx -s reload
# 查看状态
sudo systemctl status nginx
# 看日志(实时)
sudo tail -f /var/log/nginx/access.log
sudo tail -f /var/log/nginx/error.log模板
nginx
# 定义后端服务池(可多台)
upstream api_pool {
least_conn; # 最少连接策略(更均衡)
server 127.0.0.1:3000; # 后端 API 服务
# server 10.0.0.12:3000; # 第二台(需要就打开)
# max_fails=3 fail_timeout=10s
# 10 秒内失败 3 次就临时踢出
}
server {
listen 80;
server_name example.com www.example.com;
# 所有 HTTP 请求跳转到 HTTPS
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2; # http2 可提升多资源加载速度
server_name example.com www.example.com;
##
## ===== SSL 证书配置 =====
##
ssl_certificate /etc/nginx/certs/fullchain.pem;
ssl_certificate_key /etc/nginx/certs/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
##
## ===== Gzip(站点级,也可放 http{})=====
##
gzip on;
gzip_min_length 1024;
gzip_comp_level 5;
gzip_types
text/plain
text/css
application/json
application/javascript
image/svg+xml;
##
## ===== 前端静态资源 =====
##
root /var/www/myapp/dist; # 前端构建产物目录
index index.html;
# SPA 路由支持(Vue / React / Svelte 必备)
location / {
try_files $uri $uri/ /index.html;
}
##
## ===== API 反向代理 =====
##
location /api/ {
proxy_pass http://api_pool/; # 转发到 upstream
# 保留客户端真实信息
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;
# WebSocket 支持(如果不用也没坏处)
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
##
## ===== 静态资源缓存(强烈推荐)=====
##
location ~* \.(js|css|png|jpg|jpeg|gif|svg|ico|webp)$ {
expires 30d; # 浏览器缓存 30 天
add_header Cache-Control
"public, max-age=2592000, immutable";
# immutable:内容不变就不重新请求
}
##
## ===== 基础安全 Header =====
##
add_header X-Frame-Options SAMEORIGIN always;
add_header X-Content-Type-Options nosniff always;
add_header Referrer-Policy strict-origin-when-cross-origin always;
}