用 Dufs 开启 WebDAV 文件共享服务

一键脚本

下面的脚本会安装 dufs、生成 launchd 配置、加载 WebDAV 服务,并打包出一个可点击启动的 WebDAV.app

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
#!/bin/zsh
set -eu

SHARE_DIR="$HOME/Documents/PT"                              # 需要共享的目录,改成实际路径
PORT="9999"                                                 # WebDAV 监听端口
APP_NAME="WebDAV"                                           # 打包后显示的应用名称
LABEL="com.anthony.dufs.webdav"                             # launchd 服务标识,通常保持不变
BASE_DIR="$HOME/Library/Application Support/dufs-webdav"    # 运行脚本保存目录
SCRIPT_PATH="$BASE_DIR/start-dufs-webdav.sh"                # dufs 启动脚本
PLIST_PATH="$HOME/Library/LaunchAgents/${LABEL}.plist"      # launchd 配置文件
LOG_DIR="$HOME/Library/Logs/dufs-webdav"                    # 服务日志目录
APP_SCRIPT="$HOME/Desktop/webdav-launcher.applescript"      # 原始启动器脚本
APP_PATH="/Applications/${APP_NAME}.app"

if ! command -v brew >/dev/null 2>&1; then
  echo "Homebrew 未安装"
  exit 1
fi

if ! command -v dufs >/dev/null 2>&1; then
  brew install dufs
fi

DUFS_BIN="$(command -v dufs)"

mkdir -p "$SHARE_DIR" "$BASE_DIR" "$HOME/Library/LaunchAgents" "$LOG_DIR"

cat > "$SCRIPT_PATH" <<EOF
#!/bin/zsh
set -eu

SHARE_DIR="$SHARE_DIR"
PORT="$PORT"

exec "$DUFS_BIN" "\$SHARE_DIR" \\
  --bind 0.0.0.0 \\
  --port "\$PORT" \\
  --hidden ".*" \\
  --allow-all
EOF

chmod +x "$SCRIPT_PATH"

cat > "$PLIST_PATH" <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Label</key>
  <string>$LABEL</string>

  <key>ProgramArguments</key>
  <array>
    <string>/bin/zsh</string>
    <string>$SCRIPT_PATH</string>
  </array>

  <key>RunAtLoad</key>
  <true/>

  <key>KeepAlive</key>
  <true/>

  <key>WorkingDirectory</key>
  <string>$SHARE_DIR</string>

  <key>StandardOutPath</key>
  <string>$LOG_DIR/stdout.log</string>

  <key>StandardErrorPath</key>
  <string>$LOG_DIR/stderr.log</string>
</dict>
</plist>
EOF

plutil -lint "$PLIST_PATH"

cat > "$APP_SCRIPT" <<EOF
on run
	set uid_text to do shell script "id -u"
	set agent_plist to "$PLIST_PATH"
	set agent_label to "gui/" & uid_text & "/$LABEL"
	set shell_cmd to "/bin/sh -lc " & quoted form of ("launchctl bootstrap gui/" & uid_text & " " & quoted form of agent_plist & " >/dev/null 2>&1 || true; for i in 1 2 3 4 5; do launchctl kickstart -k " & quoted form of agent_label & " >/dev/null 2>&1 && exit 0; sleep 1; launchctl bootstrap gui/" & uid_text & " " & quoted form of agent_plist & " >/dev/null 2>&1 || true; done; exit 1")

	do shell script shell_cmd

	open location "http://127.0.0.1:$PORT/"
end run
EOF

osacompile -o "$APP_PATH" "$APP_SCRIPT"

launchctl bootout gui/$(id -u)/$LABEL >/dev/null 2>&1 || true
sleep 1
launchctl bootstrap gui/$(id -u) "$PLIST_PATH"
sleep 1
launchctl kickstart -k gui/$(id -u)/$LABEL

echo "服务地址: http://127.0.0.1:${PORT}/"
echo "已生成: $APP_PATH"

前提

这套配置会将 SHARE_DIR 目录以匿名可写方式共享到局域网,适合可信内网环境。默认端口为 9999

变量说明

SHARE_DIR 决定实际共享目录。需要更换共享位置时,只需要修改这一个变量。

PORT 决定 WebDAV 监听端口。局域网访问地址和本机访问地址都会随这个端口变化。

APP_NAMEAPP_PATH 控制打包后 .app 的显示名称。需要将 PT WebDAV 改为 WebDAV 这类变化时,直接修改这里即可。

APP_SCRIPT 是原始 AppleScript 文件,APP_PATH 是打包产物。后续若只重建桌面启动器,直接重新编译这两个路径即可。

LABELlaunchd 服务标识。没有同时维护多个实例的需求时,保持固定最简单。

脚本做了什么

脚本首先确保 dufs 已安装,并解析当前系统中的实际二进制路径。这样可以同时兼容 Apple Silicon 和 Intel Mac 上不同的 Homebrew 安装位置。

随后会生成一个独立的 dufs 启动脚本,并把共享目录、端口等运行参数集中写入其中。真正的后台服务由 launchd 读取这个脚本来启动。

接着会生成 LaunchAgent plist,把服务注册为当前用户会话中的常驻后台任务,并将日志输出到 ~/Library/Logs/dufs-webdav

最后会生成一个 AppleScript 启动器,并通过 osacompile 打包成 .app。这个启动器会先尝试拉起后台服务,再自动打开 http://127.0.0.1:$PORT/。当前打包结果仍使用默认 applet 图标,本文仅覆盖功能性封装。

访问与验证

本机访问地址:

1
http://127.0.0.1:9999/

局域网其他设备访问地址:

1
http://<Mac 的局域网 IP>:9999/

端口监听状态可以直接检查:

1
2
lsof -nP -iTCP:9999 -sTCP:LISTEN
curl -I http://127.0.0.1:9999/

Finder 的“连接服务器”也可以直接填写相同地址。

常见维护

共享目录、端口或 .app 名称发生变化时,直接修改脚本开头的 SHARE_DIRPORTAPP_NAME,然后重新执行整段脚本即可。打包后的 .app 不需要单独维护内部配置。

如果只需要重新加载后台服务,可执行:

1
2
3
4
5
launchctl bootout gui/$(id -u)/com.anthony.dufs.webdav >/dev/null 2>&1 || true
sleep 1
launchctl bootstrap gui/$(id -u) "$HOME/Library/LaunchAgents/com.anthony.dufs.webdav.plist"
sleep 1
launchctl kickstart -k gui/$(id -u)/com.anthony.dufs.webdav

如果只需要重建桌面启动器,可执行:

1
2
APP_NAME="WebDAV"
osacompile -o "/Applications/${APP_NAME}.app" "$HOME/Desktop/webdav-launcher.applescript"

日志位置如下:

1
2
tail -f "$HOME/Library/Logs/dufs-webdav/stdout.log"
tail -f "$HOME/Library/Logs/dufs-webdav/stderr.log"
Licensed under CC BY-NC-SA 4.0
Built with Hugo
Theme Stack designed by Jimmy