-
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. Self-hosted mode now requires a device-bound Secure Enclave proof, but transport encryption is still required to protect session credentials and Tandem credentials in transit, so the container 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 enrolls a protocol 3 Secure Enclave P-256 key and creates a renewable session. Self-hosted authentication does not contact or depend on Apple, does not submit an App Attest receipt, and does not store an App Attest risk outcome. - 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. -
Keys: generate independent random values for
PumpSync__ServiceTokenSigningKeyandSessionSecurity__MasterKey. Changing the signing key invalidates access tokens. Changing the session-security key invalidates challenges and refresh credentials; the app must reconnect in the foreground. -
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