在 VPS 上部署 Vikunja 待办事项

部署 Vikunja 和 PostgreSQL,把附件存到持久化目录。测试成员权限,并在同一停写窗口备份数据库和文件。

任务、讨论和附件散在聊天里,可以用 Vikunja 集中整理。自建后先试创建任务、上传和下载附件,再检查成员权限与恢复,之后再放正式项目。

下面部署应用与 PostgreSQL,数据库不开放宿主机端口。第一次通过 SSH 建立账户,再切换到实际 HTTPS 域名。

准备数据库和附件目录

准备 Linux VPS、普通 Docker Engine、Compose 插件和可用 SSH。应用附件在 files,数据库在 db,两处都需要持久化。PostgreSQL 18 的挂载位置与旧版本示例不同,已有旧数据库不能直接改标签套用新安装配置。

sudo mkdir -p /opt/vikunja/files
sudo chown 1000 /opt/vikunja/files
cd /opt/vikunja
umask 077
printf 'DB_PASSWORD=%s\n' "$(openssl rand -hex 32)" > .env
printf 'SERVICE_SECRET=%s\n' "$(openssl rand -hex 32)" >> .env
chmod 600 .env

默认应用以 UID 1000 运行。上述权限步骤适用于普通 Linux Docker Engine;rootless 与 Docker Desktop 要按各自的映射处理。这个镜像不支持用 PUID、PGID 改运行身份。

创建 compose.yaml:

services:
  vikunja:
    image: vikunja/vikunja:latest
    restart: unless-stopped
    ports:
      - "127.0.0.1:3456:3456"
    environment:
      VIKUNJA_SERVICE_PUBLICURL: http://127.0.0.1:3456/
      VIKUNJA_SERVICE_SECRET: ${SERVICE_SECRET:?set SERVICE_SECRET}
      VIKUNJA_SERVICE_ENABLEREGISTRATION: "true"
      VIKUNJA_SERVICE_TIMEZONE: Asia/Shanghai
      VIKUNJA_DATABASE_TYPE: postgres
      VIKUNJA_DATABASE_HOST: db
      VIKUNJA_DATABASE_USER: vikunja
      VIKUNJA_DATABASE_PASSWORD: ${DB_PASSWORD:?set DB_PASSWORD}
      VIKUNJA_DATABASE_DATABASE: vikunja
    volumes:
      - ./files:/app/vikunja/files
    depends_on:
      db:
        condition: service_healthy
  db:
    image: postgres:18
    restart: unless-stopped
    environment:
      POSTGRES_USER: vikunja
      POSTGRES_DB: vikunja
      POSTGRES_PASSWORD: ${DB_PASSWORD:?set DB_PASSWORD}
    volumes:
      - ./db:/var/lib/postgresql
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -h 127.0.0.1 -U $$POSTGRES_USER -d $$POSTGRES_DB"]
      interval: 5s
      timeout: 3s
      retries: 10
      start_period: 30s

数据库地址是共同 Compose 网络中的 db,不是应用容器自己的 localhost。正式运行后记录两个镜像摘要,固定已验证的版本或摘要;latest 与主要版本标签都可能更新,数据库跨主要版本需要单独迁移。

docker compose config --quiet
docker compose pull
docker compose up -d
docker compose logs --tail=100 vikunja db

自己的电脑建立转发,再打开 http://127.0.0.1:3456:

ssh -N -L 127.0.0.1:3456:127.0.0.1:3456 user@YOUR_VPS_IP

PUBLICURL 必须与浏览器实际入口一致,非标准端口也要包含;本机端口被占用时,转发和配置一起修改。页面能加载而注册报 unauthorized 时,先核对这个值。

测试任务、成员权限和附件下载

创建所需账户与一个测试项目,增加任务、到期时间和小附件。用普通成员登录,核对它能看到哪些项目;再用未登录窗口检查私人内容。实际下载附件,不能只看上传按钮提示成功。

附件失败时看日志与 files 权限。应用镜像基于 scratch,没有常规 shell,docker compose exec vikunja sh 不是可用的排障方法。读日志和宿主机挂载信息,不要靠给目录开放所有人写权限解决。

接域名后,将 HTTPS 网关代理到服务器本机 3456,更新 PUBLICURL 并重建应用。重新登录,验证页面刷新、任务操作和附件。成员加入后将注册开关设为 false,检查未登录访问,避免私有项目实例长期开放自助注册。

数据库与附件在同一个停写窗口备份

官方备份范围包括数据库与附件。只备份 PostgreSQL,恢复后可能看得到任务却打不开文件。小型实例可以停止应用,让数据库保持运行,在停止期间导出并备份附件。

下面用 PostgreSQL 自定义格式导出,先写临时文件,确认导出成功以后再保留正式文件:

cd /opt/vikunja
umask 077
mkdir -p /opt/backups
backup_file="/opt/backups/vikunja-$(date -u +%Y%m%dT%H%M%SZ).dump"
docker compose stop vikunja
if docker compose exec -T db pg_dump -U vikunja -d vikunja -Fc \
  > "$backup_file.partial"; then
  mv "$backup_file.partial" "$backup_file"
else
  docker compose start vikunja
  exit 1
fi
# 此处用自己的备份工具保存 files、compose.yaml、.env 与版本记录
docker compose start vikunja

这是数据库导出片段,尚未完成附件与异地上传。把注释位置补成真实备份动作,失败也要恢复应用并记录错误;全部完成以后再认定本次备份成功。数据库导出与文件副本要来自同一个停写窗口,受保护的副本还包含部署密钥。

恢复时在独立数据库与目录使用相同应用版本,用 pg_restore 导入这份自定义格式备份,并放回对应附件。暂时停用邮件与 webhook,再核对成员、项目、评论、到期日期和附件下载;确认恢复可用后接回域名。

应用、数据库和附件一起运行时,应按它们的总开销选配置。有空余机器先验证;确实需要新实例,再比较Docker 应用 VPS的内存、磁盘与续费,别只按空白项目刚启动时的占用选配置。

Vikunja 与 PostgreSQL 共机,可以从 2 核、4 GB 内存开始试部署,附件、导出包与数据库备份空间一起算。个人项目统一管理可看 雨云 RCS 的任务服务配置;已有云数据库或想规划数据盘,可比较 ECS 的计算与存储方案。先用真实项目副本测试附件、查询和恢复,再按成员与资料增长调整规格。