Nginx 教程

纯干货教学,从零开始学习 Nginx

Nginx 高级配置

掌握 Nginx 的高级配置选项和特性

Nginx 重写规则 (rewrite)

rewrite 指令用于修改请求的 URI,支持正则表达式匹配和重定向。

基本语法

rewrite regex replacement [flag];

常用标志

  • last - 停止处理当前 rewrite 指令,开始搜索与新 URI 匹配的 location
  • break - 停止处理当前 rewrite 指令,继续执行当前 location 块中的其他指令
  • redirect - 返回 302 临时重定向
  • permanent - 返回 301 永久重定向

rewrite 示例

server {
    listen 80;
    server_name example.com;
    
    # 将 HTTP 重定向到 HTTPS
    rewrite ^ https://$server_name$request_uri? permanent;
    
    # 移除 URL 中的 www 前缀
    server_name www.example.com example.com;
    if ($host = 'www.example.com') {
        rewrite ^ https://example.com$request_uri? permanent;
    }
    
    # 重写友好 URL
    location / {
        rewrite ^/products/([0-9]+)/?$ /product.php?id=$1 last;
        rewrite ^/categories/([a-z]+)/?$ /category.php?name=$1 last;
    }
}

访问控制配置

基于 IP 的访问控制

server {
    listen 80;
    server_name example.com;
    
    # 允许特定 IP 访问
    location /admin {
        allow 192.168.1.1;
        allow 10.0.0.0/24;
        deny all;
        root /var/www/admin;
        index index.html;
    }
    
    # 禁止特定 IP 访问
    location /private {
        deny 192.168.1.100;
        allow all;
        root /var/www/private;
        index index.html;
    }
}

基于密码的访问控制

server {
    listen 80;
    server_name example.com;
    
    # 密码保护目录
    location /secure {
        auth_basic "Restricted Area";
        auth_basic_user_file /etc/nginx/.htpasswd;
        root /var/www/secure;
        index index.html;
    }
}

创建密码文件

使用 htpasswd 命令创建密码文件:

# 安装 apache2-utils(包含 htpasswd 命令)
sudo apt install apache2-utils  # Ubuntu/Debian
sudo yum install httpd-tools    # CentOS/RHEL

# 创建密码文件并添加用户
sudo htpasswd -c /etc/nginx/.htpasswd admin

# 添加新用户(不覆盖现有文件)
sudo htpasswd /etc/nginx/.htpasswd user1

# 查看密码文件内容
cat /etc/nginx/.htpasswd

Nginx 缓存配置

代理缓存配置

http {
    # 配置代理缓存
    proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m max_size=10g inactive=60m use_temp_path=off;
    
    server {
        listen 80;
        server_name example.com;
        
        location / {
            proxy_pass http://localhost:3000;
            proxy_cache my_cache;
            proxy_cache_valid 200 302 10m;
            proxy_cache_valid 404 1m;
            proxy_cache_key "$scheme$request_method$host$request_uri";
            add_header X-Cache-Status $upstream_cache_status;
        }
    }
}

FastCGI 缓存配置(用于 PHP)

http {
    # 配置 FastCGI 缓存
    fastcgi_cache_path /var/cache/nginx/fastcgi levels=1:2 keys_zone=fastcgi_cache:10m max_size=10g inactive=60m use_temp_path=off;
    
    server {
        listen 80;
        server_name example.com;
        root /var/www/html;
        index index.php;
        
        location ~ \.php$ {
            include fastcgi_params;
            fastcgi_pass unix:/run/php/php7.4-fpm.sock;
            fastcgi_index index.php;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            
            # 启用 FastCGI 缓存
            fastcgi_cache fastcgi_cache;
            fastcgi_cache_valid 200 60m;
            fastcgi_cache_key "$scheme$request_method$host$request_uri";
            add_header X-FastCGI-Cache $upstream_cache_status;
        }
    }
}

缓存清除

可以使用第三方模块如 ngx_cache_purge 来实现缓存清除功能:

http {
    proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m max_size=10g inactive=60m use_temp_path=off;
    
    server {
        listen 80;
        server_name example.com;
        
        # 缓存清除配置
        location ~ /purge(/.*) {
            allow 127.0.0.1;
            deny all;
            proxy_cache_purge my_cache "$scheme$request_method$host$1";
        }
        
        location / {
            proxy_pass http://localhost:3000;
            proxy_cache my_cache;
            # 其他缓存配置...
        }
    }
}

Nginx 限流配置

基于连接的限流

http {
    # 配置连接限制区域
    limit_conn_zone $binary_remote_addr zone=conn_limit_per_ip:10m;
    
    server {
        listen 80;
        server_name example.com;
        
        # 限制每个 IP 的并发连接数
        location / {
            limit_conn conn_limit_per_ip 10;
            root /var/www/html;
            index index.html;
        }
    }
}

基于请求的限流

http {
    # 配置请求限制区域
    limit_req_zone $binary_remote_addr zone=req_limit_per_ip:10m rate=10r/s;
    
    server {
        listen 80;
        server_name example.com;
        
        # 限制每个 IP 的请求速率
        location /api {
            limit_req zone=req_limit_per_ip burst=20 nodelay;
            proxy_pass http://localhost:3000;
        }
    }
}

限流参数说明

  • rate - 允许的请求速率,如 10r/s(每秒 10 个请求)
  • burst - 允许的突发请求数,超过 rate 的请求会被放入队列
  • nodelay - 当队列满时,直接返回错误而不是延迟处理

