Frame docs · Reference
Troubleshooting
First look at the server's own log: journalctl -u frame -n 100 with the Linux installer, or docker compose logs --tail 100 frame with Docker. systemctl status frame tells you whether it is running.
The app says it can't connect
- On your phone's browser, open
https://your-domain/api/v1/server. You should see JSON with your server's name. - If the page doesn't load:
- DNS: does
dig +short your-domainshow your server's IP? - Firewall:
sudo ufw statusshould allow 80 and 443. Check the provider's firewall too. - Service: run
systemctl status frameandjournalctl -u frame -n 50. - Tunnel: is
cloudflaredrunning (systemctl status cloudflared), and is the public hostname set tolocalhost:8080(orhttp://frame:8080with Docker)?
- DNS: does
- In the app, type the address without
https://and without a trailing slash, such asframe.example.com. The app adds the rest.
A friend can't sign up
"Invite required" or "invite invalid": the server is invite-only. Send them a link from Invites → New invite in the admin panel, or have a member share theirs from the app. "Invalid" means the link was revoked, expired or used up (server invites are single-use by default), or that Members can invite is off and they used a member's link. Check Settings and Invites in the panel.
Lost the setup link, or locked out of the panel
Run sudo frame-admin setup-link while no admin exists. Otherwise: sudo frame-admin user reset-password <you> for a forgotten password, sudo frame-admin user reset-2fa <you> for a lost authenticator, or sudo frame-admin user promote <you> to make an existing account an admin. With Docker, use docker compose exec frame frame-server admin ….
HTTPS or certificate errors
- With
FRAME_DOMAIN, Let's Encrypt must reach ports 80 and 443 on your server directly. If the DNS record is proxied by Cloudflare (orange cloud), switch it to DNS only, or use a Cloudflare Tunnel instead. - Did you run
sudo sh install.sh --reconfigureafter settingFRAME_DOMAIN? Without it, Frame can't bind ports 80/443, and the log shows "permission denied". - Let's Encrypt rate limits failed attempts. If you retried many times, wait an hour.
- The apps reject self-signed certificates. Use a real domain.
Uploads fail or videos won't send
A proxy in front is probably limiting the request size. Caddy: request_body max_size 64MB. nginx: client_max_body_size 64m. Cloudflare's free plan: 100 MB at most. Also check FRAME_MAX_UPLOAD_MB.
New messages arrive slowly behind a proxy
The proxy is buffering /api/v1/events, a Server-Sent Events stream. Turn buffering off for that path (nginx: proxy_buffering off; and proxy_read_timeout 1h;); see Behind Caddy, nginx or another proxy.
Everyone gets "too many requests"
Or rate limits hit the wrong people: Frame sees your proxy's IP instead of the visitors'. Set FRAME_TRUSTED_PROXIES to match your setup:
| Setup | Value |
|---|---|
| cloudflared on the same host | cloudflare,127.0.0.1/32 |
| Caddy or nginx on the same host | 127.0.0.1/32,::1/128 |
| Docker with Caddy | preset in the compose file |
| Docker with a tunnel or a host proxy | the (b) or (d) line in docker-compose.yml |
- cloudflared on the same host
cloudflare,127.0.0.1/32 - Caddy or nginx on the same host
127.0.0.1/32,::1/128 - Docker with Caddypreset in the compose file
- Docker with a tunnel or a host proxythe (b) or (d) line in
docker-compose.yml
cloudflare on its own trusts nobody: it must be paired with the address the tunnel connects from.
Sign in with Apple or Google is missing
Set FRAME_PUBLIC_URL to the exact address people type into the app, then restart. If people use more than one address, list them all, separated by commas.
Notifications don't arrive
- Check that
FRAME_PUSH_RELAYisn't empty. - Check that the server can reach the relay:
curl -sI https://frame.crow.sg/healthz. - On the phone, allow notifications for Frame. On Android, also turn off battery optimisation for Frame. On iOS, check Focus modes.
- Look for
push failedin the logs.
"Permission denied" or "readonly database" after admin commands
You probably ran frame-server directly as root, which left root-owned files in the data directory. Give them back to the service and restart, and from then on use sudo frame-admin …:
sudo chown -R --reference=/var/lib/private/frame /var/lib/private/frame && sudo systemctl restart frameTesting on your computer, an emulator or the local network
Use http://10.0.2.2:8080 in the Android emulator, http://localhost:8080 in the iOS simulator, and your computer's LAN address (such as http://192.168.1.20:8080) from a phone on the same Wi-Fi, with FRAME_LISTEN not set to 127.0.0.1. Dev mode uses port 8787. See Try it locally.
Still stuck? Ask in the GitHub repository, or write to [email protected].
For AI tools: this page as Markdown, the page index and all pages in one file.