Nginx 静态文件服务

Nginx 静态文件服务配置和优化


📋 目录


基础配置

最简单的静态文件服务

server {
    listen 80;
    server_name static.example.com;
 
    root /var/www/static;
    index index.html index.htm;
 
    location / {
        try_files $uri $uri/ =404;
    }
}

多目录静态文件服务

server {
    listen 80;
    server_name assets.example.com;
 
    # 静态资源目录
    location /images/ {
        root /var/www/assets;
        try_files $uri $uri/ =404;
    }
 
    location /css/ {
        root /var/www/assets;
        try_files $uri $uri/ =404;
    }
 
    location /js/ {
        root /var/www/assets;
        try_files $uri $uri/ =404;
    }
 
    location /fonts/ {
        root /var/www/assets;
        try_files $uri $uri/ =404;
    }
}

使用别名 (Alias)

server {
    listen 80;
    server_name assets.example.com;
 
    # Alias 方式
    location /images/ {
        alias /var/www/static/images/;  # 注意最后的斜杠
    }
 
    # 多个目录合并
    location /assets/ {
        alias /var/www/static/;  # /assets/logo.png → /var/www/static/logo.png
    }
}

Root vs Alias:

# Root 方式
location /images/ {
    root /var/www/static;  # /images/logo.png → /var/www/static/images/logo.png
}
 
# Alias 方式
location /images/ {
    alias /var/www/static/images/;  # /images/logo.png → /var/www/static/images/logo.png
}

文件类型处理

MIME 类型配置

http {
    include mime.types;  # 包含 MIME 类型定义
    default_type application/octet-stream;  # 默认类型
 
    # 自定义 MIME 类型
    types {
        text/html                             html htm shtml;
        text/css                              css;
        text/xml                              xml rss;
        image/gif                             gif;
        image/jpeg                            jpeg jpg;
        application/javascript                js;
        application/json                      json map;
        font/woff2                            woff2;
        font/woff                             woff;
        font/ttf                              ttf;
        font/otf                              otf;
        font/eot                              eot;
        image/svg+xml                         svg svgz;
        image/x-icon                          ico;
    }
}

默认文件 (Index)

server {
    listen 80;
    server_name example.com;
 
    root /var/www/html;
 
    # 默认首页
    index index.html index.htm index.php;
 
    location / {
        try_files $uri $uri/ @index;
    }
 
    location @index {
        rewrite ^ /index.html break;
    }
}

默认文档处理

server {
    root /var/www/html;
 
    # 方式 1: 使用 try_files
    location / {
        try_files $uri $uri/ /index.html;
    }
 
    # 方式 2: 使用 error_page
    location / {
        try_files $uri $uri/ =404;
        error_page 404 /index.html;
    }
 
    # 方式 3: 使用 rewrite (SPA 应用)
    location / {
        try_files $uri $uri/ @spa;
    }
 
    location @spa {
        rewrite ^ /index.html break;
    }
}

目录浏览

启用目录浏览

server {
    listen 80;
    server_name files.example.com;
 
    root /var/www/files;
 
    location / {
        autoindex on;                          # 启用目录浏览
        autoindex_exact_size off;              # 人性化显示文件大小
        autoindex_localtime on;                # 显示本地时间
        autoindex_format html;                 # HTML 格式
    }
}

目录浏览美化

server {
    listen 80;
    server_name files.example.com;
 
    root /var/www/files;
 
    location / {
        autoindex on;
        autoindex_exact_size off;
        autoindex_localtime on;
 
        # 添加头部信息
        add_header X-Frame-Options "SAMEORIGIN" always;
 
        # 隐藏特定文件
        location ~ /\. {
            deny all;
        }
 
        location ~ \.tmp$ {
            deny all;
        }
    }
}

FancyIndex 美化(需要第三方模块)

server {
    listen 80;
    server_name files.example.com;
 
    root /var/www/files;
 
    location / {
        fancyindex on;                          # 启用 FancyIndex
        fancyindex_exact_size off;              # 人性化大小
        fancyindex_localtime on;                # 本地时间
        fancyindex_name_length 255;             # 文件名长度
        fancyindex_header /fancyindex/header.html;
        fancyindex_footer /fancyindex/footer.html;
        fancyindex_css_href /fancyindex/style.css;
    }
}

缓存控制

基础缓存配置

server {
    listen 80;
    server_name static.example.com;
 
    root /var/www/static;
 
    # 根据文件类型设置缓存
    location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
        expires 1y;                          # 缓存 1 年
        add_header Cache-Control "public, immutable";
    }
 
    location ~* \.(woff|woff2|ttf|otf|eot|svg)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }
 
    # HTML 文件缓存较短时间
    location ~* \.html$ {
        expires 1h;
        add_header Cache-Control "public, must-revalidate";
    }
}

动态缓存控制

server {
    root /var/www/static;
 
    # 使用 map 设置缓存时间
    map $request_uri $cache_time {
        default 0;                           # 不缓存
        ~^/static/ 1y;                       # 静态资源缓存 1 年
        ~*\.(jpg|jpeg|png|gif|css|js)$ 1y;  # 图片和样式缓存 1 
        ~*\.html$ 1h;                        # HTML 缓存 1 小时
    }
 
    location / {
        expires $cache_time;
        try_files $uri $uri/ =404;
    }
}

