Hass.io Add-ons: Wger
I maintain this and other Home Assistant add-ons in my free time: keeping up with upstream changes, HA changes, and testing on real hardware takes a lot of time (and some money). I use around 5-10 of my >110 addons so regularly I install test machines (and purchase some test services such as vpn) that I don't use myself to troubleshoot and improve the addons
If this add-on saves you time or makes your setup easier, I would be very grateful for your support!
Addon informations
Thanks to everyone having starred my repo! To star it click on the image below, then it will be on top right. Thanks!
About
wger Workout Manager is a free, open source web application that helps you manage your personal workouts, weight and diet plans and can also be used as a simple gym management utility. It offers a REST API as well, for easy integration with other projects and tools.
Configuration
Use the add-on env_vars option to pass extra environment variables (uppercase or lowercase names). See https://github.com/alexbelgium/hassio-addons/wiki/Add-Environment-variables-to-your-Addon-2 for details.
- Start the addon. Wait a while and check the log for any errors. Initial start can take up to 15 minutes !
- Open yourdomain.com:9927 (default host mapping for the add-on port
80/tcp, as indicated by thewebuihint). - Default
- Username:
admin - Password:
adminadmin
- Username:
Options can be configured through two ways :
- Addon options
"CONFIG_LOCATION": location of the config.yaml # Sets the location of the config.yaml (see below)
- Config.yaml (advanced usage)
Additional variables can be set as ENV variables by adding them in the config.yaml in the location defined in your addon options according to this guide : https://github.com/alexbelgium/hassio-addons/wiki/Addons-feature:-add-env-variables
The complete list of ENV variables can be seen here : not available
Mobile app offline sync (PowerSync)
The official wger mobile app (2.0.3 and newer) syncs offline through a
PowerSync service, which it expects to find at
<SITE_URL>/ps/. The add-on ships that service and can run it alongside wger, off by
default. Turn it on with the POWERSYNC_ENABLED option.
Switching to PostgreSQL, and switching back
PowerSync cannot replicate from SQLite, which is what this add-on uses by default, and wger's integration with it is built around PostgreSQL. Enabling PowerSync therefore means pointing wger at a PostgreSQL database — and the add-on moves your data across for you.
The first time you start it with PowerSync enabled, the add-on copies the contents of its SQLite database into the PostgreSQL one. Two things are guaranteed about that:
- The SQLite database is never written to. It is copied first, and everything is read
from the copy, so the original is left byte for byte as it was. Removing
PS_DATABASE_URIagain puts wger straight back onto it — remove it from everywhere you set it, both theenv_varsoption and theCONFIG_LOCATIONfile, since either one takes precedence over the SQLite default. - An import only ever happens into a PostgreSQL database with no user accounts. That is wger's own test for a database that was never set up, since its bootstrap creates the admin user as the very last step. So once your data is in PostgreSQL, turning PowerSync off and on again later imports nothing and leaves it alone. The test is that one and no more: a PostgreSQL database holding rows but no users at all — a half-built one, say — still counts as never set up and would be imported into.
What the import does not do is keep the two databases in step. After the switch, PostgreSQL is the live database and the SQLite file is a frozen copy of the moment you switched. If you go back to SQLite, anything you did in the meantime stays in PostgreSQL, and vice versa. You will also be logged out of the web interface once, because sessions are deliberately not carried over.
If the import cannot finish — the database is unreachable, or the copy or the load fails — the add-on refuses to start wger at all, with the reason in the log. That is deliberate: if it carried on, wger would set the empty PostgreSQL database up as a brand new instance, complete with its own admin user, and from then on the add-on would see a database that already holds data and would never import your SQLite rows again. Stopping instead keeps them importable.
So if the add-on will not start and the log says the import did not complete, fix the
cause — most often the database connection or the privileges above — and start it again.
To abandon the move entirely, remove PS_DATABASE_URI and the add-on goes back to the
SQLite database as if nothing had happened.
What you need
-
A PostgreSQL server the add-on can reach — the Postgres 17 add-on from this repository works. PowerSync reads the logical write-ahead log, so the server needs
wal_level = logical, which is not the default. With the Postgres add-on, addwal_level = logicalto the file its
CONFIG_LOCATIONoption points at, then restart it. The add-on checks this on startup and tells you in the log if it is stillreplica. -
A database and a role for wger. PowerSync's bucket storage lives in a dedicated role and schema inside that same database, and the add-on creates them on every startup with upstream's idempotent
manage.py setup-powersync-storage. The wger role therefore needsCREATEROLE, andCREATEon the database, for as long as PowerSync is enabled — not just for the first start:ALTER ROLE wger CREATEROLE; GRANT CREATE ON DATABASE wger TO wger;The same role — the one in
PS_DATABASE_URI, notpowersync_storage— also needsREPLICATION, which is how PowerSync reads the logical WAL:ALTER ROLE wger REPLICATION;On PostgreSQL 16 and later — which includes the Postgres 17 add-on — that is still not quite enough. Creating the schema runs
CREATE SCHEMA ... AUTHORIZATION powersync_storage, and the documentation requires that you "must be able to SET ROLE to that role". ACREATEROLEuser is only givenADMIN OPTIONon the roles it creates, notSET, becausecreaterole_self_grantdefaults to empty. Grant it for the roles wger is about to create:ALTER ROLE wger SET createrole_self_grant = 'set, inherit';If the storage role already exists from an earlier attempt, grant it directly instead — this one has to be run by a role allowed to hand out that membership, normally the superuser:
GRANT powersync_storage TO wger WITH ADMIN OPTION, SET TRUE;The PostgreSQL superuser has all of this already, which is why pointing at it works and is the quickest way to get going, but a role with just these grants is the better choice.
-
The URL your phone uses to reach wger, in
SITE_URL. The app is handed<SITE_URL>/ps/as its sync endpoint, so a LAN-only address will not work from outside your network.
Add-on configuration
Set POWERSYNC_ENABLED to true and add the following through the add-on's env_vars
option (the CONFIG_LOCATION config.yaml file documented above works for these too):
env_vars:
- name: PS_DATABASE_URI
value: postgres://wger:yourpassword@db21ed7f-postgres-latest:5432/wger
- name: PS_STORAGE_PG_URI
value: postgres://powersync_storage:anotherpassword@db21ed7f-postgres-latest:5432/wger
- name: SITE_URL
value: https://wger.yourdomain.com
PS_DATABASE_URIis wger's own database. Setting it takes precedence over theDJANGO_DB_*variables, so this single value both moves wger onto PostgreSQL and tells PowerSync what to replicate: in the shipped configuration they read the same URI, so they cannot be pointed at different databases by accident.PS_STORAGE_PG_URIis PowerSync's bucket storage. Point it at the same database with a different role name and a password of your choosing; that is the role the add-on creates. It must be set, it has no useful default.SITE_URLmust be an absolutehttp://orhttps://URL with no path.
db21ed7f-postgres-latest is the internal hostname of this repository's Postgres 17
add-on, so it works without exposing port 5432. A LAN IP also works when PostgreSQL is
running on an external server.
Use passwords made only of letters, digits and -._~. Characters such as @, :,
/, ?, # or % break the URI, and percent-encoding them is no way out: wger
decodes %40 back to @, but PowerSync passes it to PostgreSQL unchanged, so its
connections fail to authenticate.
Set these through the env_vars option rather than the CONFIG_LOCATION file if the
password contains a $ or a backtick. Both routes work, but the config.yaml route
writes the value unquoted into the add-on's environment file, where the shell expands
those characters and silently truncates the password — wger would get the mangled value
too, not just PowerSync.
The two URIs contain passwords, and the add-on prints every variable it loads to its log at startup. The shared startup code masks values whose variable name looks like a secret, and these two names do not, so both PostgreSQL passwords appear in the add-on log in full — including when the value comes from
!secret. Treat the add-on log as sensitive, and prefer a dedicated wger role with a password you are willing to see there over reusing credentials from elsewhere.
The add-on generates the RS256 JWT keypair the app and PowerSync need on first start and
keeps it at /data/powersync/jwt.env, so app sessions survive restarts. If you would
rather manage it yourself, generate one with
python3 manage.py generate-jwt-keys and pass both JWT_PUBLIC_KEY and
JWT_PRIVATE_KEY as env vars — both halves or neither.
Your PostgreSQL server also has to be a version PowerSync supports, and the sync rules
shipped with the add-on come from the upstream wger project. If replication fails for a
reason other than wal_level, the add-on log carries PowerSync's own error.
Checking it works
With everything in place the add-on log reports the PowerSync URL, and
<SITE_URL>/ps/probes/liveness answers instead of logging Not Found: /ps/probes/liveness.
If a variable is missing or invalid, the log says exactly which one and /ps/ stays
unrouted. wger itself still starts, unless PS_DATABASE_URI points at Postgres while
there is SQLite data waiting to be imported: then it refuses to start, so the empty
Postgres database is not set up as a new instance. Fix the variable, or remove
PS_DATABASE_URI to go back to SQLite.
The wal_level check and the PowerSync storage setup only run once wger is up, after
/ps/ is already routed. If either fails, the log says so, PowerSync is not started,
and /ps/ answers 502 Bad Gateway until you fix the cause and restart the add-on.
If you put your own reverse proxy in front of the add-on, nothing extra is needed: the
/ps/ route forwards an incoming X-Forwarded-Proto unchanged and only falls back to
its own scheme when there is none, so PowerSync sees the external scheme your proxy
terminated.
Licence
The bundled PowerSync service is published by Journey Mobile, Inc. under the
Functional Source License 1.1 with an Apache 2.0 future grant
(FSL-1.1-ALv2). Its licence text ships in the image at /opt/powersync/LICENSE. The
service is pinned to a specific upstream release rather than tracking latest.
Installation
The installation of this add-on is pretty straightforward and not different in comparison to installing any other Hass.io add-on.
- Add my add-ons repository to your home assistant instance (in supervisor addons store at top right, or click button below if you have configured my HA)
- Install this add-on.
- Click the
Savebutton to store your configuration. - Start the add-on.
- Check the logs of the add-on to see if everything went well.
- Carefully configure the add-on to your preferences, see the official documentation for for that.
Support
If you have in issue with your installation, please be sure to checkout github.
