Draft: not yet reviewed by a clinician
Use this page to prepare questions for your care team. It does not replace their advice. Your own targets and doses come from your nephrologist, diabetes team and renal dietitian.
Troubleshooting¶
Find the message you see, then follow the fix. Most problems are an address the app does not know, a volume it cannot write, or a proxy it does not trust (deployment guide).
First checks¶
- The log: the last 50 lines usually name the problem (secrets are redacted from logs).
python -m app.admin checkinside the container: configuration, database integrity, schema version and the secret key in one report.- The health check, run by hand.
The commands for each engine, and the fixes below in more detail, are in the deployment guide's troubleshooting section.
Messages and fixes¶
| You see | Why | Fix |
|---|---|---|
400 Unknown host |
the browser used a host name the app does not know (DNS-rebinding defense) | set PUBLIC_URL, or add the name to ALLOWED_HOSTS; the log names the refused host. IP addresses and localhost always work |
403 on every save |
the browser's origin does not match | set PUBLIC_URL to exactly the address bar's scheme, host and port, especially if your proxy rewrites Host |
503 Setup required |
first-run setup is not done | use the setup code from the log (Users and keys) |
| Sign-in refused over HTTP | two or more accounts exist, so plain-HTTP sign-in from other machines is refused | set up HTTPS (HTTPS for phones) |
unable to open database file, attempt to write a readonly database |
/data is not writable by UID 10001 |
named volumes need nothing; a bind mount needs its owner fixed and, on SELinux, a label (volumes). Kubernetes: fsGroup: 10001 |
SECRET_KEY_FILE points to ..., which does not exist, or permission denied |
the secret is missing or unreadable for UID 10001 | create the Podman secret or Kubernetes Secret; compose files need 0644 in a 0700 directory. Setting both X and X_FILE is also refused |
The app exits naming ALLOW_PRIVATE_AI_HOSTS |
that old name is not accepted | use AI_PRIVATE_HOSTS with explicit host:port entries (Configuration) |
| Health check failing | a string-form health command runs through /bin/sh, which the image does not have |
use ["python", "-m", "app.healthcheck"]; on Docker do not pass --health-cmd. On slow storage raise the start period |
| Every request from one address; rate limits hit everyone | the engine hides client addresses, or TRUSTED_PROXIES does not match the proxy |
read the peer address from the log and set TRUSTED_PROXIES (Security) |
database is locked |
two processes share one database | run exactly one container (one pod) per volume |
| Memory or process limit ignored | rootless engines need cgroup v2 with systemd (Docker) | check the cgroup version the engine reports |
USDA request failed / USDA API key was rejected |
no route to api.nal.usda.gov:443 / a wrong key |
check egress rules (Network allowlist) / the key |
Kubernetes pod Pending |
the volume claim cannot bind | describe the claim kidney-health-data: storage class name, default class, node selector |
| Pod rejected by Pod Security | an added container misses a restricted setting | non-root, allowPrivilegeEscalation: false, drop ALL, seccomp RuntimeDefault |
NetworkPolicy test pod gets {"status":"ok"} |
policies are not enforced (Kubernetes) | enable enforcement in your network plugin (Talos Flannel: kubeNetworkPoliciesEnabled) |
Phones and the installed app¶
| People report | Fix |
|---|---|
| "My data is gone" | they opened a different address (name, port or scheme). The same app at another address starts empty; the data is still on the server (design note 02) |
| The app does not open offline | offline needs trusted HTTPS; check the padlock and Settings → This device says "Offline ready" |
| "Update ready" never appears | close the app fully and reopen; if you set PWA_ENABLED=false, opening it once removes the old version |
| The camera shows black | use the photo or type-in options for barcodes |
| Asked to sign in again | an installed app keeps its own sign-in, separate from the browser's |
Only the header shows over a VPN¶
The app opens on the home Wi-Fi. Over a VPN such as NetBird, Tailscale or WireGuard, only the header shows, and after about 8 seconds the page says "The app did not start". The page arrived, but the app's script files did not.
This is fixed in your network, not in the app. The app answers whatever reaches it. It cannot change how the VPN carries packets. Whoever runs the VPN, or the machine that routes it to the server, makes the change below.
The likely cause is packets that are too big for the tunnel. A VPN wraps each packet in another one, so packets inside it must be smaller. Small answers get through, but large files stall when the big packets are dropped and the "too big" messages never come back. This is called a path MTU black hole. It is likely when the server sits behind a NetBird routing peer, which passes traffic between the tunnel and your home network (NetBird: routing peers), instead of running NetBird itself.
To check, download the largest script file once over the VPN and once on the home Wi-Fi. On Wi-Fi it arrives at
once. Over a black hole it stops after a few kilobytes, while a small address such as /healthz still answers.
To fix it, do one of these, then check again:
- clamp the TCP segment size (MSS clamping) on the NetBird routing peer, so connections through it use packets that fit;
- lower the MTU of the NetBird interface on both ends. NetBird's default is 1280 (NetBird: command line);
- run NetBird on the server itself, so it is a peer and no route is involved.
Also rule out:
400 Unknown hostin the browser or the log: add the NetBird name you use (for example one ending in.netbird.cloud) toALLOWED_HOSTS, or setPUBLIC_URLto it (Configuration);- an old copy of the app on the device: where the app works, use Settings → This device → Clear offline data on this device, after waiting entries have synced, or clear the site's data in the browser;
- a content blocker, or a filtering proxy or DNS on the VPN, that blocks script files.
The commands for each step are in the deployment guide's section Only the header shows over a VPN.
Accounts¶
| Problem | Fix |
|---|---|
| Lost the setup code | restart the app, or python -m app.admin setup-code |
| The only admin is locked out | python -m app.admin reset-password USERNAME --stdin (design note 07) |
| A lost phone is still signed in | python -m app.admin revoke-sessions USERNAME, or Signed-in devices in the person's settings |
| Two-step sign-in: the phone and the recovery codes are both lost | python -m app.admin remove-two-step USERNAME |
| Settings says passkeys need a name for the server | open the app by its name, not an IP address, and set PUBLIC_URL to that address |
| A device with a passkey is lost or stolen | Server administration → People → Remove passkeys, or python -m app.admin remove-passkeys USERNAME |
| Proxy mode: "Your account is not enabled here" | create the account, or set PROXY_AUTO_CREATE_USERS=true |
| Proxy mode will not start | TRUSTED_PROXY_SECRET_FILE is missing, or TRUSTED_PROXIES contains 0.0.0.0/0 |
Which version is running?¶
Server administration → About this server shows the version and schema. The engine shows the image digest; the commands are at the end of the guide's troubleshooting section.
Debugging without a shell¶
The image has no shell on purpose. Most tasks have a python -m app.admin command. Otherwise use a
debug container that shares the app's volumes, as described in the deployment guide.
Still stuck?¶
Collect the log lines around the problem (secrets are redacted from logs), the output of
python -m app.admin check, your engine and version, and open an issue on the repository. Report security
problems privately (Security).
Sources¶
- Deployment guide: troubleshooting; operator security guide; HTTPS guide.
- Design note 01; design note 02; design note 07.
- Docker: rootless mode limitations; Kubernetes: Network Policies.
- NetBird: command line; NetBird: routing peers.
Not yet reviewed by a clinician. Facts and sources last checked 2026-10-30.