
为什么要在飞牛OS上跑一个运动记录服务我用飞牛OS有一段时间了它本质上是基于Debian的NAS系统自带Docker和Docker Compose管理界面做得比群晖顺手一些。日常我拿它存文件、跑一些轻量容器。之前运动数据一直散在手机App里各家App导出格式不统一想做个长期统计很麻烦所以打算自建一套运动记录服务数据放自己硬盘上。选ExerciseDiary的原因很简单它是一个自托管、带Web界面的运动/健身日志项目支持记录训练、体重、目标之类的数据前后端打包在一个镜像里部署成本低。它并不是那种功能特别庞大的健身平台但对我这种只想记录看趋势的需求刚好够用。需要说明的是ExerciseDiary并不是一个特别主流、更新极频繁的项目社区规模有限这一点在选型时要有心理预期。本文会覆盖三块Compose部署、运动记录的日常使用、以及外网访问飞牛自带方案和Cloudflare Tunnel两条路。远程访问部分我会重点讲思路因为不同网络环境差异很大具体到端口和配置要按你自己的情况调整。部署前的准备在飞牛OS上Docker相关操作我基本走两条路一是Web界面里的Docker应用二是SSH进去用命令行。Compose文件我倾向用命令行管理因为改起来直观日志也好查。先确认环境docker--versiondockercompose version飞牛OS一般已经装好这两样。如果docker compose带空格V2语法不可用试试docker-compose带横杠V1。现在新系统基本是V2我下面统一用docker compose。接着规划目录。我习惯把所有自托管服务的数据集中放方便备份mkdir-p/vol1/1000/docker/exercisediary/datacd/vol1/1000/docker/exercisediary/vol1/1000/是我飞牛上的存储池路径你的可能不一样用df -h或文件管理器确认一下。ExerciseDiary的数据主要是一个数据库文件通常是SQLite所以持久化目录指到data就行。【注意】ExerciseDiary的官方镜像名称和标签不同来源说法不完全一致。我在部署时用的是社区常见的镜像名如果你在Docker Hub搜不到建议先去项目仓库确认当前推荐的镜像地址。这一点我没有逐一验证所有镜像tag请以项目README为准。编写docker-compose.yml我最终的Compose文件大致长这样services:exercisediary:image:exercisediary/exercisediary:latestcontainer_name:exercisediaryrestart:unless-stoppedports:-8383:80volumes:-./data:/app/dataenvironment:-TZAsia/Shanghai几个地方解释一下为什么这么写restart: unless-stopped——NAS重启后容器自动拉起但手动停了不会自己回来这个策略对家用服务最省心。ports映射——左边是宿主机端口右边是容器内端口。这里我假设容器内部监听80。如果项目实际用的是别的端口比如3000、5000右边要改。我写作时没法保证所有版本都用80所以这一步务必以镜像文档为准或者启动后看日志里打印的监听端口。volumes——把宿主机./data挂到容器内数据目录。ExerciseDiary的数据路径在不同版本里可能是/app/data也可能是别的。如果挂载后数据没持久化八成是路径对不上进容器看一眼dockercomposeexecexercisediaryls/appTZ环境变量——让容器用东八区时间否则记录时间戳会差8小时做趋势统计时很别扭。启动dockercompose up-ddockercompose logs-f日志里如果出现数据库初始化、监听端口之类的信息基本就起来了。浏览器访问http://飞牛IP:8383。【踩坑提醒】如果页面能打开但样式全乱、接口报错常见原因是反向代理或端口没配对如果完全打不开先docker compose ps看容器状态是不是Up再看日志有没有崩溃堆栈。运动记录的日常使用ExerciseDiary的界面逻辑不复杂新建一条记录选运动类型填时长或距离保存。它一般会提供一个仪表盘把历史记录按时间轴或图表展示。我自己的用法是每天训练完随手记一笔字段不用填太细重点是坚持。真正有价值的是积累一段时间后看趋势——比如每周总时长有没有下降某类运动频率够不够。这也是我放弃手机App改用自托管的原因数据在我手里导出和二次分析不受限。数据存在SQLite里的话备份就是复制文件cp/vol1/1000/docker/exercisediary/data/*.db /vol1/1000/backup/exercisediary-$(date%F).db【注意】数据库文件在容器运行时直接复制可能拿到不一致的快照。稳妥做法是先停容器再复制或者用SQLite的.backup命令。我平时是停容器备份几十秒的事。远程访问两条路本地能用之后真正麻烦的是外网访问。这里我讲两种方案各有取舍。方案一飞牛OS自带的远程访问飞牛系统提供了一些远程访问能力类似内网穿透/中转可以在不暴露公网端口的前提下从外部访问NAS上的服务。具体入口和配置项在飞牛的设置里我这边是通过它的远程访问功能把内网服务映射出去。优点是不用自己搞域名和证书配置门槛低缺点是依赖厂商中转速度和稳定性受中间链路影响且功能形态可能随系统版本变化。我没有对它的带宽和并发做严格测试只能说日常打开记录页面够用。方案二Cloudflare TunnelCR如果你有自己的域名、且域名托管在Cloudflare用Cloudflare Tunnel是个更可控的方案。它的原理是在NAS上跑一个cloudflared容器主动向Cloudflare建立出站隧道外部请求经Cloudflare转发进来全程不需要在路由器上开公网端口。先在Cloudflare Zero Trust后台创建一条Tunnel拿到token然后加一个Compose服务services:cloudflared:image:cloudflare/cloudflared:latestcontainer_name:cloudflaredrestart:unless-stoppedcommand:tunnel--no-autoupdate run--token 你的TUNNEL_TOKENnetwork_mode:host把你的TUNNEL_TOKEN换成后台给你的实际token。network_mode: host是为了让cloudflared能直接用宿主机的网络访问到ExerciseDiary容器所在的端口省去跨网络配置的麻烦。然后在Zero Trust里给这条Tunnel配一个Public Hostname比如diary.你的域名.comService指向http://localhost:8383即ExerciseDiary在宿主机上的地址。保存后等几十秒外网就能访问了。【关键结论】Cloudflare Tunnel的核心优势是零公网端口暴露 自动HTTPS安全性比直接端口转发高很多。代价是你得有个托管在Cloudflare的域名并且接受流量经过Cloudflare。两种方案的对比方案优点缺点适用场景飞牛自带远程访问配置简单、无需域名依赖中转、速度受链路影响偶尔外网查看、不想折腾Cloudflare Tunnel不暴露端口、自动HTTPS、可控需自有域名、流量经CF长期使用、重视安全一个容易忽略的点认证不管是哪种远程方案ExerciseDiary本身如果只有简单登录甚至没有强认证把界面直接暴露到公网是有风险的。我的做法是在前面加一层认证——Cloudflare Tunnel可以配合Access策略要求邮箱验证才能访问飞牛自带方案则看它有没有提供访问控制。【踩坑提醒】不要把没有认证的自托管服务直接挂公网。哪怕只是运动数据被人乱改或扫到也是麻烦。小结整套跑下来飞牛OS上部署ExerciseDiary本身不难Compose文件十几行就够。真正需要花心思的是两处一是数据持久化路径要和镜像实际结构对上二远程访问的安全与稳定性。前者靠进容器确认目录后者根据自己有没有域名、对安全的要求来选方案。如果你也在飞牛上跑自托管服务欢迎交流你们的远程访问是怎么做的——尤其是不同宽带环境下Cloudflare Tunnel的实际速度表现这块我样本有限还值得多验证。备用标题飞牛OS自建运动记录ExerciseDiary的Docker部署与外网访问实践用Docker Compose在飞牛OS跑ExerciseDiary并打通远程访问飞牛OS部署ExerciseDiary从Compose到Cloudflare Tunnel远程访问自托管运动日志ExerciseDiary在飞牛OS上的部署与远程访问配置飞牛OSDocker搭建ExerciseDiary运动记录服务并实现外网访问