茄子的个人空间

使用Docker构建Webdav服务器

字数统计: 2.1k阅读时长: 9 min
2025/06/17
loading

1. 前言

半年前,我曾基于 Apache2 搭建了一套 WebDAV 服务,用于实现 Obsidian 和 Zotero 的多端同步。那次部署过程可谓一波三折,尤其是在配置 SSL 签名和 Apache2 时遇到了不少麻烦。由于当时我没有备案的域名,只能使用公网 IP 申请 SSL 证书,而且免费证书只有 3 个月有效期,到期后还需要手动续签。虽然最终勉强配置成功,但也花了我不少时间和精力。

遗憾的是,这套服务没能持续使用太久。等 SSL 证书过期之后,我因为忙于其他事务也就没有再去续签。而当我想重新启用这套同步方案时,却发现当时使用的华为云廉价服务器(仅 1GB 内存)卡顿严重,连 SSH 登录都成问题。即便重启系统,性能也没有好转,于是这件事便被我搁置了下来。

直到最近,我再次感受到 Obsidian 与 Zotero 多端同步的强烈需求。恰好这段时间我也深入学习了 Docker 的使用,便想到或许可以通过 Docker 来部署 WebDAV。通过容器化部署,既可以简化配置流程,又能保证未来迁移或重建时的复用性,大大提升效率。

于是,我选择使用了现成的 WebDAV Docker 镜像,并将服务器迁移到了腾讯云的海外节点。通过购买廉价轻量化域名和海外 IP,我可以在无需备案的情况下正常使用域名访问。更令人欣喜的是,这一次我通过自动化工具配置了 HTTPS,SSL 证书可以自动续签,彻底解决了上一次的痛点。

这次部署过程整体顺利许多,但中途仍然踩了一些坑。因此,我决定将整个过程记录下来,既是对自己的总结,也希望能为有类似需求的朋友提供参考。

2. 概述

这次配置的基于Docker的WebDAV文件共享服务,主要有如下特点:

  • 使用Traefik作为反向代理和SSL证书管理
  • 部署在Docker环境中

3. 部署指南

3.1 前提条件

  • 已安装Docker和Docker Compose
  • 域名DNS已正确解析到服务器IP

3.2 配置说明

主要的配置文件有三个,分别是docker-compose.yml、traefik.toml以及.env。

  • docker-compose.yml
    主要负责定义整个服务栈的容器组成和网络配置。包括每个服务使用的镜像、端口映射、卷挂载、环境变量引用、依赖服务等。

  • traefik.toml
    Traefik 的主配置文件,负责定义 Traefik 本身的行为。例如是否启用 Web UI、监听哪些 entrypoints(如 HTTP/HTTPS)、证书自动申请(Let’s Encrypt)方式、日志输出级别等。

  • .env
    用于存放环境变量,供 docker-compose.yml 中引用。这样可以实现配置的灵活管理和版本控制的安全性,避免在 compose 文件中硬编码敏感信息(如密码、域名、端口等)。

注意:需要手动修改 traefik.toml中的邮箱地址,因为traefik.toml 不支持使用 .env 文件中的 ACME_EMAIL 变量。

3.3 docker-compose.yml 配置

下面是 docker-compose.yml中应该填写的配置,这个配置经过多次修改,按照操作一步步下来,是可以直接跑通的。

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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
version: '3'
# See https://docs.docker.com/compose/overview/ for more information.

# If you make changes to this file or any related files, apply them by
# navigating to the directory that holds this file and run this as root:
# docker-compose down; docker-compose up -d

# Create two networks: one for front-end containers that we'll make
# publicly accessible to the internet, and one for private back-end.
networks:
frontend:
name: webdav_frontend # Explicitly set network name
backend:
name: webdav_backend # Explicitly set network name

# Create persistent Docker volumes to preserve important data.
# We don't want our data to be lost when restarting containers.
volumes:
vol-webdav:

