Deploy wger

Workout, nutrition and body weight tracker with a REST API

Deploy wger

Just deployed

Just deployed

Just deployed

/data

/var/lib/postgresql/data

Just deployed

wger-media

Bucket

Just deployed

Deploy and Host wger on Railway

Self-host wger to keep your training log, nutrition diary and body measurements on infrastructure you control. wger is an AGPL fitness manager for lifters tracking their progression, coaches running a small gym, and anyone who would rather not hand a year of body-weight data to an app that might shut down. It ships a workout planner with 800+ exercises, a nutrition diary backed by Open Food Facts, measurement charts, gym management, a REST API, and official Android and iOS apps.

Deploy wger on Railway and this template builds the production shape upstream documents, not a single container. The wger service is the only public one: Django under gunicorn, with Caddy in front serving static files and routing media. celery-worker runs the background jobs and celery-beat schedules them. Postgres holds every workout, meal and measurement, Redis is Django's cache and the Celery broker, and the wger-media bucket holds photos, exercise images and videos so the web and worker tiers share one store.

Diagram of the wger, Celery and datastore services on Railway

Getting Started with wger on Railway

Set WGER_ADMIN_PASSWORD before you deploy — it is the admin account's password, replacing the adminadmin default wger's bootstrap fixture creates. The first boot loads fixtures, migrates and collects static files, so give it a couple of minutes.

Open the public URL and sign in at /en/user/login as admin. To confirm the deployment end to end: open Training → Routines, create a routine, add a training day, then use the exercise search to add movements with sets, reps and weight. The search hitting the database proves the fixtures loaded; saving proves Postgres is writable. Add a body-weight entry from the dashboard's Weight card — after two or three the chart, moving average and trend line render. Then upload a photo under Body weight → Gallery: that round-trips through the bucket, so if it renders, media storage is wired correctly.

Self-registration is closed by default. Set ALLOW_REGISTRATION to True on the wger service to let visitors create accounts, or add members yourself from the gym-management screens under the Administrator menu, which is the safer default on a public URL.

wger dashboard showing a routine and a body weight trend chart wger routine detail listing four exercises with sets and weights wger body weight chart with trend line and the entry table

About Hosting wger

wger is a Django application developed in the open since 2012. It covers the whole loop a lifter or a small gym needs: plan a routine, log what you lifted and ate, weigh in, watch the numbers move. Self-hosting wins when the data matters more than the convenience — your history stays in a database you can dump.

Key features:

  • Routine builder with progression rules, supersets, rest days and per-iteration sets
  • 800+ exercises with muscle diagrams, images and videos from a public instance
  • Nutrition diary with a barcode scanner and Open Food Facts lookup
  • Body weight and custom measurements with trend lines
  • Gym management: members, trainers, per-member configuration
  • REST API with JWT auth, used by the official mobile apps

The Railway topology separates the tiers so one never blocks the other. Django serves requests; Celery does the long work — the catalogue sync alone pulls hundreds of images — so it never stalls a page load. Media goes to object storage rather than a disk, which is what lets the web and worker services write to the same place.

Why Deploy wger on Railway

Railway removes the parts of self-hosting that have nothing to do with fitness tracking:

  • Postgres, Redis and object storage provisioned and wired up for you
  • HTTPS and a public domain from the first deploy, no reverse proxy to configure
  • Worker and scheduler are their own services, so you scale them separately
  • Private networking keeps the database, cache and workers off the internet
  • Rolling deploys and per-service logs, no server to patch

Common Use Cases

  • Personal training log — years of workouts, weigh-ins and progress photos, with the mobile app syncing to your own domain.
  • Small gym or PT studio — members, trainers and per-member routines, with accounts created by staff.
  • Coaching with data you own — pull the REST API into your dashboards, or read raw tables out of Postgres.
  • Nutrition tracking with no subscription — ingredient database and barcode scanner, no monthly cost, no ads.

Dependencies for wger

  • wgerdocker.io/wger/server:2.7, built from gridalpha/wger-railway. Django + gunicorn behind Caddy, which serves static files and signs reads from the media bucket.
  • celery-worker — same image, running celery worker: catalogue and ingredient syncs, image downloads, cache warming.
  • celery-beat — same image, running celery beat. Enqueues the recurring jobs; without it no sync ever fires.
  • Postgres 18 — users, routines, workout logs, meals and measurements.
  • Redis 8.2 — Django's cache plus the Celery broker and result backend.
  • wger-media bucket — gallery photos, exercise images and videos.

