大家好,我是 WeiyiGeek,一名深耕安全运维开发(SecOpsDev)领域的技术从业者,致力于探索DevOps与安全的融合(DevSecOps),自动化运维工具开发与实践,企业网络安全防护,欢迎各位道友一起学习交流、一起进步 ,若此文对你有帮助,一定记得点个关注⭐与小红星❤️或加入到作者知识星球『 全栈工程师修炼指南』,转发收藏学习不迷路 。
前言简述
由于 Ingress NGINX 将在2026年3月正式退役,因此,我们迫切需要寻找替代方案。在众多选项中,我们还是选择了 OpenResty 作为替代方案。OpenResty 是一个基于 NGINX 与 LuaJIT 的高性能 Web 平台,它通过将 NGINX 和 Lua 语言相结合,提供了强大的动态网页处理能力,并利用 Kubernetes 集群进行管理以及横向扩容。
此外,我们原本使用 Nginx 单独部署一个静态文件服务器,然后使用 Ingress NGINX 暴露在互联网中作为 CDN 回源服务器,先在由于使用 OpenResty 作为网关入口,所以就不需要再部署一个 Nginx 服务了,因此我们也需要寻找一个高性能的静态文件服务器,
通过在 Google 以及查阅相关资料后,我们发现了一个名为 Dufs 的独特实用文件服务器。它支持静态服务、上传、搜索、访问控制以及 WebDAV 等功能。值得一提的是,Dufs 是一个基于 Rust 语言开发的轻量级文件服务器,具有高性能和低资源消耗的特点,所以最终选择使用 Dufs 作为静态文件服务器,然后通过 OpenResty 作为反向代理,暴露给 CDN 作为回源服务器。
好了,话不多说,接下来将详细介绍如何在 Linux 二进制部署,以及在 Kubernetes 集群中部署 Dufs 作为静态文件服务器。
温馨提示:若文章代码块中存在乱码或不能复制,请联系作者,也可通过文末的阅读原文链接,加入知识星球中阅读,原文链接:https://articles.zsxq.com/id_3ezswe14oru4.html
0x01 dufs 基于 Rust 高性能静态文件服务器
dufs 是什么?
Dufs 是一个独特的实用文件服务器,使用 Rust 语言开发拥有高性能和低资源消耗特点,支持静态服务(前端项目),上传,搜索,访问控制,webdav 挂载,可以非常方便的管理(CURD)服务器上的文件。
dufs 主要特性:
- • 服务静态文件• 下载文件夹为zip文件• 上传文件和文件夹(拖放)• 创建/编辑/搜索文件• 可恢复/部分上传/下载• 访问控制• 支持https• 支持webdav• 支持api调用,方便curl使用
weiyigeek.top-Dufs文件服务器工具图
项目地址:https://github.com/sigoden/dufs/
dufs 快速上手
通过官方文档,我们可以快速上手使用 Dufs 作为静态文件服务器,可以通过以下命令快速启动 Dufs 服务:
# Binary 安装
mkdir /opt/dufs && cd /opt/dufs
wget https://github.com/sigoden/dufs/releases/download/v0.45.0/dufs-v0.45.0-x86_64-unknown-linux-musl.tar.gz
tar -zxvf dufs-v0.45.0-x86_64-unknown-linux-musl.tar.gz
ls# dufs dufs-v0.45.0-x86_64-unknown-linux-musl.tar.gz
ln -s /opt/dufs/dufs /usr/local/bin/dufs
dufs --version # dufs 0.45.0
dufs /var/www/html/ -b 0.0.0.0 -p 5000 -A
# 容器安装
docker run -v /var/www/html/:/www -p 5000:5000 --rm sigoden/dufs /www -A
语法参数
$ dufs --help
Usage: dufs [OPTIONS] [serve-path]
Arguments:
[serve-path] # 指定服务目录,默认为当前工作目录 .
Options:
-c, --config <file> # 指定配置文件路径
-b, --bind <addrs> # 指定网卡地址
-p, --port <port> # 指定服务端口 [default: 5000]
--path-prefix <path> # 指定路径前缀, e.g. /my-prefix
--hidden <value> # 指定隐藏目录, e.g. tmp,*.log,*.lock
-a, --auth <rules> # 指定认证及权限, e.g. user:pass@/dir1:rw,/dir2 ,可指定多个 -a
-A, --allow-all # 允许所有操作权限
--allow-upload Allow upload files/folders
--allow-delete Allow delete files/folders
--allow-search Allow search files/folders
--allow-symlink Allow symlink to files/folders outside root directory
--allow-archive Allow download folders as archive file
--enable-cors Enable CORS, sets `Access-Control-Allow-Origin: *`
--render-index # 请求目录时提供index.html,如果找不到index.html,则返回404
--render-try-index # 请求目录时提供index.html,如果找不到index.html,则返回目录列表
--render-spa # 启用单页应用模式,即不渲染目录列表 (静态站点使用)
--assets <path> # 设置 assets 目录覆盖内置
--log-format <format> # 自定义日志格式,例如:'$time_local - $remote_addr "$request" $status'
--log-file <file> # 自定义日志文件路径,例如:/var/log/dufs.log
--compress <level> Set zip compress level [default: low] [possible values: none, low, medium, high]
--completions <shell> # 打印 Shell [possible values: bash, elvish, fish, powershell, zsh]
--tls-cert <path> # 指定证书路径,例如:/etc/ssl/certs/server.crt
--tls-key <path> # 指定密钥路径,例如:/etc/ssl/private/server.key
-h, --help Print help
-V, --version Print version
在 --config 参数中,可以指定配置文件路径,配置文件参数如下:
serve-path: '.'
bind: 0.0.0.0
port: 5000
path-prefix: /dufs
hidden:
- tmp
- '*.log'
- '*.lock'
auth:
- admin:admin@/:rw
- user:pass@/src:rw,/share
- '@/'# According to the YAML spec, quoting is required.
allow-all: false
allow-upload: true
allow-delete: true
allow-search: true
allow-symlink: true
allow-archive: true
allow-hash: true
enable-cors: true
render-index: true
render-try-index: true
render-spa: true
assets: ./assets/
log-format: '$remote_addr "$request" $status $http_user_agent'
log-file: ./dufs.log
compress: low
tls-cert: tests/data/cert.pem
tls-key: tests/data/key_pkcs1.pem
在脚本/容器中还可通过环境变量进行配置,参数选项与环境变量(以 DUFS_ 前缀打头)对应关系如下:
[serve-path] DUFS_SERVE_PATH="."
--config <file> DUFS_CONFIG=config.yaml
-b, --bind <addrs> DUFS_BIND=0.0.0.0
-p, --port <port> DUFS_PORT=5000
--path-prefix <path> DUFS_PATH_PREFIX=/dufs
--hidden <value> DUFS_HIDDEN=tmp,*.log,*.lock
-a, --auth <rules> DUFS_AUTH="admin:admin@/:rw|@/"
-A, --allow-all DUFS_ALLOW_ALL=true
--allow-upload DUFS_ALLOW_UPLOAD=true
--allow-delete DUFS_ALLOW_DELETE=true
--allow-search DUFS_ALLOW_SEARCH=true
--allow-symlink DUFS_ALLOW_SYMLINK=true
--allow-archive DUFS_ALLOW_ARCHIVE=true
--allow-hash DUFS_ALLOW_HASH=true
--enable-cors DUFS_ENABLE_CORS=true
--render-index DUFS_RENDER_INDEX=true
--render-try-index DUFS_RENDER_TRY_INDEX=true
--render-spa DUFS_RENDER_SPA=true
--assets <path> DUFS_ASSETS=./assets
--log-format <format> DUFS_LOG_FORMAT=""
--log-file <file> DUFS_LOG_FILE=./dufs.log
--compress <compress> DUFS_COMPRESS=low
--tls-cert <path> DUFS_TLS_CERT=cert.pem
--tls-key <path> DUFS_TLS_KEY=key.pem
在 --log-format 参数中日志格式可以使用以下变量及其效果展示,缺省情况下输出到控制台。
$remote_addr client address
$remote_user user name supplied with authentication
$request full original request line
$status response status
$http_ arbitrary request header field. examples: $http_user_agent, $http_referer
$ dufs --log-format '$remote_addr "$request" $status'
# 2026-03-14T09:49:13+08:00 INFO - 10.20.172.103 "GET /css/style.css" 304
$ dufs --log-format '$remote_addr "$request" $status $http_user_agent'
# 2026-03-14T10:53:55+08:00 INFO - 127.0.0.1 "GET /" 200 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36
快速启动(开发测速环境)
# 缺省:以只读模式服务当前工作目录
dufs
# 允许所有操作,如上传/删除/搜索/创建/编辑.
dufs -A
# 直接运行,指定监听接口以及端口
./dufs /usr/local/nginx/html/ -b 10.20.172.213 -p 5000
Listening on http://10.20.172.213:5000/
# 或使用环境变量
export DUFS_PORT=8080
export DUFS_BIND=0.0.0.0
dufs /usr/local/nginx/html/
# 直接运行,指定监听 unix socket 接口
dufs -b /tmp/dufs.socket
# 或利用 Shell 脚本运行,示例脚本中指定了隐藏目录,指定认证规则,以及日志格式。
tee dufs_server.sh <<'EOF'
STATIC_DIR="/usr/local/nginx/html/"
HOST="0.0.0.0"
PORT="5000"
LOG_FILE="/var/log/dufs.access.log"
AUTH_RULES="admin:123456@/:rw"
dufs $STATIC_DIR
--bind$HOST
--port $PORT
--log-file $LOG_FILE
--log-format '$remote_addr "$request" $status'
--render-index
--render-try-index
--hidden '.*,*.lock,*.tmp,'
--auth $AUTH_RULES
EOF
weiyigeek.top-dufs文件服务器图
使用 systemd 管理启动(生产环境)
步骤 01. 创建 dufs 服务用户,创建并设置其相关目录, 作者将自己主页站点放在 /var/www/html/ 目录下。
# 创建 dufs 用户
useradd dufs --no-create-home --shell /usr/sbin/nologin
# 创建配置目录、工作目录、日志目录
mkdir -pv /etc/dufs
mkdir -pv /var/log/dufs
mkdir -pv /var/www/html/
# 将静态文件移动到工作目录(模拟)
cp -a /usr/local/nginx/html/* /var/www/html/
步骤 02.创建 /etc/dufs/config.yaml 并写入以下内容,设置了隐藏文件规则。
tee /etc/dufs/config.yaml <<'EOF'
serve-path: /var/www/html
bind: 0.0.0.0
port: 5000
path-prefix: /
hidden:
- tmp
- .git
- '*.gitignore'
- '*.log'
- '*.lock'
auth:
- user01:123456@/:rw
- user02:123456@/css:rw,/js:rw
allow-all: false
allow-upload: true
allow-delete: true
allow-search: true
allow-symlink: true
allow-archive: true
allow-hash: true
# enable-cors: true
# render-index: true
render-try-index: true
# render-spa: true
# assets: ./assets/
log-format: '$remote_addr "$request" $status $http_user_agent'
log-file: /var/log/dufs/access.log
compress: low
# tls-cert: tests/data/cert.pem
# tls-key: tests/data/key_pkcs1.pem
EOF
# 权限设置
chown -R dufs:dufs /etc/dufs /var/log/dufs /var/www/html/
步骤 03.创建 /etc/systemd/system/dufs.service 文件,并写入以下内容。
tee /etc/systemd/system/dufs.service <<'EOF'
[Unit]
Description=Dufs Static File Server
After=network.target
[Service]
Type=simple
User=dufs
Group=dufs
WorkingDirectory=/var/www/html
ExecStart=/usr/local/bin/dufs --config /etc/dufs/config.yaml
Restart=always
RestartSec=10
# 安全限制
NoNewPrivileges=yes
PrivateTmp=yes
ProtectSystem=strict
ProtectHome=yes
ReadWritePaths=/var/log/dufs
ReadOnlyPaths=/var/www/html/data
[Install]
WantedBy=multi-user.target
EOF
步骤 04.重载 systemd 配置并使用其进行管理服务。
# 重新加载 systemd 配置文件,使之生效
sudo systemctl daemon-reload
# 开机自启用 systemd 服务
sudo systemctl enable dufs --now
# 启动&停止
sudo systemctl start|stop dufs
步骤 05.查看服务状态,如果服务正常使用浏览器访问 http://ip:5000 即可。
# 查看状态
sudo systemctl status dufs
# 查看日志
sudo journalctl -u dufs -f
# 访问日志
tail -f /var/log/dufs/access.log
weiyigeek.top-dufs使用实践图
dufs 容器化部署
由于我们业务都在 K8s 集群中运行,单独在一台物理机或者虚拟机中运行也不现实,所以这里也顺便演示一下如何在 K8s 集群中部署 dufs 服务,用于在流量高峰时开启 CDN 回源使用,流量低估时直接提供访问。
这里如何搭建 K8S 集群及相关知识就不赘述了,在作者知识星球【全栈工程师修炼指南】中有详细介绍,有兴趣的看友可以去瞅瞅。
实践演示
步骤 01.从 Docker Hub 拉取 sigoden/dufs 镜像,或者在本地构建,可以看到镜像大小很小,仅有几兆左右,与 Nginx 镜像相比 dufs 镜像可以说是非常轻量级,当前最新版本为 v0.45.0。
docker pull sigoden/dufs:v0.45.0
docerk tag sigoden/dufs:v0.45.0 hub.weiyigeek.top/library/sigoden/dufs:v0.45.0
docker push hub.weiyigeek.top/library/sigoden/dufs:v0.45.0
weiyigeek.top-sigoden/dufs图
步骤 02.建议使用 Deployment 或者 Statesfulset 在容器中可使用环境变量进行配置。
# 创建名称空间kubectl create ns app# 部署清单tee dufs-deploy.yaml <<'EOF'apiVersion: v1kind: Servicemetadata:name: web-cdnnamespace: appannotations:ops.k8s.io/name: web-cdnops.k8s.io/desc: 综合项目-存放公共CDN静态资源文件ops.k8s.io/type: frontend-webops.k8s.io/url: https://cdn.weiyigeek.topops.k8s.io/git: https://git.weiyigeek.top/pub/web-cdnlabels:app: web-cdntype: webrole: frontendspec:externalTrafficPolicy: Clusterports:- name: httpport: 8080protocol: TCPtargetPort: 8080selector:app: web-cdntype: webrole: frontendtype: NodePort---apiVersion: apps/v1kind: StatefulSetmetadata:name: web-cdnnamespace: appannotations:ops.k8s.io/name: web-cdnops.k8s.io/desc: 综合项目-存放公共CDN静态资源文件ops.k8s.io/type: frontend-webops.k8s.io/url: https://cdn.weiyigeek.topops.k8s.io/git: https://git.weiyigeek.top/pub/web-cdnlabels:app: web-cdntype: webrole: frontendspec:replicas: 1selector:matchLabels:app: web-cdntype: webrole: frontendserviceName: web-cdntemplate:metadata:annotations:ops.k8s.io/name: web-cdnops.k8s.io/desc: 综合项目-存放公共CDN静态资源文件ops.k8s.io/type: frontend-webops.k8s.io/url: https://cdn.weiyigeek.topops.k8s.io/git: https://git.weiyigeek.top/pub/web-cdnlabels:app: web-cdntype: webrole: frontendspec:affinity:nodeAffinity:requiredDuringSchedulingIgnoredDuringExecution:nodeSelectorTerms:- matchExpressions:- key: kubernetes.io/osoperator: Invalues:- linuxpodAntiAffinity:preferredDuringSchedulingIgnoredDuringExecution:- podAffinityTerm:labelSelector:matchExpressions:- key: appoperator: Invalues:- web-cdntopologyKey: kubernetes.io/hostnameweight: 100containers:- name: appimage: hub.weiyigeek.top/library/sigoden/dufs:v0.45.0imagePullPolicy: IfNotPresentenv:- name: TZvalue: Asia/Shanghai- name: DUFS_BINDvalue: "0.0.0.0"- name: DUFS_SERVE_PATHvalue: "/var/www/html"- name: DUFS_PORTvalue: "8080"- name: DUFS_PATH_PREFIXvalue: "/"- name: DUFS_RENDER_INDEXvalue: 'true'- name: DUFS_RENDER_TRY_INDEXvalue: 'false'- name: DUFS_RENDER_SPAvalue: 'true'- name: DUFS_LOG_FORMATvalue: '$remote_addr "$request" $status'ports:- containerPort: 8080name: httpprotocol: TCPresources:limits:cpu: "2"memory: 4Girequests:cpu: "1"memory: 512MivolumeMounts:- mountPath: /var/www/htmlname: workdirimagePullSecrets:- name: harbor-weiyigeekinitContainers:- name: init-cdncommand:- sh- -c- |cp -a /app/* /work/image: hub.weiyigeek.top/app/cdn:20260316132518-prodimagePullPolicy: IfNotPresentsecurityContext:privileged: truevolumeMounts:- mountPath: /workname: workdirrestartPolicy: AlwaysterminationGracePeriodSeconds: 15volumes:- emptyDir: {}name: workdirEOF# 部署kubectl apply -f dufs-deploy.yaml
最后,考虑到大家可能对 K8s 不是很熟悉,也整理一个 docker 运行示例,供参考。
$ docker run -d --name dufs_server -p 5000:5000
-e DUFS_SERVE_PATH="/var/www/html"
-e DUFS_BIND=0.0.0.0
-e DUFS_PORT="5000"
-e DUFS_PATH_PREFIX=/
-e DUFS_HIDDEN=.git,*.tmp,*.log,*.lock,*.zip,*.tar.gz
-e DUFS_RENDER_INDEX=true
-e DUFS_RENDER_SPA=true
-e DUFS_LOG_FORMAT='$remote_addr "$request" $status'
-v /var/www/html:/var/www/html:ro
hub.weiyigeek.top/library/sigoden/dufs:v0.45.0
$ docker ps --filter name=dufs_server
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ae53ec0f96e3 hub.weiyigeek.top/library/sigoden/dufs:v0.45.0 "/bin/dufs" 31 seconds ago Up 30 seconds 0.0.0.0:5000->5000/tcp, :::5000->5000/tcp dufs_server
$ docker logs -f --tail 50 dufs_server
weiyigeek.top-docker 运行 dufs 图
至此,作者在 K8S 以及 Docker 中使用 dufs 搭建的静态资源服务就完成了,希望对大家有所帮助!如果有帮助请一定要关注我哟,后续将发布利用 OpenResty 反向代理作为 CDN 回源,学习更多运维开发知识!
181