Ctrl K
ComunidadGuías…

README.md

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
<!--
THIS FILE IS AUTOGENERATED - DO NOT EDIT MANUALLY
Source: dbuild templates
-->

# 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)
[![OCI Pulls](https://img.shields.io/docker/pulls/daemonless/sparkyfitness?style=flat-square&label=OCI+Pulls&color=blue)](https://hub.docker.com/r/daemonless/sparkyfitness)

Self-hosted privacy-first fitness tracker on FreeBSD.

| | |
|---|---|
| **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 — recommended. |

## Parts

| Service | Image | Role | |
|---|---|---|---|
| **sparkyfitness** | `ghcr.io/daemonless/sparkyfitness:${SPARKYFITNESS_TAG:-latest}` |  | [docs](https://github.com/daemonless/sparkyfitness) |
| **sparkyfitness-db** | `ghcr.io/daemonless/postgres:18` |  | [docs](https://github.com/daemonless/postgres) |

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

**1.** Save as `.env` and fill in what is empty:

```env { data-zip-bundle="sparkyfitness-podman" data-zip-filename=".env" }
# SparkyFitness for FreeBSD (Daemonless)
# Copy to .env and edit.

# Timezone (TZ identifier)
# TZ=UTC

# Where data lives on the host
UPLOADS_LOCATION=/containers/sparkyfitness/uploads
BACKUPS_LOCATION=/containers/sparkyfitness/backups
DB_DATA_LOCATION=/containers/sparkyfitness/postgres

# PostgreSQL superuser + database (provisioned by the sidecar)
SPARKY_FITNESS_DB_NAME=sparkyfitness
SPARKY_FITNESS_DB_USER=sparky
# Change this to a random password! A-Za-z0-9 only.
SPARKY_FITNESS_DB_PASSWORD=sparky

# Limited app role the backend creates during migrations
SPARKY_FITNESS_APP_DB_USER=sparky_app
SPARKY_FITNESS_APP_DB_PASSWORD=sparky_app

# Secrets: no defaults on purpose -- these become the catalog's install
# defaults, and a shipped value would be shared by every install. Generate
# your own, e.g. `openssl rand -hex 32` for each.
SPARKY_FITNESS_API_ENCRYPTION_KEY=
BETTER_AUTH_SECRET=

# Public URL the browser uses to reach the app, e.g. http://myhost:3004.
# No default on purpose: Better Auth compares this against the request origin
# and rejects the sign-up POST when it does not match, so a shipped default is
# wrong for everyone who does not browse from the server itself.
SPARKY_FITNESS_FRONTEND_URL=
```

**2.** Save as `compose.yaml`:

```yaml { data-zip-bundle="sparkyfitness-podman" data-zip-filename="compose.yaml" }
name: sparkyfitness

services:
  sparkyfitness:
    # Tag in a ${VAR} so the catalog exposes it as an image_tag variable and the
    # install wizard can offer this repo's published versions. The database is
    # pinned deliberately: retagging it would be a destructive migration.
    image: ghcr.io/daemonless/sparkyfitness:${SPARKYFITNESS_TAG:-latest}
    container_name: sparkyfitness
    restart: unless-stopped
    network_mode: host
    depends_on:
      - sparkyfitness-db

    environment:
      - PUID=1000
      - PGID=1000
      - TZ=${TZ:-UTC}
      - NODE_ENV=production
      - SPARKY_FITNESS_DB_HOST=${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:
      - ${UPLOADS_LOCATION}:/app/server/uploads
      - ${BACKUPS_LOCATION}:/app/server/backup

  sparkyfitness-db:
    image: ghcr.io/daemonless/postgres:18
    container_name: sparkyfitness-db
    restart: unless-stopped
    network_mode: host

    annotations:
      org.freebsd.jail.allow.sysvipc: "true"

    # Generic daemonless PostgreSQL 18 image. Only the superuser role + database
    # are provisioned here; the SparkyFitness backend creates its own limited
    # app role (SPARKY_FITNESS_APP_DB_USER) during migrations.
    environment:
      - POSTGRES_DB=${SPARKY_FITNESS_DB_NAME}
      - POSTGRES_USER=${SPARKY_FITNESS_DB_USER}
      - POSTGRES_PASSWORD=${SPARKY_FITNESS_DB_PASSWORD}
      # Distinct port (NOT 5432) so this can run alongside another host-networked Postgres
      # (e.g. Immich on 5432) without colliding. ⚠ Requires the daemonless/postgres image to
      # honor POSTGRES_PORT — if it doesn't, it falls back to 5432 and WILL collide. Two
      # host-net Postgres must never share a port.
      - POSTGRES_PORT=5433

    volumes:
      - ${DB_DATA_LOCATION}:/var/lib/postgresql/data
```

Then run `podman-compose up -d`.

### AppJail Director
**.env**:

```
# .env

DIRECTOR_PROJECT=sparkyfitness
PUID=1000
PGID=1000
TZ=UTC
NODE_ENV=production
SPARKY_FITNESS_DB_HOST=127.0.0.1
SPARKY_FITNESS_DB_PORT=5433
SPARKY_FITNESS_DB_NAME=sparkyfitness
SPARKY_FITNESS_DB_USER=sparky
SPARKY_FITNESS_DB_PASSWORD=sparky
SPARKY_FITNESS_APP_DB_USER=sparky_app
SPARKY_FITNESS_APP_DB_PASSWORD=sparky_app
SPARKY_FITNESS_API_ENCRYPTION_KEY=<SPARKY_FITNESS_API_ENCRYPTION_KEY>
BETTER_AUTH_SECRET=<BETTER_AUTH_SECRET>
SPARKY_FITNESS_FRONTEND_URL=
SPARKY_FITNESS_SERVER_HOST=127.0.0.1
SPARKY_FITNESS_SERVER_PORT=3010
SPARKY_FITNESS_LOG_LEVEL=ERROR
UPLOADS_LOCATION=/containers/sparkyfitness/uploads
BACKUPS_LOCATION=/containers/sparkyfitness/backups
DB_DATA_LOCATION=/containers/sparkyfitness/postgres
```

**appjail-director.yml**:

```yaml
# appjail-director.yml

options:
  - alias:
  - ip4_inherit:
services:
  sparkyfitness:
    name: sparkyfitness
    options:
      - container: '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}'
        - UPLOADS_LOCATION: !ENV '${UPLOADS_LOCATION}'
        - BACKUPS_LOCATION: !ENV '${BACKUPS_LOCATION}'
        - DB_DATA_LOCATION: !ENV '${DB_DATA_LOCATION}'
    volumes:
      - sparkyfitness_uploads: /app/server/uploads
      - sparkyfitness_backup: /app/server/backup
  sparkyfitness-db:
    name: sparkyfitness_db
    options:
      - from: ghcr.io/daemonless/postgres:18
      - template: !ENV '${PWD}/postgres-template.conf'
    oci:
      environment:
        - POSTGRES_DB: !ENV '${SPARKY_FITNESS_DB_NAME}'
        - POSTGRES_USER: !ENV '${SPARKY_FITNESS_DB_USER}'
        - POSTGRES_PASSWORD: !ENV '${SPARKY_FITNESS_DB_PASSWORD}'
        - POSTGRES_PORT: "5433"
    volumes:
      - db_data: /var/lib/postgresql/data
volumes:
  sparkyfitness_uploads:
    device: '/containers/sparkyfitness/uploads'
  sparkyfitness_backup:
    device: '/containers/sparkyfitness/backup'
  db_data:
    device: !ENV '${DB_DATA_LOCATION}'
```

**Makejail**:

```
# Makejail

ARG tag=latest

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

Save the files above, then run `appjail-director up`.



## Parameters

### Environment Variables

| Variable | Default | Description |
|----------|---------|-------------|
| `PUID` | `1000` | User ID for the application process |
| `PGID` | `1000` | Group ID for the application process |
| `TZ` | `UTC` | Timezone for the container |
| `NODE_ENV` | `production` | Node runtime mode; leave as 'production' |
| `SPARKY_FITNESS_DB_HOST` | `127.0.0.1` | Where the backend finds PostgreSQL (fjord sets this; 127.0.0.1 on 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` | `sparkyfitness` | PostgreSQL database name |
| `SPARKY_FITNESS_DB_USER` | `sparky` | PostgreSQL superuser |
| `SPARKY_FITNESS_DB_PASSWORD` | `sparky` | PostgreSQL password |
| `SPARKY_FITNESS_APP_DB_USER` | `sparky_app` | Limited app DB role the backend creates during migrations |
| `SPARKY_FITNESS_APP_DB_PASSWORD` | `sparky_app` | Password for the limited app DB role |
| `SPARKY_FITNESS_API_ENCRYPTION_KEY` | `<SPARKY_FITNESS_API_ENCRYPTION_KEY>` | 64-char hex encryption key |
| `BETTER_AUTH_SECRET` | `<BETTER_AUTH_SECRET>` | Auth session signing secret |
| `SPARKY_FITNESS_FRONTEND_URL` | `` | URL you will open this app at, e.g. http://myhost:3004 (sign-up fails if it does not match) |
| `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) |
| `UPLOADS_LOCATION` | `/containers/sparkyfitness/uploads` | Path to store user uploads (profile pictures, exercise images) |
| `BACKUPS_LOCATION` | `/containers/sparkyfitness/backups` | Path to store server backups |
| `DB_DATA_LOCATION` | `/containers/sparkyfitness/postgres` | Path to store PostgreSQL data files |

### Volumes

| Path | Description |
|------|-------------|
| `/app/server/uploads` | User-uploaded files (profile pictures, exercise images) |
| `/app/server/backup` | Server backup data |

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

---

Need help? Join our [Discord](https://discord.gg/Kb9tkhecZT) community.