Skip to content
Merged
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
16 changes: 16 additions & 0 deletions phones.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
```
Expand All @@ -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:
Expand Down
30 changes: 27 additions & 3 deletions security.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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.
Expand All @@ -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.
31 changes: 29 additions & 2 deletions updates-and-backups.md
Original file line number Diff line number Diff line change
Expand Up @@ -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/<one of them>.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

Expand Down
Loading