用海外云服务器自建 Vikunja 任务管理平台完整教程:看板、甘特图与团队协作实战(2026最新版)

📅 · 海外云服务器自建服务教程 - ChengziCloud

一句话结论

Meta Description: 2026 最新 Vikunja 自建教程:在海外云服务器用 Docker Compose 部署 Vikunja 任务管理平台,配 PostgreSQL、Nginx 反代与 HTTPS、真实客户端 IP、看板与甘特图、CalDAV、API 令牌、Fail2Ban 与…

本文要点
  • 前言
  • 先搞清楚:Vikunja 解决什么问题(与站内方案的分工)
  • 部署前的三条前置条件(先确认,再动手)
  • 第一步:用 Docker Compose 部署 Vikunja + PostgreSQL
  • 第二步:Nginx 反向代理 + HTTPS + 真实客户端 IP
  • 第三步:初始化管理员与「上线必改」的五项
  • 第四步:四种视图、团队协作与多端接入
  • 第五步:数据迁移导入、API 令牌与自动化

Meta Description: 2026 最新 Vikunja 自建教程:在海外云服务器用 Docker Compose 部署 Vikunja 任务管理平台,配 PostgreSQL、Nginx 反代与 HTTPS、真实客户端 IP、看板与甘特图、CalDAV、API 令牌、Fail2Ban 与备份升级,附价格表。

关键词:Vikunja 搭建、自建任务管理、Vikunja 教程、开源项目管理工具、Kanban 看板、甘特图工具、Vikunja Docker 部署、Vikunja 反向代理配置、Vikunja 备份、海外云服务器

前言

自建 Vikunja 之后,你和团队的任务、看板、甘特图与项目数据就全部留在自己的海外云服务器上,不经过任何第三方 SaaS——而部署本身只需要一份 docker compose 加上一条 chown 命令。Vikunja 是一款用 Go 编写的开源任务管理 / 项目协作平台(AGPLv3 许可),它把 API 与前端打包进同一个可执行文件或同一个 Docker 镜像,默认监听 3456 端口,1 核 1G 的服务器即可流畅运行,同时原生提供 列表、看板(Kanban)、甘特图(Gantt)、表格 四种视图,还能通过 CalDAV 把任务同步进手机日历。当前最新稳定版为 v2.7.0(2026-10-02 发布)。

这篇文章给出一份可直接复制执行的完整教程:从服务器选型、Docker Compose 部署、PostgreSQL 配置、Nginx 反向代理与 HTTPS、真实客户端 IP 提取、管理员初始化,一路讲到四种视图与多端接入、数据迁移、API 令牌、Webhooks / n8n 自动化、安全加固、Fail2Ban、备份升级与故障排查,最后附一份配置价格对比表和 10 条常见问题。

在动手之前,请记住官方反复强调的三条前置条件:① 可以用 SQLite 起步,但只要超过「一小撮用户」就该换 PostgreSQL 或 MySQL;② 上传目录必须先 chown 1000 再启动,否则容器起不来;③ 第一件事是把 service.secret 写死,否则每次重启所有人都会掉线。

🚀 需要一台海外云服务器来跑 Vikunja?通过 5.chengzicloud.cloud 购买阿里云国际版 / 腾讯云国际版 / AWS,享专属折扣。

一、先搞清楚:Vikunja 解决什么问题(与站内方案的分工)

Vikunja 的定位是「任务与项目怎么推进」,而不是「文件放在哪里」。它存的是一条条任务(标题、描述、截止日期、优先级、标签、负责人、子任务、提醒、重复规则),以及承载任务的项目、看板列和团队。附件只是任务的附属品(默认单个上限 20MB),它不做文件同步,也不做知识库。

很多人在自建时会把几个「办公类」服务混在一起选,其实它们回答的是完全不同的问题。下表把站内已经写过的相邻方案和 Vikunja 逐一切开:

站内已有方案它回答的问题与 Vikunja 的分工
Nextcloud 私有云盘文件存在哪、怎么同步与协作存放文件正文;Vikunja 只存任务字段与少量附件
Wiki.js 团队知识库知识怎么沉淀成可检索文档写「这件事是什么」;Vikunja 管「谁在什么时候做完」
n8n 工作流自动化事件怎么自动流转让机器自动跑流程;Vikunja 是人推着任务走
Uptime Kuma 监控服务是否健康、要不要告警盯机器的健康;Vikunja 盯人的待办
Paperless-ngx 文档归档纸质件 / PDF 怎么归档与检索归档静态资料;Vikunja 是动态任务
Vikunja任务 / 项目怎么推进本文的主角

两条必须说清楚的反向边界:

  1. 它不是云盘,也不是知识库。 Vikunja 没有「同步文件夹」的概念,也没有 Wiki 式的页面树。你之所以选它,是因为你要的是「任务的状态、负责人和截止日期」,而不是「把一堆文件搬到服务器上」。
  2. 它不是自动化引擎。 n8n 的价值是「A 发生后自动触发 B」;Vikunja 的价值是「把要做的事摆清楚,让人知道下一步干什么」。Vikunja 有 Webhooks 和 API(可以和 n8n 联动),但它本身不替你做决策、也不自动执行流程。

想明白这两条,选型就不会跑偏:凡是「人要做的事」,交给 Vikunja;「机器自动做的事」,交给 n8n。

