Docker 下载服务部署指南:Caddy / Filebrowser / Dufs 三方案

面向第三方用户提供文件下载服务的三种 Docker 部署方案:Caddy 纯静态下载站(公开访问 / 密码认证 / 自定义端口 HTTPS)、Filebrowser 网页网盘、Dufs 极速分发与 WebDAV,含完整配置、避坑要点与实战验证。

如果你需要在自己的服务器上搭一个「给第三方用户下载文件」的服务——比如给客户分发安装包、给群友分享资源、给终端用户提供固件下载——用 Docker 几分钟就能搞定。本文整理一套完整的部署方案,覆盖 Caddy(纯静态下载站)Filebrowser(网页网盘)Dufs(极速分发 + WebDAV) 三种主流选择,并给出经过实际部署验证的配置与避坑要点。

💡 先分清需求:如果你是自己下载 BT/PT 种子、HTTP 直链(比如 qBittorrent、Aria2),那属于「下载工具」;本文讲的是给别人提供下载服务——用户通过浏览器或 wget/curl 直接拉取你服务器上的文件。

三方案速览

方案定位界面权限管理适合场景
Caddy纯静态 HTTP 下载站极简目录列表可公开 / 可 HTTP 基础认证文件公开分发、脚本批量拉取
Filebrowser网页网盘现代网盘 UI(预览/编辑/上传)内置多用户角色 + 分享链接需要图形化管理、发分享链接
Dufs静态服务器 + WebDAV极简目录列表 + 搜索命令行规则控制(可按路径分配)极致轻量、WebDAV 挂载

方案一:Caddy(纯静态下载站)

Caddy 是最简单、性能最好的文件分发方案:把目录映射进去,浏览器打开就是目录列表,点谁下载谁,也能用 wget/curl 批量拉取。

1.1 公开模式(无需账号密码)

这是最常用的形态:任何人不登录就能浏览目录、下载文件,适合公开资源分发。

第一步:创建目录结构

mkdir -p downloads
cd downloads   # 后续所有文件都在这个目录里操作

第二步:编写 Caddyfile(与 docker-compose.yml 同级)

:8081 {
    root * /srv
    file_server browse
}

🔑 :8081 是容器内部监听端口,宿主机用 8081 映射。file_server browse 开启目录列表(不带 browse 就只能访问已知路径,看不到列表页)。

第三步:编写 docker-compose.yml

services:
  caddy:
    image: caddy:alpine
    container_name: download_server
    ports:
      - 8081:8081
    volumes:
      - ./downloads:/srv      # 要提供下载的文件目录
      - ./Caddyfile:/etc/caddy/Caddyfile
    restart: unless-stopped

第四步:启动

docker compose up -d

把文件放进 downloads/,访问 http://服务器IP:8081/ 就能看到目录列表并直接下载。用命令行拉取也很方便:

wget http://服务器IP:8081/filename.zip
curl -O http://服务器IP:8081/filename.zip

1.2 密码认证模式(basicauth)

如果不想完全公开,Caddy 内置 basicauth 指令:浏览器访问时弹出登录框,输入账号密码才能浏览下载。

第一步:生成密码哈希

Caddy 出于安全考虑不允许在配置里写明文密码,必须先把它转成 bcrypt 哈希。用 Docker 临时容器生成(示例密码 123456,务必换成你自己的强密码):

docker run --rm caddy:alpine caddy hash-password --plaintext "123456"

输出一串以 $2a$14$ 开头的字符串(不同机器每次生成的哈希不同,这是正常的),复制它

第二步:修改 Caddyfile(把 $2a$14$... 替换成你刚复制的那串哈希)

