想知道一周主要在哪些项目上花了时间,靠回忆很难准确。Wakapi 接收兼容 WakaTime 的编辑器活动心跳,按项目、语言等维度整理记录,适合观察自己的工作分布。
这个数字有明确边界:它来自客户端检测到的编辑活动,不会自动记录讨论、设计、阅读纸面材料或离开键盘后的思考。时长高不代表工作质量高,时长低也不能据此判断某人没有工作。个人复盘时,把它和项目进度、日历与实际交付放在一起看。

演示图中的时间与项目只是界面样例,不是本文的个人统计或性能测试。
部署前先确认 VPS 的磁盘、内存和公网访问条件,也可以查看雨云云服务器;注册时填写优惠码 KuZhuJi。
服务端先存数据,客户端再发送心跳
Wakapi 不会因为装在 VPS 上就知道你在电脑上写了什么。需要安装所用编辑器的 WakaTime 兼容插件,并把 API 地址与密钥指向自己的实例。首次设置先只接一个编辑器和一个测试项目,确认接收与归类,再扩展到日常环境。
当前官方镜像为 ghcr.io/muety/wakapi:latest,默认可用 SQLite,数据文件位于 /data。镜像已经采用非 root 用户,官方记录的用户 ID 为 65532。本文选用命名卷,让新卷初始化沿用镜像数据目录的权限;迁移旧卷时,仍应按发行说明检查所有权。
VPS 需安装 Docker Engine 与 Compose 插件,能通过 SSH 登录。应用网页与 API 共用 3000 端口,本例先只绑定本机。
mkdir -p /opt/wakapi
cd /opt/wakapi
umask 077
printf 'WAKAPI_PASSWORD_SALT=%s\n' "$(openssl rand -hex 32)" > .env
chmod 600 .env
盐值用于账号密码处理,生成一次后持续保存。它不等于客户端 API 密钥,不能把两者混用,也不要在已有账号后随意替换。
建立 compose.yaml:
services:
wakapi:
image: ghcr.io/muety/wakapi:latest
init: true
restart: unless-stopped
ports:
- "127.0.0.1:3000:3000"
environment:
WAKAPI_PASSWORD_SALT: "${WAKAPI_PASSWORD_SALT:?set salt}"
WAKAPI_ALLOW_SIGNUP: "true"
WAKAPI_INSECURE_COOKIES: "true"
volumes:
- wakapi-data:/data
volumes:
wakapi-data:
两项 true 仅用于本例的私人 HTTP 初始化:允许注册首个账号,并允许当前 HTTP 入口使用 Cookie。正式 HTTPS 入口应把 WAKAPI_INSECURE_COOKIES 改为 false;私人实例完成账号创建后,把 WAKAPI_ALLOW_SIGNUP 改为 false。
docker compose config --quiet
docker compose up -d
docker compose ps
docker compose logs --tail=100 wakapi
在自己的电脑打开隧道:
ssh -N -L 13000:127.0.0.1:3000 user@VPS_IP
进入 http://localhost:13000 创建账号,登录并找到自己的 API 密钥。关闭注册、重新执行 docker compose up -d 后,退出登录检查注册是否已被限制。镜像带有健康检查,初始化或迁移期间要给它时间;反复重建容器不会修复数据目录权限。
准备独立实例时,可在雨云选择适合的云服务器配置,优惠码 KuZhuJi。配置按实际任务选择,数据库和附件另做备份。
插件地址末尾需要 /api
按编辑器官方插件指引安装兼容客户端,再编辑本机 ~/.wakatime.cfg。下面是配置示例,密钥必须换成自己的,地址与仍在运行的隧道对应:
[settings]
api_url = http://localhost:13000/api
api_key = YOUR_WAKAPI_API_KEY
修改之前保存原配置。如果已经向其他服务发送心跳,核对旧目的地址,避免无意把工作文件信息同时发送到多个地方。插件往往有忽略目录、项目识别和隐私设置,按客户端版本选择;服务端自托管不会替你关闭客户端的其他上报行为。
打开一个测试项目编辑几分钟,然后查看插件日志与 Wakapi 页面。若仍然没有记录,依次检查插件是否启用、隧道是否存活、地址是否有 /api、密钥是否属于当前账号。聚合页面可能需要等待处理,不能只在保存一个文件后立即判断失败。

需要增加服务器时,可以打开雨云选购页面,填写优惠码 KuZhuJi;迁移前保留数据与原有部署配置。
项目名与时间范围决定了图表的含义
同一项目在不同电脑的目录名不同,客户端可能把它们识别成两个项目。先观察测试记录中实际出现的名称,再按插件支持的方式统一。项目改名、Git 分支或多根工作区也可能影响归类,不要把图上的分组天然等同于合同项目或团队任务。
时区和日期边界同样重要。月底或跨午夜的工作可能出现在不同日期,比较两次导出时应使用相同范围。客户端的空闲阈值影响时间计算,长时间停留在编辑器里和连续操作不一定得到相同记录。复盘时保留这种口径,不要给数据补上它没有测量的活动。
文件路径、项目名称、编辑器与操作系统等信息可能随心跳进入系统。具体字段按客户端确认,私密项目可以配置排除规则。API 密钥按凭据保护,公开分享页面也要单独确认可见范围,别把自己的统计入口当成所有记录都私密的保证。
日常访问用 HTTPS,备份保存整卷与盐值
长期连接不适合依赖手动隧道。准备一个独立子域名,用反向代理提供 HTTPS,转发到 127.0.0.1:3000,确认 API 路径也能通过。切换安全 Cookie 设置后重新登录,将客户端地址改为正式域名的 /api,再次发送测试心跳。
本例没有配置邮件服务,不能据此承诺每周邮件已经可用。需要周报或外部监控时,按当前配置文档分别接入,并避免在公开监控页展示账号和项目细节。
SQLite 卷停止写入后,可以用含归档工具的辅助容器读取。当前 Wakapi 镜像采用 distroless,不能假设里面有 Shell 或 tar。先建立只有自己可读的输出目录,并用 docker volume ls 找到此 Compose 项目的确切卷名;下面的 EXACT_WAKAPI_VOLUME 必须换成该名称,不能凭印象选择另一个项目的卷。
cd /opt/wakapi
umask 077
mkdir -p backup-out
docker volume ls
先将下面的卷名替换为上一步查到的名称。归档时只读挂载数据,配置和盐值一起保存:
docker compose stop wakapi
docker run --rm --user 0:0 -v EXACT_WAKAPI_VOLUME:/data:ro -v "$PWD/backup-out:/backup" alpine:3.22 tar -czf /backup/wakapi-data.tgz -C /data .
cp compose.yaml .env backup-out/
docker compose start wakapi
恢复时还原卷内容、目录权限和原盐值,启动原验证过的镜像版本。抽查一个旧项目,再接一次新的测试心跳,确认旧历史与新数据都可用。统计用于解释自己的时间分布,不能替代对实际工作的判断。