Nginx 变量和映射

内置变量

Nginx 提供了许多内置变量,可以在配置中使用:

$host          # 请求的主机名
$server_name   # 配置文件中定义的服务器名
$request_uri   # 完整的请求 URI,包括查询字符串
$uri           # 请求的 URI,不包括查询字符串
$args          # 请求的查询字符串
$remote_addr   # 客户端 IP 地址
$remote_port   # 客户端端口
$server_addr   # 服务器 IP 地址
$server_port   # 服务器端口
$scheme        # 请求协议(http 或 https)
$request_method # 请求方法(GET, POST 等)
$status        # 响应状态码
$body_bytes_sent # 发送的响应体字节数
$http_user_agent # 客户端 User-Agent
$http_referer  # 请求的 Referer 头

使用 map 指令

map 指令用于创建变量映射,基于一个变量的值设置另一个变量的值:

http {
    # 配置用户代理映射
    map $http_user_agent $is_mobile {
        default 0;
        ~*mobile 1;
        ~*android 1;
        ~*iphone 1;
        ~*ipad 1;
    }
    
    # 配置国家映射(基于 IP)
    map $remote_addr $country {
        default unknown;
        192.168.1.0/24 cn;
        10.0.0.0/24 local;
    }
    
    server {
        listen 80;
        server_name example.com;
        
        location / {
            # 根据设备类型提供不同内容
            if ($is_mobile) {
                rewrite ^ /mobile$request_uri? last;
            }
            
            root /var/www/html;
            index index.html;
        }
        
        location /mobile {
            root /var/www;
            index index.html;
        }
    }
}

Nginx 高级模块配置

启用 Gzip 压缩

http {
    # Gzip 压缩配置
    gzip on;
    gzip_comp_level 6;
    gzip_min_length 1000;
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
    gzip_vary on;
    gzip_proxied any;
    gzip_disable "MSIE [1-6]\.";
    
    # 其他配置...
}

启用 Brotli 压缩(需要安装模块)

http {
    # Brotli 压缩配置
    brotli on;
    brotli_comp_level 6;
    brotli_min_length 1000;
    brotli_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
    
    # 其他配置...
}

配置 HTTP/2

server {
    listen 443 ssl http2;
    server_name example.com;
    
    # SSL 配置
    ssl_certificate /etc/nginx/ssl/example.com.crt;
    ssl_certificate_key /etc/nginx/ssl/example.com.key;
    
    # 其他配置...
}

Nginx 配置优化

工作进程配置

# 主配置文件顶部
user nginx;
# 设置为 CPU 核心数
worker_processes auto;
# 绑定工作进程到特定 CPU 核心
worker_cpu_affinity auto;
# 最大打开文件数
worker_rlimit_nofile 65536;

events {
    # 每个工作进程的最大连接数
    worker_connections 10240;
    # 使用 epoll 事件模型(Linux)
    use epoll;
    # 允许多个连接同时接受
    multi_accept on;
}

HTTP 核心优化

http {
    # 隐藏 Nginx 版本号
    server_tokens off;
    
    # 启用 sendfile
    sendfile on;
    # 启用 tcp_nopush
    tcp_nopush on;
    # 启用 tcp_nodelay
    tcp_nodelay on;
    
    # 连接超时设置
    keepalive_timeout 65;
    keepalive_requests 100;
    
    # 客户端请求体大小限制
    client_max_body_size 1m;
    
    # 缓冲区设置
    client_body_buffer_size 16k;
    client_header_buffer_size 1k;
    large_client_header_buffers 4 8k;
    
    # 其他配置...
}

实践练习

练习 1:配置 URL 重写

  1. 配置将 HTTP 重定向到 HTTPS
  2. 配置移除 URL 中的 www 前缀
  3. 配置友好的产品详情页 URL,如 /product/123 重写到 /product.php?id=123
  4. 测试重写规则是否生效

练习 2:配置访问控制

  1. 创建一个需要密码保护的目录
  2. 使用 htpasswd 创建密码文件
  3. 配置基于 IP 的访问控制,只允许特定 IP 访问管理后台
  4. 测试访问控制是否生效

练习 3:配置缓存和限流

  1. 配置代理缓存,缓存后端 API 的响应
  2. 配置请求限流,限制每个 IP 的请求速率
  3. 测试缓存是否生效(检查响应头中的 X-Cache-Status)
  4. 测试限流是否生效(快速发送多个请求)

常见问题解答

Q: 如何调试 rewrite 规则?

A: 可以在配置中添加以下指令来启用 rewrite 日志:

http {
    # 启用 rewrite 日志
    rewrite_log on;
    # 设置错误日志级别为 notice
    error_log /var/log/nginx/error.log notice;
    
    # 其他配置...
}

Q: 如何处理大文件上传?

A: 需要调整客户端请求体大小限制:

http {
    # 允许上传 100MB 的文件
    client_max_body_size 100m;
    
    # 其他配置...
}

Q: 如何配置 Nginx 作为文件服务器?

A: 可以使用 autoindex 指令启用目录浏览:

server {
    listen 80;
    server_name files.example.com;
    root /var/www/files;
    
    # 启用目录浏览
    location / {
        autoindex on;
        autoindex_exact_size off;
        autoindex_localtime on;
    }
}