SparkyFitness is a self-hosted, privacy-first alternative to MyFitnessPal that runs inside a Proxmox container on Ubuntu Server. It gives you local control over nutrition logs, exercise data, body measurements, goals, reports, and optional AI-powered food logging — all without depending on a hosted fitness platform.
This guide walks through installing SparkyFitness in an Ubuntu LXC container on Proxmox using Docker Compose. We’ll keep Proxmox as the container host, Ubuntu as the application environment, Docker as the runtime, and SparkyFitness as a three-service stack with PostgreSQL, backend, and frontend containers.

Quick Answer: The cleanest way to install SparkyFitness on Proxmox is to create an Ubuntu 24.04 LXC container, enable nesting for Docker, install Docker Engine inside the container, download the official SparkyFitness production Docker Compose file and environment file, edit the required secrets and URLs, then start the stack with docker compose up -d. For a small homelab deployment, 2 CPU cores, 2 GB RAM, and 16–32 GB storage is a practical starting point.
What You’re Installing
SparkyFitness isn’t a single binary. The official project describes it as a self-hosted fitness tracking platform with a backend server, a web frontend, and native mobile app support. The current Docker Compose deployment runs multiple services: PostgreSQL for persistence, a Node.js backend, and a React frontend served through Nginx. You can verify the project details from the official GitHub repository.
The app is useful if you want fitness tracking without sending every meal, weight entry, progress photo, or body metric to a third-party SaaS platform. It supports common fitness-tracking workflows like food logging, exercise tracking, water intake, body measurements, goals, reports, multiple users, and optional integrations.
Proxmox LXC or VM: Which Should You Use?
You can run SparkyFitness in either a full VM or an LXC container. For a lightweight homelab service, an Ubuntu LXC container is attractive because it boots quickly and uses fewer resources than a VM. Proxmox containers are based on LXC, and Proxmox manages them through its own container tooling, as documented in the Proxmox Linux Container documentation.
The tradeoff is Docker inside LXC. It works well for many homelab setups, but it requires nesting support and slightly relaxes the isolation model compared with a plain unprivileged container. If this instance will be exposed to the public internet, used by several people, or treated as sensitive infrastructure, a small Ubuntu VM is still the more conservative choice.
| Option | Best For | Pros | Watch Out For |
|---|---|---|---|
| Ubuntu LXC | Homelab, private LAN, lightweight deployment | Low RAM use, fast boot, easy Proxmox snapshots | Docker needs nesting; isolation isn’t as clean as a VM |
| Ubuntu VM | Public-facing or more security-sensitive deployment | Cleaner Docker support, stronger isolation boundary | Uses more RAM and disk than LXC |
For this tutorial, we’ll use an Ubuntu Server LXC container because the target is a Proxmox container deployment. If you already run Docker workloads in LXC, this will feel familiar. If you’re still deciding how to structure Docker on Proxmox, this related guide on Proxmox Docker workloads gives useful context on container-based approaches.
Recommended Resources
SparkyFitness isn’t heavy, but it stores a PostgreSQL database and user uploads, so don’t size the container too aggressively. Start with this baseline and adjust after a week of real usage.
| Resource | Recommended Starting Point | Notes |
|---|---|---|
| CPU | 2 cores | Enough for frontend, backend, and PostgreSQL in a small deployment |
| RAM | 2 GB | Use 4 GB if you plan to test AI or several integrations |
| Disk | 16–32 GB | Give more space if you expect many uploads or long-term backups |
| OS | Ubuntu 24.04 LTS | Docker officially supports Ubuntu Noble 24.04 LTS |
| Network | Static DHCP lease or static IP | Makes reverse proxy and mobile app access easier |
Step 1: Create the Ubuntu LXC Container in Proxmox
In the Proxmox web interface, create a new container using an Ubuntu 24.04 template. Here’s the GUI path:
- Download the template: Go to
localor your preferred storage, openCT Templates, and download the Ubuntu 24.04 standard template. - Create the container: Click
Create CT, choose a hostname likesparkyfitness, and set a strong root password or SSH key. - Assign resources: Use at least 2 CPU cores, 2 GB RAM, and 16 GB disk.
- Configure networking: Use DHCP with a router reservation or assign a static IP directly in Proxmox.
- Finish creation: Don’t start the container yet if you still need to enable nesting.
If you prefer the Proxmox shell, the exact command will vary based on your storage name, bridge name, and template path. A typical container creation command looks like this:
pct create 120 local:vztmpl/ubuntu-24.04-standard_24.04-2_amd64.tar.zst \
--hostname sparkyfitness \
--cores 2 \
--memory 2048 \
--swap 512 \
--rootfs local-lvm:20 \
--net0 name=eth0,bridge=vmbr0,ip=dhcp \
--unprivileged 1 \
--features nesting=1,keyctl=1 \
--start 1
Replace 120 with your preferred container ID and adjust the template filename to match the one available on your Proxmox node.
Step 2: Enable Nesting for Docker
Docker needs additional container features when it runs inside LXC. If you created the container from the GUI, select the container, go to Options, open Features, and enable Nesting. If your Proxmox version exposes keyctl, enable that too.
From the Proxmox host shell, you can set those options like this:
pct stop 120
pct set 120 -features nesting=1,keyctl=1
pct start 120
Pro Tip: Don’t install Docker directly on the Proxmox host for this setup. Keep Docker inside the Ubuntu container so the SparkyFitness stack, its networks, and its volumes stay isolated from the Proxmox management layer.
Step 3: Update Ubuntu and Install Basic Tools
Enter the container from the Proxmox console or SSH into it. Then update the OS and install the basic packages needed for Docker installation and troubleshooting.
apt update
apt upgrade -y
apt install -y ca-certificates curl gnupg nano openssl lsb-release
Set the timezone if needed:
timedatectl set-timezone Asia/Kolkata
timedatectl
Check that the container has working DNS and internet access:
ping -c 3 github.com
curl -I https://github.com
If DNS fails inside Docker later, the issue may be related to how Ubuntu, systemd-resolved, Docker, and your local DNS server interact. This guide on Docker DNS failures is worth keeping nearby for homelab troubleshooting.
Step 4: Install Docker Engine on Ubuntu
Use Docker’s official apt repository rather than the older distro package. Docker’s own Ubuntu instructions list Ubuntu 24.04 LTS and 22.04 LTS among the supported releases and recommend installing Docker Engine from the official repository. The current steps are available in Docker’s Ubuntu installation documentation.
First, remove conflicting packages if they exist:
for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do
apt remove -y $pkg 2>/dev/null || true
done
Add Docker’s official GPG key and apt source:
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
-o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc
cat <<EOF > /etc/apt/sources.list.d/docker.sources
Types: deb
URIs: https://download.docker.com/linux/ubuntu
Suites: $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}")
Components: stable
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/docker.asc
EOF
apt update
Install Docker Engine, Docker CLI, containerd, Buildx, and the Docker Compose plugin:
apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Verify that Docker works inside the LXC container:
docker run hello-world
docker compose version
You should see Docker download and run the test image successfully. If Docker fails with a permissions, overlay, or cgroup error, recheck that the Proxmox container has nesting enabled.
Step 5: Create a Clean Directory for SparkyFitness
Keep application files under /srv/apps instead of scattering Compose files in the root home directory. This makes backups, upgrades, and reverse proxy configuration easier later.
mkdir -p /srv/apps/sparkyfitness
cd /srv/apps/sparkyfitness
Download the official production Compose file and the default environment file from the latest SparkyFitness release:
curl -L -o docker-compose.yml \
https://github.com/CodeWithCJ/SparkyFitness/releases/latest/download/docker-compose.prod.yml
curl -L -o .env \
https://github.com/CodeWithCJ/SparkyFitness/releases/latest/download/default.env.example
This matches the project’s recommended Docker Compose method, where the official installation flow is to create a folder, download docker-compose.prod.yml and default.env.example, then start the stack with Docker Compose. You can compare this with the SparkyFitness Compose guide.
Step 6: Edit the SparkyFitness Environment File
Open the environment file:
nano .env
At minimum, review and set the following values. The exact names may change as SparkyFitness evolves, so use the downloaded .env file as the source of truth.
SPARKY_FITNESS_DB_NAME=sparkyfitness_db
SPARKY_FITNESS_DB_USER=sparky
SPARKY_FITNESS_DB_PASSWORD=replace_with_a_strong_database_password
SPARKY_FITNESS_APP_DB_USER=sparky_app
SPARKY_FITNESS_APP_DB_PASSWORD=replace_with_a_strong_app_database_password
SPARKY_FITNESS_FRONTEND_URL=http://192.168.1.50:3004
SPARKY_FITNESS_API_ENCRYPTION_KEY=replace_with_64_character_hex_key
BETTER_AUTH_SECRET=replace_with_long_random_secret
DB_PATH=./postgresql
SERVER_BACKUP_PATH=./backup
SERVER_UPLOADS_PATH=./uploads
TZ=Asia/Kolkata
NODE_ENV=production
Generate the encryption key and auth secret with OpenSSL:
openssl rand -hex 32
openssl rand -hex 32
Use the first value for SPARKY_FITNESS_API_ENCRYPTION_KEY and the second for BETTER_AUTH_SECRET.
Important: Don’t casually change BETTER_AUTH_SECRET after users start using two-factor authentication. SparkyFitness documentation warns that this value is tied to authentication security, and changing it later can lock users out of 2FA-protected accounts.
The SparkyFitness environment documentation also notes that mandatory persistent paths include the PostgreSQL database path, server backup path, and uploads path. That matters because your nutrition database and uploaded files should survive container recreation. See the SparkyFitness environment variables page for the full list.
Step 7: Start SparkyFitness with Docker Compose
From inside /srv/apps/sparkyfitness, pull the images and start the stack:
docker compose pull
docker compose up -d
Check the running containers:
docker compose ps
You should see services similar to:
sparkyfitness-db
sparkyfitness-server
sparkyfitness-frontend
Follow the logs during the first startup:
docker compose logs -f
The first run can take a little longer because images are pulled, PostgreSQL initializes, and the backend prepares its database. Once the stack is healthy, open the frontend URL in your browser. If you used the default production Compose mapping documented by SparkyFitness, the frontend is typically available on port 3004:
http://192.168.1.50:3004
Replace 192.168.1.50 with the IP address of your Ubuntu LXC container.
Step 8: Create the First User and Lock Down Signup
After the web interface loads, create your first account. Then decide whether you want open registration enabled. For a private home server, it’s usually better to disable public signup once your admin account exists.
In the .env file, look for signup-related settings and set them according to your preference:
SPARKY_FITNESS_DISABLE_SIGNUP=true
[email protected]
Restart the stack after changing environment values:
docker compose up -d
If you plan to use OIDC with Authentik, Authelia, Keycloak, Google, or another identity provider, configure that only after the basic email login works. SparkyFitness supports OpenID Connect and lets you define issuer URL, client ID, client secret, redirect URI, and related login behavior through the application’s authentication settings.
Step 9: Add a Reverse Proxy with Caddy or Nginx
You can use SparkyFitness directly on http://server-ip:3004, but a reverse proxy is cleaner if you want HTTPS, a friendly domain, or remote mobile app access.
If you already run Caddy on another Proxmox container or VM, add a local DNS record like:
fitness.lan -> 192.168.1.50
Then configure Caddy to proxy traffic to the SparkyFitness frontend:
fitness.lan {
reverse_proxy 192.168.1.50:3004
}
If you use a real domain with public DNS and Caddy can complete ACME validation, the same structure works with HTTPS:
fitness.example.com {
reverse_proxy 192.168.1.50:3004
}
After adding the domain, update SPARKY_FITNESS_FRONTEND_URL in .env:
SPARKY_FITNESS_FRONTEND_URL=https://fitness.example.com
Then recreate the stack:
cd /srv/apps/sparkyfitness
docker compose up -d
The official reverse proxy notes for SparkyFitness mention common proxy headers like Host, X-Real-IP, X-Forwarded-For, and X-Forwarded-Proto. If you use Nginx Proxy Manager or a hand-written Nginx config, make sure those headers are passed correctly. The SparkyFitness reverse proxy page has the project’s reference header example.
If you use Caddy heavily in your homelab, you may also like this related setup on Caddy service discovery, especially if you route several internal services through local DNS.
Step 10: Back Up the Database and Uploads
SparkyFitness stores valuable personal data: meals, body weight, workouts, measurements, reports, and possibly uploaded images. Don’t treat the container as disposable unless you have backups.
At the filesystem level, back up the whole application directory:
tar -czf /root/sparkyfitness-backup-$(date +%F).tar.gz /srv/apps/sparkyfitness
For a more database-aware backup, dump PostgreSQL from the Compose network. First check the database service name:
docker compose ps
Then run a dump command similar to this, adjusting the database name and user to match your .env file:
mkdir -p /srv/backups/sparkyfitness
docker compose exec -T sparkyfitness-db \
pg_dump -U sparky -d sparkyfitness_db \
> /srv/backups/sparkyfitness/sparkyfitness-db-$(date +%F).sql
You should also back up uploads and the environment file:
cp .env /srv/backups/sparkyfitness/env-$(date +%F).backup
tar -czf /srv/backups/sparkyfitness/uploads-$(date +%F).tar.gz ./uploads
The SparkyFitness documentation includes manual backup and restore guidance, including warnings that restores can be destructive and that independent backups are still recommended. For a private health-tracking app, follow a 3-2-1 backup approach: three copies, two different media types, and one offsite copy.
Useful Management Commands
Once SparkyFitness is running, these are the commands you’ll use most often.
Check Container Status
cd /srv/apps/sparkyfitness
docker compose ps
View Logs
docker compose logs -f
For only the backend:
docker compose logs -f sparkyfitness-server
Stop the Stack Without Deleting Data
docker compose stop
Start the Stack Again
docker compose up -d
Update SparkyFitness
cd /srv/apps/sparkyfitness
docker compose pull
docker compose up -d
docker image prune -f
Before updating, take a backup. This is especially important because SparkyFitness uses PostgreSQL and may include schema migrations between versions.
Common Problems and Fixes
Docker Won’t Start Inside the LXC Container
If docker run hello-world fails, check that nesting is enabled:
pct config 120 | grep features
You should see something like:
features: keyctl=1,nesting=1
If not, stop the container from the Proxmox host and set the features again:
pct stop 120
pct set 120 -features nesting=1,keyctl=1
pct start 120
The Web UI Doesn’t Load
Check that the frontend container is running and that the port mapping exists:
docker compose ps
ss -tulpn | grep 3004
Then test locally from inside the LXC container:
curl -I http://127.0.0.1:3004
If the local test works but another computer can’t open the page, check Proxmox firewall rules, the LXC IP address, your router firewall, and whether you’re using the correct host port.
Login or API Requests Fail Behind a Reverse Proxy
The most common cause is a mismatch between the browser URL and SPARKY_FITNESS_FRONTEND_URL. If users access the app at https://fitness.example.com, that exact URL should be configured in the environment file.
SPARKY_FITNESS_FRONTEND_URL=https://fitness.example.com
After changing it, restart the stack:
docker compose up -d
Database Data Disappears After Recreating Containers
This usually means the persistent paths weren’t configured correctly or the stack was removed with volumes. Avoid this unless you really want to delete data:
docker compose down -v
Use this instead for normal restarts:
docker compose down
docker compose up -d
Container DNS Works on Ubuntu but Not Inside Docker
Check the container’s resolver:
cat /etc/resolv.conf
If it points to a loopback resolver like 127.0.0.53, Docker containers may not be able to use it as expected. You can define Docker daemon DNS servers explicitly:
mkdir -p /etc/docker
cat <<EOF > /etc/docker/daemon.json
{
"dns": ["1.1.1.1", "8.8.8.8"]
}
EOF
systemctl restart docker
In a homelab, replace those public resolvers with your Pi-hole, Technitium, or internal DNS server if you want local names like fitness.lan to resolve from containers.
Security Checklist for a Private Fitness App
Because SparkyFitness stores health and fitness data, treat it with more care than a casual dashboard. A few small decisions make a big difference.
- Use strong secrets: Generate unique values for database passwords, API encryption key, and auth secret.
- Disable open signup: Turn off registration after creating your account unless you intentionally want family members to register themselves.
- Keep it private by default: Use LAN-only access, VPN, or Tailscale before exposing it publicly.
- Use HTTPS: Put Caddy, Nginx, or another reverse proxy in front if accessing from mobile devices or outside the LAN.
- Back up before updates: Database-backed apps should never be updated without a rollback path.
- Snapshot carefully: Proxmox snapshots are useful, but application-level PostgreSQL backups are still safer for restore testing.
If you expose self-hosted services publicly, rate limiting and edge controls become important. This related article on Traefik rate limiting covers the same defensive mindset for internet-facing homelab services.
Should You Use the Community Proxmox Helper Script?
SparkyFitness documentation also points Proxmox users to a community-maintained Proxmox VE Helper Script. That can be convenient if you want a quick automated install, but the project notes that the script is community-contributed rather than directly maintained by SparkyFitness.
For a service that stores personal health data, I prefer the manual Docker Compose method shown in this guide. It gives you a clearer understanding of where the Compose file lives, where the database is stored, which environment variables matter, and how to back up or move the deployment later.
| Method | When to Use It | Why |
|---|---|---|
| Manual Docker Compose | You want control and repeatability | Best for learning, backups, customization, and troubleshooting |
| Community Proxmox script | You want a fast test install | Convenient, but you should still inspect what it creates |
| Ubuntu VM | You want stronger isolation | Best if exposing the app publicly or sharing with multiple users |
Final Thoughts
Installing SparkyFitness on Proxmox LXC is a good fit if you want a self-hosted, privacy-first alternative to MyFitnessPal without dedicating a full VM to a small fitness-tracking app. The important parts are enabling Docker-friendly LXC features, installing Docker from the official Ubuntu repository, setting persistent paths correctly, generating stable secrets, and backing up PostgreSQL before every serious change.
Once the basics are running, you can improve the setup with a reverse proxy, HTTPS, local DNS, OIDC login, mobile app access, and scheduled backups. Start simple, confirm the core app works on your LAN, then add the extra layers one at a time.