三股水
Running Page 完整部署教程(Docker + Keep 数据同步)
本文从 Obsidian 撰写发布

Running Page 完整部署教程(Docker + Keep 数据同步)

本教程基于 Ubuntu/Debian 系统,使用 Docker 部署 Running Page,实现 Keep 运动数据的自动同步与可视化展示。最后更新:2026-07-08

目录

  1. 环境准备
  2. 部署 Running Page
  3. 配置 Keep 数据同步
  4. 前端样式自定义
  5. 设置定时自动同步
  6. 常用命令速查
  7. 常见问题排查

1. 环境准备

1.1 系统要求

  • Ubuntu 20.04+ / Debian 11+
  • Docker 20.10+
  • 至少 2 GB 内存
  • 开放端口 8085(或自定义)

1.2 安装 Docker

sudo apt update && sudo apt upgrade -y
curl -fsSL https://get.docker.com | bash
sudo systemctl start docker
sudo systemctl enable docker
docker --version

1.3 安装 Python3 和 pip

sudo apt install -y python3 python3-pip python3-venv

2. 部署 Running Page

2.1 克隆官方项目

mkdir -p /wwwroot/running_page_official
cd /wwwroot/running_page_official
git clone https://github.com/yihong0618/running_page.git
cd running_page

2.2 修改 Dockerfile(修复 Node.js 版本兼容性)

nano Dockerfile
# 找到 FROM node:18 AS frontend-build,改为 FROM node:20 AS frontend-build
# 保存:Ctrl+X,按 Y,按 Enter

2.3 构建 Docker 镜像

docker build -t running-page-official .

2.4 运行容器

mkdir -p data
docker run -d \
  --name running-page-official \
  -p 8085:80 \
  -v $(pwd)/data:/data \
  -e KEEP_PHONE="你的Keep手机号" \
  -e KEEP_PASSWORD="你的Keep密码" \
  -e RUNNER_NAME="你的名字" \
  --restart unless-stopped \
  running-page-official

2.5 查看容器状态

docker ps | grep running-page-official
docker logs -f running-page-official

2.6 访问页面

浏览器打开:http://你的服务器IP:8085

3. 配置 Keep 数据同步

3.1 安装项目依赖

cd /wwwroot/running_page_official/running_page
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt

3.2 执行数据同步

python run_page/keep_sync.py 你的Keep手机号 你的Keep密码

3.3 复制数据到容器

docker cp src/static/activities.json running-page-official:/usr/share/nginx/html/assets/activities-DQ6mP_-C.json
docker restart running-page-official

3.4 创建一键更新脚本

cat > update.sh << 'EOF'
#!/bin/bash
cd /wwwroot/running_page_official/running_page
source venv/bin/activate
python run_page/keep_sync.py 你的Keep手机号 你的Keep密码
docker cp src/static/activities.json running-page-official:/usr/share/nginx/html/assets/activities-DQ6mP_-C.json
deactivate
echo "✅ 数据更新完成!刷新页面即可查看。"
EOF
chmod +x update.sh

4. 前端样式自定义

4.1 修改"夜晚跑步"显示问题

问题原因RICH_TITLE = true 导致页面优先使用 run.name,时间判断逻辑把所有运动归类为"夜晚跑步"。

解决方案

cd /wwwroot/running_page_official/running_page

修改 src/utils/const.ts

nano src/utils/const.ts
# 将 const RICH_TITLE = true; 改为 const RICH_TITLE = false;

修改 src/utils/utils.ts

nano src/utils/utils.ts

找到 getActivitySport 函数,替换为:

const getActivitySport = (act: Activity): string => {
  const type = act.type.toLowerCase();
  const subtype = act.subtype?.toLowerCase() || '';
  if (type === 'run') {
    if (subtype === 'generic' || subtype === '') {
      const runDistance = act.distance / 1000;
      if (runDistance > 20 && runDistance < 40) return RUN_TITLES.HALF_MARATHON_RUN_TITLE;
      else if (runDistance >= 40) return RUN_TITLES.FULL_MARATHON_RUN_TITLE;
      return ACTIVITY_TYPES.RUN_GENERIC_TITLE;
    } else if (subtype === 'trail') {
      return ACTIVITY_TYPES.RUN_TRAIL_TITLE;
    } else if (subtype === 'treadmill') {
      return ACTIVITY_TYPES.RUN_TREADMILL_TITLE;
    }
    return ACTIVITY_TYPES.RUN_GENERIC_TITLE;
  } else if (type === 'walk' || type === 'walking') {
    return ACTIVITY_TYPES.WALKING_TITLE;
  } else if (type === 'ride' || type === 'cycling') {
    return ACTIVITY_TYPES.CYCLING_TITLE;
  } else if (type === 'hiking') {
    return ACTIVITY_TYPES.HIKING_TITLE;
  } else if (type.includes('skiing')) {
    return ACTIVITY_TYPES.SKIING_TITLE;
  }
  return '';
};

