openGym: a self-hosted gym and body-weight tracker you run with docker compose
https://github.com/DuarteSantos8/openGym
At a glance
- What is it?
- openGym is an AGPL-3.0 self-hosted workout tracker built on React 19, a Node API and passkey login. It suits people who want their training data in a folder they control, and it assumes you are comfortable running containers.
- Who is it for?
- Adopt openGym if you already run Docker on a home server or VPS and want your training history in a folder you back up yourself; the compose file makes the whole stack three services and one port. Skip it if you want a hosted app with zero maintenance, or if you need an official mobile build, because the README describes an installable PWA rather than an App Store release.
- Can I use it commercially?
- Yes, with strict conditions. AGPL-3.0 is a network copyleft licence: if people use a modified version over a network, for example as a hosted service, you must offer them its source code under the same licence.
- Is it still maintained?
- Yes. The repository last received commits 45 days ago.
- What is it written in?
- Mainly JavaScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 16, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
What openGym actually solves, and for whom
Most workout apps keep your training history on someone else's server behind an account you do not control. openGym inverts that. The README states the project's position plainly: it "runs on your box, your data stays in a folder you control, and it's yours to fork." The practical consequence is that the unit of ownership is a directory, not a login. The compose file mounts ./data into the API container and labels it "users, passkeys, per-user state, session secret: BACK THIS UP", so the backup question is answered by copying one folder rather than exporting from a vendor's settings page.
The audience is narrow and specific. You need to be willing to run Docker and keep a host reachable from your phone. In exchange you get features that usually sit behind a subscription: a weekly plan, guided workouts with rest timers, body-weight tracking against a goal line, estimated 1RM, an activity heatmap and a muscle map. The README also notes that the hosted demo runs "entirely in your browser on example data" with no server behind it, which means passkey sign-in, cross-device sync and the admin dashboard only exist in a self-hosted instance. That is the honest boundary of the project: the demo shows the interface, your instance is the product.
Three containers, one origin, and why passkeys force that shape
The architecture is visible in docker-compose.yml and is smaller than the feature list suggests. There are three services. media is a one-shot alpine/git container that clones a third-party exercise dataset and copies images and GIFs into ./media/img and ./media/gif, roughly 140 MB, and skips the download if the folders are already populated. api is a Node service, described in the compose comments as "Passkey auth + per-user data (Node, no framework)", listening on PORT=3000 internally with DATA_DIR=/data. web builds the React frontend in a multi-stage Dockerfile and serves the static output through nginx, proxying /api back to the api service and serving exercise media from the shared volume.
The reason web and api share a single origin is passkeys. WebAuthn credentials are bound to a relying party identifier, so serving the app and its API from one hostname avoids the configuration that a split frontend/backend deployment would require. The compose file exposes only ${WEB_PORT:-8080}:80; the API port stays internal. That is a deliberate simplification, and it means the reverse-proxy story is mostly handled for you by nginx.conf inside the image. The Dockerfile carries a second, less obvious decision: the build stage is pinned with --platform=$BUILDPLATFORM, and a comment explains that QEMU-emulated npm installs are "known to corrupt esbuild/rollup's platform-specific native binaries, which is what breaks vite build with unrelated-looking module-resolution errors." If you cross-build for a Raspberry Pi from an amd64 machine, that line is the reason it works.
Installing openGym with docker compose and logging a first workout
The README's install story is the tagline: docker compose up. The compose file expects an .env file next to it (the api service loads env_file: .env), and it publishes the web container on port 8080 unless WEB_PORT overrides it. Clone the repository, then start the stack. The first run downloads the exercise media, so expect a pause before the web container comes up; the media service must complete successfully before web starts, which the depends_on condition enforces.
Where openGym gets in your way
The first-run media download is a real dependency, not a nicety. It clones github.com/hasaneyldrm/exercises-dataset, a third-party repository under a CC licence, into a temporary path and copies roughly 140 MB of JPEGs and GIFs into ./media. If that repository moves, changes layout, or is unreachable from your network, the media service fails and web never starts, because depends_on requires service_completed_successfully. The compose file's skip logic checks only whether /out/img is non-empty, so a partial copy that left one file behind will be treated as complete on the next run.
The second constraint is the data directory. Everything lives in ./data, including the session secret. Lose it and you lose passkey registrations, not just history; there is no documented export path in the README, and the README does not describe rollback or migration between versions. Recent releases were not retrieved, so there is no versioned upgrade note to lean on. The third is the exercise library itself: 1,324 exercises with animated demos is a lot of surface, but the animations come from the external dataset, and the README's own custom-exercise feature exists precisely because that library will not cover everything, offering "an optional description instead of an animation."
openGym compared with a plain notes app or a hosted tracker
The obvious alternative is not another self-hosted project; it is the spreadsheet or notes app you already use. A spreadsheet costs nothing to run, has no media download, no passkey setup and no container to update, and it never fails because a third-party dataset repository went away. What it cannot do is the part openGym is built around: pre-filling your weights from last session, applying a named progression rule (the README lists linear, Greyskull LP with AMRAP top sets and 10 percent resets, double progression through a rep range, and adding time), detecting PRs, running a rest timer, and keeping the screen awake for the length of a workout. Those are stateful behaviours tied to a session, and a spreadsheet only reproduces them with formulas you maintain yourself.
The other alternative is a hosted tracker with a mobile app. That removes the operational burden entirely: no Docker, no backups, no port to expose. The trade is the one openGym was written against. Your history sits in an account, and the README's framing of apps that "disappear when the startup does" is the failure mode you accept. Between the two, the deciding question is whether you already run a server. If you do, openGym adds one compose file and one port. If you do not, the spreadsheet is the more honest choice.
Licence, maintenance and what an upgrade actually costs
openGym is AGPL-3.0. The practical implication for a self-hoster is that if you modify it and let other people use your instance over a network, the licence's network clause can require you to offer those users the corresponding source. Running it privately for yourself and your household is the ordinary case the README describes. Note also that the exercise media is not covered by the project licence: the compose file credits github.com/hasaneyldrm/exercises-dataset as a CC-licensed dataset, and NOTICE.md exists at the top level, so check that file before redistributing an instance with media included. This is a description of what the files say, not legal advice.
On maintenance, the repository is not archived and the last push was on 2026-08-03. That is recent enough that the project is neither abandoned nor old, but there are no retrieved releases, so upgrades are a git pull plus a rebuild rather than a tagged version bump. Because the API image is published as ghcr.io/duartesantos8/opengym-api:latest and the web image as ghcr.io/duartesantos8/opengym-web:latest, compose pull will move you to whatever was pushed most recently. The safe sequence is to stop the stack, copy ./data somewhere else, pull, and start again; the compose file's own comment on the data volume is the only backup guidance the repository provides.
Editorial conclusion
Adopt openGym if you already run Docker on a home server or VPS and want your training history in a folder you back up yourself; the compose file makes the whole stack three services and one port. Skip it if you want a hosted app with zero maintenance, or if you need an official mobile build, because the README describes an installable PWA rather than an App Store release. Before committing, verify two things on your own hardware: that the one-time media download finishes (it pulls roughly 140 MB from a third-party dataset) and that passkey sign-in works on every device you plan to train with, since the README notes the hosted demo has no server behind it and therefore cannot exercise passkeys, sync or the admin dashboard.
Frequently asked questions
What is openGym?
It is a self-hosted gym and body-weight tracker that runs on your own machine. The README describes a weekly plan, guided workouts, body-weight tracking, estimated 1RM, a muscle map and passkey login, all served from a Docker Compose stack.
How do I install openGym?
The README's install instruction is docker compose up. The compose file defines three services (media, api, web) and publishes the web container on port 8080 by default, with an .env file loaded by the API service.
Is openGym free to run?
The project is licensed AGPL-3.0 and there is no account or subscription described in the README. Your costs are whatever host you run it on, plus roughly 140 MB of one-time exercise media downloaded from a third-party dataset.
Can I use openGym without Docker?
The README only documents the Docker path. The Dockerfile notes that self-hosters never need Node locally because docker compose up builds everything, and no bare-metal install steps appear in the README.
Does openGym sync across devices?
Yes, per the README, sync across devices is one of the features that only exists in a self-hosted instance. The hosted demo has no server behind it, so it cannot demonstrate sync or passkey sign-in.
Community notes