浏览器缓存控制

server {
    root /var/www/static;
 
    # 版本化文件(带版本号)
    location ~* \.v\d+\.(js|css)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }
 
    # 不缓存的文件
    location ~* \.nocache\.(js|css)$ {
        expires -1;                          # 不缓存
        add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0";
    }
 
    # 通用静态资源
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }
}

缓存清理

# 清理缓存接口(需要 nginx-plus 或第三方模块)
server {
    listen 80;
    server_name static.example.com;
 
    location / {
        root /var/www/static;
        try_files $uri $uri/ =404;
    }
 
    # 缓存清理接口
    location ~ /purge(/.*) {
        allow 127.0.0.1;          # 只允许本地访问
        allow 192.168.1.0/24;     # 允许内网
        deny all;                 # 拒绝其他
 
        proxy_cache_purge cache_one $1$is_args$args;
    }
}

范围请求

启用范围请求

server {
    listen 80;
    server_name static.example.com;
 
    root /var/www/static;
 
    # 默认已启用范围请求
    location ~* \.(mp4|mp3|pdf)$ {
        # 对于大文件,启用异步 I/O
        aio on;
        directio 512k;
 
        # 启用线程池(如果编译时包含)
        # thread_pool default threads=32 max_queue=65536;
        # aio threads=default;
    }
}

视频流媒体

server {
    listen 80;
    server_name video.example.com;
 
    root /var/www/videos;
 
    # MP4 流媒体
    location ~* \.mp4$ {
        mp4;                      # 启用 MP4 模块
        mp4_buffer_size 1m;       # MP4 缓冲区大小
        mp4_max_buffer_size 10m;  # MP4 最大缓冲区
    }
 
    # FLV 流媒体
    location ~* \.flv$ {
        flv;                      # 启用 FLV 模块
    }
 
    # HLS 流媒体
    location /hls/ {
        types {
            application/vnd.apple.mpegurl m3u8;
            video/mp2t ts;
        }
        root /var/www/hls;
        add_header Cache-Control no-cache;
        add_header Access-Control-Allow-Origin *;
    }
}

文件压缩

Gzip 压缩

http {
    gzip on;                           # 启用 Gzip
    gzip_vary on;                      # 添加 Vary 头
    gzip_min_length 1024;              # 最小压缩大小
    gzip_comp_level 6;                 # 压缩级别(1-9)
 
    # 压缩类型
    gzip_types
        text/plain
        text/css
        text/xml
        text/javascript
        application/javascript
        application/json
        application/xml+rss
        application/atom+xml
        image/svg+xml;
 
    # 禁用 IE6 压缩
    gzip_disable "msie6";
 
    # 代理请求压缩
    gzip_proxied any;
 
    # 分片压缩(HTTP/1.1)
    gzip_http_version 1.1;
 
    # 使用磁盘缓存压缩结果
    # gzip_static on;  # 需要预压缩文件
}

Brotli 压缩(需要第三方模块)

http {
    # Brotli 压缩
    brotli on;
    brotli_comp_level 6;               # 压缩级别(1-11)
    brotli_min_length 100;             # 最小压缩大小
 
    # Brotli 压缩类型
    brotli_types
        text/plain
        text/css
        text/xml
        text/javascript
        application/javascript
        application/json
        application/xml+rss
        application/atom+xml
        image/svg+xml
        font/opentype
        font/ttf;
 
    # Brotli 静态文件
    brotli_static on;
}

预压缩文件

# 创建预压缩文件
gzip -k -9 index.html  # 保留原文件,创建 index.html.gz
brotli -k -q 11 index.html  # 保留原文件,创建 index.html.br
server {
    root /var/www/html;
 
    # 自动选择最佳压缩格式
    location ~* \.(html|css|js|xml|json)$ {
        # 优先使用 Brotli
        add_header Vary "Accept-Encoding";
 
        # Brotli 静态文件
        brotli_static on;
        brotli_types *;
 
        # Gzip 静态文件
        gzip_static on;
        gzip_types *;
 
        expires 1d;
    }
}

性能优化

文件传输优化

http {
    # 启用 sendfile
    sendfile on;
 
    # 优化包发送
    tcp_nopush on;    # 与 sendfile 一起使用
    tcp_nodelay on;   # 禁用 Nagle 算法
 
    # 文件缓冲区大小
    output_buffers 1 32k;
 
    # 异步 I/O
    aio on;
    directio 4m;      # 大于 4M 的文件使用直接 I/O
 
    # 线程池(需要编译时包含)
    # thread_pool default threads=32 max_queue=65536;
    # aio threads=default;
}

缓存优化

http {
    # 打开文件缓存
    open_file_cache max=10000 inactive=30s;
    open_file_cache_valid 60s;
    open_file_cache_min_uses 2;
    open_file_cache_errors on;
 
    # 文件描述符缓存
    open_file_cache max=65536 inactive=60s;
}
 
