Nginx 作为 Web 服务器
2026/3/20大约 9 分钟
Nginx 作为 Web 服务器
静态资源服务
基础配置
server {
listen 80;
server_name static.example.com;
# 网站根目录
root /var/www/static;
# 默认首页
index index.html index.htm;
# 字符集
charset utf-8;
# 访问日志
access_log /var/log/nginx/static.access.log main;
error_log /var/log/nginx/static.error.log;
# 默认路由
location / {
# 按顺序查找文件
# 1. 查找 $uri 对应的文件
# 2. 查找 $uri/ 目录下的 index 文件
# 3. 都找不到返回 404
try_files $uri $uri/ =404;
}
}
文件类型处理
server {
listen 80;
server_name static.example.com;
root /var/www/static;
# HTML 文件 - 不缓存
location ~* \.html?$ {
expires -1;
add_header Cache-Control "no-store, no-cache, must-revalidate";
}
# CSS 和 JS 文件 - 中等缓存
location ~* \.(css|js)$ {
expires 7d;
add_header Cache-Control "public, immutable";
# 开启 gzip
gzip on;
gzip_types text/css application/javascript;
}
# 图片文件 - 长期缓存
location ~* \.(jpg|jpeg|png|gif|ico|webp|svg)$ {
expires 30d;
add_header Cache-Control "public, immutable";
# 关闭访问日志减少 I/O
access_log off;
}
# 字体文件 - 长期缓存
location ~* \.(woff|woff2|ttf|eot|otf)$ {
expires 365d;
add_header Cache-Control "public, immutable";
# 跨域支持
add_header Access-Control-Allow-Origin *;
access_log off;
}
# 视频音频文件 - 支持断点续传
location ~* \.(mp4|mp3|webm|ogg|avi|mov)$ {
expires 30d;
add_header Accept-Ranges bytes;
# 限制单个连接的带宽
limit_rate_after 5m; # 前 5MB 不限速
limit_rate 512k; # 之后限速 512KB/s
}
# PDF 和文档
location ~* \.(pdf|doc|docx|xls|xlsx|ppt|pptx)$ {
expires 7d;
add_header Content-Disposition "inline";
}
# 压缩包 - 强制下载
location ~* \.(zip|tar|gz|rar|7z)$ {
add_header Content-Disposition "attachment";
expires 1d;
}
}
sendfile 与文件传输优化
http {
# 开启高效文件传输
sendfile on;
# 在一个数据包中发送 HTTP 响应头
tcp_nopush on;
# 禁用 Nagle 算法
tcp_nodelay on;
# 异步 I/O(适合大文件)
aio on;
# 直接 I/O(绕过系统缓存,适合超大文件)
directio 4m;
# 文件描述符缓存
open_file_cache max=10000 inactive=60s;
open_file_cache_valid 30s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
server {
# 大文件下载专用配置
location /downloads/ {
alias /data/downloads/;
# 输出缓冲
output_buffers 2 1m;
# 断点续传
max_ranges 1;
# 限速
limit_rate_after 10m;
limit_rate 1m;
}
}
}
虚拟主机配置
基于域名的虚拟主机
# 站点 A
server {
listen 80;
server_name www.site-a.com site-a.com;
root /var/www/site-a;
index index.html;
access_log /var/log/nginx/site-a.access.log;
location / {
try_files $uri $uri/ =404;
}
}
# 站点 B
server {
listen 80;
server_name www.site-b.com site-b.com;
root /var/www/site-b;
index index.html;
access_log /var/log/nginx/site-b.access.log;
location / {
try_files $uri $uri/ =404;
}
}
# 默认站点(处理未匹配的请求)
server {
listen 80 default_server;
server_name _;
return 444; # 关闭连接,不返回响应
}
基于端口的虚拟主机
# 端口 8080 - 开发环境
server {
listen 8080;
server_name localhost;
root /var/www/dev;
index index.html;
# 开发环境配置
add_header X-Environment "development";
}
# 端口 8081 - 测试环境
server {
listen 8081;
server_name localhost;
root /var/www/test;
index index.html;
add_header X-Environment "testing";
}
# 端口 8082 - 预生产环境
server {
listen 8082;
server_name localhost;
root /var/www/staging;
index index.html;
add_header X-Environment "staging";
}
基于 IP 的虚拟主机
# IP 192.168.1.100 - 内网访问
server {
listen 192.168.1.100:80;
server_name internal.example.com;
root /var/www/internal;
index index.html;
# 内网专用配置
allow 192.168.0.0/16;
allow 10.0.0.0/8;
deny all;
}
# IP 公网 - 外网访问
server {
listen 203.0.113.10:80;
server_name www.example.com;
root /var/www/public;
index index.html;
}
泛域名配置
# 泛域名解析
server {
listen 80;
server_name *.example.com;
# 从子域名提取目录名
set $subdomain "";
if ($host ~* ^([^.]+)\.example\.com$) {
set $subdomain $1;
}
root /var/www/sites/$subdomain;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
# 正则提取子域名
server {
listen 80;
server_name ~^(?<user>.+)\.users\.example\.com$;
root /home/$user/public_html;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
目录浏览(autoindex)
基础目录浏览
server {
listen 80;
server_name files.example.com;
root /data/files;
location / {
# 开启目录浏览
autoindex on;
# 显示文件大小
# on: 精确字节数
# off: 人性化显示(KB、MB、GB)
autoindex_exact_size off;
# 显示本地时间(默认 UTC)
autoindex_localtime on;
# 输出格式
# html: HTML 页面
# xml: XML 格式
# json: JSON 格式
# jsonp: JSONP 格式(需要 callback 参数)
autoindex_format html;
}
}
美化目录浏览
server {
listen 80;
server_name files.example.com;
root /data/files;
# 自定义首页和页脚
location / {
autoindex on;
autoindex_exact_size off;
autoindex_localtime on;
# 添加自定义头部和尾部 HTML
# 需要 ngx_http_addition_module 模块
add_before_body /.header.html;
add_after_body /.footer.html;
}
# 隐藏头部和尾部文件
location ~ /\.(header|footer)\.html$ {
internal;
}
}
安全的目录浏览
server {
listen 80;
server_name files.example.com;
root /data/files;
# 基本认证
auth_basic "Restricted Files";
auth_basic_user_file /etc/nginx/.htpasswd;
location / {
autoindex on;
autoindex_exact_size off;
autoindex_localtime on;
}
# 禁止访问特定目录
location /private/ {
deny all;
return 404;
}
# 禁止访问隐藏文件
location ~ /\. {
deny all;
}
# 限制文件类型
location ~* \.(sh|sql|conf|ini|env)$ {
deny all;
}
}
创建密码文件:
# 安装 htpasswd 工具
# CentOS
sudo yum install -y httpd-tools
# Ubuntu
sudo apt install -y apache2-utils
# 创建密码文件
sudo htpasswd -c /etc/nginx/.htpasswd admin
# 添加更多用户
sudo htpasswd /etc/nginx/.htpasswd user2
URL 重写(rewrite)
rewrite 指令语法
# rewrite 语法
# rewrite regex replacement [flag];
# flag 选项:
# last - 重写后重新搜索 location(内部重定向)
# break - 停止处理后续 rewrite 指令
# redirect - 302 临时重定向
# permanent - 301 永久重定向
常见重写场景
server {
listen 80;
server_name example.com www.example.com;
root /var/www/html;
# 1. 强制添加 www
if ($host = 'example.com') {
rewrite ^(.*)$ http://www.example.com$1 permanent;
}
# 2. 强制去除 www
if ($host = 'www.example.com') {
rewrite ^(.*)$ http://example.com$1 permanent;
}
# 3. 强制 HTTPS
if ($scheme = 'http') {
rewrite ^(.*)$ https://$host$1 permanent;
}
# 4. 添加尾部斜杠
rewrite ^([^.]*[^/])$ $1/ permanent;
# 5. 移除尾部斜杠
rewrite ^/(.*)/$ /$1 permanent;
# 6. 旧 URL 重定向到新 URL
rewrite ^/old-page\.html$ /new-page/ permanent;
rewrite ^/blog/(\d{4})/(\d{2})/(.*)$ /articles/$1-$2-$3 permanent;
# 7. 移除 .html 扩展名
rewrite ^(/.*)\.html$ $1 permanent;
location / {
try_files $uri $uri.html $uri/ =404;
}
# 8. SEO 友好的 URL
# /product/123 -> /product.php?id=123
rewrite ^/product/(\d+)$ /product.php?id=$1 last;
# 9. 伪静态
# /article-123.html -> /article.php?id=123
rewrite ^/article-(\d+)\.html$ /article.php?id=$1 last;
}
return 指令
server {
listen 80;
server_name example.com;
# 返回指定状态码
location /deprecated {
return 410; # Gone
}
# 返回文本
location /health {
return 200 "OK";
}
# JSON 响应
location /api/status {
default_type application/json;
return 200 '{"status": "healthy", "version": "1.0.0"}';
}
# 重定向
location /old {
return 301 https://new.example.com$request_uri;
}
# 临时重定向
location /maintenance {
return 302 /maintenance.html;
}
# 关闭连接(不发送响应)
location /blocked {
return 444;
}
}
try_files 指令
server {
listen 80;
server_name example.com;
root /var/www/html;
index index.html;
# 基本用法
location / {
# 依次尝试:
# 1. 查找 $uri 文件
# 2. 查找 $uri/ 目录(使用 index 指令)
# 3. 回退到 /index.html
try_files $uri $uri/ /index.html;
}
# SPA 应用(Vue、React)
location / {
try_files $uri $uri/ /index.html;
}
# PHP 应用
location / {
try_files $uri $uri/ /index.php?$query_string;
}
# 命名 location 回退
location / {
try_files $uri @backend;
}
location @backend {
proxy_pass http://127.0.0.1:8080;
}
# 多级回退
location /images/ {
try_files $uri /images/default.jpg =404;
}
# 带参数的回退
location / {
try_files $uri $uri/ /index.php?q=$uri&$args;
}
}
访问控制
IP 访问控制
server {
listen 80;
server_name admin.example.com;
# 白名单模式
location / {
# 允许的 IP
allow 192.168.1.0/24;
allow 10.0.0.0/8;
allow 127.0.0.1;
# 拒绝其他所有
deny all;
}
# 黑名单模式
location /public/ {
# 拒绝特定 IP
deny 192.168.1.100;
deny 10.10.10.0/24;
# 允许其他所有
allow all;
}
}
# 使用 geo 模块进行复杂 IP 控制
http {
geo $allowed {
default 0;
127.0.0.1 1;
192.168.0.0/16 1;
10.0.0.0/8 1;
}
server {
location /admin/ {
if ($allowed = 0) {
return 403;
}
}
}
}
HTTP 基本认证
server {
listen 80;
server_name secure.example.com;
# 全站认证
auth_basic "Restricted Area";
auth_basic_user_file /etc/nginx/.htpasswd;
location / {
root /var/www/secure;
}
# 特定路径认证
location /admin/ {
auth_basic "Admin Area";
auth_basic_user_file /etc/nginx/.htpasswd-admin;
}
# 公开路径(取消认证)
location /public/ {
auth_basic off;
}
# 结合 IP 白名单
location /internal/ {
satisfy any; # 满足任一条件即可(all 表示全部满足)
allow 192.168.1.0/24;
deny all;
auth_basic "Internal Area";
auth_basic_user_file /etc/nginx/.htpasswd;
}
}
请求方法限制
server {
listen 80;
server_name api.example.com;
# 只允许 GET 和 POST
location / {
limit_except GET POST {
deny all;
}
}
# 静态资源只允许 GET
location /static/ {
limit_except GET HEAD {
deny all;
}
}
# 使用 if 判断
location /api/ {
if ($request_method !~ ^(GET|POST|PUT|DELETE)$) {
return 405;
}
}
}
User-Agent 限制
http {
# 定义爬虫 User-Agent
map $http_user_agent $bad_bot {
default 0;
~*crawl 1;
~*spider 1;
~*bot 1;
~*slurp 1;
~*wget 1;
~*curl 1;
"" 1; # 空 User-Agent
}
server {
# 阻止恶意爬虫
if ($bad_bot) {
return 403;
}
# 或者返回假数据
location / {
if ($bad_bot) {
return 200 "Fake content for bots";
}
try_files $uri $uri/ =404;
}
}
}
Referer 防盗链
server {
listen 80;
server_name example.com;
# 图片防盗链
location ~* \.(jpg|jpeg|png|gif|webp)$ {
# 检查 Referer
valid_referers none blocked server_names
*.example.com
example.com
~\.google\.
~\.baidu\.;
if ($invalid_referer) {
# 返回 403
return 403;
# 或返回防盗链图片
# rewrite ^/.*$ /images/hotlink-denied.jpg break;
}
root /var/www/images;
expires 30d;
}
}
valid_referers 参数说明:
| 参数 | 说明 |
|---|---|
| none | 允许空 Referer(直接访问) |
| blocked | 允许被防火墙删除了 Referer 的请求 |
| server_names | 允许当前 server_name 列表 |
| 字符串 | 允许指定域名 |
| ~正则 | 正则匹配 |
错误页面处理
自定义错误页面
server {
listen 80;
server_name example.com;
root /var/www/html;
# 自定义错误页面
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
# 错误页面位置
location = /404.html {
root /var/www/errors;
internal; # 只能内部访问
}
location = /50x.html {
root /var/www/errors;
internal;
}
# 错误页面重定向到其他 URL
error_page 404 = @fallback;
location @fallback {
proxy_pass http://backend;
}
# 错误页面指向外部 URL
error_page 404 https://example.com/not-found;
}
动态错误页面
server {
listen 80;
server_name example.com;
# 传递状态码给后端
error_page 404 = /error-handler.php?error=404;
error_page 500 = /error-handler.php?error=500;
# PHP 处理错误
location ~ \.php$ {
fastcgi_pass unix:/var/run/php-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
# 使用命名 location
error_page 404 = @error_handler;
location @error_handler {
proxy_pass http://127.0.0.1:8080/errors$request_uri;
proxy_set_header X-Original-URI $request_uri;
proxy_set_header X-Error-Status 404;
}
}
优雅降级
server {
listen 80;
server_name example.com;
root /var/www/html;
# 主站
location / {
proxy_pass http://backend;
proxy_intercept_errors on;
# 后端错误时显示静态页面
error_page 500 502 503 504 = @static_fallback;
}
location @static_fallback {
root /var/www/fallback;
try_files /maintenance.html =503;
}
# API 优雅降级
location /api/ {
proxy_pass http://api-backend;
proxy_intercept_errors on;
error_page 502 503 504 = @api_fallback;
}
location @api_fallback {
default_type application/json;
return 503 '{"error": "Service temporarily unavailable", "retry_after": 60}';
}
}
配置示例
静态网站完整配置
server {
listen 80;
listen [::]:80;
server_name www.example.com example.com;
# 强制 www
if ($host = 'example.com') {
return 301 http://www.example.com$request_uri;
}
root /var/www/example;
index index.html index.htm;
charset utf-8;
# 日志
access_log /var/log/nginx/example.access.log main buffer=32k;
error_log /var/log/nginx/example.error.log;
# 主页面
location / {
try_files $uri $uri/ /index.html;
}
# HTML 不缓存
location ~* \.html?$ {
expires -1;
add_header Cache-Control "no-store, no-cache, must-revalidate";
}
# 静态资源缓存
location ~* \.(css|js)$ {
expires 7d;
add_header Cache-Control "public, immutable";
gzip_static on;
}
location ~* \.(jpg|jpeg|png|gif|ico|webp|svg)$ {
expires 30d;
add_header Cache-Control "public, immutable";
access_log off;
}
location ~* \.(woff|woff2|ttf|eot)$ {
expires 365d;
add_header Cache-Control "public, immutable";
add_header Access-Control-Allow-Origin *;
access_log off;
}
# 安全设置
location ~ /\. {
deny all;
access_log off;
log_not_found off;
}
# 错误页面
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
location = /404.html {
internal;
}
location = /50x.html {
internal;
}
}
SPA 应用配置
server {
listen 80;
server_name app.example.com;
root /var/www/spa;
index index.html;
# Gzip 压缩
gzip on;
gzip_types text/plain text/css application/json
application/javascript text/xml application/xml;
gzip_min_length 1024;
# 主路由 - 所有路径都返回 index.html
location / {
try_files $uri $uri/ /index.html;
}
# API 代理
location /api/ {
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;
}
# 静态资源
location /assets/ {
expires 1y;
add_header Cache-Control "public, immutable";
access_log off;
}
# JS 和 CSS(带 hash 的文件)
location ~* \.[a-f0-9]{8,}\.(js|css)$ {
expires 1y;
add_header Cache-Control "public, immutable";
access_log off;
}
# 图片
location ~* \.(jpg|jpeg|png|gif|ico|webp|svg)$ {
expires 30d;
add_header Cache-Control "public";
access_log off;
}
# 安全头
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
# 禁止访问隐藏文件
location ~ /\. {
deny all;
}
}
多语言站点配置
http {
# 根据 Accept-Language 设置语言
map $http_accept_language $lang {
default en;
~^zh zh;
~^ja ja;
~^ko ko;
}
server {
listen 80;
server_name example.com;
root /var/www/i18n;
# 自动跳转到对应语言版本
location = / {
return 302 /$lang/;
}
# 各语言版本
location ~ ^/(en|zh|ja|ko)/ {
try_files $uri $uri/ /$1/index.html;
}
# 语言切换 cookie
location /set-lang/ {
if ($arg_lang) {
add_header Set-Cookie "lang=$arg_lang; Path=/; Max-Age=31536000";
}
return 302 /;
}
}
}
总结
本章介绍了 Nginx 作为 Web 服务器的核心功能:
- 静态资源服务:文件类型处理、sendfile 优化、文件描述符缓存
- 虚拟主机:基于域名、端口、IP 的配置,泛域名支持
- 目录浏览:autoindex 配置、美化、安全设置
- URL 重写:rewrite 指令、return、try_files
- 访问控制:IP 限制、认证、方法限制、防盗链
- 错误处理:自定义错误页面、优雅降级