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.brserver {
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;
}
}