Skip to documentation
HealthSync

Documentation

Server setup

Run the HealthSync API and Postgres with Docker, or connect the API to a managed database.

Read as Markdown

1. Get the server code

You need Git, Python 3.11 or newer for the token helper, and Docker with Compose. Docker Desktop works for local testing; a Linux server with Docker works for production. Run the following commands from the repository root.

git clone https://github.com/megabyte0x/healthykit.git
cd healthykit
cp .env.example .env
python3 -m backend.scripts.generate_token
python3 -m backend.scripts.generate_token

2. Configure secrets

Edit .env before starting the server. Replace POSTGRES_PASSWORD with a long random password, API_TOKEN with the first generated token, and TOKEN_HASH_SECRET with the second. Use a URL-safe database password (letters and digits are sufficient) because Compose inserts it into the database connection URL. Keep .env private and uncommitted.

  • API_TOKEN: the credential used by the standard self-hosted app and read APIs. It allows uploads as well as reads.
  • TOKEN_HASH_SECRET: a separate HMAC secret required by the API. Preserve it across restarts and upgrades; changing it invalidates existing hosted tokens.
  • POSTGRES_DB and POSTGRES_USER: default to healthsync.
  • API_HOST_PORT: defaults to 8080. POSTGRES_HOST_PORT: defaults to 15432.
  • HOSTED_PROVISIONING_ENABLED: leave false for the standard self-hosted setup.

3. Start and check the API

docker compose config --quiet
docker compose up --build -d
docker compose ps
curl --fail http://127.0.0.1:8080/health

The health endpoint should return {"ok":true}. The API container runs database migrations before starting FastAPI. Postgres data is stored in the healthsync-postgres-data named volume and survives normal container restarts. Do not run docker compose down -v unless you intend to delete the database.

To verify an authenticated database read, set API_TOKEN in your shell to the value saved in .env, then run:

curl --fail -H "Authorization: Bearer $API_TOKEN" \
  "http://127.0.0.1:8080/api/apple-health/metrics?limit=10"

An empty items array is expected before your first upload. If you change API_HOST_PORT, use that port in these checks.

4. Make the API reachable over HTTPS

For production, point a domain at your server and place the API behind an HTTPS reverse proxy. For example, if Caddy runs directly on the same server, add the following site block to its configuration and replace api.example.com with your domain. Allow the proxy's HTTP/HTTPS ports through your firewall and ensure certificate issuance can reach the server.

api.example.com {
    reverse_proxy 127.0.0.1:8080
}

The supplied Compose file publishes both database and API ports on all interfaces. With a proxy running on the host, change the db ports entry to the first line below and the api ports entry to the second line. Keep Postgres private. A proxy running in a container needs a shared Docker network and the api:8080 service address instead of host loopback.

"127.0.0.1:${POSTGRES_HOST_PORT:-15432}:5432"
"127.0.0.1:${API_HOST_PORT:-8080}:8080"

Apply port changes with docker compose up -d. Check https://api.example.com/health from a device outside the server, then repeat an authenticated read through HTTPS.

5. Connect your iPhone

  • In HealthSync Settings, choose your own backend.
  • Set the backend URL to your HTTPS base URL, such as https://api.example.com, and the auth token to API_TOKEN.
  • Grant Apple Health read permissions, run Sync last 24 hours, and inspect Sync Logs.
  • Repeat the metrics or workouts fetch after uploading to confirm the records were persisted.
  • For same-Wi-Fi testing only, use http://<server-lan-ip>:8080 and allow iOS Local Network access. 127.0.0.1 on an iPhone refers to the phone itself. The simulator can use http://127.0.0.1:8080 when the server runs on its Mac.

Back up and maintain your server →

Alternative: use a managed Postgres database

You can run the same FastAPI service against a managed Postgres database. Obtain the provider's connection string and required TLS settings. Set DATABASE_URL explicitly where the API runs; the supplied Compose stack constructs its own local database URL and does not use this alternative automatically.

python3 -m venv .venv
source .venv/bin/activate
pip install -r backend/requirements.txt
export DATABASE_URL='postgresql+psycopg://USER:PASSWORD@HOST:PORT/DATABASE'
export API_TOKEN="$(python3 -m backend.scripts.generate_token)"
export TOKEN_HASH_SECRET="$(python3 -m backend.scripts.generate_token)"
alembic upgrade head
uvicorn backend.main:app --host 0.0.0.0 --port 8080

Replace the connection-string placeholders, percent-encode special characters in credentials, and apply the provider's TLS requirements. Save the generated secrets securely and configure your service manager to reuse them on restart. Put the API behind HTTPS as above. The iPhone receives only the API base URL and API_TOKEN; database credentials stay on the server.

Optional: provision workspaces with read-only agent tokens →