Vikunja 自部署:搭建属于自己的待办管理系统(Docker + Cloudflare Tunnel + CalDAV 手机同步)

2026-06-21

引言

市面上待办 App 很多——Todoist、Things 3、Microsoft To Do、TickTick……但都面临同一个问题:数据在别人手里。你的任务列表、到期日、优先级,全存在 SaaS 厂商的服务器上。哪天服务涨价、关停、或者你只是想换个客户端,数据迁移就是一场噩梦。

自部署待办系统的好处显而易见:

  • 数据完全自主——存在自己的服务器上,不经过第三方
  • 隐私——任务内容不上传云端
  • 零订阅费——只需一台小服务器(树莓派、NAS、云服务器都行)
  • 自由选择客户端——直接搭配手机自带日历/待办 App,不需要装额外应用

本文介绍 Vikunja——一个开源、现代、功能完善的自部署待办管理平台。用 Docker Compose 一键部署,搭配 Cloudflare Tunnel 安全暴露到公网,再用 CalDAV 协议同步到手机,打造一套”零成本、高隐私”的待办管理系统。

Vikunja 是什么

Vikunja(发音 /viːˈkuːnjə/)是一个用 Go 编写的开源待办任务管理平台,AGPLv3 协议许可。它的定位介于轻量待办(如 Todoist)和重量级项目管理(如 Jira/OpenProject)之间。

核心功能一览:

功能 说明
项目/列表 按项目组织任务,支持嵌套层级
看板视图 以 Kanban Board 形式查看任务
Gantt 图表 可视化任务的时间依赖关系
标签 & 优先级 用标签分类,四级优先级标记
任务关联 关联到另一个任务(依赖/引用关系)
团队协作 邀请其他用户协作同一项目
重复任务 支持 RRULE 规则的周期性任务
提醒通知 邮件通知 + Webhook
公开分享 生成分享链接给外部用户(无需登录)
CalDAV 同步 通过开放协议同步到手机/其他应用
REST API 完整的 API,可编程操作所有功能
全平台支持 Web 端 + Linux/Windows/macOS 桌面端 + iOS/Android 客户端

和主流待办工具的对比:

Vikunja Todoist Things 3 Microsoft To Do
开源 ✅ AGPLv3
自部署
CalDAV 同步 ✅(实验性)
看板视图
团队协作 ✅(付费)
价格 免费 免费/付费 ¥328 买断 免费

自部署意味着你完全掌控数据——但如果不想自己维护服务器,Vikunja 官方也提供托管版 Vikunja Cloud,需要付费订阅。

一、Docker Compose 部署

Vikunja 官方推荐用 Docker Compose 部署。核心架构是两个容器:Vikunja 应用(Go 二进制) + PostgreSQL 数据库

准备工作

在一台有 Docker 和 Docker Compose 的 Linux 服务器上操作。需要什么配置?门槛很低:

  • 内存:最低 512MB,推荐 1GB+
  • CPU:单核即可
  • 磁盘:初始占用 ~200MB(不含数据库数据)
  • 操作系统:支持 Docker 的任何 Linux 发行版

适合部署的位置:闲置的树莓派、NAS(群晖/飞牛/unRAID)、云服务器(阿里云/腾讯云/Vultr 最低配都绰绰有余)。

创建项目目录

mkdir -p /path/to/vikunja
cd /path/to/vikunja
mkdir files    # 存储用户上传的附件、项目背景图
mkdir -p db    # PostgreSQL 数据目录
chown 1000 files  # ⚠️ 重要:Vikunja 容器以 UID 1000 运行

docker-compose.yml

