openGym

Self-hosted gym and body-weight tracker with passkey login

  • registry.gitlab.com/duartesantos8/opengym/web:1.4.2
  • port 6115
  • Productivity
openGym screenshot 1openGym screenshot 2openGym screenshot 3openGym screenshot 4openGym screenshot 5openGym screenshot 6

Web App

/
http://localhost:6115/

openGym is a self-hosted gym and body-weight tracker: plan routines, log workouts (supersets and cardio included), and track your weight and progress over time, all stored on your own server.

Features

  • Weekly routine planner and guided workout logging, with supersets, drop-sets, rest-pause and planned warm-ups
  • Body-weight tracking with a goal line and progress charts, plus estimated 1RM and other stats
  • Passkey (WebAuthn) sign-in, with optional invite-only signup and an admin dashboard
  • Push notifications for workout-day reminders
  • Everything is stored as plain files, no separate database to run or back up
  • A helper step downloads the exercise photo and GIF library (about 140 MB) once on first start

How to use

  1. Open openGym from your dashboard.
  2. Tap "Create profile" and register a passkey.
  3. Build your first weekly routine, then start a guided workout and log your sets.
  4. Add a body-weight entry and set a goal line under the Weight tab.
  5. Turn on the admin dashboard, invite-only signup or the AI Coach later from Settings.

Before you install

Set RP_ID and ORIGIN in the opengym-api service. They must point at the same address, or sign-in fails. To test on the same computer only, use localhost and http://localhost:6115. To use openGym from your phone, you need a real domain with HTTPS in front, like gym.example.com and https://gym.example.com. Pick your final address before inviting people: moving later breaks every passkey. The first start downloads about 140 MB of exercise pictures, so give it a few minutes. More settings are in the Variables tab; add them to the opengym-api service in the app settings.

The settings in the first table are already in the app settings. To use any other one, open the app settings, add the variable with your value, save, and the app restarts with it. A setting you leave out uses its default.

Passkeys

VariableDefault valueDescription
RP_NAMEopenGymThe name shown in the passkey prompt when signing in. Add it to the opengym-api service.

Sign-up and accounts

VariableDefault valueDescription
SESSION_DAYS90How many days a sign-in lasts. Lower it if openGym is reachable from the internet. Add it to the opengym-api service.
INVITE_ONLY—Set to 1 so new profiles need an invite code. Add it to the opengym-api service.
FIRST_USER_ADMIN—Set to 1 so the first profile on a new install becomes the admin. Add it to the opengym-api service.
ADMIN_UIDS—Account IDs that get the admin dashboard, separated by commas. Add it to the opengym-api service.
ALLOW_GUEST1Set to 0 to remove "Continue without account". Add it to the opengym-api service.
PASSWORD_LOGIN—Set to 1 to also allow name-and-password sign-in. Add it to the opengym-api service.

Server

VariableDefault valueDescription
DEFAULT_LANG—The language for sign-in and new profiles, like en or de. Leave it out to use the browser's language. Add it to the opengym-api service.
TRUST_PROXY—Set to 1 when openGym is behind a reverse proxy, so it sees real visitor addresses. Add it to the opengym-api service.

Notifications

VariableDefault valueDescription
VAPID_SUBJECT—Contact address given to push services, like mailto:[email protected]. Leave it out to use ORIGIN. Add it to the opengym-api service.

Logs

VariableDefault valueDescription
AUDIT_LOG1Set to 0 to turn the activity log off. Add it to the opengym-api service.
AUDIT_DAYS90Days of activity log to keep. Add it to the opengym-api service.

Uploads

VariableDefault valueDescription
MEDIA_UPLOADS1Set to 0 to turn off photo and video uploads. Add it to the opengym-api service.
MEDIA_QUOTA_MB200Storage per profile in MB. Set to 0 for no limit. Add it to the opengym-api service.
docker-compose.yml
name: opengym

