- Go 54.5%
- TypeScript 36.5%
- CSS 6.5%
- Shell 1.9%
- JavaScript 0.3%
- Other 0.2%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| .forgejo/workflows | ||
| assets | ||
| cmd/lastgym | ||
| deploy | ||
| docs | ||
| internal | ||
| scripts | ||
| web | ||
| .dockerignore | ||
| .editorconfig | ||
| .env.example | ||
| .gitignore | ||
| bun.lock | ||
| CHANGELOG.md | ||
| CONTRIBUTING.md | ||
| docker-compose.yml | ||
| Dockerfile | ||
| go.mod | ||
| go.sum | ||
| install.sh | ||
| LICENSE | ||
| Makefile | ||
| NOTICE | ||
| package.json | ||
| README.md | ||
| SECURITY.md | ||
| tsconfig.json | ||
📖 Read the Documentation for detailed guides on installation, configuration, security, and everyday use.
Why LastGYM
Everyone who lifts ends up choosing between an app that keeps your training on somebody else's server and a self-hosted one that gave up on phones years ago. LastGYM was built with a simple rule: a set you recorded is never lost, and the basement with no signal is where that gets proven.
- A whole session offline — sets, reps, weight, RPE, rest timers, recorded with no network at all and synced when there is one. Every set reaches the disk before the screen shows it.
- A progression engine — templates, supersets, and a suggested weight for the next session instead of arithmetic in your head. It proposes; it never records what you did not confirm.
- Progress that means something — personal records, estimated 1RM, volume by muscle and by movement pattern, plateau detection, and a load model that answers "can I push today?" before "what do I train today?".
- Body and cardio — weight, body fat, girths and progress photos, with every derived figure showing the method behind it. Heart-rate zones from your own profile, reading
.fit,.tcxand.gpxfrom Garmin, COROS, Polar and others. - Coaching without surveillance — a coach sees only the athletes who granted access, only what they granted, and revoking takes effect on the next request.
- Notifications that arrive — a rest timer that reaches you with the screen off, through Web Push or your own ntfy, Gotify or webhook.
- One binary, one file — no database server, no runtime, no dependencies. SQLite and the whole interface are compiled in, and a backup is a copy of one file.
- Twenty languages, translated by hand, with right-to-left laid out properly for Arabic, Persian and Urdu.
- Small enough for a Pi — 16 MB resident at rest with five years of training in it, measured rather than estimated.
Security & Privacy
Security
LastGYM is built from the ground up with defence-in-depth principles: argon2id with a floor configuration cannot lower, opaque sessions with CSRF checked against the session row, strict CSP headers with a per-request nonce, aggressive rate limiting, an anti-SSRF gate inside the dial for every outbound request, push payloads encrypted before they leave, and signature-verified updates.
For a detailed breakdown of our security measures, including what the threat model does not cover, see the Security Policy.
Privacy
Your training belongs to you, and the administrator is not an exception. The admin role manages accounts and the server; it has no endpoint, no view and no export that reads another person's workouts, measurements or photos. A test walks the route table on every build to keep that true.
There is no telemetry of any kind. Nothing about you or your instance is reported to us, ever.
Installation Methods
Quick Start with Docker
Images are built and published to our Forgejo registry on every release.
Using Docker Compose:
services:
lastgym:
image: git.codigosh.com/codigosh/lastgym:beta
container_name: lastgym
ports:
- "127.0.0.1:8080:8080"
environment:
- TZ=Europe/Madrid
- LASTGYM_EXTERNAL_URL=https://gym.example.org
# - TRUST_PROXY=true # Uncomment if running behind a reverse proxy
volumes:
- lastgym-data:/data
restart: unless-stopped
volumes:
lastgym-data:
Using Docker CLI:
# Note: Add `-e TRUST_PROXY=true \` before the image name if running behind a reverse proxy.
docker run -d \
--name lastgym \
-p 127.0.0.1:8080:8080 \
-e TZ=Europe/Madrid \
-e LASTGYM_EXTERNAL_URL=https://gym.example.org \
-v lastgym-data:/data \
--restart unless-stopped \
git.codigosh.com/codigosh/lastgym:beta
The tag is beta until there is a stable release: latest is only ever moved by a stable one, so nobody pulling it lands on a prerelease. The image is scratch and has no shell in it, and it is built without a signing key — the binary inside refuses to update itself, because updating a container is pulling a new image.
For advanced configuration options and environment variables, see the .env.example and the Configuration Guide.
Quick Install (Linux)
Run this command to install or update LastGYM automatically:
curl -fsSL https://git.codigosh.com/CodigoSH/LastGYM/raw/branch/main/install.sh | sudo sh
It asks three things — port, whether a reverse proxy sits in front, and the release channel. Answer beta: there is no stable release yet. --uninstall removes it and leaves your training where it is.
It has to be served over HTTPS. Browsers refuse to install a service worker on an insecure origin, so over plain HTTP there is no offline support — the application works perfectly right up until the moment there is no signal, which is the moment it was built for. See Installing.
The first account you create is the administrator. Open the address the installer printed and choose a username and a password; a server with somebody in it cannot be claimed again.
For more details on building from source, check the Development Guide.
Updates
LastGYM updates are delivered directly from our own Forgejo instance — no proxy, no intermediary and no telemetry.
The updater checks the signature over the checksum list before it downloads anything, then the binary's own checksum, then makes the candidate prove it runs and report its schema, then refuses any binary older than the database, takes a verified backup, and only then replaces anything. None of those has a switch. It does not need anybody to stop training first: phones record without the server and send when it is back.
For detailed updating instructions, see the Installing guide, or the Security Policy for how the signing works.
Support & Recognition
We are an open-source initiative managed through Open Collective Europe.
Financial Support
If you find our tools useful, consider supporting our infrastructure through an unconditional donation.
Acknowledgments
Special thanks to everyone supporting our mission.
Organizations
We appreciate the organizations that support us as a gesture of goodwill to help maintain our infrastructure.
Credits
- Body diagrams:
- react-native-body-highlighter (MIT - https://github.com/HichamELBSI/react-native-body-highlighter), redrawn as static SVG
- Everything else drawn here: the mascot, the icons and the charts are drawn by hand in this repository — no icon library, no chart library, no frontend framework.
Full attribution, including the Go modules compiled into the binaries, lives in NOTICE.
A project by CodigoSH — built to last.