Environment Variables Reference

VariablePurpose
WGER_ADMIN_PASSWORDPassword for admin, replacing the shipped default
SECRET_KEYDjango signing key; changing it invalidates every session
ALLOW_REGISTRATIONFalse by default; True opens public sign-up
SYNC_EXERCISES_CELERYWeekly catalogue sync from WGER_INSTANCE
SYNC_INGREDIENTS_CELERYOff by default; the bulk dump is 408 MB compressed
JWT_PRIVATE_KEY / JWT_PUBLIC_KEYMobile-app token signing pair, generated at first boot

Deployment Dependencies

Hardware Requirements for Self-Hosting wger

ResourceMinimumRecommended
CPU1 vCPU across all services2 vCPU
RAM1 GB total2 GB (web 768 MB, worker 512 MB, beat 256 MB)
Storage1 GB Postgres5 GB Postgres, plus object storage that grows with uploads
RuntimePostgres 13+, Redis 6+Postgres 18, Redis 8

Enabling the bulk ingredient sync changes this entirely — the compressed dump is 408 MB and expands to gigabytes of rows, so raise the database first.

Self-Hosting wger with Docker

Upstream publishes a Compose stack. Clone and start it:

git clone https://github.com/wger-project/docker.git wger
cd wger
docker compose up -d

Edit config/prod.env before the first start: SECRET_KEY, SITE_URL and a fresh JWT keypair from ./manage.py generate-jwt-keys. To keep uploads in object storage rather than a local volume, set the S3 block in the same file:

USE_S3_MEDIA_FILES=True
AWS_ACCESS_KEY_ID=your-key
AWS_SECRET_ACCESS_KEY=your-secret
AWS_STORAGE_BUCKET_NAME=your-bucket
AWS_S3_REGION_NAME=auto
AWS_S3_ENDPOINT_URL=https://your-endpoint
AWS_S3_DOMAIN=your-endpoint-host

wger builds unsigned media URLs, so a bucket configured this way must be browser-readable — public-read, or something in front that signs the reads, which is what this Railway template does for you.

Is wger Free to Self-Host?

wger is free and open source under the AGPL-3.0: no paid tier, no licence key, no vendor to pay. On Railway you pay only for the compute, database and object storage the deployment uses — small for a personal instance, scaling with members and uploads.

FAQ

What is wger? An open-source workout, nutrition and body-weight tracker you run yourself: routine planning, workout logging, a nutrition diary with barcode scanning, body measurements and gym member management, plus a REST API and official mobile apps.

What does this Railway template deploy? Six pieces: the wger web app, a Celery worker, a Celery scheduler, Postgres, Redis and an object-storage bucket. Only the web service gets a public URL; the rest stay private.

Why does the template include Redis and a separate worker service? Catalogue syncs, ingredient fetches and image downloads are slow background jobs. Redis carries the queue, the worker runs the jobs, the scheduler enqueues the recurring ones. Redis is also Django's cache, which the exercise API leans on.

Why is uploaded media stored in a bucket instead of a disk? Both the web service and the worker write media — you upload gallery photos, the worker downloads exercise images. A shared object store lets both write to one place, and uploads survive every redeploy.

How do I connect the wger mobile app to my self-hosted server? In the app's server settings enter your deployment's URL instead of wger.de, then sign in. Token auth uses the RS256 keypair generated on first boot, so nothing else is needed.

How do I get the full exercise database with images? The catalogue sync runs weekly once the worker and scheduler are up, pulling from the instance in WGER_INSTANCE. To fill it now, run manage.py sync-exercises then download-exercise-images on the wger service.


Template Content

More templates in this category

View Template
Rocky Linux
Hosted Rocky Linux 9 workspace with SSH and persistent storage. 🚀

codestorm
47
View Template
Foundry Virtual Tabletop
A Self-Hosted & Modern Roleplaying Platform

Lucas
71
View Template
Letta Code Remote
Run a Letta Code agent 24/7. No inbound ports, just deploy.

Letta
50