services:
  opengym-media:
    image: alpine/git:2.54.0
    container_name: opengym-media
    restart: "no"
    networks:
      - opengym_network
    entrypoint: ["/bin/sh", "-c"]
    command:
      - |
        if [ -z "$$(ls -A /out/img 2>/dev/null)" ]; then
          git clone --depth 1 https://github.com/hasaneyldrm/exercises-dataset /tmp/ds
          cp /tmp/ds/images/*.jpg /out/img/ && cp /tmp/ds/videos/*.gif /out/gif/
        fi
    volumes:
      - type: bind
        source: /DATA/AppData/$AppID/media/img
        target: /out/img
        bind:
          create_host_path: true
      - type: bind
        source: /DATA/AppData/$AppID/media/gif
        target: /out/gif
        bind:
          create_host_path: true
    deploy:
      resources:
        limits:
          cpus: "1.00"
          memory: 256M
        reservations:
          cpus: "0.00"
          memory: 64M
    x-casaos:
      id: com.icestore.opengym
      volumes:
        - container: /out/img
          description:
            en_US: Exercise photos, downloaded once from the public exercises-dataset project and shared with the web service.
        - container: /out/gif
          description:
            en_US: Exercise animated GIFs, downloaded once from the public exercises-dataset project and shared with the web service.

  opengym-api:
    image: registry.gitlab.com/duartesantos8/opengym/api:1.4.2
    container_name: opengym-api
    restart: unless-stopped
    stop_grace_period: 40s
    networks:
      opengym_network:
        aliases:
          - api
    environment:
      - TZ=$TZ
      - DATA_DIR=/data
      - RP_ID=CHANGEME_RP_ID
      - ORIGIN=CHANGEME_ORIGIN
      - COACH_DISABLED=1
    volumes:
      - type: bind
        source: /DATA/AppData/$AppID/data
        target: /data
        bind:
          create_host_path: true
    deploy:
      resources:
        limits:
          cpus: "1.00"
          memory: 512M
        reservations:
          cpus: "0.00"
          memory: 128M
    labels:
      icon: https://cdn.jsdelivr.net/gh/HSinghHira/IceStore@main/Apps/opengym/icon.png
    x-casaos:
      id: com.icestore.opengym
      envs:
        - container: TZ
          description:
            en_US: Your time zone. ZimaOS fills this in for you.
        - container: DATA_DIR
          description:
            en_US: Where openGym keeps its files inside the container. Leave it as /data.
        - container: RP_ID
          description:
            en_US: The exact hostname passkeys are locked to. Use "localhost" for local-only testing, or your real domain (e.g. gym.example.com) once this sits behind HTTPS. Must match the hostname in ORIGIN exactly, in both services.
        - container: ORIGIN
          description:
            en_US: The full web address people open openGym at, including http:// or https://, e.g. http://localhost:6115 or https://gym.example.com. Must match RP_ID's hostname exactly, or passkey login fails.
        - container: COACH_DISABLED
          description:
            en_US: Keeps the optional AI Coach feature turned off for every profile. Set to empty to allow admins to turn it on later from Settings.
      volumes:
        - container: /data
          description:
            en_US: Everything openGym stores — profiles, passkeys, workout history, the session-signing secret and push notification keys. Back this up regularly.

  opengym:
    image: registry.gitlab.com/duartesantos8/opengym/web:1.4.2
    container_name: opengym
    restart: unless-stopped
    stop_grace_period: 40s
    networks:
      opengym_network:
        aliases:
          - web
    depends_on:
      - opengym-media
      - opengym-api
    ports:
      - target: 80
        published: "6115"
        protocol: tcp
    volumes:
      - type: bind
        source: /DATA/AppData/$AppID/media/img
        target: /usr/share/nginx/html/img
        read_only: true
        bind:
          create_host_path: true
      - type: bind
        source: /DATA/AppData/$AppID/media/gif
        target: /usr/share/nginx/html/gif
        read_only: true
        bind:
          create_host_path: true
    deploy:
      resources:
        limits:
          cpus: "1.00"
          memory: 256M
        reservations:
          cpus: "0.00"
          memory: 64M
    labels:
      icon: https://cdn.jsdelivr.net/gh/HSinghHira/IceStore@main/Apps/opengym/icon.png
    x-casaos:
      id: com.icestore.opengym
      ports:
        - container: "80"
          description:
            en_US: Web UI (published on host as 6115)
      volumes:
        - container: /usr/share/nginx/html/img
          description:
            en_US: Read-only copy of the exercise images the media step downloaded, served alongside the app.
        - container: /usr/share/nginx/html/gif
          description:
            en_US: Read-only copy of the exercise GIFs the media step downloaded, served alongside the app.

networks:
  opengym_network:
    driver: bridge

x-casaos:
  id: com.icestore.opengym
  architectures:
    - amd64
    - arm64
  main: opengym
  author: HSinghHira
  category: Productivity
  developer: DuarteSantos8
  icon: https://cdn.jsdelivr.net/gh/HSinghHira/IceStore@main/Apps/opengym/icon.png
  thumbnail: https://cdn.jsdelivr.net/gh/HSinghHira/IceStore@main/Apps/opengym/screenshot-1.png
  screenshot_link:
    - https://cdn.jsdelivr.net/gh/HSinghHira/IceStore@main/Apps/opengym/screenshot-1.png
    - https://cdn.jsdelivr.net/gh/HSinghHira/IceStore@main/Apps/opengym/screenshot-2.png
    - https://cdn.jsdelivr.net/gh/HSinghHira/IceStore@main/Apps/opengym/screenshot-3.png
    - https://cdn.jsdelivr.net/gh/HSinghHira/IceStore@main/Apps/opengym/screenshot-4.png
    - https://cdn.jsdelivr.net/gh/HSinghHira/IceStore@main/Apps/opengym/screenshot-5.png
    - https://cdn.jsdelivr.net/gh/HSinghHira/IceStore@main/Apps/opengym/screenshot-6.png
  title:
    en_US: openGym
  tagline:
    en_US: Self-hosted gym and body-weight tracker with passkey login
  description:
    en_US: >-
      Visit: [https://icestore.hsinghhira.me/app/opengym/](https://icestore.hsinghhira.me/app/opengym/) for full details


      openGym is a self-hosted gym and body-weight tracker: plan routines, log
      workouts (supersets and cardio included), and track your weight and
      progress over time, all stored on your own server.


      **Features**


      - Weekly routine planner and guided workout logging, with supersets,
        drop-sets, rest-pause and planned warm-ups.

      - Body-weight tracking with a goal line and progress charts, plus
        estimated 1RM and other stats.

      - Passkey (WebAuthn) sign-in — no passwords to manage, with optional
        invite-only signup and an admin dashboard.

      - Push notifications for workout-day reminders, generated on first
        run with no setup required.

      - Everything is stored as plain files under /DATA/AppData/$AppID — no
        separate database container to run or back up.

      - An exercise-media step downloads the exercise photo and GIF library
        (~140 MB) once on first start and shares it with the web service.


      **How to use?**


      1. Open openGym from the Zima OS dashboard.

      2. On first visit, tap "Create profile" and register a passkey for
         your account.

      3. Build your first weekly routine, then start a guided workout from
         it and log your sets as you go.

      4. Add a body-weight entry and set a goal line under the Weight tab
         to start tracking progress.

      5. Optional: turn on the admin dashboard, invite-only signup, or the
         AI Coach later from Settings — none of these need the container
         rebuilt.
  tips:
    before_install:
      en_US: >-
        Visit: [https://icestore.hsinghhira.me/app/opengym/](https://icestore.hsinghhira.me/app/opengym/) for full details
  index: /
  port_map: "6115"
  scheme: http
  is_uncontrolled: false
  version: "1.4.2"
  update_at: "2026-10-25"
  release_notes:
    en_US: |-
      - Moved to IceStore. Port changed from 8435 to 6115.
      - Removed PORT from the opengym-api service; openGym already uses 3000.
      - RP_NAME and SESSION_DAYS moved to the Variables tab on the IceStore website.
      - api and web pinned to 1.4.2 instead of latest.
      - The media helper uses alpine/git 2.54.0, a one-time download step.
      - Services renamed to opengym, opengym-api and opengym-media to match their container names.
  repo: "https://gitlab.com/DuarteSantos8/opengym"
  support: "https://gitlab.com/DuarteSantos8/opengym/-/issues"
  docs: "https://gitlab.com/DuarteSantos8/opengym/-/blob/main/docs/SELF_HOSTING.md"