services:
  vikunja:
    image: vikunja/vikunja:latest
    environment:
      VIKUNJA_SERVICE_PUBLICURL: https://todo.yourdomain.com
      VIKUNJA_DATABASE_HOST: db
      VIKUNJA_DATABASE_PASSWORD: changeme
      VIKUNJA_DATABASE_TYPE: postgres
      VIKUNJA_DATABASE_USER: vikunja
      VIKUNJA_DATABASE_DATABASE: vikunja
      VIKUNJA_SERVICE_SECRET: <生成一个随机密钥>
      VIKUNJA_SERVICE_ENABLEREGISTRATION: true    # 首次部署开启注册
    ports:
      - "3456:3456"
    volumes:
      - ./files:/app/vikunja/files
    depends_on:
      db:
        condition: service_healthy
    restart: unless-stopped

  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: changeme
      POSTGRES_USER: vikunja
    volumes:
      - ./db:/var/lib/postgresql/data
    restart: unless-stopped
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -h localhost -U vikunja"]
      interval: 5s
      start_period: 30s

几个关键配置说明:

  • VIKUNJA_SERVICE_PUBLICURL:填最终用户访问的地址(含协议和路径)。如果用了反向代理/Cloudflare Tunnel,填公网域名;如果只是局域网用,填 http://192.168.x.x:3456注意:如果端口不是 80/443,URL 中必须包含端口号,否则注册账号时会返回「unauthorized」错误。
  • VIKUNJA_SERVICE_SECRET:用于 JWT 签名。用 openssl rand -base64 32 生成,不要用示例中的值。
  • VIKUNJA_SERVICE_ENABLEREGISTRATION: true:首次部署先开启注册,建好管理员账号后关掉,防止陌生人注册。

启动

docker compose up -d

检查启动日志:

docker compose logs -f

看到类似输出说明启动成功:

vikunja_1 | ⇨ http server started on [::]:3456
vikunja_1 | INFO ▶ Vikunja version 0.24.0

验证 API 是否正常:

curl http://localhost:3456/api/v1/info

返回 JSON 包含版本号即成功。打开浏览器访问 http://服务器IP:3456,应该看到 Vikunja 登录页面。

