SparkyFitness
| Description / name | Input element |
|---|---|
| Container Registry | |
| Container Configuration Root Path | |
| Timezone | |
| User ID | |
| Group ID | |
| SparkyFitness /uploads Path | |
| SparkyFitness /backups Path |
Self-hosted privacy-first fitness tracker on FreeBSD.
| Registry | ghcr.io/daemonless/sparkyfitness |
| Daemonless | daemonless/sparkyfitness |
| Source | CodeWithCJ/SparkyFitness |
| Website | github.com/CodeWithCJ/SparkyFitness |
Version Tags
| Tag | Description | Best For |
|---|---|---|
latest |
Upstream Binary. Built from official release. | Most users — recommended. |
Before deploying, ensure your host environment is ready. See the Quick Start Guide for host setup instructions, including the security model for host vs. container privileges.
Deployment
Save as compose.yaml, then run podman-compose up -d.
Save as run.sh, then run sh run.sh.
Save as sparkyfitness-deploy.yaml, then run ansible-playbook sparkyfitness-deploy.yaml.
Save the files above, then run appjail-director up.
Save the files above, then run sh run.sh.
Experimental
Bastille's OCI support is experimental. It requires buildah and shares the host network stack (inherit). Mount volumes with --volume HOST JAIL; without it, image-declared volumes are stored under ${bastille_volumesdir}/${jail}.
Save as bastille-compose.yml, then run bastille up.
Interactive Configuration
Parameters
Environment Variables
| Variable | Default | Description |
|---|---|---|
PUID |
1000 |
User ID for the application process |
PGID |
1000 |
Group ID for the application process |
TZ |
${TZ} |
Timezone for the container |
NODE_ENV |
production |
Node runtime mode; leave as 'production' |
SPARKY_FITNESS_DB_HOST |
127.0.0.1 |
PostgreSQL host the backend connects to; leave as 127.0.0.1 (host networking) |
SPARKY_FITNESS_DB_PORT |
5433 |
PostgreSQL port; MUST match the sidecar's POSTGRES_PORT. Default 5433 (NOT 5432) so this can coexist with another host-networked Postgres (e.g. Immich on 5432) on the same host. ⚠ With network_mode: host, two Postgres on the same port silently collide — keep each service on a distinct port. NOTE: this only takes effect if the daemonless/postgres image honors POSTGRES_PORT (see project README / upstream fix); otherwise the sidecar falls back to 5432. |
SPARKY_FITNESS_DB_NAME |
${SPARKY_FITNESS_DB_NAME} |
PostgreSQL database name |
SPARKY_FITNESS_DB_USER |
${SPARKY_FITNESS_DB_USER} |
PostgreSQL superuser |
SPARKY_FITNESS_DB_PASSWORD |
${SPARKY_FITNESS_DB_PASSWORD} |
PostgreSQL password (from secrets.env) |
SPARKY_FITNESS_APP_DB_USER |
${SPARKY_FITNESS_APP_DB_USER} |
Limited app DB role the backend creates during migrations (from secrets) |
SPARKY_FITNESS_APP_DB_PASSWORD |
${SPARKY_FITNESS_APP_DB_PASSWORD} |
Password for the limited app DB role (from secrets) |
SPARKY_FITNESS_API_ENCRYPTION_KEY |
${SPARKY_FITNESS_API_ENCRYPTION_KEY} |
64-char hex encryption key (from secrets.env) |
BETTER_AUTH_SECRET |
${BETTER_AUTH_SECRET} |
Auth session signing secret (from secrets.env) |
SPARKY_FITNESS_FRONTEND_URL |
${SPARKY_FITNESS_FRONTEND_URL} |
Public URL of the frontend for CORS |
SPARKY_FITNESS_SERVER_HOST |
127.0.0.1 |
Internal bind address for the node backend; leave as 127.0.0.1 (nginx proxies to it) |
SPARKY_FITNESS_SERVER_PORT |
3010 |
Internal node backend port; leave as default |
SPARKY_FITNESS_LOG_LEVEL |
ERROR |
Backend log verbosity (e.g. ERROR, INFO, DEBUG) |
Volumes
| Path | Description |
|---|---|
/uploads |
User-uploaded files (profile pictures, exercise images) |
/backups |
Server backup data |
Implementation Details
- Architectures: amd64
- User:
bsd(UID/GID set via PUID/PGID). Defaults to1000:1000. - Base: Built on
ghcr.io/daemonless/base(FreeBSD 15.1).
Need help? Join our Discord community.