server {
    listen 80;
    server_name static.example.com;
 
    root /var/www/static;
 
    location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
 
        # 文件缓存
        open_file_cache_valid 30d;
        open_file_cache_min_uses 5;
    }
}

访问控制

server {
    root /var/www/static;
 
    # 限制访问
    location ~ /\. {
        deny all;                          # 禁止访问隐藏文件
        access_log off;
        log_not_found off;
    }
 
    location ~ \.php$ {
        deny all;                          # 禁止直接访问 PHP 文件
    }
 
    location ~ \.sh$ {
        deny all;                          # 禁止访问脚本文件
    }
 
    location ~ /private/ {
        internal;                          # 只允许内部访问
    }
 
    # 限制特定 IP
    location /admin/ {
        allow 192.168.1.0/24;              # 允许内网
        deny all;                          # 拒绝其他
    }
}

防盗链

server {
    root /var/www/static;
 
    # 防盗链
    location ~* \.(jpg|jpeg|png|gif|bmp|swf|flv|rar|zip|doc|pdf|gz|bz2|exe|mp4|mkv|avi|rmvb)$ {
        valid_referers none blocked server_names
                       *.example.com
                       ~\.google\. ~\.baidu\.;
 
        if ($invalid_referer) {
            return 403;
            # 或者返回其他图片
            # rewrite ^/ https://example.com/forbidden.png;
        }
 
        expires 7d;
        access_log off;
    }
}

下载限速

server {
    root /var/www/static;
 
    # 下载限速
    location ~* \.(mp4|mp3|zip|rar|exe)$ {
        limit_rate 1m;              # 限速 1MB/s
        limit_rate_after 5m;        # 下载 5MB 后开始限速
 
        expires 7d;
        access_log off;
    }
}

跨域配置

server {
    root /var/www/static;
 
    # 跨域资源共享(CORS)
    location ~* \.(ttf|ttc|otf|eot|woff|woff2|svg)$ {
        add_header Access-Control-Allow-Origin *;
        add_header Access-Control-Allow-Methods "GET, POST, OPTIONS";
        add_header Access-Control-Allow-Headers "Origin, X-Requested-With, Content-Type, Accept, Authorization";
 
        # 处理预检请求
        if ($request_method = 'OPTIONS') {
            return 204;
        }
 
        expires 1y;
    }
 
    # 图片跨域
    location ~* \.(jpg|jpeg|png|gif|bmp|webp)$ {
        add_header Access-Control-Allow-Origin *;
        expires 1y;
    }
}

🔧 高级技巧

多个目录合并

server {
    listen 80;
    server_name assets.example.com;
 
    # 根据文件类型从不同目录提供
    location ~* \.(jpg|jpeg|png|gif)$ {
        root /var/www/images;
        try_files $uri @fallback;
    }
 
    location ~* \.(css|js)$ {
        root /var/www/static;
        try_files $uri @fallback;
    }
 
    location ~* \.(woff|woff2|ttf|eot)$ {
        root /var/www/fonts;
        try_files $uri @fallback;
    }
 
    location @fallback {
        # 回退到默认目录
        root /var/www/default;
        try_files $uri =404;
    }
}

根据 Referer 提供不同资源

server {
    root /var/www/static;
 
    # 根据 Referer 设置不同的资源目录
    map $http_referer $static_dir {
        default "default";
        ~*example1\.com "example1";
        ~*example2\.com "example2";
    }
 
    location ~* \.(css|js|png|jpg|jpeg|gif)$ {
        root /var/www/$static_dir;
        try_files $uri @default;
    }
 
    location @default {
        root /var/www/default;
        try_files $uri =404;
    }
}

动态生成缩略图

server {
    root /var/www/images;
 
    # 动态生成缩略图(需要配合后端脚本)
    location ~* ^/thumb/(\d+)x(\d+)/(.*)$ {
        set $width $1;
        set $height $2;
        set $image $3;
 
        # 检查缩略图是否存在
        try_files /cache/thumb/$width/${image} @generate_thumb;
    }
 
    location @generate_thumb {
        # 调用后端脚本生成缩略图
        proxy_pass http://thumb_backend/generate?w=$width&h=$height&img=$image;
        proxy_cache thumb_cache;
        proxy_cache_valid 200 7d;
    }
}

图片懒加载支持

server {
    root /var/www/images;
 
    # 占位图
    location ~* ^/placeholder/(\d+)x(\d+)\.png$ {
        empty_gif;  # 返回 1x1 透明 GIF
        # 或者返回指定大小的占位图
        # rewrite ^ /placeholder.png break;
    }
 
    # 懒加载真实图片
    location ~* \.(jpg|jpeg|png|gif|webp)$ {
        # 检查是否是懒加载请求
        if ($http_x_lazy_load = "true") {
            # 返回低质量图片(需要后端支持)
            proxy_pass http://image_processor/low_quality?$request_uri;
            break;
        }
 
        try_files $uri =404;
    }
}

📚 相关链接


相关笔记