Nginx 站点配置实战
Nginx 作为网站入口,最常见的三种用法是:托管静态站点、把 PHP 请求转发给 PHP-FPM、把 API 请求反向代理给 Node.js。本文把这三份配置放在一起,并给出上线时常用的命令和容易踩的坑。无论哪种用法,配置的核心都围绕 server、location 两个块展开:server 决定请求匹配哪个站点,location 决定请求落到哪个处理逻辑。
场景一:静态站点 + HTTPS
静态站点(HTML、CSS、JS)配置最简单。下面的配置把 80 端口请求 301 跳到 HTTPS,并给静态资源设置一年缓存:
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name example.com www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
root /var/www/example.com;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
location ~* \.(jpg|jpeg|png|gif|ico|css|js|webp|svg)$ {
expires 365d;
add_header Cache-Control "public, immutable";
}
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;
}
参考:Nginx 官方文档 https://nginx.org/en/docs/
证书可以从 Let's Encrypt 免费申请,自动续期方案见Certbot 自动续期。
场景二:PHP-FPM 代理(WordPress / Laravel)
动态站点需要把 .php 请求交给 PHP-FPM 处理,try_files 的回退规则保证前端路由能正常落到 index.php:
server {
listen 443 ssl http2;
server_name example.com;
root /var/www/example.com/public;
index index.php;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
location ~ /\.ht {
deny all;
}
}
场景三:Node.js 反向代理
Node 应用通常监听某个本地端口(如 3000),由 Nginx 统一对外。WebSocket 场景记得带上 Upgrade 头:
server {
listen 443 ssl http2;
server_name api.example.com;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
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;
}
}
关键指令说明
这几份配置里反复出现的指令值得单独说:server_name 用域名匹配请求,写错会导致 404 或匹配到默认站点;root 指定站点文件目录,必须和实际部署路径一致;try_files 按顺序尝试文件,最后一项是兜底回退;add_header 给响应追加响应头,加 always 后对所有状态码生效。反向代理场景里,proxy_pass 决定请求转给谁,proxy_set_header 负责把原始 Host、客户端 IP、协议信息透传给后端——后端日志和分析脚本都依赖这些字段。
三种配置对比
| 场景 | 核心指令 | 典型用途 | 关键注意点 |
|---|---|---|---|
| 静态站点 | root / try_files | 落地页、文档站 | 静态资源缓存 |
| PHP-FPM | fastcgi_pass | WordPress、Laravel | SCRIPT_FILENAME 别写错 |
| 反向代理 | proxy_pass | Node.js、API、WebSocket | 转发 Host 与真实 IP |
日志与访问控制
站点上线后,日志就是排障的第一手资料。默认配置已经会在 access.log 里记录每个请求,建议在 server 块里加自定义格式,把响应时间、请求体大小也记下来,方便定位慢请求:
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" $request_time';
access_log /var/log/nginx/example.com.access.log main;
同时别忘记基本访问控制:隐藏的 .git、.env、backup 等目录要显式拒绝访问,管理后台可以用 allow/deny 按 IP 限制,配合 fail2ban 拦截暴力扫描。这些规则组合起来,能在配置层面先挡掉一批不速之客。另外记得用 logrotate 定期轮转日志,避免单个日志文件无限增长拖慢磁盘。
配置组织与 include
站点多了之后,把每份配置都写完整会显得冗长。Nginx 支持 include,把公共部分抽成片段:SSL 参数放 conf.d/ssl.conf,缓存规则放 conf.d/cache.conf,站点配置里用 include 引入。这样新增站点时只需要写 server_name、root 和 location 的差异部分,可维护性会好很多。
性能小贴士
静态资源缓存、开启 HTTP/2、隐藏版本号这些基础调优能让站点响应更快。HTTP/2 在 listen 443 ssl http2 里已经开启;静态资源用 expires 设置长缓存;server_tokens off 隐藏版本号,减少信息泄露。更系统的性能调优建议直接参考 Nginx 优化指南。
上线操作
# 1. 创建站点配置
sudo nano /etc/nginx/sites-available/example.com
# 2. 启用站点
sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
# 3. 校验配置
sudo nginx -t
# 4. 重载 Nginx
sudo systemctl reload nginx
# 5. 查看状态
sudo systemctl status nginx
常见坑
- 改完配置忘记
nginx -t与 reload。语法错误会导致整个 Nginx 拒绝启动,先-t再reload是标准流程。 - 代理请求里丢了真实 IP。后端拿到的
REMOTE_ADDR全是 127.0.0.1,记得设置X-Real-IP和X-Forwarded-For。 - SSL 证书路径写错。证书更新后路径不一致会报
no such file,建议直接用软链接管理证书路径。 try_files回退行为不符合预期。单页应用用/index.html,PHP 应用用/index.php?$query_string,两者别混用。proxy_pass结尾斜杠的坑。proxy_pass http://127.0.0.1:3000不带斜杠会保留完整 URI,带斜杠则会去掉匹配到的前缀,两者行为差异不小,配置前先想清楚。
常见问题
为什么改了配置不生效? Nginx 不会自动重载,必须执行 nginx -t 校验后再 systemctl reload nginx;另外检查站点是否已软链接进 sites-enabled。www 与不带 www 的域名怎么统一? 在 80 和 443 的 server 块里都声明两个域名,并加一条 301 把 www 跳转到主域名,避免重复内容。PHP 站点返回 404 而不是执行? 常见原因是 try_files 回退写成了 /index.html,PHP 应用应该回退到 /index.php?$query_string。证书快到期怎么提醒? 配合 certbot 的 renew hook,到期前 30 天自动续期,失败会发邮件通知。如何为多个站点复用配置? 把公共的缓存、安全头配置拆到 conf.d/*.conf 里 include,站点配置只保留差异部分。404 页面怎么自定义? 在 server 块里用 error_page 404 /404.html; 指定错误页,再在 root 下放一个 404.html。如何限制单 IP 请求频率? 用 limit_req_zone 配合 limit_req,对登录接口等敏感路径做限流。
Nginx 的更多性能调优可以参考Nginx 优化指南,反向代理的完整讲解见Nginx 反向代理指南;如果要用 Docker 部署,多容器部署会更有帮助。这类配置都属于环境部署的范畴。