-
Notifications
You must be signed in to change notification settings - Fork 0
Self Hosting
Self-hosting is for users with real Tandem accounts who want to run their own PumpSync-compatible backend. This page is the end-to-end walkthrough; the backend repository's docs/docker-self-host.md is the repo-local quickstart these steps stay in sync with.
Want to try PumpSync without a Tandem account first? See Demo Mode instead.
You need Docker, and — to reach the server from a physical iPhone — a reverse proxy (below).
Using the published image (no build needed; it is public on GitHub Container Registry):
mkdir pumpsync && cd pumpsync
curl -fsSLO https://raw.githubusercontent.com/eslutz/PumpSync-Backend/main/.env.example
cp .env.example .env
sed -i.bak "s#^PumpSync__ServiceTokenSigningKey=.*#PumpSync__ServiceTokenSigningKey=$(openssl rand -base64 32)#" .env
rm .env.bak
mkdir -p data
docker run --detach --name pumpsync-backend \
--publish 127.0.0.1:8080:8080 \
--env-file .env \
--volume "$PWD/data:/data" \
--restart unless-stopped \
ghcr.io/eslutz/pumpsync-backend-self-hosted:latestOr build from source with Docker Compose:
git clone https://github.com/eslutz/PumpSync-Backend.git && cd PumpSync-Backend
cp .env.example .env
sed -i.bak "s#^PumpSync__ServiceTokenSigningKey=.*#PumpSync__ServiceTokenSigningKey=$(openssl rand -base64 32)#" .env
rm .env.bak
docker compose up --build -d.env.example already runs against a real Tandem account by default — the only required change is the signing key, which replaces a well-known placeholder with a real random secret (the backend refuses to start with the placeholder).
curl http://localhost:8080/api/v1/capabilities
curl http://localhost:8080/healthThe capabilities response should include "serviceMode":"selfHosted" and "dataSourceMode":"tandemSource". The backend also logs its active mode in its first startup lines (docker logs pumpsync-backend).
The container only speaks plain HTTP and only listens on 127.0.0.1:8080 — in self-hosted mode it issues app sessions without authentication, so it must never be directly reachable over plain HTTP from other machines. The PumpSync app also requires https:// for any address other than localhost/127.0.0.1/::1, so a phone needs HTTPS.
-
iOS Simulator on the same machine: nothing more to do; use
http://localhost:8080/apiin the app. -
Physical iPhone: put a reverse proxy in front of
127.0.0.1:8080— something that speaks HTTPS to the phone and plain HTTP to the container — then usehttps://your-host.example/api.
This project doesn't try to be the reverse-proxy documentation — pick a well-maintained, self-hosted option and follow its own guide:
-
Nginx Proxy Manager (recommended if you're new to this) — a web UI over nginx with a built-in Let's Encrypt client, so there's no separate certbot install or renewal cron to set up. For PumpSync: add a Proxy Host, forward it to
127.0.0.1:8080, enable "Request a new SSL certificate." See its setup guide. - Caddy — config-file-based, also does automatic HTTPS. See its reverse proxy quickstart.
- Traefik — Docker-label-driven auto-discovery, a common choice if you're already running several containers under Compose.
All three are actively maintained, self-hosted (nothing routes through a third party), and equally capable of the one thing PumpSync needs.
If your proxy forwards the real client IP via X-Forwarded-For (all three above do by default), set PumpSync__TrustForwardedHeaders=true in .env so per-IP rate limiting uses the phone's real address instead of the proxy's; leave it unset otherwise.
-
Settings → Connection: set the mode to Self-hosted, enter the server URL (including
/api), tap Connect. The app creates a 12-hour session token automatically and renews it as needed. - Settings → Tandem Account: enter your real Tandem username, password, and region, then Save Credentials. The backend validates them against Tandem Source and never stores them — they live only in your device's Keychain.
- Settings → Apple Health: allow insulin and carbohydrate write access.
- Sync tab: pick the initial history range and tap Start Initial Sync. Tandem Source retains roughly 14 days of history, so that is the maximum lookback.
-
Persistence: operational state (never credentials, tokens, or health samples) lives in
data/pumpsync.db. Back it up before host or volume changes. -
Permissions: the container runs as non-root UID
1654; on Linux,./datamust be writable by that UID (chown 1654:1654 data). -
Upgrades: stop the container, back up
data/pumpsync.db, pull the new stablelatestimage or an explicit numeric SemVer tag (orgit pullfor source builds), start again, and re-run the capabilities smoke test.latestmoves only for stable backend releases; unreleased builds are available by commit-SHA tag. -
Key rotation: changing
PumpSync__ServiceTokenSigningKeyinvalidates outstanding app sessions; the app reconnects on its next use. -
Data deletion: the backend repo's
docs/data-deletion.mdcovers removing an installation's rows from your SQLite database.
-
Container exits immediately: the signing key is still the placeholder, or
./datais not writable by UID 1654. Checkdocker logs. -
App says the URL is invalid: self-hosted URLs must be
https://unless the host is loopback (localhost,127.0.0.1,::1), and should end in/api. -
Real Tandem credentials rejected: the backend is running in demo mode instead — the startup log and
/api/v1/capabilities(dataSourceMode) both show this. Confirm you copied.env.example, not.env.demo.example. - "Sync limit reached": the backend rate-limits sync/validate to 12 per hour per user; wait and retry.
- "Re-save your Tandem account credentials": Tandem rejected the stored password (for example after you changed it on tandemdiabetes.com); re-enter it under Settings → Tandem Account.
PumpSync documentation: iOS repository · Backend repository · Issues