3.1 静态文件服务概述

3.1.1 什么是静态文件服务

静态文件服务是Web服务器的基本功能之一,用于直接提供存储在服务器文件系统中的文件,如HTML、CSS、JavaScript、图片、视频等。Caddy的静态文件服务功能强大且易于配置。

3.1.2 Caddy静态文件服务的特点

  1. 零配置启动:最简单的情况下只需一行配置
  2. 自动MIME类型检测:根据文件扩展名自动设置Content-Type
  3. 目录浏览:可选的目录列表功能
  4. 范围请求支持:支持HTTP Range请求,适合大文件下载
  5. 压缩支持:自动压缩响应内容
  6. 缓存优化:智能的缓存头设置
  7. 安全特性:文件隐藏、路径遍历保护等

3.2 基础文件服务配置

3.2.1 最简配置

# 最简单的静态文件服务
localhost {
    file_server
}

这个配置将当前目录作为网站根目录,提供静态文件服务。

3.2.2 指定根目录

# 指定网站根目录
example.com {
    root * /var/www/html
    file_server
}

# 不同路径指定不同根目录
example.com {
    root /static/* /var/www/static
    root /uploads/* /var/www/uploads
    root * /var/www/html
    file_server
}

3.2.3 启用目录浏览

# 启用目录浏览
example.com {
    root * /var/www/html
    file_server browse
}

# 仅在特定路径启用目录浏览
example.com {
    root * /var/www/html
    
    @browse {
        path /files/*
    }
    file_server @browse browse
    file_server
}

3.3 高级文件服务配置

3.3.1 索引文件配置

example.com {
    root * /var/www/html
    
    # 自定义索引文件
    file_server {
        index index.html index.htm default.html
    }
}

# 禁用索引文件
example.com {
    root * /var/www/html
    
    file_server {
        index off
    }
}

3.3.2 文件隐藏

example.com {
    root * /var/www/html
    
    file_server {
        # 隐藏特定文件和目录
        hide .htaccess .git .env .DS_Store
        
        # 使用通配符隐藏
        hide *.log *.tmp
        
        # 隐藏以点开头的文件
        hide .*
    }
}

3.3.3 预压缩文件支持

example.com {
    root * /var/www/html
    
    # 启用预压缩文件支持
    file_server {
        precompressed gzip br zstd
    }
    
    # 同时启用动态压缩
    encode gzip br
}

3.3.4 自定义错误页面

example.com {
    root * /var/www/html
    
    # 自定义404页面
    handle_errors {
        @404 {
            expression {http.error.status_code} == 404
        }
        rewrite @404 /404.html
        file_server
    }
    
    file_server
}

3.4 路径处理和重写

3.4.1 URL重写

example.com {
    root * /var/www/html
    
    # 简单重写
    rewrite /old-path /new-path
    
    # 使用正则表达式
    rewrite ^/user/([0-9]+)$ /users.html?id=$1
    
    # 条件重写
    @mobile {
        header User-Agent *Mobile*
    }
    rewrite @mobile /mobile{uri}
    
    file_server
}

3.4.2 try_files指令

# SPA应用配置
example.com {
    root * /var/www/spa
    
    # 尝试文件,最后回退到index.html
    try_files {path} {path}/ /index.html
    file_server
}

# 多级回退
example.com {
    root * /var/www/html
    
    # 尝试多个文件
    try_files {path} {path}.html {path}/index.html /404.html
    file_server
}

3.4.3 路径清理

example.com {
    root * /var/www/html
    
    # 移除URL中的.html扩展名
    @html {
        path *.html
    }
    redir @html {path_except_last}.html{query} 301
    
    # 尝试添加.html扩展名
    try_files {path} {path}.html {path}/index.html
    file_server
}

3.5 缓存策略配置

3.5.1 基本缓存配置

example.com {
    root * /var/www/html
    
    # 静态资源长期缓存
    @static {
        file
        path *.css *.js *.png *.jpg *.gif *.ico *.svg *.woff *.woff2
    }
    header @static {
        Cache-Control "public, max-age=31536000, immutable"
        Expires "Thu, 31 Dec 2037 23:55:55 GMT"
    }
    
    # HTML文件短期缓存
    @html {
        file
        path *.html
    }
    header @html {
        Cache-Control "public, max-age=3600"
    }
    
    file_server
}

3.5.2 版本化资源缓存

example.com {
    root * /var/www/html
    
    # 版本化资源(包含hash的文件)
    @versioned {
        path_regexp versioned \.(\w{8,})\.(css|js|png|jpg|gif)$
    }
    header @versioned {
        Cache-Control "public, max-age=31536000, immutable"
    }
    
    # 普通静态资源
    @static {
        file
        path *.css *.js *.png *.jpg *.gif
        not path_regexp \.(\w{8,})\.(css|js|png|jpg|gif)$
    }
    header @static {
        Cache-Control "public, max-age=86400"
    }
    
    file_server
}

3.5.3 条件缓存

example.com {
    root * /var/www/html
    
    # 基于文件修改时间的缓存
    @recent {
        file
        file_modified_before 1h
    }
    header @recent {
        Cache-Control "public, max-age=300"
    }
    
    # 开发环境禁用缓存
    @dev {
        query debug=true
    }
    header @dev {
        Cache-Control "no-cache, no-store, must-revalidate"
        Pragma "no-cache"
        Expires "0"
    }
    
    file_server
}

3.6 安全配置

3.6.1 访问控制

example.com {
    root * /var/www/html
    
    # 禁止访问敏感文件
    @forbidden {
        path *.env *.config *.log *.bak
        path /admin/* /.git/* /config/*
    }
    respond @forbidden "Access denied" 403
    
    # IP白名单
    @admin {
        path /admin/*
    }
    @allowed_ips {
        remote_ip 192.168.1.0/24 10.0.0.0/8
    }
    respond @admin not @allowed_ips "Access denied" 403
    
    file_server {
        hide .env .git .config
    }
}

3.6.2 防盗链配置

example.com {
    root * /var/www/html
    
    # 防止图片盗链
    @images {
        path *.jpg *.png *.gif *.webp
    }
    @hotlink {
        not header Referer
        not header Referer *example.com*
        not header Referer *localhost*
    }
    
    # 返回防盗链图片或403错误
    respond @images @hotlink "Hotlinking not allowed" 403
    # 或者重定向到防盗链图片
    # redir @images @hotlink /images/no-hotlink.png
    
    file_server
}

3.6.3 安全头部

example.com {
    root * /var/www/html
    
    # 安全头部配置
    header {
        # 防止点击劫持
        X-Frame-Options "DENY"
        # 防止MIME类型嗅探
        X-Content-Type-Options "nosniff"
        # XSS保护
        X-XSS-Protection "1; mode=block"
        # 引用策略
        Referrer-Policy "strict-origin-when-cross-origin"
        # 内容安全策略
        Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'"
    }
    
    file_server
}

3.7 性能优化

3.7.1 压缩配置

example.com {
    root * /var/www/html
    
    # 启用多种压缩算法
    encode {
        gzip 6
        zstd
        br 6
        
        # 指定压缩的文件类型
        match {
            header Content-Type text/*
            header Content-Type application/json
            header Content-Type application/javascript
            header Content-Type application/xml
        }
        
        # 最小压缩大小
        minimum_length 1024
    }
    
    file_server {
        # 预压缩文件支持
        precompressed gzip br zstd
    }
}

3.7.2 并发和连接优化

{
    # 全局配置
    servers {
        protocols h1 h2 h3
        max_header_size 16KB
        read_timeout 30s
        write_timeout 30s
        idle_timeout 120s
    }
}

example.com {
    root * /var/www/html
    
    # 启用HTTP/2服务器推送
    @push {
        path /
    }
    push @push /css/style.css /js/app.js
    
    file_server
}

3.7.3 大文件处理

example.com {
    root * /var/www/html
    
    # 大文件下载配置
    @large_files {
        path *.zip *.tar.gz *.iso *.dmg *.exe
    }
    
    # 禁用大文件压缩
    encode {
        match {
            not path *.zip *.tar.gz *.iso *.dmg *.exe
        }
        gzip
    }
    
    # 大文件缓存配置
    header @large_files {
        Cache-Control "public, max-age=604800"
        # 启用范围请求
        Accept-Ranges "bytes"
    }
    
    file_server
}

3.8 多站点和虚拟主机

3.8.1 基于域名的虚拟主机

# 主站点
example.com {
    root * /var/www/example.com
    file_server
}

# 子域名站点
blog.example.com {
    root * /var/www/blog
    file_server browse
}

# 开发站点
dev.example.com {
    root * /var/www/dev
    
    # 开发环境特殊配置
    header {
        X-Environment "development"
    }
    
    file_server browse
}

# 通配符子域名
*.example.com {
    root * /var/www/subdomains/{labels.1}
    
    # 检查目录是否存在
    @exists {
        file {
            root /var/www/subdomains/{labels.1}
            try_files /index.html
        }
    }
    
    handle @exists {
        file_server
    }
    
    # 默认处理
    respond "Subdomain not found" 404
}

3.8.2 基于端口的虚拟主机

# 主站点(端口80/443)
example.com {
    root * /var/www/main
    file_server
}

# 管理界面(端口8080)
example.com:8080 {
    root * /var/www/admin
    
    # 基本认证
    basicauth {
        admin $2a$14$Zkx19XLiW6VYouLHR5NmfOFU0z2GTNqq9qB6FY9gZKOOdOoKw6Uw.
    }
    
    file_server browse
}

# API文档(端口8081)
example.com:8081 {
    root * /var/www/docs
    file_server browse
}

3.8.3 基于路径的虚拟主机

example.com {
    # 主站点
    handle / {
        root * /var/www/main
        file_server
    }
    
    # 博客子路径
    handle /blog/* {
        root * /var/www/blog
        uri strip_prefix /blog
        file_server
    }
    
    # 文档子路径
    handle /docs/* {
        root * /var/www/docs
        uri strip_prefix /docs
        file_server browse
    }
    
    # API子路径
    handle /api/* {
        reverse_proxy localhost:8080
    }
}

3.9 日志和监控

3.9.1 访问日志配置

example.com {
    root * /var/www/html
    
    # 基本访问日志
    log {
        output file /var/log/caddy/access.log {
            roll_size 100mb
            roll_keep 10
            roll_keep_for 720h
        }
        format json
    }
    
    file_server
}

3.9.2 自定义日志格式

example.com {
    root * /var/www/html
    
    # 自定义日志格式
    log {
        output file /var/log/caddy/access.log
        format single_field common_log
        level INFO
    }
    
    # 错误日志
    log error {
        output file /var/log/caddy/error.log
        level ERROR
    }
    
    file_server
}

3.9.3 条件日志

example.com {
    root * /var/www/html
    
    # 只记录错误和特定路径的访问
    @log_condition {
        or {
            status 4xx 5xx
            path /admin/* /api/*
        }
    }
    
    log @log_condition {
        output file /var/log/caddy/filtered.log
        format json
    }
    
    file_server
}

3.10 实战案例

3.10.1 个人博客站点

# 个人博客配置
blog.example.com {
    root * /var/www/blog
    
    # 启用压缩
    encode gzip
    
    # 静态资源缓存
    @static {
        path *.css *.js *.png *.jpg *.gif *.ico *.svg
    }
    header @static {
        Cache-Control "public, max-age=31536000"
    }
    
    # HTML缓存
    @html {
        path *.html
    }
    header @html {
        Cache-Control "public, max-age=3600"
    }
    
    # 安全头部
    header {
        X-Frame-Options "SAMEORIGIN"
        X-Content-Type-Options "nosniff"
        Referrer-Policy "strict-origin-when-cross-origin"
    }
    
    # 自定义404页面
    handle_errors {
        @404 {
            expression {http.error.status_code} == 404
        }
        rewrite @404 /404.html
        file_server
    }
    
    file_server
}

3.10.2 企业官网

# 企业官网配置
www.company.com, company.com {
    # 重定向到www
    @non_www {
        host company.com
    }
    redir @non_www https://www.company.com{uri} 301
    
    root * /var/www/company
    
    # 启用多种压缩
    encode gzip br
    
    # 静态资源优化
    @assets {
        path /assets/* /css/* /js/* /images/*
    }
    header @assets {
        Cache-Control "public, max-age=31536000, immutable"
        Vary "Accept-Encoding"
    }
    
    # 安全配置
    header {
        Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
        X-Frame-Options "DENY"
        X-Content-Type-Options "nosniff"
        X-XSS-Protection "1; mode=block"
        Referrer-Policy "strict-origin-when-cross-origin"
        Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' https://www.google-analytics.com; style-src 'self' 'unsafe-inline'"
    }
    
    # 隐藏敏感文件
    file_server {
        hide .git .env .htaccess
    }
    
    # 访问日志
    log {
        output file /var/log/caddy/company-access.log {
            roll_size 100mb
            roll_keep 30
        }
        format json
    }
}

3.10.3 文件下载站点

# 文件下载站点
files.example.com {
    root * /var/www/files
    
    # 启用目录浏览
    file_server browse {
        hide .DS_Store Thumbs.db
    }
    
    # 大文件处理
    @large {
        path *.zip *.tar.gz *.iso *.dmg *.exe *.msi
    }
    
    # 大文件不压缩
    encode {
        match {
            not path *.zip *.tar.gz *.iso *.dmg *.exe *.msi
        }
        gzip
    }
    
    # 下载文件缓存
    header @large {
        Cache-Control "public, max-age=604800"
        Content-Disposition "attachment"
    }
    
    # 防盗链
    @hotlink {
        not header Referer
        not header Referer *example.com*
    }
    respond @large @hotlink "Direct linking not allowed" 403
    
    # 下载统计日志
    log {
        output file /var/log/caddy/downloads.log
        format json
        include http.request.uri http.request.remote_ip http.request.headers.User-Agent
    }
}

本章总结

本章我们全面学习了Caddy的静态文件服务功能:

  1. 基础配置:掌握了静态文件服务的基本配置方法
  2. 高级功能:学习了索引文件、文件隐藏、预压缩等高级特性
  3. 路径处理:了解了URL重写、try_files等路径处理技巧
  4. 缓存策略:掌握了各种缓存配置和优化方法
  5. 安全配置:学习了访问控制、防盗链、安全头部等安全措施
  6. 性能优化:了解了压缩、并发、大文件处理等性能优化技巧
  7. 多站点管理:掌握了虚拟主机的配置方法
  8. 日志监控:学习了访问日志和监控的配置
  9. 实战案例:通过实际案例巩固了所学知识

通过本章的学习,你应该能够: - 配置高性能的静态文件服务 - 实现复杂的路径处理和重写规则 - 应用适当的缓存和安全策略 - 管理多站点和虚拟主机 - 监控和优化文件服务性能

练习题

基础练习

  1. 基本文件服务

    • 创建一个简单的静态网站
    • 配置自定义根目录和索引文件
    • 启用目录浏览功能
  2. 文件隐藏和安全

    • 隐藏敏感文件和目录
    • 配置基本的安全头部
    • 实现简单的访问控制
  3. 缓存配置

    • 为不同类型的文件配置不同的缓存策略
    • 实现版本化资源的长期缓存
    • 配置开发环境的缓存禁用

进阶练习

  1. 路径重写

    • 实现URL美化(去除.html扩展名)
    • 配置SPA应用的路由回退
    • 实现基于条件的路径重写
  2. 性能优化

    • 配置多种压缩算法
    • 实现预压缩文件支持
    • 优化大文件的处理
  3. 防盗链和安全

    • 实现图片防盗链保护
    • 配置完整的安全头部
    • 实现基于IP的访问控制

实战练习

  1. 多站点部署

    • 配置基于域名的多个虚拟主机
    • 实现基于路径的站点分离
    • 配置通配符子域名处理
  2. 企业级配置

    • 创建一个完整的企业官网配置
    • 包含性能优化、安全配置、日志监控
    • 实现多环境的配置管理
  3. 文件服务器

    • 搭建一个功能完整的文件下载服务器
    • 包含目录浏览、防盗链、下载统计
    • 实现大文件的优化处理

下一章我们将学习Caddy的反向代理功能,这是现代Web架构中的重要组件。