静态资源服务 #

概述 #

Caddy 可以轻松配置静态文件服务,用于托管网站、图片、CSS、JavaScript 等静态资源。

text
┌─────────────────────────────────────────────────────────────┐
│                  Caddy 静态文件服务                          │
├─────────────────────────────────────────────────────────────┤
│  📁 文件服务 - 托管静态文件                                   │
│  📂 目录浏览 - 列出目录内容                                   │
│  🗜️ 压缩传输 - Gzip/Zstd 压缩                                │
│  📦 缓存控制 - 浏览器缓存配置                                 │
│  🔗 范围请求 - 断点续传支持                                   │
└─────────────────────────────────────────────────────────────┘

基本配置 #

最简单的静态站点 #

caddyfile
example.com {
    root * /var/www/html
    file_server
}

完整配置示例 #

caddyfile
example.com {
    # 设置根目录
    root * /var/www/html
    
    # 启用静态文件服务
    file_server {
        # 启用目录浏览
        browse
        
        # 预压缩文件
        precompressed
        
        # 自定义索引文件
        index index.html index.htm
    }
    
    # 启用压缩
    encode gzip zstd
    
    # 日志
    log {
        output file /var/log/caddy/access.log
    }
}

root 指令 #

基本用法 #

caddyfile
# 设置根目录
root * /var/www/html

# 使用变量
root * /var/www/{host}

动态根目录 #

caddyfile
example.com {
    # 根据主机名设置不同目录
    @sub host sub.example.com
    root @sub /var/www/sub
    root * /var/www/main
    
    file_server
}

匹配器使用 #

