One-shot prettier pass so the new format:check gate starts from a clean baseline. Formatting only — no behaviour change. Generator-owned and vendored artifacts stay untouched via .prettierignore.
5.1 KiB
Reproductive-health data on your own server
HealthLog's cycle tracking stores menstrual, fertility, and related reproductive-health data the same way it stores every other metric: in the PostgreSQL database that runs on the host you control, encrypted at rest for the intent-revealing fields. This page explains what that arrangement does and does not change about who can reach that data, in plain terms and without overstating the protection.
What self-hosting changes
A consumer cycle-tracking app runs on the vendor's servers. Your reproductive-health data lives in their database, under their keys, in their jurisdiction. If that vendor receives a subpoena, a civil discovery request, or a law-enforcement demand it judges valid, the vendor — not you — decides how to respond, and it holds the data and the keys needed to comply. Several vendors state in their own privacy policies that they comply with valid legal process; that is a factual description of where the data sits, not an accusation.
Self-hosting removes that vendor from the picture. There is no cloud account holding your cycle data, no vendor key escrow, and no third party that can be served process to hand over data it does not have. The honest framing is narrow and worth stating precisely:
Self-hosting means there is no cloud vendor to subpoena for your reproductive-health data. It does not make the data unreachable.
The encryption-at-rest layer is real: the intent-revealing day-log
fields (free-text notes always; pregnancy, contraception, and
sexual-activity fields by default for this category) are encrypted with
AES-256-GCM under a key you supply via ENCRYPTION_KEYS, and the
application fails closed rather than ever writing those fields in
plaintext. Flow, basal body temperature, ovulation-test results,
cervical-mucus observations, and the cycle dates stay in plaintext
because the prediction and correlation engines read them; they are
health observations, not the disclosure-sensitive intent fields.
The residual threat (read this part)
Self-hosting moves the data onto a box you own. That box can still be reached:
- Physical or legal seizure of your own host. If the machine running PostgreSQL — your VPS, your home server, your NAS — is seized, imaged, or compelled, the data is on it. Encryption at rest protects against a stolen disk or a leaked backup only while the key is not also available; if the host is running, or the key is stored next to the data, that protection is gone.
- Your hosting provider. A VPS provider can snapshot your disk and can be served process the same way a SaaS vendor can. Self-hosting on rented infrastructure narrows the set of parties who hold your data; it does not reduce it to zero.
- Your own backups. Off-host backups (the optional S3 export, or any
pg_dumpyou take) carry the same data. Encrypt them, control where they land, and treat them as part of the same threat surface. - The device that talks to the server. A phone or laptop with a live session, a cached PWA, or the native client holds data locally too. Protecting the server does nothing for an unlocked device.
The promise is therefore specific: no cloud vendor to subpoena, not data nobody can ever reach. If your threat model includes seizure of your own infrastructure, encryption at rest plus a key you keep off the host is the floor, and the threat-model note below covers the rest.
Public record
The reason this distinction matters is documented in public legal record, not speculation:
- In 2021 the U.S. Federal Trade Commission settled with the maker of a period- and fertility-tracking app over allegations that it shared users' health data with third-party analytics and advertising services despite privacy promises. The settlement is public record.
- In 2025 a federal jury found that the same app's maker violated a California privacy statute over the sharing of menstrual-tracking data; the verdict and the underlying class action are public record.
These are cited as factual public record to explain why the "who holds the data" question is the one that matters for this category. HealthLog makes no claim about any other product's current practices.
Practical hardening
If reproductive-health privacy is the reason you self-host, the operator-side steps that matter most:
- Keep
ENCRYPTION_KEYSoff the host that runs PostgreSQL where your threat model allows it (an injected secret at boot, not a file next to the database). Seedocs/ops/encryption-key-rotation.md. - Turn off any integration you do not need. The fewer outbound paths, the smaller the surface.
- Encrypt and control your backups. The off-host backup feature uses AES-GCM; the destination bucket and its access are yours to lock down.
- Use the in-app discreet notifications toggle so cycle reminders never name the event on a lock screen, and the client-managed reminders path if you want the device, not the server, to own those notifications.
- Lock the devices that hold a live session.
See also the threat-model note for a compact "protects against / does not protect against" summary.