From 1222fbb0189a01f5b3d99b72ab2c5c936c185091 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 5 Nov 2026 14:15:45 +0000 Subject: [PATCH] Say when it's safe to put the apps online, keep the admin UI private, and how to restore - security.md: "Can I put the apps on the internet?" and "What not to keep in the apps yet"; two-step sign-in under Not done yet; the restore guide in Your part. - phones.md: the Caddyfile blocks the admin UI (/_/ and the superuser API), and a note on keeping it private behind any proxy. - updates-and-backups.md: a restore guide, from the admin UI or by hand. --- phones.md | 16 ++++++++++++++++ security.md | 30 +++++++++++++++++++++++++++--- updates-and-backups.md | 31 +++++++++++++++++++++++++++++-- 3 files changed, 72 insertions(+), 5 deletions(-) diff --git a/phones.md b/phones.md index ac10343..b36e6f4 100644 --- a/phones.md +++ b/phones.md @@ -75,13 +75,21 @@ For public addresses such as `https://splitwiz.example.com`: and use a `Caddyfile` like this: ``` + (no-admin) { + # keep the admin UI off the internet; open it through Tailscale or on the machine + respond /_/* 404 + respond /api/collections/_superusers/* 404 + } splitwiz.example.com { + import no-admin reverse_proxy 127.0.0.1:8090 } should-we.example.com { + import no-admin reverse_proxy 127.0.0.1:8091 } flowy.example.com { + import no-admin reverse_proxy 127.0.0.1:8092 } ``` @@ -93,6 +101,14 @@ to 8095) in your router: that serves the app over plain `http://`, so passwords internet unencrypted, and it skips the proxy. Turn off **UPnP** in the router too, so no device on your network can open a port by itself. +**Keep the admin UI private.** Each app's admin UI (`/_/`) can see and change all of its +data, and its only protection is the owner's password and a limit of 10 tries a minute. On a +public address, block it at the proxy as in the `Caddyfile` above, and open it through +Tailscale or on the machine itself when you need it (for example +`ssh -L 8092:127.0.0.1:8092 yourserver`, then `http://localhost:8092/_/`). A proxy that can't +block a path, such as DSM's, leaves it reachable: then use Tailscale instead, or at least a +long, unique owner password. See [Can I put the apps on the internet?](security.md#can-i-put-the-apps-on-the-internet) + ## Install the app on the phone Open the app's `https://` address on the phone and sign in. Then: diff --git a/security.md b/security.md index c79148b..8a66cb1 100644 --- a/security.md +++ b/security.md @@ -35,10 +35,31 @@ and a published advisory after each fix ([policy](https://github.com/selfhostit/ | No Docker socket, no privileged mode, no host network for the apps | the compose files (only the optional Tailscale node uses the host network, to reach the apps on `127.0.0.1`) | | One-time setup code: the first account (the owner) can only be made with the code printed at install, which is deleted after setup | `backend/app/setup.go` in [plasto](https://github.com/selfhostit/plasto/blob/main/backend/app/setup.go) and each app built on it, and Splitwiz | | Sign-in rate limits: 10 password attempts a minute for people and for the admin UI, 5 a minute for setup | `backend/migrations/*_rate_limits.go` in each app | -| Access rules on every collection: people only see their own records or their group's | the collection API rules in `backend/migrations` | +| Access rules on every collection: people only see their own records or their group's. In Flowy, others on the same server see only your name and role, not your cycle settings or day logs, and tests check it | the collection API rules in `backend/migrations` | | Content Security Policy (`script-src 'self'`), `nosniff`, `frame-ancestors 'none'` and a same-origin referrer, so injected scripts and outside resources don't load | `backend/app/headers.go` in each app | | Discreet reminders (Flowy, off by default): notifications only say "Reminder from Flowy", for a lock screen others can see | Flowy settings, `discreet_reminders` | -| Nightly database backups, the last 7 kept | [Updates and backups](updates-and-backups.md#backups) | +| Nightly database backups, the last 7 kept, and a guide to restore one | [Updates and backups](updates-and-backups.md#backups) | + +## Can I put the apps on the internet? + +- **Through Tailscale: yes, and the installer offers to set it up.** The apps stay off the + internet; only your own devices, signed in to your Tailscale account, can reach them, over + an encrypted connection with an `https://` address. +- **On a public address, with your own reverse proxy:** you can, but then anyone can reach + the sign-in page and try passwords, and you take on keeping that safe. Only do it with + HTTPS, with the admin UI (`/_/`) blocked at the proxy, with a long unique password for + every account, and with the apps kept updated. [Phones](phones.md#your-own-domain-with-a-reverse-proxy) + shows a proxy setup that does this. The apps limit password attempts, but have no + two-step sign-in yet. +- **By forwarding an app's port in your router: no.** That serves the app over plain + `http://`, so passwords cross the internet readable. + +## What not to keep in the apps yet + +The apps are built for household data: periods, food, expenses, plans. Until the database +is encrypted on disk and there has been an independent review, don't make them the only +place you keep passwords, bank or card details, identity documents or medical records, +and keep an encrypted [backup](updates-and-backups.md#backups) of what you do keep. ## Sign-in, sessions and logs @@ -187,6 +208,7 @@ is MIT licensed so anyone can keep building it, and your data is a SQLite databa These are planned, in roughly this order: - A "sign out everywhere" button in every app (Flowy has it), for a lost phone. +- Two-step sign-in, for anyone who puts an app on a public address. - An OpenSSF Scorecard run on each repository. - An independent security review. If you do one, please share what you find through the reporting route above; findings and fixes will be published as advisories. @@ -196,5 +218,7 @@ These are planned, in roughly this order: - Keep the apps updated: `selfhostit update all` or the installer again ([Updates and backups](updates-and-backups.md)). - Keep a backup somewhere else, encrypted. -- Don't forward ports to the apps; use Tailscale or your own reverse proxy with HTTPS. +- Don't forward ports to the apps; use Tailscale, or your own reverse proxy with HTTPS and + the admin UI (`/_/`) blocked. +- Restore a backup once, to know it works ([how](updates-and-backups.md#restore-a-backup)). - Use a strong password for the owner account; it is also the admin UI (`/_/`) password. diff --git a/updates-and-backups.md b/updates-and-backups.md index 4a807d0..b5dd313 100644 --- a/updates-and-backups.md +++ b/updates-and-backups.md @@ -77,8 +77,35 @@ Tailscale key, which lets whoever has it join your tailnet as that machine. Selling or throwing away the machine or its SD card? Delete the apps' folders and wipe the disk first; the data on it is not encrypted. -To restore, stop the app (`docker compose down`), put `pb_data` back, and start it again -(`docker compose up -d`). +## Restore a backup + +Try this once now, while nothing is wrong, so you know your backups work. + +**From a nightly backup, in the admin UI:** open the app's `/_/` (through Tailscale or on +the machine itself), sign in with the owner's email and password, and go to **Settings > +Backups**. Pick a backup and choose **Restore**. The app restarts with that data. + +**By hand,** from a nightly backup or a copy of your own. For example, for Flowy: + +```sh +cd ~/selfhostit/flowy # the app's folder +docker compose down +mv pb_data pb_data.old # keep the current data until the restore works +mkdir pb_data +ls pb_data.old/backups # the nightly backups, newest last +unzip pb_data.old/backups/.zip -d pb_data +cp -r pb_data.old/backups pb_data/ # keep the other backups too +sudo chown -R 1000:1000 pb_data # the user the app runs as (not needed for Splitwiz and should-we) +docker compose up -d +``` + +For a copy of your own, put that `pb_data` folder in place instead of unzipping (and +decrypt it first, for example `age -d ... | tar xzf -`). On a Synology, do the same in File +Station and restart the project in Container Manager, or restore the folder with Hyper +Backup. + +Then open the app and check that your newest entries are there. Once they are, delete +`pb_data.old`. ## Removing an app