最近在整理家里那台 NAS 和几台云主机上的文件共享方案时,我又把Dufs 文件服务器翻出来重新梳理了一轮。Dufs 是那种用一次就会爱上的小工具:Rust 写的,编译出来就一个二进制文件,不装运行环境、不依赖数据库,扔到任意一台 x86/ARM 机器上都能跑,默认 Web 界面干净但确实朴素。这次我顺手把dufs-material-assets 美化主题集成进去,界面直接跳了一个档次,手机浏览器上访问列表文件也舒服多了。这篇围绕 Dufs 的部署和主题美化展开,二进制和 Docker 两条路都走一遍,再分享实际部署中遇到的那些坑,适合准备搭内网文件服务、NAS 文件管理,或者临时给外部发文件链接的朋友参考。
1. Dufs 的定位:这就是为"快速共享文件"准备的轻量服务
1.1 Dufs 到底解决了什么问题
Dufs 的全称是 Dumb Utility File Server,翻译过来就是"傻瓜式文件服务器"。它的核心诉求非常直接:用一个最简单的办法,把某个目录变成可以随时访问的文件服务。
我们家用的 NAS 场景里,SMB/NFS 虽然好用,但手机端、同事的笔记本、临时访客访问起来并不方便,要么装客户端要么折腾局域网发现。Dufs 跑起来之后,浏览器打开 IP:5000 就能看到目录结构,文件点一下就能下载,支持续传,还能直接在网页上拖拽上传。这种感觉比在一堆协议配置里打滚要清爽太多。
它实际覆盖的场景大概是这几类:
- 给手机、平板提供一个不需要装 App 的网页文件入口;
- 把服务器上的构建产物、安装包快速分享给客户或同事,给个链接即可;
- 需要 WebDAV 协议挂载远程目录,方便本机同步和编辑;
- 一家人或者小团队共享文档、电影、照片,但不想为了这点需求去部署一套完整的云盘系统。
Dufs 在这些场景下非常能打。它内置 HTTP 访问和 WebDAV 支持,自带基本认证,还能按目录配置读写权限,支持搜索、目录打包下载、Markdown 和 PDF 在线预览等功能。一个不到 10MB 的二进制文件干完这么多事,很难不让喜欢折腾的人心动。
1.2 和 nginx autoindex、filebrowser、miniserve 的取舍
很多朋友可能会问:我本来就有 nginx,开个 autoindex 不也能看目录吗?或者为啥不直接用 filebrowser?
我拿常见的几个方案做个对比:
| 方案 | 优势 | 劣势 | 适合场景 |
|---|---|---|---|
| nginx + autoindex | 性能好,无需额外组件 | 只读为主,上传要单独配,权限控制麻烦 | 单纯对外静态下载 |
| Caddy + file_server | 配 HTTPS 极简 | 动态上传、删除功能弱 | 只读站点 |
| miniserve | 单二进制,简单 | 功能过于基础,权限/WebDAV 欠缺 | 临时传文件 |
| filebrowser | 功能全面,界面友好 | 带数据库和完整用户体系,偏重 | 多用户管理场景 |
| Dufs | 单二进制,轻量,权限灵活,内置 WebDAV | 界面默认朴素(但可换主题) | 轻量共享、NAS、临时分发 |
我当时的选型逻辑很明确:filebrowser 确实界面不错,但它的用户系统和数据库对一台小 NAS 来说有点杀鸡用牛刀;nginx autoindex 只读没问题,可一旦需要上传、WebDAV 就麻烦起来。Dufs 正好卡在中间——不需要数据库,不需要额外运行时,但该有的文件操作能力都有。
1.3 什么场景不建议用 Dufs
我也得泼点冷水。Dufs 再轻量,也不是万能的。
如果你需要的是多个用户分角色管理,每个人有自己的目录配额、操作审计、回收站和版本历史,那 Dufs 就不太合适了,这种需求老老实实上 Seafile 或者 Nextcloud 更稳。如果团队需要在线协同编辑 Office 文档,Dufs 也干不了,它只能做基础的 Markdown/PDF 预览。还有一点需要注意的是,Dufs 的权限模型是"路径 + 权限位",比 filebrowser 灵活,但也意味着精细到"每个用户只见自己那一片目录"时需要多写几条 auth 规则。好在多数个人场景根本用不到那么复杂的模型。
总之,Dufs 的定位就是"轻量"两个字。需求一旦超出轻量共享,就不要硬上,选型时清楚边界,后面维护起来才不闹心。
2. 基础部署:二进制与 Docker Compose 两条路线一次跑通
2.1 二进制安装:下载、解压、最简启动
Dufs 的部署方式非常简单,因为它本身就是单文件。以 Linux x86_64 为例,我从 GitHub Releases 页面下载对应压缩包:
wget https://github.com/sigoden/dufs/releases/latest/download/dufs-x86_64-unknown-linux-musl.tar.gz tar -zxvf dufs-x86_64-unknown-linux-musl.tar.gz sudo mv dufs /usr/local/bin/ dufs --version这里我特意选了 musl 静态编译版,它在哪个发行版上都能直接跑,不会出现 glibc 版本导致的兼容问题。如果你要部署到树莓派、电视盒子或者 RK3588 那类 ARM 设备上,记得下载aarch64对应的包。
最简启动就一条命令:
mkdir -p /srv/files dufs /srv/files --bind 0.0.0.0 --port 5000 --allow-all--bind 0.0.0.0表示监听所有网卡,--port 5000是默认端口,--allow-all相当于一次打开上传、删除、搜索所有权限。浏览器访问http://服务器IP:5000,就能看到目录列表了。
要注意的是,--allow-all这种参数我一般在本地调试才用。真实环境我建议按需放开,比如只开后台上传和搜索,删除权限保持关闭,避免误操作把目录清空。
2.2 用 systemd 把 Dufs 托管为常驻服务
手动敲命令跑起来的进程,终端一关就没了。为了让它常驻,我写了 systemd 单元文件,这块是实际部署中很容易漏掉的一步。
[Unit] Description=DUFS File Server After=network-online.target Wants=network-online.target [Service] Type=simple ExecStart=/usr/local/bin/dufs /srv/files --bind 0.0.0.0 --port 5000 --assets /opt/dufs-assets --allow-upload --allow-search Restart=on-failure RestartSec=3 [Install] WantedBy=multi-user.target把它保存到/etc/systemd/system/dufs.service,然后执行:
sudo systemctl daemon-reload sudo systemctl enable --now dufs sudo systemctl status dufs这里的 ExecStart 我已经把--assets /opt/dufs-assets加进去了,也就是后面第三节要讲的主题资源目录。实际部署时建议先把这一行加上,免得服务跑起来后还要改配置重启两遍。
2.3 Docker Compose 部署:参数对应的完整清单
如果你和我一样,NAS 或者云主机上已经跑着一堆 Docker 容器,那用 Docker Compose 统一管理更省心。下面是一个我实际在用的 compose 文件:
services: dufs: image: sigoden/dufs:latest container_name: dufs restart: unless-stopped ports: - "5000:5000" volumes: - ./files:/data - ./dufs-assets:/assets:ro command: - /data - --bind - 0.0.0.0 - --port - 5000 - --assets - /assets - --allow-upload - --allow-search这份配置里,宿主机的./files目录对应容器内的/data,./dufs-assets以只读方式挂载到/assets,并通过--assets /assets告诉 Dufs 使用外部 UI 资源。之所以把 assets 单独挂载而不是打进镜像,是因为主题资源更新时只需要替换宿主机目录,不必重建容器。
启动命令同样简单:
docker compose up -d docker compose logs -f dufs需要注意:容器网络里绑定的 IP 指的是容器自己的网卡,所以写0.0.0.0即可。真正对外生效的是ports这一段,宿主机的 5000 端口会被转发到容器内。
2.4 常用参数速查:部署时要认清楚的几个选项
Dufs 的参数不算多,但每个都很关键。我把部署时最常用的几个整理成了一张速查表,方便配置时对照:
| 参数 | 作用 | 常用示例 |
|---|---|---|
--bind | 监听地址 | --bind 0.0.0.0 |
--port | 监听端口 | --port 5000 |
--root | 根目录的位置参数 | dufs /srv/files |
--auth | 认证规则,可多次指定 | --auth "admin:pass@/:rw" |
--assets | 自定义 Web UI 资源目录 | --assets /opt/dufs-assets |
--readonly | 全局只读 | 不需要上传时使用 |
--allow-upload | 允许上传 | 按需开启 |
--allow-delete | 允许删除 | 慎用 |
--allow-search | 允许搜索 | 文件多了建议开 |
--download-zip | 支持目录打包下载 | 分发大目录时好用 |
--webdav | 启用 WebDAV | 挂载网络磁盘用 |
--hidden | 隐藏指定路径 | --hidden .git |
--log-file | 写日志到文件 | /var/log/dufs.log |
--tls-cert/--tls-key | 直接启用 HTTPS | 一般交给反代 |
我建议第一次上手时不要用--allow-all,从需求出发逐个放开权限,对权限模型的理解也会更清楚。
3. 集成 dufs-material-assets 主题:原理、步骤与生效验证
3.1 Dufs 支持自定义 UI 的机制:--assets 到底做了什么
先理解一件事:Dufs 的 Web 界面本质上就是一组前端静态资源,包括index.html、CSS、JS、图标等文件。这些资源在编译时被打包进了二进制里,所以你第一次打开页面看到的那个朴素界面,其实就是这组静态资源被 Dufs 读取后返回给浏览器的结果。
--assets参数的作用,是让 Dufs 启动时优先从外部目录读取同名资源,如果外部目录里有index.html,就直接用它;如果没有,才回落到内置资源。这就给了我们"换肤"的空间——只要准备一套符合 Dufs 页面逻辑的自定义前端资源,就能彻底改变界面外观,不需要改任何 Rust 代码。
dufs-material-assets 这套主题就是这样工作的。它把 Dufs 默认的界面替换成 Material Design 风格:列表变成了卡片式,文件图标更清晰,面包屑导航、搜索框、上传按钮的布局全部重排过,还对移动端做了较好的适配。做 NAS 文件分享,手机上访问频率其实挺高,默认界面在小屏上显示得比较拥挤,换这套主题后体验提升非常明显。
3.2 下载并摆好 dufs-material-assets 资源目录
获取主题资源的方式取决于项目的 Release 方式,一般是从项目仓库的 Release 页面下载打包好的静态目录,或者直接 clone 仓库。下载下来后,我把资源解压到服务器上固定的位置:
mkdir -p /opt/dufs-assets tar -zxvf dufs-material-assets.tar.gz -C /opt/dufs-assets --strip-components=1这里的关键一点是目录结构。Dufs 读取外部资源时,找的是index.html 所在的那一层目录。所以解压完成后,请检查一下:
ls -la /opt/dufs-assets正常情况下应该能直接看到index.html文件,而不是套在里面一层文件夹里。如果看到的是一个名为dist或build之类的子目录,那就需要把路径往下指一层,指向真正包含index.html的那个目录。
我见过不少朋友在这一步踩坑,把--assets写到了上一级目录,结果 Dufs 找不到index.html,界面直接白屏。目录层级搞对,后面就顺了。
3.3 启动参数挂载与两种验证方式
二进制部署时,把 assets 路径加到启动命令里:
dufs /srv/files \ --bind 0.0.0.0 \ --port 5000 \ --assets /opt/dufs-assets \ --allow-upload \ --allow-search如果你用等已经写好 systemd 单元的版本,直接重启服务即可:
sudo systemctl restart dufsDocker Compose 部署时,我在前面的 compose 文件里已经带上了挂载和参数,直接执行docker compose up -d就行。
验证主题是否生效,我一般用两种方式:
第一种,命令行快速验证,看返回的 HTML 里是否包含主题的特征内容:
curl -s http://127.0.0.1:5000/ | head -n 20如果返回的 HTML 里出现了 Material 风格特有的 class 名或者主题资源文件名,就说明加载的是自定义资源而不是内置界面。
第二种,浏览器强制刷新。由于浏览器可能会缓存旧页面的 CSS/JS 文件,按Ctrl + F5或Cmd + Shift + R强制刷新一次,看到卡片式界面基本就成功了。
4. 认证、WebDAV 与 Nginx 反代:把这台文件服务真正用起来
4.1 账号认证与只读覆盖:--auth 权限规则写法
文件服务跑起来之后,第一个要解决的问题就是权限。Dufs 的--auth参数支持按路径配置多组账号,格式大致是用户名:密码@路径:权限,权限位包括读取、上传、删除等。例如:
dufs /srv/files --bind 0.0.0.0 --port 5000 \ --auth "admin:ChangeMe@/:rw" \ --auth "guest:guest123@/public:r" \ --allow-search这条命令里,admin对整个根目录有读写权限,guest账号只能访问/public目录,且只有读取权限,既不也能上传也不能删除。加上--allow-search后,所有有读权限的用户都可以搜索可见范围内的文件。
这里说一个容易误操作的地方:如果--readonly存在,所有写操作会被全局禁用,这时候即使某个账号配置了w权限也无效。反过来,如果你希望某些目录只读、某些目录可写,那就不要用--readonly,而是用不同账号对不同路径给不同权限位。这样设计的好处是公网访客账号可以只给r,自己管理账号给rw,从根上降低风险。
4.2 开启 WebDAV:把文件服务变成网络磁盘
Dufs 原生支持 WebDAV,这是一个我很看重的能力。在启动命令中加上--webdav,文件服务就同时变成了一个网络磁盘:
dufs /srv/files --webdav --auth "admin:ChangeMe@/:rw"Linux 客户端可以用 davfs2 挂载:
sudo apt install davfs2 sudo mkdir -p /mnt/dufs sudo mount -t davfs http://127.0.0.1:5000/ /mnt/dufsWindows 里直接在"添加网络位置"里填http://IP:5000或者https://域名/就能挂载。macOS 的 Finder 里按Cmd + K,输入服务地址即可。
有了 WebDAV 之后,Dufs 不只是"浏览器里点着玩"的工具了。我可以在本机上把 NAS 目录挂载成一个盘符,IDE 直接打开远程文件编辑,也能用脚本定期往里同步备份文件。文件内容变更后,浏览器访问同一个地址看到的就是最新状态,无需额外同步逻辑。
4.3 Nginx 反向代理与 HTTPS:对外暴露前的标准操作
我不太推荐把 5000 端口直接暴露到公网,一个习惯性做法是统一走 Nginx 反向代理,把 TLS 终结在 Nginx 这一层。这样既不需要 Dufs 自己处理证书,也方便以后做访问控制和统一入口。
以下是我常用的 Nginx 站点配置:
server { listen 443 ssl; server_name files.example.com; ssl_certificate /etc/nginx/ssl/fullchain.pem; ssl_certificate_key /etc/nginx/ssl/key.pem; client_max_body_size 0; location / { proxy_pass http://127.0.0.1:5000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }client_max_body_size 0这一项别漏了,Nginx 默认只允许请求体最大 1MB,如果不放开,大文件上传就会直接报 413。实际场景中传几个 GB 的安装包很常见,这个参数至关重要。
证书获取可以用 Let's Encrypt,配合 certbot 自动续期,整体维护成本很低。反代配置好之后,Dufs 端只需要监听127.0.0.1:5000就够了,不要直接暴露在所有网卡上。
5. 实测避坑记录:主题白屏、大文件断传与安全底线
5.1 主题不生效或白屏:先按这个顺序排查
集成主题看起来简单,但我在实际操作中确实遇到过几次白屏和小问题,这里把排查顺序列出来,照着走基本能解决。
第一,确认--assets参数指向的目录直接包含index.html。这是最常见的原因,层级错一层就会白屏。检查命令:
ls /opt/dufs-assets/index.html第二,启动日志里有没有报错。二进制运行时直接看终端输出,systemd 部署用journalctl -u dufs -n 50,Docker 用docker logs dufs。如果 Dufs 告诉你找不到资源目录,多半是路径拼错。
第三,浏览器缓存。旧界面的 CSS/JS 文件可能被浏览器缓存了,强制刷新一次再判断。
第四,主题资源与 Dufs 版本的兼容性。一些新主题利用的 Dufs 内部接口字段如果在新版本里变了,可能表现出白屏或者功能按钮点击无效。这时候看一下 dufs-material-assets 项目说明里支持哪一版本的 Dufs,把 Dufs 锁定到指定版本即可。为了避免升级引起问题,我在 systemd 或 compose 里都写死了具体镜像版本标签,而不是用latest。
5.2 大文件上传断传与 Docker 卷权限
大文件上传遇到的坑,绝大多数不在 Dufs 本身,而在它前面的代理层。直连 5000 端口时,Dufs 对上传大小基本没有限制;但一旦走了 Nginx,就必须处理我之前说的client_max_body_size。还有超时配置,大文件上传耗时较长,建议在 Nginx 里同时调大几个超时时间:
proxy_read_timeout 600s; proxy_send_timeout 600s;这样在弱网环境下传大文件,不会因为读超时被 Nginx 主动掐断连接。
另一个常见问题出现在 Docker 部署时:容器内进程对挂载卷没有写权限。表现是网页上传按钮点了没反应,或者报错提示无法创建文件。原因通常是宿主机./files目录的属主和容器内进程的用户不一致。解决办法很简单,先把目录属主调整到与容器运行用户一致,或者直接给目录放宽权限并保证容器能够写入:
sudo chown -R 1000:1000 ./files不同镜像的默认用户不一样,最稳妥的办法是在项目文档里确认运行用户。如果容器跑不要求强隔离的家中场景,直接在 compose 里user: root能让问题消失,但公网环境下不建议这么干。
还有一点:--allow-delete我给所有在线用户都不开。实际上我远程管理时也不需要网页删除,真要清理文件时 SSH 上去执行命令,比误点删除安全太多。
5.3 公网部署的安全底线清单
最后聊一下安全。文件服务一旦暴露到公网,就是攻击者的重点观察对象,以下几条是我每次部署都会检查的清单。
第一,绝对不要直接dufs / --allow-all把整个文件系统挂出去。Dufs 的根目录应该是一个专门的共享目录,里面只放需要对外暴露的内容。敏感文件即使在同一台机器上,只要不在根目录里,也不会被扫描到。
第二,使用--hidden把点文件和敏感子目录藏起来:
dufs /srv/files --hidden ".*" --hidden "backup"第三,账号密码尽量用强密码,并且每个场景单独建账号,不要全世界共用一个 admin。--auth支持多账号,给公网访客只读账号,给自己读写账号,这种方式比一刀切的全局密码要稳很多。
第四,启用日志记录。加上--log-file /var/log/dufs.log,事后排查访问痕迹时非常有用。
第五,按时升级。Dufs 更新频率不算低,安全修复和功能改进都在里面。升级前先看一眼 Release Notes,重点确认没有破坏性变更,再看一眼主题资源的兼容说明。
我记得一次踩坑就是因为 Nginxclient_max_body_size没调整,客户传一个 3GB 的数据库备份文件,折腾了半天都失败,一开始还怀疑是 Dufs 的 bug,最后抓包才发现是反代层拦截了。所以排查问题时一定记得把链路完整看一遍,不要只盯着 Dufs 本体。
现在我这套 Dufs 文件服务器已经稳定跑了一段时间:家里 NAS 上用 Docker Compose 管理,端口固定 5000,内网直接访问,不去套认证;云主机上的实例则反代 HTTPS,只读开放一个专门目录,其他路径全部隐藏。集成 dufs-material-assets 主题后,手机端访问的频次明显变高了,这大概就是界面改进带来的实际效果。如果你也打算把 Dufs 用起来,我的建议是第一遍搭的时候就把主题 assets 单独放在一个固定目录,和二进制、systemd 配置分开,之后升级维护会轻松很多。