首次设置

  1. 注册一个账号(第一个注册的用户默认是管理员)
  2. 进入「设置 → 用户」关闭公开注册(Enable Registration: OFF
  3. 也可以在环境变量中设置 VIKUNJA_SERVICE_ENABLEREGISTRATION: false 并重启

注册关闭后如何创建用户

如果关闭了公开注册,再想添加用户只能用 CLI:

docker compose exec vikunja /app/vikunja/vikunja user create \
  -u 用户名 \
  -e email@example.com \
  -p 密码

列出所有用户:

docker compose exec vikunja /app/vikunja/vikunja user list

⚠️ Vikunja 镜像基于 scratch 基础镜像——它没有 shell。你无法 docker exec -it vikunja sh 进入容器。所有 CLI 操作必须通过 docker compose exec vikunja /app/vikunja/vikunja <subcommand> 执行完整路径。

二、Cloudflare Tunnel 公网暴露

自部署应用的最大痛点:如何安全地从公网访问

传统方案是在路由器上做端口转发(Port Forwarding),但这意味着:
- 你的公网 IP 直接暴露(容易被扫端口)
- 需要手动管理 SSL 证书
- 家宽 IP 变动后 DDNS 有延迟
- 运营商可能封 80/443 端口

Cloudflare Tunnel(原名 Argo Tunnel)解决了这些问题:你的服务器主动向外连到 Cloudflare Edge,不开放任何入站端口。用户通过 Cloudflare 网络访问,流量全程加密。

整体架构

用户 → https://todo.yourdomain.com 
     → Cloudflare Edge (SSL 终结)
     → Cloudflare Tunnel (加密隧道)
     → 本地 cloudflared 容器
     → Vikunja (localhost:3456)

全程没有开放防火墙端口。甚至你的服务器可以在一台没有公网 IP 的设备上(接入 CGNAT 的家宽、5G 路由器都行)。

前提

  • 一个在 Cloudflare 管理的域名(免费套餐即可)
  • 服务器能出站访问互联网

步骤 1:Cloudflare 侧创建 Tunnel

登录 Cloudflare Dashboard → Zero Trust → Networks → Tunnels → Create a tunnel:

  1. 选择 Cloudflared 类型
  2. 给隧道命名(如 vikunja-tunnel
  3. 复制生成的 Tunnel Token(一串很长的字符串,形如 eyJhIjoi...

步骤 2:Docker Compose 中增加 cloudflared

在上面的 docker-compose.yml 中增加一个服务:

  cloudflared:
    image: cloudflare/cloudflared:latest
    command: tunnel --no-autoupdate run
    environment:
      - TUNNEL_TOKEN=你的Tunnel Token
    restart: unless-stopped

或者你也可以独立部署 cloudflared(同一个 Docker Compose 文件或单独的项目都行)。

步骤 3:配置公网主机名

Cloudflare Tunnel Dashboard → 你的隧道 → Public Hostnames → Add:

  • Subdomaintodo(或你想要的子域名)
  • Domain:选择你的域名
  • Type:HTTP
  • URLhttp://vikunja:3456

这里的 vikunja 是 Docker Compose 中 Vikunja 服务的容器名,Docker 内部 DNS 会自动解析。如果你把 cloudflared 放在独立的 compose 文件中,URL 可能需要填服务器内网 IP(如 http://192.168.1.100:3456)。

保存后,等待几十秒 DNS 生效,访问 https://todo.yourdomain.com 即可看到 Vikunja。

可选:Caddy/Nginx 反代 + Cloudflare Tunnel

如果你的网络架构中有反向代理(如 Caddy、Nginx Proxy Manager、Traefik),Cloudflare Tunnel 也可以指向反代而非直接指向 Vikunja:

用户 → Cloudflare Tunnel → Caddy (端口 443) → Vikunja (端口 3456)

这样你可以在反代层统一管理 SSL、缓存、URL 重写。对 Vikunja 而言,Caddy 配置极其简单:

todo.yourdomain.com {
    reverse_proxy 127.0.0.1:3456
}

Docker Hub 镜像拉取限流怎么办

国内网络环境拉 Docker 镜像经常遇到 Hub 限流。备选镜像前缀:

# hub.rat.dev 镜像
docker pull hub.rat.dev/vikunja/vikunja:latest
docker tag hub.rat.dev/vikunja/vikunja:latest vikunja/vikunja:latest

docker pull hub.rat.dev/library/postgres:16
docker tag hub.rat.dev/library/postgres:16 postgres:16

其他可用的镜像加速:docker.1ms.run/docker.xuanyuan.me/。注意镜像来源的可靠性。

三、CalDAV 手机同步

⚠️ Vikunja 的 CalDAV 集成目前仍处于早期 Alpha 阶段,作者明确标注有 bug。部分客户端工作正常,部分客户端有问题。建议先在非主力设备上测试。

CalDAV 是什么

CalDAV 是一个开放标准协议(RFC 4791),用于在服务器和客户端之间同步日历和待办数据。原生被 iOS/macOS 系统日历和提醒事项支持。Android 端通过第三方 App 支持。Vikunja 实现了 CalDAV VTODO 扩展,可以把任务同步到手机自带的待办 App。

获取 CalDAV 凭证

Vikunja 的 CalDAV 认证有两种方式:

  1. 账号密码:用你 Vikunja 的用户名 + 登录密码直接认证
  2. 专用 Token:在 Vikunja「设置 → CalDAV」中生成一个以 tk_ 开头的专用 token(推荐,更安全)

CalDAV 端点信息

项目
基准 URL https://todo.yourdomain.com/dav(或内网 http://192.168.x.x:3456/dav
认证方式 Basic Auth(用户名 + 密码/Token)
用户主体 /principals/<用户名>/
所有项目 /projects/
单个项目 /projects/<项目ID>/
单个任务 /projects/<项目ID>/<任务UID>

💡 项目 ID 可以在 Vikunja Web 界面打开项目后,从浏览器地址栏的 URL 中看到。

iOS 配置(iPhone/iPad)

iOS 系统自带的「提醒事项」App 支持 CalDAV 同步,无需安装第三方应用:

  1. 设置 → 日历 → 添加账户 → 其他 → 添加 CalDAV 账户
  2. 填写:
  3. 服务器todo.yourdomain.com(或内网 IP)
  4. 路径/dav
  5. 用户名:你的 Vikunja 用户名
  6. 密码:CalDAV Token 或登录密码
  7. 打开「提醒事项」App,会自动加载 Vikunja 的项目作为清单

⚠️ iOS 的提醒事项同步可能会出现:
- 项目列表可能需要手动刷新才能看到
- 首次同步可能耗时较长(取决于任务数量)
- 部分属性(如富文本描述)可能不同步

Android 配置

Android 采用的是双层面架构,需要两个 App 配合:

第一层:同步引擎(DAVx⁵)

DAVx⁵ 负责与 CalDAV 服务器通信,将任务数据拉到手机本地存储。

  • 下载:推荐从 F-Droid 下载开源免费版(Google Play 版收费)
  • 配置:
  • 打开 DAVx⁵ → 添加账户
  • 选择 CalDAV 类型
  • URL:https://todo.yourdomain.com/dav 或内网地址
  • 用户名 + 密码/Token
  • 选择需要同步的项目列表

第二层:待办界面(Tasks.org)

Tasks.org 是一个开源、功能丰富的待办 App,通过系统同步框架读取 DAVx⁵ 的数据。

  • 下载:F-Droid 或 Google Play(开源免费)
  • 配置:
  • 如果 DAVx⁵ 和 Tasks.org 都正确安装,Tasks.org 会自动识别 DAVx⁵ 同步过来的清单
  • 进入 Tasks.org 设置 → 同步 → 确认 DAVx⁵ 集成已开启
  • 同步后的任务会显示在 app 中,可正常编辑、勾选完成

DAVx⁵ 与 Tasks.org 直接 CalDAV 的取舍

Tasks.org 支持两种同步方式:

方式 优点 缺点
DAVx⁵ → Tasks.org 任务数据存本地,离线可用 需要在 Tasks.org 中额外配置同步集成
Tasks.org 直接 CalDAV 一步到位 不支持在 Tasks.org 中创建/重命名/删除清单,同步稳定性略差

建议首选 DAVx⁵ 方案,离线可用性更好。

受支持的 VTODO 属性

Vikunja 的 CalDAV 支持以下任务属性同步:

已支持:UID、SUMMARY(标题)、DESCRIPTION(描述)、PRIORITY(优先级)、CATEGORIES(标签)、COMPLETED(完成时间)、DUE(截止日期)、DURATION(持续时间)、DTSTART(开始时间)、RRULE(重复规则)、STATUS(状态)、VALARM(提醒)

不支持:ATTACH(附件)、GEO(地理位置)、LOCATION(位置)、URL

四、运维与常见陷阱

部署完成只是第一步。以下是实测中遇到的坑和解决方案:

1. files 目录权限问题

Vikunja 容器内进程以 UID 1000 运行。files/ 目录必须由这个用户拥有,否则上传附件、背景图会报权限拒绝:

open /app/vikunja/files/1: permission denied

解决

chown 1000:1000 files
# 不要递归 chown,只改顶层目录即可

2. 容器无 Shell,调试靠日志

Vikunja 镜像基于 scratch,是最精简的 Docker 镜像。这意味着:

# ❌ 这些都不行
docker exec -it vikunja sh
docker exec -it vikunja bash

# ✅ 只能这样
docker compose logs -f
docker compose logs vikunja | tail -50

3. VIKUNJA_SERVICE_PUBLICURL 必须正确

这个环境变量决定了 Vikunja 生成的链接、API 请求路径是否正确。如果填错,注册页面会报「unauthorized」错误。部署在反代后时尤其容易出问题:

  • 用了 Cloudflare Tunnel → 填 https://todo.yourdomain.com
  • 局域网直连(无反代)→ 填 http://192.168.x.x:3456(含端口)
  • 用了反代且反代非标准端口 → 填完整的公网地址

4. Cloudflare Tunnel 配置后 Vikunja 提示数据库连接失败

如果通过 Cloudflare Tunnel 访问 Vikunja 时页面一直加载然后报错,通常是 VIKUNJA_SERVICE_PUBLICURL 配置不正确。Cloudflare Tunnel 改写了一些请求头,Vikunja 需要正确的 PUBLICURL 才能生成有效的内部链接。

解决:确保 VIKUNJA_SERVICE_PUBLICURL 填的是公网 https:// URL,而不是内网 HTTP 地址。

5. Docker Hub 拉取限流

国内频繁拉取 Docker Hub 镜像会遇到 rate limit。除了上面提到的镜像前缀,还可以考虑:

  • registry.docker-cn.com 等国内镜像站(部分已关闭,需自行测试可用性)
  • 在 NAS 或其他服务器上部署 Docker Registry Mirror
  • 只更新稳定版标签(vikunja/vikunja:latest 更新不频繁,基本不会触限)

6. 数据备份

最小化备份方案:

# 备份数据库 + 上传文件
docker compose exec db pg_dump -U vikunja vikunja > vikunja-db-backup.sql
tar czf vikunja-backup-$(date +%Y%m%d).tar.gz \
  vikunja-db-backup.sql \
  files/

恢复时重建容器,然后:

cat vikunja-db-backup.sql | docker compose exec -T db psql -U vikunja

7. 关闭注册后的用户管理

如果关闭了公开注册(推荐生产环境这么做),需要添加用户时只能用容器 CLI。由于容器没有 shell,命令格式是:

# 创建用户
docker compose exec vikunja /app/vikunja/vikunja user create \
  -u newuser -e newuser@example.com -p securepassword

# 列出所有用户
docker compose exec vikunja /app/vikunja/vikunja user list

8. Docker 容器版本更新

cd /path/to/vikunja
docker compose pull
docker compose up -d

Vikunja 使用数据库迁移自动升级 schema,启动时自动完成。如果升级后出现问题,检查日志:

docker compose logs vikunja | grep -i error

9. 容器数据导出

Vikunja 的数据导出功能需要容器内的 /tmp 目录可写。如果你的 Docker 配置限制了 /tmp 权限,可以在 compose 文件中添加:

volumes:
  - /tmp:/tmp

可选:用户端的替代选择

Vikunja 不是唯一的选择。以下是同类型自部署待办工具对比:

项目 语言 数据库 看板 CalDAV 协作
Vikunja Go PostgreSQL/MySQL/SQLite ✅(实验性)
Nextcloud Tasks PHP 依赖 Nextcloud
OpenProject Ruby PostgreSQL ✅(重型)
Taiga Python/Django PostgreSQL
Plane Python/Django PostgreSQL
Huly TypeScript MongoDB

选型建议

  • 如果已经在用 Nextcloud:直接用 Nextcloud Tasks + CalDAV 同步手机,零额外部署
  • 如果只想要一个轻量、好看的待办:Vikunja 最合适
  • 如果要做项目管理(Gantt 图、工时追踪):OpenProjectPlane
  • 如果团队用敏捷开发:TaigaPlane

结语

自部署待办管理系统,搭建起来并不比注册一个 Todoist 账号复杂多少。Docker Compose 三分钟部署,Cloudflare Tunnel 五分钟配置,CalDAV 同步手机一步到位。

整个方案的优势:

  • 成本:零订阅费(域名年费几十块)
  • 隐私:数据全在自己服务器
  • 灵活性:Vikunja 有完整 API,可以编程自动化任务管理
  • 独立性:不依赖任何 SaaS 服务,服务器在数据就在

当然它也有代价——需要维护一个 Docker 容器、备份数据库、关注版本更新。但对我来说,这种”自己的数据自己管”的掌控感,比省下来的那点订阅费更有价值。

如果你也在找一款自部署的待办工具,不妨试试 Vikunja。有任何问题或者踩了坑,欢迎留言交流。