二、部署前的三条前置条件(先确认,再动手)

Vikunja 官方文档把最容易被忽略的几件事写在最前面,这里集中列出来,建议先逐条确认再往下走。

第 1 步:选系统——Ubuntu 22.04 / 24.04 或 Debian 12/13

Vikunja 官方镜像基于 scratch 构建,容器内没有 shell,所以宿主机发行版的 glibc 版本对 Docker 部署完全无影响——哪怕你在老旧的 CentOS 7(glibc 2.17)上跑容器也不会报错。但 CentOS 7 已于 2024 年 6 月 EOL,不再有安全更新,所以本文仍推荐 Ubuntu 22.04 / 24.04 或 Debian 12/13。

如果你坚持走二进制安装(不走 Docker),官方二进制对 glibc 有下限要求,在 CentOS 7 上可能直接报 GLIBC_2.xx not found。遇到这种情况直接改用 Docker,别跟 glibc 较劲。

第 2 步:选数据库——SQLite 起步,人多就换 PostgreSQL

Vikunja 支持三种数据库后端:SQLite(默认)、MySQL / MariaDB、PostgreSQL。官方原话是「如果你会用它服务超过一小撮用户,我们推荐 MySQL 或 PostgreSQL」。实践口径:

  • 个人 / 3~5 人小团队、只想快速验证:SQLite 足够,零额外依赖;
  • 5 人以上、要长期跑、要并发:PostgreSQL(本文选用官方示例的 postgres:18);
  • 用 MySQL / MariaDB:必须是 UTF-8(utf8mb4)字符集,否则中文等非拉丁字符会出问题,官方给的启动参数是 --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci。