:8081 {
    basicauth /* {
        admin $2a$14$xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    }

    root * /srv
    file_server browse
}

第三步:重启生效

docker compose restart caddy

现在访问站点会先弹登录框,输入 admin 和明文密码(如 123456)才能看到下载目录。

⚠️ 注意basicauth 的哈希值只认你 caddy hash-password 生成的那串;换一台机器、换一个密码都要重新生成。忘记密码就重新跑一次第一条命令,更新 Caddyfile 里的哈希即可。

1.3 绑定域名 + 自动 HTTPS

Caddy 最大的优势是自动申请和续签 Let’s Encrypt / ZeroSSL 证书——你只要把域名解析过来,Caddy 全自动搞定 HTTPS,无需手动配置 SSL。

第一步:DNS 解析

在域名解析商处添加 A 记录,把域名(如 dl.example.com)指向服务器公网 IP,等待生效(可以用 ping dl.example.com 确认解析成功)。

第二步:修改 docker-compose.yml

services:
  caddy:
    image: caddy:alpine
    container_name: download_server
    ports:
      - 80:80        # 用于 HTTP 自动跳转 HTTPS 及 ACME 证书验证
      - 443:443      # HTTPS 访问端口
    volumes:
      - ./downloads:/srv
      - ./Caddyfile:/etc/caddy/Caddyfile
      - ./caddy_data:/data    # 必须:持久化保存自动申请的 SSL 证书
      - ./caddy_config:/config
    restart: unless-stopped

🔑 ./caddy_data:/data 必须加:证书存在 /data 里,如果不挂载,容器每次重建都会重新申请证书,容易触发 Let’s Encrypt 的频率限制。

第三步:修改 Caddyfile(把站点地址从 :8081 换成你的域名)

dl.example.com {
    root * /srv
    file_server browse
}

第四步:重建并启动

docker compose down
docker compose up -d

等 10 秒左右,访问 https://dl.example.com/,地址栏会出现安全锁。如果上一节配置过 basicauth,把它加回到 Caddyfile 里即可(哈希值不用重新生成)。

1.4 443 被占用:用自定义端口跑 HTTPS

很多服务器上 443 端口已经被其他服务(如 sing-box、反代)占用,这时可以给 HTTPS 换一个端口,比如 8443

前提:Caddy 申请证书走 HTTP-01 验证,必须保证 80 端口空着且公网可达(哪怕最终访问走 8443)。

第一步:修改 Caddyfile(域名后直接加端口)

dl.example.com:8443 {
    root * /srv
    file_server browse
}

第二步:修改 docker-compose.yml(保留 80,加上 8443)

services:
  caddy:
    image: caddy:alpine
    container_name: download_server
    ports:
      - 80:80          # 必须保留:用于申请/续签证书
      - 8443:8443      # 自定义 HTTPS 端口
    volumes:
      - ./downloads:/srv
      - ./Caddyfile:/etc/caddy/Caddyfile
      - ./caddy_data:/data
      - ./caddy_config:/config
    restart: unless-stopped

第三步:重建生效

docker compose down
docker compose up -d

之后通过 https://dl.example.com:8443/ 访问,同样带安全锁。防火墙/安全组记得同时放行 80 和 8443。

1.5 进阶:sing-box SNI 分流(443 被 sing-box 占用的优雅解法)

既然 443 在 sing-box 手里,与其换端口,不如让 sing-box 当「前置路由」:在 sing-box 的 TLS 规则里按 SNI 识别——当用户请求的是 dl.example.com 时,直接把流量转发给内网 Caddy 的端口。这样用户端始终用标准的 https://dl.example.com/ 访问,无需记忆后缀端口。

具体做法是给 sing-box 的 443 入站开启 TLS 嗅探(sniff),在路由规则中匹配 server_name == dl.example.com 的流量,dial 到内网 Caddy 的监听地址(如 10.0.0.8:8443,示例内网地址);其余流量按原规则继续走代理。

💡 具体规则写法取决于你的 sing-box 版本和路由架构,核心思路是「按 SNI 分流 + fallback」,避免 443 端口打架。sing-box 的详细配置不属于本文范围,这里只给方向。


方案二:Filebrowser(网页网盘 + 多用户管理)

如果除了下载,你还想要图形化上传/管理文件、给用户生成带密码或有效期的分享链接,Filebrowser 是最佳选择:Go 编写,资源占用极低,自带现代网盘界面。

第一步:准备目录

mkdir -p downloads database

第二步:编写 docker-compose.yml

services:
  filebrowser:
    image: filebrowser/filebrowser:latest
    container_name: filebrowser
    user: 1000:1000        # 与宿主机目录属主 UID/GID 保持一致(见下方避坑)
    ports:
      - 8081:80            # 端口冲突就换一个,如 8082:80
    volumes:
      - ./downloads:/srv
      - ./database:/database
    environment:
      - FB_DATABASE=/database/filebrowser.db
    restart: unless-stopped

第三步:启动

docker compose up -d

第四步:获取登录密码

访问 http://服务器IP:8081/,出现登录页。注意:新版本(2.63+)已经没有默认密码 admin/admin 了——首次启动时系统会随机生成一个管理员密码并打印在容器日志里:

docker logs filebrowser | grep password

输出类似:User 'admin' initialized with randomly generated password: xxxxxxxx,复制这串随机密码,用用户名 admin + 这串密码登录。登录后建议立刻在「设置」里改掉,或者执行下面命令重置:

docker exec filebrowser filebrowser users update admin --password 你的新密码

⚠️ 避坑 1:默认密码不是 admin/admin。网上大量教程(包括一些较新的)仍写「默认账号密码都是 admin」,那是老版本行为。新版为了安全改用随机密码,且强制密码 ≥ 12 位、禁止 admin/password 这类常见弱密码。

⚠️ 避坑 2:目录权限user: 1000:1000 意味着容器进程以 UID 1000 运行,宿主机上 downloads/database/ 目录必须允许 UID 1000 读写。若日志报 permission denied,执行 chown -R 1000:1000 downloads database 后再重启。如果你的宿主机用户本身不是 1000(比如是 1001),把 user: 1000:1000 改成对应的 UID:GID。

使用:登录后可在网页上传文件、创建文件夹;选中文件可生成「分享链接」(可设密码和有效期)发给第三方;也可以创建只读用户,让第三方直接登录浏览下载。


方案三:Dufs(极速分发 + WebDAV)

Dufs 是 Rust 编写的静态文件服务器,主打极致轻量,原生支持 WebDAV,权限通过命令行参数按「路径 + 账号」控制,非常适合「匿名可下载、管理员可上传管理」的读写分离场景。

第一步:编写 docker-compose.yml

services:
  dufs:
    image: sigoden/dufs:latest
    container_name: dufs
    ports:
      - 5000:5000
    volumes:
      - ./downloads:/data
    # 权限规则说明:
    #   -a admin:123456@/:rw   → 账号 admin(密码 123456)对根目录读写
    #   -a @/                  → 匿名用户对根目录只读(浏览+下载)
    #   --allow-upload         → 全局放开上传(配合 admin 的 :rw 才真正能写)
    command: /data --allow-search --allow-upload -a admin:123456@/:rw -a @/
    restart: unless-stopped

第二步:启动

mkdir -p downloads
docker compose up -d

第三步:验证

  • 匿名访问 http://服务器IP:5000/:能看到目录列表并直接下载,但不能上传。
  • 管理员通过 WebDAV 上传:curl -u admin:123456 -T local.zip http://服务器IP:5000/(密码记得换成强密码)。

⚠️ 避坑(权限规则的真实语义):网上很多教程写 -a admin:123456@/ 就声称「admin 拥有全局读写、其他人可浏览下载」——实测这是错的

  1. -a admin:123456@/ 省略权限后缀时,admin 默认只有只读:ro),要读写必须写 :rw
  2. 只配置账号规则后,匿名访问直接 401,并不会「默认所有人可读」——要公开下载必须再叠加一条 -a @/
  3. 即使给了 :rw,Dufs 还有全局权限开关:不配 --allow-upload 就无法上传、不配 --allow-delete 就无法删除。

正确写法是上面 compose 里那一行:-a admin:123456@/:rw -a @/ + --allow-upload


Filebrowser vs Dufs 怎么选?

维度FilebrowserDufs
底层与性能Go,性能优秀,占用极低Rust,性能极致,占用几乎可忽略
核心定位Web 端文件管理器 / 私有网盘静态文件服务器 / WebDAV 服务器
UI 界面现代网盘 UI,支持图片预览、文本编辑、视频播放极简目录列表,提供基础搜索
用户与权限内置 SQLite,多用户角色、权限后台无数据库,命令行参数按路径+账号控制
分享链接支持生成含密码/有效期的分享链接直接分享真实 URL 路径
WebDAV官方不支持原生支持且稳定,可挂载为本地磁盘

选 Filebrowser:需要图形界面管理文件、给用户发带密码/限期的分享链接、有多用户需求。 选 Dufs:追求极致轻量、需要 WebDAV 挂载(把远程目录当本地磁盘)、要命令行精确控制权限。

补充:WebDAV 是什么?

WebDAV 是一种基于 HTTP 的文件传输和管理协议,核心作用是把远程服务器上的文件目录直接「挂载」到本地设备,当成本地磁盘一样使用。Dufs 原生支持它。

相比 SMB/FTP 的优势:走 HTTP 协议,防火墙友好(一般只开一个端口)、无需额外端口、天然支持 HTTPS 加密,跨平台(Windows/macOS/Linux/手机都支持)。Windows 里「映射网络驱动器」、macOS 里「连接服务器」填入 WebDAV 地址即可挂载。


实战验证

本文所有配置均在本机 Docker 环境(Docker 29.2.1)实际部署验证,结果如下:

场景配置实测结果
Caddy 公开下载站:8081 + file_server browse首页 200,目录列表正常,hello.txt 免登录直接下载 ✓
Caddy basicauthcaddy hash-password 生成哈希 + basicauth无凭据 401、错误密码 401、正确凭据 200 ✓
Filebrowseruser: 1000:1000 + FB_DATABASE日志输出随机密码,登录成功,文件列表正常 ✓
Dufs 读写分离-a admin:123456@/:rw -a @/ + --allow-upload匿名浏览/下载 200,admin WebDAV PUT 201,匿名写 401 ✓

验证中发现的坑(已写进上文避坑):

  1. Filebrowser 2.63.x 首次启动不再默认 admin/admin,而是随机生成密码打印到日志;
  2. Dufs -a user:pass@/ 权限后缀省略=只读,且加规则后匿名不再可读,需 -a @/ 显式公开;
  3. Filebrowser user: 1000:1000 与宿主机目录属主不匹配时(如宿主机 UID 1001)会报 permission denied,需 chown 对齐;
  4. Caddy 的域名 + HTTPS 部分依赖真实域名与公网 80 端口,本文在本地以 HTTP 模式验证了配置正确性,实际申请证书请按 1.3/1.4 节操作。

总结

需求推荐
纯公开分发、脚本批量拉取Caddy 公开模式(1.1)
要账号密码保护Caddy basicauth(1.2)
要 HTTPS + 域名Caddy 1.3,443 被占就 1.4
要网页管理 + 分享链接Filebrowser(方案二)
要 WebDAV + 极致轻量Dufs(方案三)

三种方案可以共存(不同端口),按需组合即可。动手时记得:所有示例密码(123456)都换成自己的强密码,域名 dl.example.com 换成你自己的。