核心指令
本章将详细介绍 Nginx 的核心配置指令,理解这些指令对于正确配置 Nginx 至关重要。
请求处理指令
root 和 alias
这两个指令用于指定文件路径,但行为不同:
# root - 将 URI 追加到路径后面
location /images/ {
root /var/www;
# 请求 /images/photo.jpg -> /var/www/images/photo.jpg
}
# alias - 用指定路径替换匹配部分
location /images/ {
alias /var/www/pictures/;
# 请求 /images/photo.jpg -> /var/www/pictures/photo.jpg
}
重要区别:
# root 示例
location /static/ {
root /var/www;
# /static/file.css -> /var/www/static/file.css
}
# alias 示例
location /static/ {
alias /var/www/assets/;
# /static/file.css -> /var/www/assets/file.css
}
解释:
root保留原始 URI,只添加根路径alias替换匹配的 location 部分- 使用
alias时,location 通常需要以/结尾
index
指定默认首页文件:
# 单个文件
index index.html;
# 多个文件(按顺序查找)
index index.html index.htm index.php;
# 带变量
index index.$geo.html index.html;
try_files
按顺序检查文件是否存在:
# 基本用法
location / {
try_files $uri $uri/ /index.html;
# 1. 检查 $uri 文件
# 2. 检查 $uri/ 目录
# 3. 都不存在,返回 /index.html
}
# 带状态码
location / {
try_files $uri $uri/ =404;
# 都不存在返回 404
}
# 代理到后端
location / {
try_files $uri $uri/ @backend;
}
location @backend {
proxy_pass http://127.0.0.1:8080;
}
解释:try_files 是处理 SPA 应用路由的关键指令。
日志指令
access_log
配置访问日志:
# 基本配置
access_log /var/log/nginx/access.log;
# 指定格式
access_log /var/log/nginx/access.log main;
# 关闭日志
access_log off;
# 多个日志
access_log /var/log/nginx/access.log main;
access_log /var/log/nginx/analytics.log analytics;
# 缓冲写入
access_log /var/log/nginx/access.log main buffer=16k flush=5s;
# 条件日志(跳过静态资源)
map $uri $is_static {
~*\.(jpg|jpeg|png|gif|css|js)$ 1;
default 0;
}
access_log /var/log/nginx/access.log main if=$is_static;
error_log
配置错误日志:
# 全局配置
error_log /var/log/nginx/error.log warn;
# 日志级别
error_log /var/log/nginx/error.log debug; # 最详细
error_log /var/log/nginx/error.log info;
error_log /var/log/nginx/error.log notice;
error_log /var/log/nginx/error.log warn; # 推荐
error_log /var/log/nginx/error.log error;
error_log /var/log/nginx/error.log crit;
error_log /var/log/nginx/error.log alert;
error_log /var/log/nginx/error.log emerg; # 最严重
# 关闭错误日志
error_log /dev/null crit;
log_format
自定义日志格式:
# 基本格式
log_format main '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent"';
# 详细格式
log_format detailed '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'request_time=$request_time '
'upstream_time=$upstream_response_time '
'upstream_addr=$upstream_addr';
# JSON 格式(便于日志分析)
log_format json escape=json
'{"time":"$time_iso8601",'
'"remote_addr":"$remote_addr",'
'"request":"$request",'
'"status":$status,'
'"body_bytes_sent":$body_bytes_sent,'
'"request_time":$request_time,'
'"http_user_agent":"$http_user_agent"}';
客户端指令
client_max_body_size
限制请求体大小:
# 全局设置
http {
client_max_body_size 8m;
}
# 特定 location
location /upload/ {
client_max_body_size 50m; # 上传接口允许更大文件
}
# 禁用限制(不推荐)
client_max_body_size 0;
解释:超过限制会返回 413 Request Entity Too Large 错误。
client_body_buffer_size
请求体缓冲区大小:
client_body_buffer_size 16k;
# 小于此大小的请求体会存入内存
# 超过则写入临时文件
client_header_buffer_size
请求头缓冲区:
client_header_buffer_size 1k;
large_client_header_buffers 4 8k;
# 单个请求头不超过 1k
# 总请求头不超过 4*8k
超时指令
连接超时
# 客户端保持连接超时
keepalive_timeout 65s;
# 读取客户端请求超时
client_body_timeout 60s;
# 发送响应到客户端超时
send_timeout 60s;
# 读取客户端请求头超时
client_header_timeout 60s;
代理超时
location / {
proxy_pass http://backend;
# 连接后端超时
proxy_connect_timeout 60s;
# 读取后端响应超时
proxy_read_timeout 60s;
# 发送请求到后端超时
proxy_send_timeout 60s;
}
文件处理指令
sendfile
使用系统调用高效传输文件:
# 开启 sendfile(推荐)
sendfile on;
# 配合 tcp_nopush 使用
sendfile on;
tcp_nopush on;
tcp_nodelay on;
解释:
sendfile使用零拷贝技术,避免数据在内核和用户空间之间复制tcp_nopush在 sendfile 模式下,等待数据包填满再发送tcp_nodelay禁用 Nagle 算法,减少延迟
open_file_cache
文件描述符缓存:
open_file_cache max=1000 inactive=20s;
open_file_cache_valid 30s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
参数说明:
max:缓存的最大文件描述符数量inactive:非活跃条目的保留时间valid:检查缓存有效性的时间间隔min_uses:文件被访问多少次后才缓存
MIME 类型
types
配置文件扩展名和 MIME 类型的映射:
# 包含默认配置
include mime.types;
# 自定义类型
types {
text/html html htm;
text/css css;
application/javascript js;
application/json json;
image/jpeg jpeg jpg;
image/png png;
image/gif gif;
image/svg+xml svg;
application/pdf pdf;
}
# 默认类型
default_type application/octet-stream;
重写指令
rewrite
URL 重写:
# 基本语法
rewrite regex replacement [flag];
# 示例
rewrite ^/old/(.*)$ /new/$1 permanent; # 301 重定向
rewrite ^/old/(.*)$ /new/$1 redirect; # 302 重定向
rewrite ^/api/(.*)$ /v1/$1 last; # 内部重写
rewrite ^/download/(.*)$ /files/$1 break; # 停止处理
# 正则表达式
rewrite ^/users/(\d+)$ /user.php?id=$1 last;
rewrite ^/posts/(\w+)$ /post.php?slug=$1 last;
标志说明:
last:停止处理当前 rewrite,重新匹配 locationbreak:停止处理所有 rewriteredirect:返回 302 临时重定向permanent:返回 301 永久重定向
return
直接返回响应:
# 返回状态码
location /forbidden {
return 403;
}
# 返回重定向
location /old {
return 301 https://new.example.com$request_uri;
}
# 返回内容
location /health {
return 200 'OK';
add_header Content-Type text/plain;
}
# 关闭连接(不返回任何内容)
location / {
return 444;
}
if 条件
条件判断(谨慎使用):
# 正确用法
if ($request_method = POST) {
return 405;
}
if ($http_user_agent ~* "bot") {
return 403;
}
if ($http_x_forwarded_proto != "https") {
return 301 https://$host$request_uri;
}
# 检查文件是否存在
if (-f $request_filename) {
# 文件存在
}
if (!-f $request_filename) {
# 文件不存在
}
注意:if 指令在某些情况下会有意想不到的行为,尽量使用 try_files 或 map 替代。
map 指令
基本用法
# 根据变量值设置新变量
map $http_user_agent $is_mobile {
default 0;
~*mobile 1;
~*android 1;
~*iphone 1;
}
# 使用
server {
location / {
if ($is_mobile) {
return 301 https://m.example.com$request_uri;
}
}
}
常见模式
# 限流白名单
map $remote_addr $limit {
default $binary_remote_addr;
192.168.1.1 ""; # 不限流
10.0.0.0/8 ""; # 内网不限流
}
# 后端选择
map $cookie_backend $backend {
default backend_a;
"new" backend_b;
}
# 文件类型判断
map $uri $is_static {
default 0;
~*\.(jpg|jpeg|png|gif|css|js|woff2)$ 1;
}
split_clients
按比例分流:
split_clients "${remote_addr}" $variant {
10% "canary"; # 10% 流量
* "stable"; # 90% 流量
}
upstream canary {
server 192.168.1.101:8080;
}
upstream stable {
server 192.168.1.102:8080;
}
server {
location / {
proxy_pass http://$variant;
}
}
隐藏和添加头
add_header
添加响应头:
# 安全头
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
# CORS 头
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods "GET, POST, OPTIONS";
add_header Access-Control-Allow-Headers "Content-Type, Authorization";
# 自定义头
add_header X-Request-ID $request_id;
add_header X-Server $hostname;
注意:add_header 不会继承到嵌套的 location。
proxy_hide_header
隐藏后端返回的头:
location / {
proxy_pass http://backend;
proxy_hide_header X-Powered-By;
proxy_hide_header Server;
}
proxy_set_header
设置发送到后端的请求头:
location / {
proxy_pass http://backend;
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;
}
变量速查
请求变量
# 客户端信息
$remote_addr # 客户端 IP
$remote_port # 客户端端口
$remote_user # 认证用户名
# 请求信息
$request_method # 请求方法:GET, POST 等
$request_uri # 完整 URI(含参数)
$uri # URI(不含参数)
$args # 查询参数
$query_string # 同 $args
$request # 完整请求行
$request_length # 请求长度
$request_time # 请求处理时间
# 主机和协议
$host # 请求的主机名
$hostname # 服务器主机名
$scheme # 协议:http 或 https
$server_name # 服务器名称
$server_port # 服务器端口
$server_protocol # 协议版本:HTTP/1.1
# 请求头
$http_user_agent # User-Agent
$http_referer # Referer
$http_host # Host 头
$http_cookie # Cookie
$http_x_forwarded_for # X-Forwarded-For
$http_x_forwarded_proto # X-Forwarded-Proto
响应变量
$status # 响应状态码
$body_bytes_sent # 发送的字节数
$bytes_sent # 发送的总字节数
$content_length # Content-Length
$content_type # Content-Type
$upstream_addr # 后端地址
$upstream_status # 后端状态码
$upstream_response_time # 后端响应时间
其他变量
$connection # 连接序列号
$connection_requests # 连接的请求数
$time_local # 本地时间
$time_iso8601 # ISO 8601 时间
$msec # 毫秒时间戳
$request_id # 请求 ID(唯一)
$ssl_protocol # SSL 协议
$ssl_cipher # SSL 加密套件
$cookie_name # Cookie 值
小结
本章学习了:
- 路径指令(root、alias、index、try_files)
- 日志指令(access_log、error_log、log_format)
- 客户端指令(client_max_body_size 等)
- 超时指令
- 文件处理指令
- 重写指令(rewrite、return)
- 条件和映射(if、map)
- 头部处理指令
- 内置变量
练习
- 配置 try_files 实现 SPA 路由
- 自定义 JSON 格式的日志
- 使用 map 实现条件判断
- 配置安全响应头