Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,7 @@ Software that does not fit in another section.
- [Network-Multitool](examples/network-multitool) - Multi-arch multitool for container network troubleshooting.
- [IT-Tools](examples/it-tools) - Collection of handy online tools for developers, with great UX.
- [Scratch-Map](examples/scratch-map) - An open-source scratch-off style map to track your travels.
- [Open-Health-Sync](examples/open-health-sync) - Self-hosted health data aggregator for Apple Health, Health Connect, Oura, WHOOP, Withings and more, with a REST API, FHIR R4 and a read-only MCP server.

## 🌟 Star History
[![Star History Chart](https://star-history.dera.page/svg?repos=Haxxnet/Compose-Examples&type=Date)](https://star-history.dera.page/#Haxxnet/Compose-Examples&type=Date)
Expand Down
33 changes: 33 additions & 0 deletions examples/open-health-sync/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# References

- https://github.com/soma-intelligence/open-health-sync
- https://github.com/soma-intelligence/open-health-sync/blob/main/docs/self-hosting.md

# Notes

Open Health Sync collects health data from Apple Health, Health Connect, Oura, WHOOP, Withings, Fitbit, Dexcom and other sources into Postgres (TimescaleDB). It serves it through a REST API, FHIR R4, Open mHealth, CSV/Parquet exports and a read-only MCP server.

Before the first start:

````
# set the same database password in both places (POSTGRES_PASSWORD and OHS_DATABASE_URL)
# generate the encryption key and paste it into OHS_ENCRYPTION_KEY
openssl rand -base64 32

# the server runs as 1000:1000, so its raw volume must be owned by that user
mkdir -p /mnt/docker-volumes/open-health-sync/raw
chown -R 1000:1000 /mnt/docker-volumes/open-health-sync/raw
````

Keep the encryption key safe: it seals stored provider tokens, and losing it means reconnecting every provider.

After `docker compose up -d`, check the configuration and create an API key (printed once):

````
docker exec open-health-sync /ohs doctor
docker exec open-health-sync /ohs admin tenant create --name dev
````

No device or provider keys yet? `docker exec open-health-sync /ohs seed --demo` loads 90 days of synthetic data and prints calls to try.

Set `OHS_PUBLIC_URL` to the address users reach (for example behind Traefik), since provider OAuth callbacks use it. Provider keys and every other setting are documented in the project's `.env.example`.
63 changes: 63 additions & 0 deletions examples/open-health-sync/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
services:

open-health-sync-db:
image: timescale/timescaledb:2.22.1-pg17
container_name: open-health-sync-db
hostname: open-health-sync-db
restart: unless-stopped
expose:
- 5432
volumes:
- ${DOCKER_VOLUME_STORAGE:-/mnt/docker-volumes}/open-health-sync/postgres:/var/lib/postgresql/data
environment:
- POSTGRES_USER=ohs
- POSTGRES_PASSWORD=CHANGEME # adjust
- POSTGRES_DB=ohs
healthcheck:
test: ["CMD-SHELL", "pg_isready -h 127.0.0.1 -U ohs -d ohs"]
interval: 5s
timeout: 3s
retries: 20
start_period: 10s

open-health-sync:
image: ghcr.io/soma-intelligence/open-health-sync:0.1.0
container_name: open-health-sync
hostname: open-health-sync
user: 1000:1000 # owner of the raw volume below
command: ["up"] # runs database migrations, then the server
restart: unless-stopped
depends_on:
open-health-sync-db:
condition: service_healthy
stop_grace_period: 35s
ports:
- 8080:8080/tcp
expose:
- 8080
volumes:
- ${DOCKER_VOLUME_STORAGE:-/mnt/docker-volumes}/open-health-sync/raw:/var/lib/ohs/raw
environment:
- OHS_DATABASE_URL=postgres://ohs:CHANGEME@open-health-sync-db:5432/ohs?sslmode=disable&pool_max_conns=20 # same password as above
- OHS_ENCRYPTION_KEY=CHANGEME # openssl rand -base64 32; keep it safe, it seals stored provider tokens
- OHS_PUBLIC_URL=http://localhost:8080 # public base URL, used for OAuth callbacks
- OHS_RAW_STORE=file:///var/lib/ohs/raw
healthcheck:
test: ["CMD", "/ohs", "doctor", "--quick"]
interval: 10s
timeout: 12s
retries: 6
start_period: 15s
#networks:
# - proxy
#labels:
# - traefik.enable=true
# - traefik.docker.network=proxy
# - traefik.http.routers.open-health-sync.rule=Host(`health.example.com`)
# - traefik.http.services.open-health-sync.loadbalancer.server.port=8080
# # Optional part for selecting certificate resolver
# - traefik.http.routers.open-health-sync.tls.certresolver=myresolver-http

#networks:
# proxy:
# external: true