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

2026-06-21

为什么还需要另一个待办 App

市面上待办工具多到数不清——Todoist、微软 To-Do、Notion、TickTick……选一个看起来不难。但这些工具有一个共同问题:你的任务数据存在别人服务器上。数据迁移、隐私、付费墙,每个都是潜在隐患。

自部署待办系统的需求一直在。很多人试过 Memos,但它只是一个轻量备忘录,没有「进行中」「已完成」这类状态字段。Nextcloud Tasks 能做,但需要部署一整套 Nextcloud 生态,太重了。OpenProject 更偏项目管理,对个人待办来说大炮打蚊子。

Vikunja 卡在了一个刚好的位置:该有的都有,不该有的不乱加。

Vikunja 是什么

Vikunja 是一个开源的(AGPLv3)待办管理平台,Go + Vue 构建,单二进制部署。原生支持四种视图——列表、甘特图、看板、表格,子任务、标签、优先级、提醒、重复任务全部内置。

我个人最看重的两个特性是 CalDAV 手机同步完整的 REST API,前者解决移动端的问题,后者解决自动化的问题。

对比下同类自部署方案:

方案 状态跟踪 手机同步 部署复杂度 项目规模
Vikunja ✅ 原生 ✅ CalDAV 低(单容器) 个人到小团队
Nextcloud Tasks 需要完整 Nextcloud
Taskwarrior 中等(CLI) 纯 CLI 用户
OpenProject ⚠️ 有限 团队项目管理

Docker Compose 部署

最新版 Vikunja 已经把 API 和前端合并为一个镜像,不再需要 nginx sidecar 架构。一个 docker-compose.yml 文件就够了:

services:
  vikunja:
    image: vikunja/vikunja
    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: generate-a-random-secret-here
      VIKUNJA_SERVICE_ENABLEREGISTRATION: false
    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

Docker 容器架构示意

注意几个配置细节:

  • VIKUNJA_SERVICE_PUBLICURL 必须填公网 URL,不能写内网 IP。这个值影响 CalDAV 同步和链接分享,填错了后面修起来很麻烦。
  • VIKUNJA_SERVICE_SECRET 是 JWT 签名密钥,用 openssl rand -base64 32 生成一个随机字符串。
  • VIKUNJA_SERVICE_ENABLEREGISTRATION: false 关闭开放注册,所有人必须通过管理员创建帐号。做自部署的应该都有这个安全意识。
  • 数据库用 PostgreSQL 16,也可以选 MySQL 或 SQLite,但 PostgreSQL 最稳定。

如果想用 docker run 而不是 Compose,把上面的环境变量和端口映射搬到 -e-p 参数里就行。Compose 的好处是升级时只需换 tag 再 docker compose up -d

用户管理

Vikunja 默认没有管理员账号,需要在容器内创建。这种设计比默认 admin/admin 然后让用户改密码更安全,但也意味着部署后多一步操作:

docker exec vikunja-vikunja-1 /app/vikunja/vikunja user create \
  -e admin@example.com \
  -p <your-strong-password> \
  -u adminusername

如果想给自动化脚本用一个独立账号,同样的命令跑一次就行。API Token 在 Web UI 里生成,也可以通过 CLI 获取。

公网访问

自部署的痛点之一是公网访问。Vikunja 本身只是一个监听 3456 端口的服务,怎么让它在外网可用,取决于你的网络环境。

几种主流方案:

Cloudflare Tunnel(推荐)
不暴露任何端口,安全性最高。在另一台机器上跑 cloudflared 容器,ingress 规则指向 localhost:3456。Cloudflare 的 CDN 还能起到加速作用。缺点是依赖 Cloudflare 的服务。

反向代理 + DDNS
如果你有公网 IP,用 Nginx/Caddy/Traefik 反向代理到本机 3456,配合 DDNS 绑定域名。控制力更强,不受限于 Cloudflare,但需要操心防火墙、HTTPS 证书续期、端口暴露的安全风险。

Tailscale / WireGuard
纯内网访问,最安全但只适合自用。如果只是自己用不分享给别人,这是最简单的方案——连域名都不需要。

我踩过的一个坑:首次部署 PUBLICURL 只填了内网 IP,结果 CalDAV 同步一直连不上,Web UI 里的共享链接也打不开。修改为域名后一切正常。

CalDAV 手机同步

这是 Vikunja 区别于大多数自部署待办系统的核心卖点——通过标准 CalDAV 协议直接同步到手机原生待办 App。

Android 上推荐 Tasks.org,一款开源待办 App,原生支持 CalDAV:

  1. 安装 Tasks.org(Google Play / F-Droid)
  2. 设置 → 同步 → 添加账户 → CalDAV
  3. URL 填你的 Vikunja 地址(https://todo.yourdomain.com),用户名和密码用 Vikunja 的登录凭据
  4. App 自动通过 /.well-known/caldav 发现目录

同步完成后,手机上创建的任务会在 Vikunja Web UI 出现,反之亦然。

CalDAV 手机同步示意

有一个已知的坑:CalDAV 协议不会保留子任务的层级关系。如果重度依赖子任务,建议主任务在 Web UI 管理,手机端只处理顶层任务。Tasks.org 社区有人提过这个 issue,但短期内不会有解决方案。

REST API 和自动化

Vikunja 内置了完整的 REST API,Swagger 文档挂在 https://todo.yourdomain.com/api/v1/docs,部署完成就能打开。

几个常用的操作:

# 列出项目
curl -H "Authorization: Bearer <token>" \
  https://todo.yourdomain.com/api/v1/projects

# 创建任务
curl -X PUT -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{"title": "调研下周部署方案"}' \
  https://todo.yourdomain.com/api/v1/projects/1/tasks

这个 API 可以接很多自动化场景:RSS 订阅自动创建任务、n8n 工作流推送、Home Assistant 联动、甚至定时脚本检查新任务并自动处理。

API 自动化工作流示意

我个人用它做 AI Agent 的任务队列——Agent 扫描 Vikunja 的新任务,自动执行并更新状态。这个组合让「自部署」从一个运维动作变成了工作流基础设施。

踩坑总结

问题 原因 解决
CalDAV 连不上 PUBLICURL 用了内网 IP 改为 https://todo.domain.com
浏览器一直加载旧页面 Service Worker 缓存了前端 清除 Service Worker 或反向代理加版本号
Docker Hub 拉取镜像很慢 Docker Hub 匿名限流 用 hub.rat.dev 镜像或登录后拉取
CalDAV 子任务层级丢失 CalDAV 协议限制 主任务和子任务分开管理
CORS 报错 反向代理未配置跨域头 在代理层加上 CORS 响应头

这些坑大部分是在部署后三天内遇到的。最有价值的教训是第一条——PUBLICURL 这个配置看起来不紧急,但漏掉之后 CalDAV、链接分享、Webhook 全部受影响,排查一圈才发现是它。

什么时候值得上自部署待办

如果你只是记几件杂事,A4 纸比任何一个待办 App 都快。如果你用 Todoist 已经满足需求且不在乎数据存在哪,没必要折腾。

自部署 Vikunja 最合适的场景是:你已经有服务器在跑了,需要一个管线式的任务系统跟你的自动化脚本、Agent 或者团队成员协同。Vikunja 提供的 REST API + CalDAV 双通道,让任务系统和外部世界的连接非常自然。

它不是 Todoist 的平替——它解决的是不同的需求。

标签: 工具 教程 Docker