第 3 步:先锁定一个「专属域名」和一个「端口」

  • 域名:service.publicurl 必须填你最终访问的 HTTPS 地址(末尾带斜杠,如 https://tasks.example.com/)。官方默认开启 CORS,而这个设置要求必须提供 public url;不填又不关 CORS,前端请求会被跨域拦掉。这个地址还会被写进邮件里的链接,所以别填 IP。
  • 端口:Vikunja 默认监听 3456。容器内外都用它,宿主机上是否暴露由你决定(本文只绑到 127.0.0.1,由 Nginx 对外)。
  • 一个必须知道的限制:Vikunja 官方不支持装在子目录(如 https://example.com/vikunja/)。要么用独立域名 / 子域名,要么自己构建前端并设置 VIKUNJA_FRONTEND_BASE。最省事的做法就是给它一个独立子域名。

另外提醒一句:Vikunja 有官方云托管(Vikunja Cloud)和两家一键托管(Zenith、PikaPods),也有付费的 Vikunja Pro。官方明确说 Cloud 版不支持用户名密码登录(只走 OAuth)。如果你要的是「数据在自己服务器上、能用本地账号」,那就老老实实自建,也就是本文的路线。

三、第一步:用 Docker Compose 部署 Vikunja + PostgreSQL

下面这份 compose 文件对齐了官方 "Full docker example",并额外加入了本文推荐的几个安全设置(绑定 localhost、真实客户端 IP、关闭注册)。先把目录和权限准备好。

第 1 步:创建目录并修正权限(最关键的一步)

官方镜像以 UID 1000 运行,且不带组,而且不会去抢上传目录的所有权(因为那意味着要以 root 运行)。所以启动前你必须手动把上传目录、数据库目录交给 UID 1000:


mkdir -p /opt/vikunja/files /opt/vikunja/db
chown -R 1000 /opt/vikunja/files /opt/vikunja/db
cd /opt/vikunja

⚠️ 这一步必须在第一次启动之前做完。漏掉它,容器日志里会出现文件写入被拒的错误,前端上传附件也会失败。如果你用的是 rootless Docker,UID 映射规则不同,官方给的做法是在 compose 里把容器用户设为 user: "0:0"(在 rootless 模式下容器 root 会被映射成宿主机的普通用户,没有提权风险)。

第 2 步:生成两个随机密钥


openssl rand -hex 32

把输出结果当作 VIKUNJA_SERVICE_SECRET。这个密钥用来签发会话令牌,官方明确警告:如果它为空,Vikunja 会在每次启动时随机生成一个新的,于是所有会话在重启后立刻失效,多实例之间也会互相拒绝对方的令牌。所以它必须固定下来。数据库密码同理,也换成一个强随机值。

第 3 步:写 docker-compose.yml


services:
  vikunja:
    image: vikunja/vikunja:2.7.0
    container_name: vikunja
    environment:
      VIKUNJA_SERVICE_PUBLICURL: "https://tasks.example.com/"
      VIKUNJA_SERVICE_SECRET: "<把 openssl rand -hex 32 的结果填这里>"
      VIKUNJA_DATABASE_TYPE: postgres
      VIKUNJA_DATABASE_HOST: db
      VIKUNJA_DATABASE_DATABASE: vikunja
      VIKUNJA_DATABASE_USER: vikunja
      VIKUNJA_DATABASE_PASSWORD: "<换成强随机密码>"
      VIKUNJA_SERVICE_IPEXTRACTIONMETHOD: xff
      VIKUNJA_SERVICE_TRUSTEDPROXIES: "127.0.0.1/32,::1/128"
      VIKUNJA_SERVICE_ENABLEREGISTRATION: "false"
      VIKUNJA_SERVICE_TIMEZONE: Asia/Shanghai
    ports:
      - "127.0.0.1:3456:3456"
    volumes:
      - ./files:/app/vikunja/files
    depends_on:
      db:
        condition: service_healthy
    restart: unless-stopped

  db:
    image: postgres:18
    container_name: vikunja-db
    environment:
      POSTGRES_USER: vikunja
      POSTGRES_PASSWORD: "<与上面 VIKUNJA_DATABASE_PASSWORD 保持一致>"
      POSTGRES_DB: vikunja
    volumes:
      - ./db:/var/lib/postgresql
    restart: unless-stopped
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -h localhost -U $$POSTGRES_USER"]
      interval: 30s
      start_period: 15s
      start_interval: 5s

几个必须解释的点:

  • image: vikunja/vikunja:2.7.0 而不是 :latest。官方建议固定版本号,这样升级时机由你决定,而不是某天容器重启就悄悄换了版本。从 v2.7.1 起,官方镜像还用 cosign 签名并附带 build provenance 证明,可以用 cosign verify 或 gh attestation verify 校验镜像确实由官方发布流水线构建。
  • ports 写成 127.0.0.1:3456:3456,不要写成 3456:3456 对外裸奔。只有 Nginx 能连到它,外部无法直连 3456,这样 trustedproxies 才不会被人伪造。
  • VIKUNJA_SERVICE_ENABLEREGISTRATION: "false":注册默认是开启的,任何人都能自己注册账号。我们先用 CLI 建好管理员,再把它关掉(见第五节)。布尔值要加引号,否则 YAML 会解析成布尔型。
  • VIKUNJA_SERVICE_TIMEZONE:必须用 tz 数据库名(如 Asia/Shanghai),不能用 UTC+8 这类偏移写法,官方明确说偏移量不支持。
  • PostgreSQL 18 的数据卷挂到 /var/lib/postgresql(不是 /var/lib/postgresql/data),这是官方示例的写法,别自作聪明改掉。

想用 SQLite 的话,把 db 整段删掉,把 VIKUNJA_DATABASE_TYPE 改成 sqlite,并在 vikunja 容器上额外挂一个 ./db:/db 即可。官方镜像已经预设 VIKUNJA_DATABASE_PATH=/db/vikunja.db;注意环境变量优先级高于配置文件,所以你在挂载的 config.yml 里改 database.path 是不生效的,要改就改环境变量或宿主机侧的挂载路径。

第 4 步:启动并确认


docker compose up -d
docker compose logs -f vikunja

看到 Vikunja 打印出启动完成、并监听 3456 的日志即可。此时用 curl 在本机自测一下:


curl -s http://127.0.0.1:3456/api/v1/info

能返回 JSON(含版本号)就说明 API 已经活着。Vikunja 会在启动时自动执行数据库迁移,所以第一次启动稍慢是正常的。

四、第二步:Nginx 反向代理 + HTTPS + 真实客户端 IP

Vikunja 自己只讲明文 HTTP,官方要求把 TLS 终结交给反向代理,否则账号密码和令牌会在网络上明文传输。反代配置本身很短,但有三个坑必须一起处理。

第 1 步:配置 Nginx

先把 WebSocket 升级头的映射写进 http 块(放到 /etc/nginx/nginx.conf 的 http { } 内部),官方在 Nginx Proxy Manager 的说明里明确要求打开 Websockets Support,手写 Nginx 配置时要自己补上:


map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

然后新建站点配置(/etc/nginx/sites-available/vikunja.conf):


server {
    listen 80;
    server_name tasks.example.com;

    location / {
        proxy_pass http://127.0.0.1:3456;
        client_max_body_size 20M;

        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
    }
}

启用它:


ln -s /etc/nginx/sites-available/vikunja.conf /etc/nginx/sites-enabled/
nginx -t && systemctl reload nginx

坑 1:client_max_body_size 20M 不是随便写的。 Vikunja 默认单个附件上限是 20MB(files.maxsize 默认 20MB)。官方特别说明:如果你改了 Vikunja 的上传上限,Nginx 这边也要同步改,否则上传大附件时会出现「前端提示失败、Nginx 返回 413」的现象。

坑 2:不要给 Vikunja 加缓存 location。 它就是 SPA + API,静态资源由它自己伺服,额外加 expires 缓存反而会让升级后前端读到旧文件。反向代理的通用原理可参考站内《Nginx 反向代理与负载均衡完整指南》。

第 2 步:签发 HTTPS 证书


apt install -y certbot python3-certbot-nginx
certbot --nginx -d tasks.example.com

证书会存到 /etc/letsencrypt/live/tasks.example.com/,certbot 会自动改写 Nginx 配置并加上 301 跳转。若服务器上已有别的站点在用 Nginx,别停服务,改用 certbot certonly --nginx -d tasks.example.com。证书与反代的完整原理见站内《Nginx 反向代理 + SSL 证书配置完整指南》。

签完之后,再回头确认 VIKUNJA_SERVICE_PUBLICURL 填的就是这个 https:// 地址且末尾带斜杠,然后 docker compose up -d 让容器重新读取环境变量。

第 3 步:让 Vikunja 看到「真客户端的 IP」(95% 的人会漏)

这是官方文档里被反复强调、但最常被忽略的一点。默认情况下 Vikunja 用 TCP 连接的远端地址来识别客户端,而在反向代理后面,这个地址永远是代理自己。后果是:

  • 访问日志里全是代理 IP,排查问题时毫无意义;
  • 基于 IP 的限流全都算到代理头上,等于形同虚设;
  • Fail2Ban 会列出代理 IP,达到阈值后把代理封掉,所有用户一起被锁在门外。

所以那两个环境变量(本文 compose 里已经加好)必须设置:

配置项值作用
service.ipextractionmethodxff从 X-Forwarded-For 头读取真实客户端 IP
service.trustedproxies127.0.0.1/32,::1/128只信任来自这些地址的 X-Forwarded-For

官方给出的警告值得原样记住:trustedproxies 要尽可能窄。因为 xff 模式下私网、环回、链路本地地址都是被信任的,如果你的 3456 端口能从别处访问到,一个宽泛的 10.0.0.0/8 会让内网任何机器伪造 X-Forwarded-For、冒充任意 IP。只列出「代理实际上从哪个地址连过来」——本机 Nginx 就是 127.0.0.1/32,::1/128。

五、第三步:初始化管理员与「上线必改」的五项

Vikunja 没有「安装向导」,第一次使用必须用 CLI 建号。所有 CLI 命令都在容器里执行,格式是 docker exec <容器名> /app/vikunja/vikunja <子命令>。

第 1 步:用 CLI 创建第一个管理员


docker exec -it vikunja /app/vikunja/vikunja user create -u admin -e [email protected]

不加 -p 参数时会让你交互式输入密码(更安全,不会留在 shell 历史里)。创建完用 docker exec vikunja /app/vikunja/vikunja user list 确认。Vikunja 的第一个用户就是管理员,之后所有权限都在项目 / 团队层面分配。

第 2 步:把「上线必改」的五项一次性做完

下表是官方 hardening 清单里最该马上处理的部分,建议部署当天一次性配置好:

序号配置项默认值为什么必须改
1service.enableregistrationtrue默认任何人都能自己注册。建完账号后立刻改 false
2service.secret每次启动随机不固定的话,每次重启所有人都掉线,多实例互相拒绝令牌
3service.timezoneGMT中国团队应设为 Asia/Shanghai,必须是 tz 数据库名,不能写 UTC+8
4service.enablecaldavtrue不用手机日历同步就关掉,它的端点接受 HTTP Basic 认证,是额外攻击面
5service.enablelinksharingtrue不希望项目被外发成公开链接就改 false

再补充三条同样值得一改的:

  • webhooks.enabled 默认 true:意味着任何用户都能让 Vikunja 主动去请求他指定的 URL。如果这是你不想开放的能力(内网 SSRF 面),设为 false。
  • auth.* 走统一身份:接 OpenID Connect 或 LDAP。注意两个细节——LDAP 只支持 LDAPS(隐式 TLS),不支持 StartTLS,端口默认写的是 389,你要改成 LDAPS 的 636;TOTP 两步验证只对本地账号可用,LDAP / OIDC 用户开不了,要在身份提供方那边强制 MFA。
  • 会话时长:官方默认 jwtttlshort=600(访问令牌 10 分钟)、jwtttl=259200(3 天无活动过期)、jwtttllong=2592000(勾了「保持登录」30 天)。会话没有绝对上限,一直在用就不会过期。对安全敏感就按官方示例收紧。

第 3 步:先跑一次官方体检命令

Vikunja 自带一个诊断命令,会逐项检查系统信息、配置、数据库连通性、文件目录可写性与磁盘空间(Redis / 邮件 / LDAP / OIDC 若启用也会测):


docker exec vikunja /app/vikunja/vikunja doctor

退出码 0 = 全部通过,1 = 有检查失败。它还能检测 rootless Docker 的用户命名空间问题并给出修复建议。部署完第一件事就跑它,比翻日志快得多。

六、第四步:四种视图、团队协作与多端接入

四种视图,各管一段

Vikunja 官方主打的四种视图,覆盖了「看进度 / 排计划 / 列清单 / 管数据」四个场景:

视图适合场景关键能力
列表(List)个人待办、按截止日排序分桶、排序、快速勾选完成
看板(Kanban)团队协作、按状态流转列即状态,拖拽改状态
甘特图(Gantt)排期、看依赖与工期时间轴、起止日期、进度
表格(Table)批量编辑、字段对比类电子表格批量改字段

同一条任务在不同视图里是同一份数据,你只是换了种方式看它——所以不用担心「看板和列表对不上」。

协作能力

Vikunja 用团队(Teams)来分配权限:把用户加进团队,再把项目共享给团队,成员就能在项目里建任务、改状态、写评论(service.enabletaskcomments 默认开启)。此外还有:

  • 标签(Labels):跨项目打标签,配合已保存筛选(Saved Filters)做成「我本周所有高优先级任务」这类动态视图;
  • 子任务、提醒、重复任务:重复规则可直接在任务里配,不用手工复制;
  • 链接分享:把项目以只读 / 可写公开链接发出去(默认开启,不需要就关)。官方也提供 service.enableopenidteamusersearch,开启后用户搜索只返回同团队的人,减少通讯录泄露。

多端接入

  • 网页端:就是本体,反代 + HTTPS 后直接用浏览器访问。
  • 桌面端:官方提供桌面应用,本质是把 Web 前端打包。
  • 移动端:官方有移动 App,但目前只支持最基础的功能,复杂操作仍建议用网页端。
  • CalDAV:如果保留 service.enablecaldav(默认开),Vikunja 会在 /.well-known/caldav 和 /dav/ 暴露 CalDAV 端点,客户端用用户名 + 密码(HTTP Basic 认证)接入,就能把带截止日期的任务同步进 iOS / Android 系统日历。注意两点:① 该端点用的是 Basic 认证,属于额外攻击面;② Fail2Ban 官方过滤器只匹配 /api/v1/login 与 /api/v2/login,抓不到 /dav 下的失败认证——不过 Vikunja 2.6.0 起对 Basic 认证端点自带一条常开的限流(ratelimit.basicauthlimit,默认每 IP 每分钟 10 次失败),正常同步的客户端不会把额度用掉。

七、第五步:数据迁移导入、API 令牌与自动化

从别的工具搬数据进来

Vikunja 内置导入器,官方列表里常见的是 Todoist、Trello、Microsoft To Do、TickTick、WeKan、CSV,以及 Vikunja 自己的导出文件。注意一个默认值差异:

  • 基于 OAuth 的三个导入器(Todoist / Trello / Microsoft To Do)默认是关闭的,要靠 migration.todoist.enable、migration.trello.enable、migration.microsofttodo.enable 打开;
  • 文件类导入器(Vikunja 导出、TickTick、WeKan、CSV)不能关闭,它们的上限由 migration.vikunjafile.maxsize(默认 256MB,指解压后总大小)和 migration.maxcsvrows 控制。

从 Trello 这种层级较深的工具导入后,偶尔会出现「父项目丢失导致子项目孤儿化」的情况——官方为此专门提供了修复命令:


docker exec vikunja /app/vikunja/vikunja repair projects --dry-run
docker exec vikunja /app/vikunja/vikunja repair projects

repair 家族一共四个子命令(file-mime-types、orphan-positions、projects、task-positions),全部支持 --dry-run,建议先预览再执行。

API 与令牌

Vikunja 的 REST API 分两代:v1 的文档在 /api/v1/docs、OpenAPI 描述在 /api/v1/docs.json;v2 从 2.4.0 起提供,遵循 OpenAPI 3.1。官方路线图写明 v1 会在 3.0 标记弃用、在 4.0 移除,新项目建议直接用 v2。

调用时用API 令牌:在网页端「设置 → API 令牌」生成,然后放进请求头 Authorization: Bearer <token> 即可。自建实例也支持用 POST /api/v1/login 换 JWT(官方注明 Vikunja Cloud 不支持用户名密码登录,自建才可以)。

Webhooks 与 n8n

webhooks.enabled 默认开启,你可以在项目里配置「任务创建 / 更新 / 删除」时回调某个 URL。官方专门有一篇「Using Vikunja with n8n」的文档——思路很直接:在 n8n 里建一个 HTTP Request 节点,用 Vikunja 的 API 令牌读取或创建任务,把「人要做的事」和「机器自动做的事」串起来。n8n 的部署可参考站内《n8n 工作流自动化服务器部署教程》。

安全上有一条官方默认值值得留意:outgoingrequests.allownonroutableips 默认为 false,即 Vikunja 拒绝连接私网 / 环回 / 链路本地地址,这正是为了防 SSRF。别把它改成 true。

八、安全加固清单(对齐官方 2.7.0 hardening 页)

Vikunja 官方有一页专门的《Security hardening》清单,明确写着「以下设置从 Vikunja 2.7.0 起可用」。把它整理成一张可勾选的表,部署完逐条过一遍:

类别该做什么对应配置
最小权限官方镜像是 FROM scratch 构建,无 shell、无包管理器,以 UID 1000 运行;不要用 root 覆盖它别加 user: "root"
网络收口只有代理能碰到 Vikunja。同机部署就绑 127.0.0.1,或用 Unix socketservice.interface(默认 :3456)、service.unixsocket
TLS反代终结 TLS,publicurl 填 HTTPS 地址service.publicurl
真实 IP反代后必须开 xff,否则限流/日志/Fail2Ban 全部失效service.ipextractionmethod: xff + service.trustedproxies
身份统一接 OIDC 或 LDAP;全员走 SSO 后关本地账号与注册auth.openid. / auth.ldap.、auth.local.enabled: false、service.enableregistration: false
两步验证本地账号可开 TOTP(默认允许,但不强推)service.enabletotp(默认 true)
会话收紧按需缩短令牌与空闲时长jwtttlshort / jwtttl / jwtttllong
密钥管理任意配置都能从文件读:键名加 .file,或环境变量加 _FILE 后缀见下方示例
数据库专用数据库用户(需要建表权限,因为启动会跑迁移);绝不用超级用户;加密连接;不对外暴露端口PG database.sslmode: verify-full;MySQL database.tls: true
出网请求保持默认,拒绝连私网地址,防 SSRFoutgoingrequests.allownonroutableips: false(默认)
限流开认证请求限流;多实例时把计数放 Redisratelimit.enabled: true、ratelimit.store: redis
防火墙封禁对反复失败的登录者直接封 IPFail2Ban(见下)
指标与健康/api/v1/metrics 在未配对用户名密码时是公开的,要么配对,要么在代理层拦掉;/health 是匿名端点;pprof 绝不要开在公网实例上metrics.enabled、metrics.username、metrics.password、metrics.pprof: false
日志与审计用 log.format: structured 输出 JSON 便于集中采集;需要登录/改任务审计就上 Vikunja Pro(audit.enabled,无有效许可证不写)log.format、log.standard: file
版本与补丁固定镜像版本号而不是 latest;订阅安全公告;升级前必先备份(启动会自动迁移,回不去)image: vikunja/vikunja:2.7.0

密钥从文件读(配合 Docker secrets / Kubernetes secrets / systemd 凭据):


database:
  password:
    file: /run/secrets/db_password

或直接用环境变量后缀:VIKUNJA_DATABASE_PASSWORD_FILE=/run/secrets/db_password。但有一条必须记住:vikunja dump 生成的归档里,配置文件与所有 VIKUNJA_* 环境变量都是明文(从文件加载的值只记录路径)——所以 dump 出来的 zip 要当作数据库本身一样对待:加密、限权。

Fail2Ban:把暴力破解的成本抬到离谱

先让 Vikunja 把 HTTP 请求写进文件(Docker 里用环境变量 + 挂载):


environment:
  VIKUNJA_LOG_ENABLED: "true"
  VIKUNJA_LOG_HTTP: file
  VIKUNJA_LOG_PATH: /app/vikunja/logs

然后在宿主机建过滤器 /etc/fail2ban/filter.d/vikunja.conf(官方原文):


[Definition]
datepattern = ^time=%%Y-%%m-%%dT%%H:%%M:%%S%%Z
failregex = ^.*\bmsg="POST\s+/api/v\d+/login[^"]*".*\bstatus=(?:400|403|412)\b.*\bremote_ip=<HOST>\b.*$

再在 /etc/fail2ban/jail.local 加一个 jail:


[vikunja]
enabled = true
backend = auto
filter = vikunja
port = http,https
logpath = /app/vikunja/logs/http.log
maxretry = 3
findtime = 600
bantime = 3600

最后重启并核验:


systemctl restart fail2ban
fail2ban-client status vikunja

做这一步之前,务必先完成第四节的「真实客户端 IP」配置——否则过滤器里的 remote_ip 永远是代理的地址,maxretry 一触发就把你自己的反向代理封了,效果是全体用户一起登录不进来。另外记住官方说明:这个过滤器只匹配 POST /api/v1/login 和 POST /api/v2/login,不匹配 /dav 下的 CalDAV 失败认证。

九、备份、升级与故障排查

备份:数据库 + 附件,一个都不能少

官方明确:需要备份的就两部分——数据库和附件文件。并且给了一句必须加粗的警告:

在 Vikunja 里删除项目是永久且不可逆的。没有回收站、没有垃圾桶、没有撤销。

所以「先删了再说,反正能恢复」这条路是不存在的,请务必配置带保留周期的备份策略。

数据库类型备份命令恢复命令
PostgreSQLpg_dump -U vikunja -h db vikunja > vikunja-backup.sqlpsql -U vikunja -h db vikunja < vikunja-backup.sql
MySQL / MariaDBmysqldump -u vikunja -p -h db vikunja > vikunja-backup.sqlmysql -u vikunja -p -h db vikunja < vikunja-backup.sql
SQLite直接复制数据库文件即可复制回去

附件目录直接 cp -a 到别处即可。此外 Vikunja 自带整体归档命令:


docker exec vikunja /app/vikunja/vikunja dump

它会把配置、版本、全部文件、完整数据库打成一个 zip(默认文件名 vikunja-dump_YYYY-MM-DD_HH-II-SS.zip)。恢复用 vikunja restore <zip 路径>,迁移到新环境时加 --preserve-config 保留当前配置、只灌数据。备份的整体思路可参考站内《服务器备份与容灾恢复方案》。

升级:备份 → 换版本号 → 重启,三步

Vikunja 在启动时自动执行数据库迁移,所以升级流程本身极其简单:


docker compose exec vikunja /app/vikunja/vikunja dump
docker compose pull vikunja
docker compose up -d

但官方有两条硬要求:① 每次升级前都要备份,出问题才能退回旧状态;② 升级前先看变更日志(changelog),确认这个版本有没有需要手工处理的步骤。另外官方不建议从 unstable(不稳定通道)切回 stable,可能出兼容问题。

故障排查速查表

现象最可能的原因处理
容器起不来 / 日志报文件写入被拒上传目录没有 chown 1000chown -R 1000 ./files ./db;rootless Docker 则设 user: "0:0"
重启后所有人都要重新登录service.secret 没固定用 openssl rand -hex 32 生成并写死
上传附件失败、Nginx 返回 413files.maxsize 与 client_max_body_size 不一致两边同步改(默认都是 20MB)
日志里全是代理 IP;Fail2Ban 把代理封了没开真实 IP 提取设 ipextractionmethod: xff + 窄的 trustedproxies
前端报跨域错误publicurl 没设或末尾缺斜杠填 https://域名/(必须带 /)
中文乱码MySQL/MariaDB 不是 utf8mb4启动参数加 --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
任务时间不对timezone 写了偏移量改成 tz 数据库名,如 Asia/Shanghai
装到子目录后 404 / 资源加载失败官方不支持子目录改用独立域名 / 子域名
看板上任务顺序错乱位置记录重复vikunja repair task-positions --dry-run 后执行
不确定哪配错了—先跑 vikunja doctor,看是配置、数据库还是文件权限问题

十、海外云服务器配置推荐与价格对比

Vikunja 用 Go 写成,单进程、内存占用低,是这一批自建服务里对硬件最不挑的一个:1 核 1G 就能跑个人到几个人的规模;官方文档甚至说「想更省心就用官方云托管」。但因为它把附件存在磁盘(或数据库)里,真正需要提前规划的是磁盘而不是内存。

下表的价格为 2026 年 10 月直读 DigitalOcean 与 AWS Lightsail 官方定价页的档位-规格映射(阿里云国际版 / 腾讯云国际版给区间,因活动浮动较大):

服务商最低配1 核 2G2 核 4G大规格(8 核 16G 级)计费与流量
DigitalOcean Droplet$6/月(1 vCPU / 1 GiB / 25 GiB SSD)$12/月(1 vCPU / 2 GiB / 50 GiB SSD)$24/月(2 vCPU / 4 GiB / 80 GiB SSD)$96/月(8 vCPU / 16 GiB / 320 GiB SSD)含 1~6 TB 流量;自 2026-01-01 起按秒计费(最低 60 秒或 $0.01)
AWS Lightsail$5/月(2 vCPU\* / 0.5 GiB / 20 GiB SSD)$12/月(2 vCPU\* / 2 GiB / 60 GiB SSD)$24/月(2 vCPU / 4 GiB / 80 GiB SSD)$84/月(4 vCPU / 16 GiB / 320 GiB SSD)固定月费含 1~6 TB 流量,超量另计
阿里云国际版约 $5–$9/月起约 $12–$20/月约 $24–$40/月按规格递增按量 / 包年包月,价格常随活动浮动
腾讯云国际版约 $5–$9/月起约 $12–$20/月约 $24–$40/月按规格递增轻量应用服务器常有新用户折扣

\* Lightsail 低档位标注的 2 vCPU 为突发型(burstable),持续高负载会受 CPU 积分限制;生产环境建议从 $12 档起步。DigitalOcean 另有 $4/月(512 MiB)与 $18/月(2 vCPU / 2 GiB / 60 GiB)两档可选。

声明:本文价格数据采集于 2026 年 10 月,仅为公开官网参考区间,实际以各家官网实时价格为准,金额单位均为美元(USD)。

选型口径(针对 Vikunja):

  • 个人 / 1~5 人:最低档就够(DO $6 / Lightsail $7),SQLite 或 PostgreSQL 都行;
  • 5~30 人团队:建议 2 核 4G($24 档),数据库用 PostgreSQL,反代与数据库同机;
  • 附件多、要长期留存:内存不是瓶颈,磁盘才是。要么直接选带大 SSD 的档位,要么给附件单独挂一块盘,或干脆把 files.type 切到 S3 对象存储——自建 S3 可参考站内《MinIO 对象存储搭建教程》。
  • 多人 + 想统一登录:上 OIDC / LDAP,此时你大概率已经有一台「公司内网服务器」,Vikunja 放上去顺带复用现有的数据库与证书体系即可,站内《MySQL / PostgreSQL 数据库服务器搭建指南》可作参考。

🚀 需要海外云服务器来部署 Vikunja?通过 5.chengzicloud.cloud 购买阿里云国际版 / 腾讯云国际版 / AWS,享专属折扣。

十一、常见误区速查

部署 Vikunja 时,下面这几个「想当然」最容易踩:

  1. 「先对外暴露 3456 端口,回头再收」——错。3456 一旦对外,trustedproxies 就可以被伪造,所有基于 IP 的保护形同虚设。从一开始就只绑 127.0.0.1。
  2. 「用 latest 镜像最省事」——错。官方建议固定版本号,否则某次重启就会被动升级,而升级会自动跑数据库迁移,且不可逆。
  3. 「SQLite 能随时换成 PostgreSQL」——不建议这么想。换库要么走 dump / restore,要么重新导入,绝不是改个配置那么简单。人多就直接上 PostgreSQL。
  4. 「删掉的项目还能找回来」——不能。官方原话:删除项目永久且不可逆,没有回收站、没有撤销。备份必须提前做。
  5. 「sub-path 部署应该没问题」——不行。官方仅支持独立域名 / 子域名,除非你自己构建前端并设置 VIKUNJA_FRONTEND_BASE。
  6. 「关掉 CORS 就不用填 publicurl 了」——技术上对,但不推荐。publicurl 不只用于 CORS,邮件里的链接也依赖它;填错会导致邮件链接指到 IP。

推荐方案

  • 只要「任务不丢、数据在自己手里」的个人用户:一台最低档海外云服务器(DO $6 / Lightsail $7)+ Docker Compose + SQLite + Nginx HTTPS,半小时能跑起来。这一档的性价比高到没有理由再去用免费版 SaaS。
  • 5~30 人小团队:2 核 4G($24 档)+ PostgreSQL + 每日 pg_dump 与附件目录异地备份 + Fail2Ban。把「真实客户端 IP」和 service.secret 这两个配置做对,稳定性就超过了 90% 的自建实例。
  • 更大的团队 / 已有身份体系:接 OIDC 或 LDAP,关闭本地账号与自助注册,开启审计(Vikunja Pro),并把附件迁到 S3。此时 Vikunja 就不再是一个「小工具」,而是和你的团队目录、备份体系、监控体系长在一起的基础设施。

如果你还没决定用哪家云,或想直接省掉选型这一步,5.chengzicloud.cloud 提供阿里云国际版 / 腾讯云国际版 / AWS 等海外云服务器的购买与部署支持。

常见问题(FAQ)

自建 Vikunja 最低需要什么配置的服务器?

1 核 1G 即可运行,官方文档也把它定位成轻量级 Web 应用。个人使用选最低档(DigitalOcean $6/月 或 AWS Lightsail $7/月)足够;5 人以上建议 2 核 4G。真正的瓶颈是附件占用的磁盘,而不是内存或 CPU。

Vikunja 用 SQLite 还是 PostgreSQL 更好?

官方建议:如果会服务超过一小撮用户,就用 MySQL 或 PostgreSQL。实践口径是——个人或 3~5 人小团队用 SQLite 完全没问题,零额外依赖;5 人以上、要长期稳定运行就用 PostgreSQL(本文示例用 postgres:18)。注意换数据库不像改个参数那么简单,要经过 dump / restore,所以人多就一开始直接上 PostgreSQL。

Vikunja 能装在某域名的子目录下吗?

不能。官方明确不支持子目录部署(如 https://example.com/vikunja/),除非你自己从源码构建前端并设置 VIKUNJA_FRONTEND_BASE。最省事的做法是给它一个独立子域名,例如 tasks.example.com。

为什么每次重启后所有用户都要重新登录?

这是 service.secret(VIKUNJA_SERVICE_SECRET)没有固定导致的。官方警告:如果该值为空,Vikunja 会在每次启动时随机生成一个,于是所有已签发的会话令牌在重启后立即失效,多个实例之间也会互相拒绝对方的令牌。用 openssl rand -hex 32 生成一个固定值写进配置即可解决。

上传附件失败、返回 413,怎么解决?

两处上限必须一致:Vikunja 的 files.maxsize(默认 20MB)和 Nginx 的 client_max_body_size(本文写的是 20M)。官方特别说明,改了 Vikunja 的上传上限,就必须同步改反向代理的 client_max_body_size,否则大附件会被 Nginx 直接挡掉。

Fail2Ban 把反向代理的 IP 封了,所有人被锁在外面怎么办?

根因是 Vikunja 没读到真实客户端 IP,导致日志里的 remote_ip 全是代理地址,达到 maxretry 后就把代理封了。解决顺序是:先设 service.ipextractionmethod: xff 与 service.trustedproxies: 127.0.0.1/32,::1/128,再做 Fail2Ban;已被封的话用 fail2ban-client unban <代理IP> 解封。

CentOS 7 能装 Vikunja 吗?glibc 版本有要求吗?

走 Docker 的话没有影响:官方镜像是 FROM scratch 构建、内含静态 Go 二进制,宿主机 glibc 版本不参与,CentOS 7 的 glibc 2.17 也不会报错。但如果走二进制安装,官方二进制对 glibc 有下限要求,在 CentOS 7 上可能报 GLIBC_2.xx not found——遇到就直接改用 Docker。另外 CentOS 7 已于 2024 年 6 月 EOL,建议换 Ubuntu 22.04/24.04 或 Debian 12/13。

Vikunja 支持中文吗?中文乱码或时区不对怎么办?

支持。中文乱码几乎都出在 MySQL / MariaDB 上——官方要求使用 utf8mb4,启动参数加 --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci 即可。时区问题则是因为 service.timezone 必须使用 tz 数据库名(如 Asia/Shanghai),官方明确说明 UTC+8 这类偏移写法不支持,默认值是 GMT。

Vikunja 的任务能同步到手机日历吗?

可以,靠 CalDAV。service.enablecaldav 默认为 true,端点位于 /.well-known/caldav 与 /dav/,客户端用用户名 + 密码(HTTP Basic 认证)接入,带截止日期的任务就能出现在系统日历里。如果不用这个功能,建议把它关掉以减少攻击面。注意 Fail2Ban 的官方过滤器抓不到 CalDAV 的失败认证,但 Vikunja 2.6.0 起对该端点自带每 IP 每分钟 10 次的常开限流。

升级 Vikunja 会丢数据吗?怎么安全升级?

Vikunja 启动时自动执行数据库迁移,正常升级不会丢数据,流程是:先 vikunja dump 备份 → 把镜像 tag 换成目标版本 → docker compose up -d。但有两条硬性要求:① 每次升级前必须备份,因为迁移不可逆;② 先读该版本的 changelog,确认有没有需要手工处理的步骤。同时建议固定镜像版本号而不是用 latest,把升级时机掌握在自己手里。 延伸阅读:

本文由 5.chengzicloud.cloud 提供,点击访问首页了解更多海外云服务器部署方案和专属优惠。