caddyfile
example.com {
    # 不同路径使用不同根目录
    root * /var/www/html
    
    handle /static/* {
        root * /var/www/static
        file_server
    }
    
    handle /assets/* {
        root * /var/www/assets
        file_server
    }
    
    handle {
        file_server
    }
}

file_server 指令 #

基本参数 #

caddyfile
example.com {
    root * /var/www/html
    
    file_server {
        # 启用目录浏览
        browse
        
        # 预压缩文件支持
        precompressed
        
        # 自定义索引文件
        index index.html index.htm default.html
        
        # 禁用目录浏览的排序
        browse {
            sort disabled
        }
    }
}

目录浏览 #

caddyfile
example.com {
    root * /var/www/files
    
    file_server browse {
        # 自定义模板
        template browse.html
    }
}

自定义目录浏览模板 #

caddyfile
example.com {
    root * /var/www/files
    
    file_server browse {
        template {
            # 使用内置变量
            # {path} - 当前路径
            # {files} - 文件列表
            # {dirs} - 目录列表
        }
    }
}

预压缩文件 #

Caddy 支持自动提供预压缩文件:

caddyfile
example.com {
    root * /var/www/html
    
    file_server {
        # 启用预压缩
        # 如果请求 style.css,且存在 style.css.gz
        # Caddy 会自动返回 .gz 文件
        precompressed
        
        # 指定预压缩格式
        precompressed gzip zstd br
    }
}
text
# 文件结构
/var/www/html/
├── style.css        # 原始文件
├── style.css.gz     # Gzip 压缩
├── style.css.br     # Brotli 压缩
└── style.css.zst    # Zstandard 压缩

压缩配置 #

基本压缩 #

caddyfile
example.com {
    root * /var/www/html
    file_server
    
    # 启用 Gzip 和 Zstd 压缩
    encode gzip zstd
}

压缩选项 #

caddyfile
example.com {
    root * /var/www/html
    file_server
    
    encode {
        # 压缩算法
        gzip 6          # Gzip 压缩级别 (1-9)
        zstd            # Zstandard 压缩
        
        # 排除特定类型
        except image/* video/* application/pdf
        
        # 最小压缩大小
        minimum_length 256
    }
}

条件压缩 #

caddyfile
example.com {
    root * /var/www/html
    file_server
    
    # 只压缩特定文件
    @compressable {
        path *.css *.js *.html *.xml *.json
    }
    encode @compressable gzip zstd
}

缓存控制 #

基本缓存配置 #

caddyfile
example.com {
    root * /var/www/html
    file_server
    
    # 静态资源长期缓存
    @static {
        path *.css *.js *.png *.jpg *.jpeg *.gif *.ico *.woff *.woff2
    }
    header @static Cache-Control "public, max-age=31536000, immutable"
    
    # HTML 文件短期缓存
    @html path *.html
    header @html Cache-Control "public, max-age=3600"
    
    # 禁用缓存
    @nocache path /api/*
    header @nocache Cache-Control "no-store, no-cache, must-revalidate"
}

ETag 支持 #

Caddy 自动为静态文件生成 ETag:

caddyfile
example.com {
    root * /var/www/html
    file_server
    
    # ETag 默认启用
    # 无需额外配置
}

Last-Modified 支持 #

Caddy 自动使用文件的修改时间作为 Last-Modified:

caddyfile
example.com {
    root * /var/www/html
    file_server
    
    # Last-Modified 默认启用
    # 无需额外配置
}

范围请求 #

Caddy 自动支持范围请求(断点续传):

caddyfile
example.com {
    root * /var/www/files
    file_server
    
    # 范围请求默认启用
    # 支持 Range 请求头
    # 用于视频、大文件下载
}

验证范围请求 #

bash
# 测试范围请求
curl -H "Range: bytes=0-99" https://example.com/video.mp4 -I

# 响应示例
HTTP/2 206 Partial Content
Accept-Ranges: bytes
Content-Range: bytes 0-99/1000000
Content-Length: 100

单页应用(SPA)配置 #

基本配置 #

caddyfile
example.com {
    root * /var/www/spa
    file_server
    
    # 所有路径回退到 index.html
    try_files {path} /index.html
}

完整 SPA 配置 #

caddyfile
example.com {
    root * /var/www/spa
    
    # 静态资源缓存
    @assets {
        path *.js *.css *.png *.jpg *.jpeg *.gif *.ico *.woff *.woff2 *.svg
    }
    header @assets Cache-Control "public, max-age=31536000, immutable"
    
    # 静态文件服务
    file_server
    
    # SPA 路由回退
    @notStatic {
        not path *.js *.css *.png *.jpg *.jpeg *.gif *.ico *.woff *.woff2 *.svg
    }
    try_files @notStatic {path} /index.html
}

Vue/React 应用配置 #

caddyfile
app.example.com {
    root * /var/www/app
    
    encode gzip zstd
    
    # API 代理
    handle /api/* {
        reverse_proxy localhost:3000
    }
    
    # 静态资源
    handle /assets/* {
        file_server
        header Cache-Control "public, max-age=31536000, immutable"
    }
    
    # SPA 回退
    handle {
        try_files {path} /index.html
        file_server
    }
}

虚拟主机配置 #

多站点配置 #

caddyfile
# 站点 1
site1.example.com {
    root * /var/www/site1
    file_server
    encode gzip
}

# 站点 2
site2.example.com {
    root * /var/www/site2
    file_server
    encode gzip
}

# 站点 3 - 带认证
private.example.com {
    root * /var/www/private
    file_server
    
    basicauth {
        admin $2a$14$Zkx...
    }
}

子目录配置 #

caddyfile
example.com {
    root * /var/www/main
    file_server
    
    # 子目录映射到不同目录
    handle /blog/* {
        root * /var/www/blog
        file_server
    }
    
    handle /docs/* {
        root * /var/www/docs
        file_server
    }
}

安全配置 #

禁止访问敏感文件 #

caddyfile
example.com {
    root * /var/www/html
    file_server
    
    # 禁止访问隐藏文件
    @hidden path /.*/** 
    respond @hidden "Access denied" 403
    
    # 禁止访问敏感文件
    @sensitive path *.env *.git/* *.htaccess *.htpasswd
    respond @sensitive "Access denied" 403
}

安全头部 #

caddyfile
example.com {
    root * /var/www/html
    file_server
    
    header {
        # 防止点击劫持
        X-Frame-Options "SAMEORIGIN"
        
        # 防止 MIME 类型嗅探
        X-Content-Type-Options "nosniff"
        
        # XSS 保护
        X-XSS-Protection "1; mode=block"
        
        # 内容安全策略
        Content-Security-Policy "default-src 'self'"
        
        # 引用策略
        Referrer-Policy "strict-origin-when-cross-origin"
        
        # 移除服务器标识
        -Server
    }
}

性能优化 #

连接优化 #

caddyfile
example.com {
    root * /var/www/html
    file_server
    encode gzip zstd
    
    # HTTP/2 推送
    push /style.css
    push /app.js
    
    # Keep-Alive
    header Connection "keep-alive"
}

文件描述符缓存 #

caddyfile
{
    # 全局选项
    servers {
        # 最大文件描述符缓存
        max_header_size 16KB
        protocols h1 h2 h3
    }
}

example.com {
    root * /var/www/html
    file_server
}

错误页面 #

自定义错误页面 #

caddyfile
example.com {
    root * /var/www/html
    file_server
    
    # 自定义错误页面
    handle_errors {
        @404 {
            expression {http.error.status_code} == 404
        }
        rewrite @404 /404.html
        file_server
        
        @5xx {
            expression {http.error.status_code} >= 500
        }
        rewrite @5xx /500.html
        file_server
    }
}

JSON 错误响应 #

caddyfile
api.example.com {
    root * /var/www/api
    file_server
    
    handle_errors {
        respond `{"error": "{http.error.status_text}", "code": {http.error.status_code}}` {http.error.status_code}
    }
}

日志配置 #

访问日志 #

caddyfile
example.com {
    root * /var/www/html
    file_server
    
    log {
        output file /var/log/caddy/access.log {
            # 日志轮转
            roll_size 100mb
            roll_keep 10
            roll_keep_for 168h
        }
        format json
    }
}

自定义日志格式 #

caddyfile
example.com {
    root * /var/www/html
    file_server
    
    log {
        output file /var/log/caddy/access.log
        format console {
            time_format "2006-01-02 15:04:05"
        }
    }
}

完整示例 #

企业网站配置 #

caddyfile
example.com {
    root * /var/www/html
    encode gzip zstd
    
    # 安全头部
    header {
        X-Frame-Options "SAMEORIGIN"
        X-Content-Type-Options "nosniff"
        X-XSS-Protection "1; mode=block"
        Referrer-Policy "strict-origin-when-cross-origin"
        -Server
    }
    
    # 静态资源缓存
    @static {
        path *.css *.js *.png *.jpg *.jpeg *.gif *.ico *.woff *.woff2 *.svg
    }
    header @static Cache-Control "public, max-age=31536000, immutable"
    
    # HTML 缓存
    @html path *.html
    header @html Cache-Control "public, max-age=3600"
    
    # 禁止访问敏感文件
    @hidden path /.*/** *.env *.git/*
    respond @hidden "Forbidden" 403
    
    # 文件服务
    file_server {
        precompressed
        index index.html
    }
    
    # SPA 回退
    try_files {path} /index.html
    
    # 日志
    log {
        output file /var/log/caddy/access.log {
            roll_size 50mb
            roll_keep 5
        }
        format json
    }
    
    # 错误页面
    handle_errors {
        respond "{http.error.status_code} {http.error.status_text}"
    }
}

# 带 www 重定向
www.example.com {
    redir https://example.com{uri} permanent
}

文件下载服务器 #

caddyfile
files.example.com {
    root * /var/www/files
    
    # 目录浏览
    file_server browse {
        sort name desc
    }
    
    # 压缩
    encode gzip
    
    # 认证
    basicauth {
        admin $2a$14$Zkx...
    }
    
    # 下载头部
    header Content-Disposition "attachment"
    
    # 日志
    log {
        output file /var/log/caddy/files.log
    }
}

下一步 #

现在你已经掌握了静态文件服务配置,接下来学习 反向代理 了解如何配置代理服务!

最后更新:2026-03-28