简介 什么是 Conatus?
Conatus 是一个开源的自托管任务管理器 ,适用于项目、循环任务、提醒和团队协作,灵感源自 Todoist。它可以帮助用户在一个安全可控的环境中,以列表、看板或日历视图组织日常任务和个人项目,数据完全掌握在自己手中。
主要特点
项目与组织 :支持通过项目、分区、标签和优先级来组织任务,让工作结构清晰。
循环任务与提醒 :可创建循环任务,设置截止日期、到期时间和提醒,支持直接在任务名称中输入日期、时间、时长和重复规则。
协作与共享 :通过评论、文件附件和共享项目实现多人协作,支持日历、列表或看板视图切换。
Todoist 数据导入 :支持直接导入 Todoist 的任务数据,降低迁移成本。
API 与自动化 :提供版本化 REST API(/api/v1)和 Webhooks 事件通知,可通过 API token 集成第三方工具。
MCP 支持 :提供独立的 MCP 服务器,方便 AI 智能体直接管理任务。
开源免费 :基于 AGPL-3.0 协议开源,可免费使用和修改。
应用场景
个人任务管理 :个人用户可用它替代 Todoist,管理和跟踪日常待办、习惯与项目进度。
家庭共享清单 :家庭成员可通过共享项目协作制定购物清单、家庭活动计划等。
团队项目管理 :团队可通过评论、文件附件和看板视图管理迭代任务,配合循环任务跟踪重复性工作。
自动化与 AI 集成 :开发者可通过 REST API、Webhooks 和 MCP 协议接入 CI 流水线、通知机器人或 AI 助手。
开发者测试 :开发人员可以快速搭建测试环境,体验完整的任务管理 API 和前端功能。
Conatus 是一个功能全面、注重隐私的自托管 Todoist 替代品,它把任务、循环工作和协作整合到一个你完全掌控的系统中。提供完整的 Web 端和 REST API,并支持通过 MCP 协议接入 AI 助手,让自动化管理任务成为可能。
安装 在群晖上以 Docker 方式安装。
本文写作时, latest 版本对应为 1.0.0;
Conatus 采用多容器架构部署,由 db(PostgreSQL)、minio(对象存储)、migrate、bootstrap(初始化和引导)、app(主应用)以及可选的 backup、mcp 等服务组成,建议使用 docker-compose 进行部署,可以自动处理服务间的依赖关系。
docker-compose 安装 1. 下载 Compose 文件和环境模板 首先创建目录并下载官方提供的 docker-compose.yml 和 .env.example:
1 2 3 4 5 6 7 8 9 mkdir -p /volume1/docker/conatus/{backups,data,mcp,minio}cd /volume1/docker/conatuscurl -O https://raw.githubusercontent.com/nojusmorkunas/conatus/main/docker-compose.yml curl -o env.txt https://raw.githubusercontent.com/nojusmorkunas/conatus/main/.env.example
也可以不用下载
直接复制老苏的 env.txt 和 docker-compose.yml
2. 编辑环境变量 以下为完整的 env.txt (含中文注释):
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 CONATUS_VERSION =latestCONATUS_PORT =4399 CONATUS_MCP_VERSION =latestPOSTGRES_USER =appPOSTGRES_PASSWORD =replace-with-a-long-url-safe-passwordPOSTGRES_DB =appDATABASE_URL =postgres://app:replace-with-a-long-url-safe-password@localhost:5432 /appAUTH_SECRET =generate-with-npx-auth-secretCONATUS_ADMIN_USERNAME =adminCONATUS_ADMIN_PASSWORD =replace-with-a-long-random-passwordREGISTRATION_MODE =invite-on lyS3_ENDPOINT =localhostS3_PORT =9000 S3_ACCESS_KEY =replace-with-a-random-access-keyS3_SECRET_KEY =replace-with-a-long-random-secret-keyS3_BUCKET =attachments
增加了中文注释,记得要采用 UTF-8 格式保存
只需要修改以下关键配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 # 使用 latest 表示当前稳定版,或指定版本号如 1.0.0 CONATUS_VERSION=1.0.0 # Web 界面对外端口,容器内部监听 3000 CONATUS_PORT=4399 # 如果改了参数,DATABASE_URL 也要相应的调整 POSTGRES_USER=app POSTGRES_PASSWORD=conatus123 POSTGRES_DB=app # 认证密钥,建议用较长随机字符串 AUTH_SECRET=replace-with-a-long-random-secret # 对象存储 S3 凭据(MinIO) S3_ACCESS_KEY=7e609d7743b225544d4bc29877490b6b1c958709299d163ee9e9c6705682df26 S3_SECRET_KEY=f7c61b439806e8b504abe8ef4b4be06b3710bafd98ab184a53846eb408a46b6e # 可选:在空数据库上创建首个管理员 CONATUS_ADMIN_USERNAME=admin CONATUS_ADMIN_PASSWORD=laosu123
环境变量说明 :
POSTGRES_USER / POSTGRES_PASSWORD / POSTGRES_DB:用于配置 PostgreSQL 数据库的账号、密码和库名,请使用强密码。
S3_ACCESS_KEY / S3_SECRET_KEY:MinIO 对象存储的凭据,用于存放附件的持久化数据。
CONATUS_ADMIN_USERNAME / CONATUS_ADMIN_PASSWORD:首次在空数据库部署时用于初始化管理员账号,登录后应将其移除。
如果使用了域名或反向代理,还需要设置 AUTH_URL 和 PUBLIC_BASE_URL 为外部 HTTPS 地址。
3. 启动 Conatus 以下为完整的 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 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 services: db: image: postgres:17-alpine container_name: conatus-db restart: unless-stopped volumes: - ./data:/var/lib/postgresql/data environment: POSTGRES_USER: ${POSTGRES_USER:-app} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD in .env} POSTGRES_DB: ${POSTGRES_DB:-app} healthcheck: test: ["CMD-SHELL" , "pg_isready -U \"$$POSTGRES_USER\" -d \"$$POSTGRES_DB\"" ] interval: 5s timeout: 5s retries: 10 start_period: 10s minio: image: chrislusf/seaweedfs:latest container_name: conatus-minio restart: unless-stopped volumes: - ./minio:/data environment: MINIO_ROOT_USER: ${S3_ACCESS_KEY:-minioadmin} MINIO_ROOT_PASSWORD: ${S3_SECRET_KEY:-minioadmin} command: server /data --console-address ":9001" mailpit: profiles: ["email-test" ] image: axllent/mailpit container_name: conatus-mailpit restart: unless-stopped ports: - "1025:1025" - "8025:8025" backup: image: postgres:17-alpine container_name: conatus-backup restart: unless-stopped volumes: - ./backups:/backups depends_on: db: condition: service_healthy environment: PGHOST: db PGUSER: ${POSTGRES_USER:-app} PGPASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD in .env} PGDATABASE: ${POSTGRES_DB:-app} BACKUP_INTERVAL: ${BACKUP_INTERVAL:-86400} BACKUP_KEEP: ${BACKUP_KEEP:-7} entrypoint: ["sh" , "-c" ] command: - | while true; do pg_dump -Fc -f "/backups/app-$$(date -u +%Y%m%dT%H%M%SZ).dump" ls -1t /backups/app-*.dump | tail -n +$$((BACKUP_KEEP + 1)) | xargs -r rm -- sleep "$$BACKUP_INTERVAL" done migrate: image: ${CONATUS_IMAGE:-ghcr.io/nojusmorkunas/conatus}:${CONATUS_VERSION:-latest}-ops container_name: conatus-migrate command: ["npm" , "run" , "migrate" ] restart: "no" depends_on: db: condition: service_healthy environment: DATABASE_URL: postgres://${POSTGRES_USER:-app}:${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD in .env}@db:5432/${POSTGRES_DB:-app} bootstrap: image: ${CONATUS_IMAGE:-ghcr.io/nojusmorkunas/conatus}:${CONATUS_VERSION:-latest}-ops container_name: conatus-bootstrap command: ["npm" , "run" , "bootstrap" ] restart: "no" depends_on: - migrate environment: DATABASE_URL: postgres://${POSTGRES_USER:-app}:${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD in .env}@db:5432/${POSTGRES_DB:-app} CONATUS_ADMIN_USERNAME: ${CONATUS_ADMIN_USERNAME:-} CONATUS_ADMIN_PASSWORD: ${CONATUS_ADMIN_PASSWORD:-} app: image: ${CONATUS_IMAGE:-ghcr.io/nojusmorkunas/conatus}:${CONATUS_VERSION:-latest} container_name: conatus-app restart: unless-stopped depends_on: - db - migrate - bootstrap environment: DATABASE_URL: postgres://${POSTGRES_USER:-app}:${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD in .env}@db:5432/${POSTGRES_DB:-app} AUTH_SECRET: ${AUTH_SECRET:?set AUTH_SECRET in .env} AUTH_URL: ${AUTH_URL:-} PUBLIC_BASE_URL: ${PUBLIC_BASE_URL:-} REGISTRATION_MODE: ${REGISTRATION_MODE:-invite-only} CONATUS_DEV_MODE: ${CONATUS_DEV_MODE:-0} S3_ENDPOINT: minio S3_PORT: 9000 S3_ACCESS_KEY: ${S3_ACCESS_KEY:?set S3_ACCESS_KEY in .env} S3_SECRET_KEY: ${S3_SECRET_KEY:?set S3_SECRET_KEY in .env} S3_BUCKET: ${S3_BUCKET:-attachments} SMTP_HOST: ${SMTP_HOST:-} SMTP_PORT: ${SMTP_PORT:-} SMTP_FROM: ${SMTP_FROM:-} ERROR_WEBHOOK_URL: ${ERROR_WEBHOOK_URL:-} ports: - "${CONATUS_BIND_ADDRESS:-0.0.0.0}:${CONATUS_PORT:-4399}:3000" mcp: profiles: ["mcp" ] image: ${CONATUS_MCP_IMAGE:-ghcr.io/nojusmorkunas/conatus-mcp}:${CONATUS_MCP_VERSION:-latest} container_name: conatus-mcp restart: unless-stopped depends_on: app: condition: service_healthy environment: TASKS_BASE_URL: http://app:3000 TASKS_API_TOKEN: ${TASKS_API_TOKEN:-tdm_configure_a_real_token_before_starting} MCP_HOST: 0.0 .0 .0 MCP_PORT: 4398 MCP_PUBLIC_URL: ${MCP_PUBLIC_URL:-} MCP_OAUTH_PASSWORD: ${MCP_OAUTH_PASSWORD:-} MCP_OAUTH_STORE_PATH: /data/oauth-store.json MCP_BEARER_TOKEN: ${MCP_BEARER_TOKEN:-} MCP_ALLOWED_ORIGINS: ${MCP_ALLOWED_ORIGINS:-http://localhost:4399} ports: - "4398:3001" volumes: - ./mcp:/data healthcheck: test: ["CMD" , "wget" , "-qO-" , "http://127.0.0.1:4398/health" ] interval: 30s timeout: 5s retries: 3 start_period: 10s
可选 MCP 侧车服务(用于接入 AI 助手):在 env.txt 中设置 token 后,运行 docker compose --profile mcp up -d 可启用。
1 2 3 4 5 6 7 8 9 10 11 12 AI 助手 │ │ MCP ▼ ┌──────────────┐ │ MCP 侧车服务 │ └──────┬───────┘ │ ▼ ┌──────────────┐ │ 主应用 │ └──────────────┘
执行下面的命令:
1 2 docker-compose --env-file env.txt up -d
启动时需要拉取 Conatus 应用、操作工具、PostgreSQL 和 MinIO 镜像,完成后访问 http://<IP>:4399 即可。
运行 在浏览器中访问 http://<群晖IP>:4399 即可进入登录界面。
使用 env.txt 中配置的 CONATUS_ADMIN_USERNAME / CONATUS_ADMIN_PASSWORD 登录管理员账号
登录后,从 env.txt 中移除 CONATUS_ADMIN_USERNAME 和 CONATUS_ADMIN_PASSWORD 这两项配置
默认支持两种方式导入 Todoist 的数据,使用 Todoist 的 API Token 或者备份的数据,但老苏没用过 Todoist,只能自己新建
先建 Project
再建 Task
可以根据需要添加需要的描述、优先级、重复、提醒、附件等
API 调用 从 Preferences –> API tokens
创建 API Token
调用 REST 接口获取尚未完成的任务列表
1 curl -H "Authorization: Bearer tdm_P9i382EHuTTWpAbUEc8wGJDxaNcQC0Zu" "http://192.168.0.197:4399/api/v1/tasks?completed=false"
MCP 默认情况下,MCP服务并没有启动,如果需要使用,需要先启用 env.txt 中的相关参数,然后再执行
1 2 docker-compose --env-file env.txt --profile mcp up -d
如果一切正常,应该能看到 conatus-mcp 服务
但是老苏没搞定,从日志看需要 Issuer URL must be HTTPS,但老苏手上的 freenom 域名都过期了
注意事项
数据库备份 :升级前务必先备份数据库,某些数据库迁移需要恢复才能安全回滚。可使用内置 backup 服务自动备份,默认每日执行并保留最新 7 份。
初始管理员 :只有在数据库为空时 Bootstrap 进程才会创建管理员,首次登录后请及时移除 env.txt 中的相应配置。
端口冲突 :默认宿主端口为 4399,可通过修改 CONATUS_PORT 来更换;数据库、MinIO 没有对外暴露端口。
反向代理与 HTTPS :若使用域名或反向代理,必须设置 AUTH_URL 和 PUBLIC_BASE_URL 为外部 HTTPS 地址。
安全建议 :默认注册模式为邀请制(invite-only),请使用强密码,并妥善保管 API Token(仅在创建时显示一次)。切勿在生产环境中启用 CONATUS_DEV_MODE=1,它会关闭限流并开放注册。
参考文档
nojusmorkunas/conatus: A self-hosted task manager for projects, recurring work, reminders, collaboration and automation. Inspired by Todoist. 地址:https://github.com/nojusmorkunas/conatus
Conatus 官方主页 地址:https://useconatus.com
nojusmorkunas/conatus-mcp: Conatus 的 MCP 服务器,提供 stdio 与远程 Streamable HTTP 传输,供 MCP 兼容的 AI 智能体管理任务 地址:https://github.com/nojusmorkunas/conatus-mcp