diff --git a/docs/deployment.md b/docs/deployment.md index e96da94..fa29835 100644 --- a/docs/deployment.md +++ b/docs/deployment.md @@ -323,19 +323,77 @@ Devices would then connect to `http://192.168.1.42:8080`. --- -## Part 7 – Security Notes +## Part 7 – Keeping It Off the Internet -ClubLedger is designed for a **trusted internal network** — a private club or venue Wi-Fi. It is not hardened for exposure to the public internet. +ClubLedger has no HTTPS, no brute-force protection, and no rate limiting. It is designed exclusively for use on a private local network. This section explains why it is safe by default, and how to make that guarantee explicit. + +### Why it is already protected by default + +Every home and business router uses **NAT (Network Address Translation)**. NAT means: + +- Your router has one public IP address (assigned by your internet provider). +- All devices on your network share that one address. +- Inbound connections from the internet are **dropped by the router** unless you explicitly tell it to forward them. + +ClubLedger listens on port 8000. Unless you specifically create a port-forwarding rule for port 8000 in your router settings, **no one on the internet can reach it**. This is the default state of every standard router. + +### What never to do + +- **Do not create a port-forwarding rule** for port 8000 (or whichever port ClubLedger uses) in your router's admin panel. This is the only action that would expose it. +- **Do not use a reverse proxy** (nginx, Caddy, Apache) to publish it under a public domain unless you have added authentication, HTTPS, and rate limiting first. +- **Do not run it on a cloud server** (VPS, AWS, etc.) without those same protections. + +### Verify it is not reachable from outside + +To confirm ClubLedger is not publicly accessible, check from a device that is **not on your Wi-Fi** (e.g. a phone on mobile data, or ask someone outside the building): + +1. Find your public IP address — visit [https://ifconfig.me](https://ifconfig.me) from a computer on your network. +2. From the external device, try to open `http://:8000`. +3. It should time out or refuse the connection. If it loads ClubLedger, you have an unintended port-forwarding rule — remove it from your router immediately. + +### Restrict the server to the local network interface (belt-and-suspenders) + +By default ClubLedger binds to `0.0.0.0`, meaning it accepts connections on all network interfaces, including the local one. For extra certainty you can bind it only to your specific Wi-Fi interface IP so it cannot be reached even if a forwarding rule is accidentally added. + +Find the server's local IP (e.g. `192.168.1.42`), then edit the last line of `main.py`: + +```python +uvicorn.run("main:app", host="192.168.1.42", port=8000, reload=True) +``` + +With this change, the app only accepts connections from devices on your local network. Nothing outside the router can reach it regardless of router configuration. + +> Note: if the server's local IP changes (e.g. after a reboot), the app will fail to start. Use this option only after setting a fixed/reserved IP (see Part 5). + +### Add a firewall rule (optional, Linux only) + +On Linux you can use `ufw` (Uncomplicated Firewall) to explicitly allow port 8000 only from your local network range and block everything else: + +```bash +sudo ufw enable +# Allow from local network (adjust 192.168.1.0/24 to match your network) +sudo ufw allow from 192.168.1.0/24 to any port 8000 +# Block port 8000 from everywhere else +sudo ufw deny 8000 +sudo ufw status +``` + +This means even if your router accidentally forwarded port 8000, the firewall on the server itself would drop those packets. + +To find your local network range: if your server's IP is `192.168.1.42`, your range is almost certainly `192.168.1.0/24`. + +--- + +## Part 8 – Security Notes | Risk | Mitigation | |---|---| +| Internet exposure | NAT protects by default — do not add port-forwarding rules (see Part 7) | +| Unauthorised Wi-Fi access | Use WPA2/WPA3 with a strong passphrase; consider a guest network for members separate from the staff network | | Staff accessing admin settings | Use separate staff and admin accounts; do not share admin credentials | -| Weak PINs | Encourage members to set at least 6-digit PINs | -| Data loss | Back up `clubledger.db` regularly (copy the file) | -| Unauthorised network access | Use WPA2/WPA3 Wi-Fi with a strong password; consider a separate staff VLAN if your router supports it | -| Accidental deletion | The delete button only appears on zero-balance accounts; there is no bulk delete | - -**Do not expose ClubLedger directly to the internet** (e.g. by port-forwarding port 8000 on your router) without first adding HTTPS and reviewing security. For internal-only use it is fine as-is. +| Weak member PINs | Encourage members to set at least 6-digit PINs | +| Data loss | Back up `clubledger.db` regularly — just copy the file | +| Accidental deletion | Delete only appears on zero-balance accounts; there is no bulk delete | --- @@ -352,3 +410,4 @@ ClubLedger is designed for a **trusted internal network** — a private club or | Stop the server | Press `Ctrl+C` in the terminal | | View systemd logs (Linux) | `journalctl -u clubledger -f` | | Backup data | Copy `clubledger.db` to a safe location | +| Verify not internet-accessible | From mobile data: `http://:8000` should time out |