# Create our containers.
services:
# Traefik is a reverse proxy. It handles SSL and passes traffic to
# Docker containers via rules you define in docker-compose labels.
# Its dashboard is at http://example.com/traefik/ (behind a login).
traefik:
# https://hub.docker.com/_/traefik/
image: ${BASE_IMAGE_URL}/traefik:latest
command:
# --api --docker --acme.email="${ACME_EMAIL}"
- "--api.dashboard=true"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--certificatesresolvers.letsencrypt.acme.httpchallenge=true"
- "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web"
- "--certificatesresolvers.letsencrypt.acme.email=${ACME_EMAIL}"
- "--certificatesresolvers.letsencrypt.acme.storage=/acme.json"
restart: always
networks:
- backend
- frontend
volumes:
- /var/run/docker.sock:/var/run/docker.sock # Access to Docker
- ./traefik.toml:/traefik.toml # Traefik configuration
- ./acme.json:/acme.json # SSL certificates
ports:
# Map port 80 and 443 on the host to this container.
- "801:80"
- "4431:443"
labels:
# - "traefik.docker.network=webdav_frontend"
# - "traefik.enable=true"
# - "traefik.frontend.rule=Host:${TRAEFIK_DOMAINS}; PathPrefixStrip:/traefik"
# - "traefik.port=8080"
# - "traefik.protocol=http"
# # Remove next line to disable login prompt for the dashboard.
# - "traefik.frontend.auth.basic=${BASIC_AUTH}"

# - "traefik.enable=true"
# - "traefik.http.routers.webdav.rule=Host(`eggabc.site`)"
# - "traefik.http.routers.webdav.entrypoints=websecure"
# - "traefik.http.routers.webdav.tls.certresolver=letsencrypt"
# - "traefik.http.services.webdav.loadbalancer.server.port=80"


- "traefik.enable=true"
- "traefik.http.routers.dashboard.rule=Host(`${TRAEFIK_DOMAINS}`)"
- "traefik.http.routers.dashboard.service=api@internal"
- "traefik.http.routers.dashboard.entrypoints=websecure"
- "traefik.http.routers.dashboard.tls.certresolver=letsencrypt"
- "traefik.http.routers.dashboard.middlewares=auth"
- "traefik.http.middlewares.auth.basicauth.users=${BASIC_AUTH}"

# Watchtower detects if any linked containers have an new image
# available, automatically updating & restarting them if needed.
# watchtower:
# # https://hub.docker.com/r/centurylink/watchtower/
# image: v2tec/watchtower:latest
# # https://github.com/v2tec/watchtower#options
# # This schedule applies updates (if available) at midnight.
# command: --cleanup --schedule "0 0 0 * * *"
# restart: always
# volumes:
# - /var/run/docker.sock:/var/run/docker.sock

# The main WebDAV container.
webdav:
# https://hub.docker.com/r/bytemark/webdav/
image: ${BASE_IMAGE_URL}/bytemark/webdav
restart: always
networks:
- frontend
volumes:
# - ./user.passwd:/user.passwd
- type: bind
source: ./user.passwd
target: /user.passwd
read_only: true
- vol-webdav:/var/lib/dav
environment:
SERVER_NAMES: ${WEBDAV_DOMAINS}
LOCATION: ${WEBDAV_LOCATION}
labels:
# - "traefik.docker.network=webdav_frontend"
# - "traefik.enable=true"
# - "traefik.frontend.rule=Host:${WEBDAV_DOMAINS}"
# - "traefik.port=80"
# - "traefik.protocol=http"
- "traefik.enable=true"
- "traefik.http.routers.webdav.rule=Host(`${WEBDAV_DOMAINS}`) && PathPrefix(`${WEBDAV_LOCATION}`)"
- "traefik.http.routers.webdav.entrypoints=websecure"
- "traefik.http.routers.webdav.tls.certresolver=letsencrypt"
- "traefik.http.services.webdav.loadbalancer.server.port=80"

3.4 Traefik 配置

3.4.1 新建 acme.json 文件

Traefik 需要一个 JSON 文件保存证书信息,请在根目录下新建该空文件,并设置权限:

1
2
touch acme.json
chmod 600 acme.json

3.4.2 创建 traefik.toml 文件,并添加如下内容:

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
[global]
checkNewVersion = false
sendAnonymousUsage = false