找到 titleForRun 函数,替换为:

const titleForRun = (run: Activity): string => {
  const activitySport = getActivitySport(run);
  const runHour = +run.start_date_local.slice(11, 13);
  let timePrefix = '';
  if (runHour >= 0 && runHour <= 5) {
    timePrefix = '凌晨';
  } else if (runHour >= 6 && runHour <= 8) {
    timePrefix = '清晨';
  } else if (runHour >= 9 && runHour <= 11) {
    timePrefix = '上午';
  } else if (runHour >= 12 && runHour <= 13) {
    timePrefix = '午间';
  } else if (runHour >= 14 && runHour <= 16) {
    timePrefix = '午后';
  } else if (runHour >= 17 && runHour <= 19) {
    timePrefix = '傍晚';
  } else {
    timePrefix = '夜晚';
  }
  if (activitySport && activitySport !== '') {
    return `${timePrefix}${activitySport}`;
  }
  const runDistance = run.distance / 1000;
  if (runDistance > 20 && runDistance < 40) {
    return RUN_TITLES.HALF_MARATHON_RUN_TITLE;
  }
  if (runDistance >= 40) {
    return RUN_TITLES.FULL_MARATHON_RUN_TITLE;
  }
  return `${timePrefix}运动`;
};

4.2 修改导航和 Logo

nano src/hooks/useSiteMetadata.ts

将内容替换为:

const data: ISiteMetadataResult = {
  siteTitle: '我的运动',
  siteUrl: 'https://你的域名.com',
  logo: 'https://你的图片地址.com/logo.png',
  description: '个人运动记录',
  navLinks: [
    { name: '总览', url: '/summary' },
    { name: '博客', url: 'https://你的博客地址.com' },
    { name: '关于', url: 'https://你的关于页面.com' },
  ],
};

4.3 重新构建前端

cd /wwwroot/running_page_official/running_page
rm -rf dist/
docker run --rm -v $(pwd):/app -w /app node:20 sh -c "npm config set registry https://registry.npmmirror.com && npm install && npm run build" && docker cp dist/. running-page-official:/usr/share/nginx/html/ && docker restart running-page-official

5. 设置定时自动同步

5.1 编辑 crontab

crontab -e

5.2 添加定时任务

在文件末尾添加:

# 每天凌晨 3 点自动同步 Keep 数据
0 3 * * * cd /wwwroot/running_page_official/running_page && ./update.sh >> /var/log/running_page.log 2>&1

5.3 查看定时任务

crontab -l

5.4 查看同步日志

tail -50 /var/log/running_page.log

6. 常用命令速查

操作命令
查看容器状态`docker ps \grep running-page-official`
查看容器日志docker logs -f running-page-official
重启容器docker restart running-page-official
停止容器docker stop running-page-official
启动容器docker start running-page-official
手动同步数据cd /wwwroot/running_page_official/running_page && ./update.sh
进入容器docker exec -it running-page-official /bin/sh
查看数据文件cat /wwwroot/running_page_official/running_page/src/static/activities.json

7. 常见问题排查

7.1 页面显示 Nginx 默认页

  • 检查容器是否正常运行:docker ps | grep running-page-official
  • 检查端口是否被占用:netstat -tlnp | grep 8085

7.2 数据同步失败

  • 检查 Keep 账号密码是否正确
  • 检查网络是否能访问 Keep API
  • 查看同步日志:tail -50 /var/log/running_page.log

7.3 页面显示"夜晚跑步"

  • 确认 RICH_TITLE = false 已设置
  • 确认 getActivitySport 函数已修改
  • 重新构建前端后强制刷新浏览器(Ctrl+F 5)

7.4 构建前端失败

  • 检查 Node.js 版本是否为 20+
  • 使用国内镜像源:npm config set registry https://registry.npmmirror.com
  • 删除 node_modulesdist 目录后重新构建
😊
提交