An open API service indexing awesome lists of open source software.

https://github.com/daemonless/sparkyfitness


https://github.com/daemonless/sparkyfitness

Last synced: 4 days ago
JSON representation

Awesome Lists containing this project

README

          

# SparkyFitness

[![Build Status](https://img.shields.io/github/actions/workflow/status/daemonless/sparkyfitness/build.yaml?style=flat-square&label=Build&color=green)](https://github.com/daemonless/sparkyfitness/actions)
[![Last Commit](https://img.shields.io/github/last-commit/daemonless/sparkyfitness?style=flat-square&label=Last+Commit&color=blue)](https://github.com/daemonless/sparkyfitness/commits)

Self-hosted privacy-first fitness tracker on FreeBSD.

![](.daemonless/screenshots/67a5fb86-cc98-42ce-aa1e-ded7c57647c9.png)

| | |
|---|---|
| **Registry** | `ghcr.io/daemonless/sparkyfitness` |
| **Source** | [https://github.com/CodeWithCJ/SparkyFitness](https://github.com/CodeWithCJ/SparkyFitness) |
| **Website** | [https://github.com/CodeWithCJ/SparkyFitness](https://github.com/CodeWithCJ/SparkyFitness) |

## Version Tags

| Tag | Description | Best For |
| :--- | :--- | :--- |
| `latest` | **Upstream Binary**. Built from official release. | Most users. Matches Linux Docker behavior. |

## Prerequisites

Before deploying, ensure your host environment is ready. See the [Quick Start Guide](https://daemonless.io/guides/quick-start) for host setup instructions.

## Deployment

### Podman Compose

```yaml
services:
sparkyfitness:
image: ghcr.io/daemonless/sparkyfitness:latest
container_name: sparkyfitness
environment:
- PUID=1000
- PGID=1000
- TZ=${TZ}
- NODE_ENV=production
- SPARKY_FITNESS_DB_HOST=127.0.0.1
- SPARKY_FITNESS_DB_PORT=5433
- SPARKY_FITNESS_DB_NAME=${SPARKY_FITNESS_DB_NAME}
- SPARKY_FITNESS_DB_USER=${SPARKY_FITNESS_DB_USER}
- SPARKY_FITNESS_DB_PASSWORD=${SPARKY_FITNESS_DB_PASSWORD}
- SPARKY_FITNESS_APP_DB_USER=${SPARKY_FITNESS_APP_DB_USER}
- SPARKY_FITNESS_APP_DB_PASSWORD=${SPARKY_FITNESS_APP_DB_PASSWORD}
- SPARKY_FITNESS_API_ENCRYPTION_KEY=${SPARKY_FITNESS_API_ENCRYPTION_KEY}
- BETTER_AUTH_SECRET=${BETTER_AUTH_SECRET}
- SPARKY_FITNESS_FRONTEND_URL=${SPARKY_FITNESS_FRONTEND_URL}
- SPARKY_FITNESS_SERVER_HOST=127.0.0.1
- SPARKY_FITNESS_SERVER_PORT=3010
- SPARKY_FITNESS_LOG_LEVEL=ERROR
volumes:
- "/path/to/containers/sparkyfitness/uploads:/uploads"
- "/path/to/containers/sparkyfitness/backups:/backups"
restart: unless-stopped
```

### AppJail Director

**.env**:

```
DIRECTOR_PROJECT=sparkyfitness
PUID=1000
PGID=1000
TZ=${TZ}
NODE_ENV=production
SPARKY_FITNESS_DB_HOST=127.0.0.1
SPARKY_FITNESS_DB_PORT=5433
SPARKY_FITNESS_DB_NAME=${SPARKY_FITNESS_DB_NAME}
SPARKY_FITNESS_DB_USER=${SPARKY_FITNESS_DB_USER}
SPARKY_FITNESS_DB_PASSWORD=${SPARKY_FITNESS_DB_PASSWORD}
SPARKY_FITNESS_APP_DB_USER=${SPARKY_FITNESS_APP_DB_USER}
SPARKY_FITNESS_APP_DB_PASSWORD=${SPARKY_FITNESS_APP_DB_PASSWORD}
SPARKY_FITNESS_API_ENCRYPTION_KEY=${SPARKY_FITNESS_API_ENCRYPTION_KEY}
BETTER_AUTH_SECRET=${BETTER_AUTH_SECRET}
SPARKY_FITNESS_FRONTEND_URL=${SPARKY_FITNESS_FRONTEND_URL}
SPARKY_FITNESS_SERVER_HOST=127.0.0.1
SPARKY_FITNESS_SERVER_PORT=3010
SPARKY_FITNESS_LOG_LEVEL=ERROR
```

**appjail-director.yml**:

```yaml
options:
- virtualnet: ': default'
- nat:
services:
sparkyfitness:
name: sparkyfitness
options:
- container: 'boot args:--pull'
oci:
user: root
environment:
- PUID: !ENV '${PUID}'
- PGID: !ENV '${PGID}'
- TZ: !ENV '${TZ}'
- NODE_ENV: !ENV '${NODE_ENV}'
- SPARKY_FITNESS_DB_HOST: !ENV '${SPARKY_FITNESS_DB_HOST}'
- SPARKY_FITNESS_DB_PORT: !ENV '${SPARKY_FITNESS_DB_PORT}'
- SPARKY_FITNESS_DB_NAME: !ENV '${SPARKY_FITNESS_DB_NAME}'
- SPARKY_FITNESS_DB_USER: !ENV '${SPARKY_FITNESS_DB_USER}'
- SPARKY_FITNESS_DB_PASSWORD: !ENV '${SPARKY_FITNESS_DB_PASSWORD}'
- SPARKY_FITNESS_APP_DB_USER: !ENV '${SPARKY_FITNESS_APP_DB_USER}'
- SPARKY_FITNESS_APP_DB_PASSWORD: !ENV '${SPARKY_FITNESS_APP_DB_PASSWORD}'
- SPARKY_FITNESS_API_ENCRYPTION_KEY: !ENV '${SPARKY_FITNESS_API_ENCRYPTION_KEY}'
- BETTER_AUTH_SECRET: !ENV '${BETTER_AUTH_SECRET}'
- SPARKY_FITNESS_FRONTEND_URL: !ENV '${SPARKY_FITNESS_FRONTEND_URL}'
- SPARKY_FITNESS_SERVER_HOST: !ENV '${SPARKY_FITNESS_SERVER_HOST}'
- SPARKY_FITNESS_SERVER_PORT: !ENV '${SPARKY_FITNESS_SERVER_PORT}'
- SPARKY_FITNESS_LOG_LEVEL: !ENV '${SPARKY_FITNESS_LOG_LEVEL}'
volumes:
- sparkyfitness_uploads: /uploads
- sparkyfitness_backups: /backups
volumes:
sparkyfitness_uploads:
device: '/path/to/containers/sparkyfitness/uploads'
sparkyfitness_backups:
device: '/path/to/containers/sparkyfitness/backups'
```

**Makejail**:

```
ARG tag=latest

OPTION overwrite=force
OPTION from=ghcr.io/daemonless/sparkyfitness:${tag}
```

### Podman CLI

```bash
podman run -d --name sparkyfitness \
-e PUID=1000 \
-e PGID=1000 \
-e TZ=${TZ} \
-e NODE_ENV=production \
-e SPARKY_FITNESS_DB_HOST=127.0.0.1 \
-e SPARKY_FITNESS_DB_PORT=5433 \
-e SPARKY_FITNESS_DB_NAME=${SPARKY_FITNESS_DB_NAME} \
-e SPARKY_FITNESS_DB_USER=${SPARKY_FITNESS_DB_USER} \
-e SPARKY_FITNESS_DB_PASSWORD=${SPARKY_FITNESS_DB_PASSWORD} \
-e SPARKY_FITNESS_APP_DB_USER=${SPARKY_FITNESS_APP_DB_USER} \
-e SPARKY_FITNESS_APP_DB_PASSWORD=${SPARKY_FITNESS_APP_DB_PASSWORD} \
-e SPARKY_FITNESS_API_ENCRYPTION_KEY=${SPARKY_FITNESS_API_ENCRYPTION_KEY} \
-e BETTER_AUTH_SECRET=${BETTER_AUTH_SECRET} \
-e SPARKY_FITNESS_FRONTEND_URL=${SPARKY_FITNESS_FRONTEND_URL} \
-e SPARKY_FITNESS_SERVER_HOST=127.0.0.1 \
-e SPARKY_FITNESS_SERVER_PORT=3010 \
-e SPARKY_FITNESS_LOG_LEVEL=ERROR \
-v /path/to/containers/sparkyfitness/uploads:/uploads \
-v /path/to/containers/sparkyfitness/backups:/backups \
ghcr.io/daemonless/sparkyfitness:latest
```

### Ansible

```yaml
- name: Deploy sparkyfitness
containers.podman.podman_container:
name: sparkyfitness
image: ghcr.io/daemonless/sparkyfitness:latest
state: started
restart_policy: always
env:
PUID: "1000"
PGID: "1000"
TZ: "${TZ}"
NODE_ENV: "production"
SPARKY_FITNESS_DB_HOST: "127.0.0.1"
SPARKY_FITNESS_DB_PORT: "5433"
SPARKY_FITNESS_DB_NAME: "${SPARKY_FITNESS_DB_NAME}"
SPARKY_FITNESS_DB_USER: "${SPARKY_FITNESS_DB_USER}"
SPARKY_FITNESS_DB_PASSWORD: "${SPARKY_FITNESS_DB_PASSWORD}"
SPARKY_FITNESS_APP_DB_USER: "${SPARKY_FITNESS_APP_DB_USER}"
SPARKY_FITNESS_APP_DB_PASSWORD: "${SPARKY_FITNESS_APP_DB_PASSWORD}"
SPARKY_FITNESS_API_ENCRYPTION_KEY: "${SPARKY_FITNESS_API_ENCRYPTION_KEY}"
BETTER_AUTH_SECRET: "${BETTER_AUTH_SECRET}"
SPARKY_FITNESS_FRONTEND_URL: "${SPARKY_FITNESS_FRONTEND_URL}"
SPARKY_FITNESS_SERVER_HOST: "127.0.0.1"
SPARKY_FITNESS_SERVER_PORT: "3010"
SPARKY_FITNESS_LOG_LEVEL: "ERROR"
volumes:
- "/path/to/containers/sparkyfitness/uploads:/uploads"
- "/path/to/containers/sparkyfitness/backups:/backups"
```

## 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 |

**Architectures:** amd64
**User:** `bsd` (UID/GID via PUID/PGID, defaults to 1000:1000)
**Base:** FreeBSD 15.0