[entryPoints]
[entryPoints.web]
address = ":80"
[entryPoints.websecure]
address = ":443"

[api]
dashboard = true
insecure = false

[providers]
[providers.docker]
endpoint = "unix:///var/run/docker.sock"
exposedByDefault = false
watch = true
network = "webdav_frontend"

[certificatesResolvers.letsencrypt]
[certificatesResolvers.letsencrypt.acme]
email = "your_email_address"
storage = "acme.json"
[certificatesResolvers.letsencrypt.acme.httpChallenge]
entryPoint = "web"

[log]
level = "INFO"

提示: 需要将 your_email_address 替换为你自己的邮箱地址。

3.5 配置环境变量

3.5.1 设置基本认证

  • 使用 htpasswd 命令生成用户密码文件 user.passwd
1
htpasswd -c user.passwd username

提示:如果系统中没有安装 htpasswd,可通过安装 apache2-utils(Debian/Ubuntu)或 httpd-tools(CentOS)获得该命令。

  • 设置文件权限
    设置 user.passwd 文件权限为 644 (不安全,临时快速解决方案):
1
chmod 644 user.passwd

然后将生成的哈希密码复制到 .env 文件中的 BASIC_AUTH 变量中。

3.5.2 创建 .env文件,并根据提示进行设置

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
# Docker Compose can read environment variables from this file.
# See https://docs.docker.com/compose/env-file/

# Put admin areas behind a login prompt, with username and password
# specified here. Run `htpasswd -n admin` to create a password hash
# for user "admin". Paste the output here. SSL strongly recommended.
# 使用 `htpasswd -n username` 命令生成密码哈希。
BASIC_AUTH=

# Let's Encrypt needs an email address for registration.
# 配置 Let's Encrypt 的注册邮箱,不需要在 Let's Encrypt 网站上注册。
ACME_EMAIL=
# The Traefik dashboard will be available at these domains.
# The URL is http://example.com/traefik/
# You'll need to fill in BASIC_AUTH above.
# Traefik 的仪表盘将可通过这些域名访问,要确保该域名能够被解析,不然会报错
TRAEFIK_DOMAINS=
# Your WebDAV site will be available at these domains. Every domain
# needs DNS records pointing to your server for SSL to work.
# 你的 WebDAV 站点将可通过这些域名访问。每个域名都需要 DNS 记录指向你的服务器,以便 SSL 工作。
WEBDAV_DOMAINS=

# Set the URL path where you want your WebDAV site to be.
# 设置 WebDAV 站点的 URL 路径,要以 斜杠结尾,否则报错
WEBDAV_LOCATION=/webdav/


#设置docker镜像的地址
BASE_IMAGE_URL=docker.1ms.run

提示:在上面的配置中,等号右边的变量值都不要加引号,直接填写变量值即可。

4. 服务管理

操作 命令 说明
启动服务 docker-compose up -d 后台启动所有容器
停止服务 docker-compose down 停止并移除所有容器
查看日志 docker-compose logs -f 实时查看容器日志
更新服务 docker-compose pull && docker-compose up -d 拉取最新镜像并重启服务

5. 注意事项

⚠️ 重要提示:

  • 首次启动可能需要几分钟获取SSL证书
  • 修改配置后需要重启服务生效
  • 确保.envuser.passwd文件已正确配置
  • 定期备份acme.json文件以防止证书丢失
  • 建议使用强密码保护WebDAV访问
CATALOG
  1. 1. 1. 前言
  2. 2. 2. 概述
  3. 3. 3. 部署指南
    1. 3.1. 3.1 前提条件
    2. 3.2. 3.2 配置说明
    3. 3.3. 3.3 docker-compose.yml 配置
    4. 3.4. 3.4 Traefik 配置
      1. 3.4.1. 3.4.1 新建 acme.json 文件
      2. 3.4.2. 3.4.2 创建 traefik.toml 文件,并添加如下内容:
    5. 3.5. 3.5 配置环境变量
      1. 3.5.1. 3.5.1 设置基本认证
      2. 3.5.2. 3.5.2 创建 .env文件,并根据提示进行设置
  4. 4. 4. 服务管理
  5. 5. 5. 注意事项