113 lines
5.4 KiB
Markdown
113 lines
5.4 KiB
Markdown
# Hosting
|
|
|
|
Noisebell is hosted with DigitalOcean as the public service and observability hub, the Raspberry Pi on Tailscale, and Cloudflare Tunnel as the only intended public HTTP entry point.
|
|
|
|
## Public Routes
|
|
|
|
| Hostname | Target | Access |
|
|
|---|---|---|
|
|
| `noisebell.extremist.software` | cache public routes | public via Cloudflare Tunnel |
|
|
| `rss-noisebell.extremist.software` | RSS service | public via Cloudflare Tunnel |
|
|
| `grafana-noisebell.extremist.software` | Grafana | public via Cloudflare Tunnel, Grafana login required |
|
|
|
|
`discord.noisebell.extremist.software` is not routed through the tunnel. The Discord bot stays local to the DigitalOcean host and receives cache webhooks at `127.0.0.1`.
|
|
|
|
## Private Routes
|
|
|
|
| Route | Purpose |
|
|
|---|---|
|
|
| `jet@noisebell-do` | DO administration over Tailscale SSH |
|
|
| `pi@noisebell-pi` or `pi@100.66.45.36` | Pi administration over Tailscale SSH |
|
|
| `noisebell-do:3000/webhook` | Pi state-change webhook to cache |
|
|
| `noisebell-pi:80` | DO cache polling and Pi app metrics |
|
|
| `noisebell-pi:8090` | cache to Pi Home Assistant relay |
|
|
| `noisebell-pi:9100` | Pi node exporter metrics |
|
|
| `noisebell-do:3100` | Pi journal shipping to Loki |
|
|
|
|
## DigitalOcean Firewall
|
|
|
|
NixOS firewall policy is in `hosts/noisebell-do/configuration.nix`.
|
|
|
|
SSH is Tailscale-only because no public TCP SSH port is opened and `tailscale0` is trusted. Direct public HTTP and HTTPS stay open while `services.noisebell-public-gateway.enable = false` so an accidental pre-tunnel deploy does not break the existing site. Once the Cloudflare Tunnel module is enabled, public TCP ports close and all public web access enters through the tunnel.
|
|
|
|
After the tunnel is verified, mirror that policy in the DigitalOcean cloud firewall: close public inbound `22`, `80`, and `443`; keep outbound open; keep Tailscale UDP reachable as needed.
|
|
|
|
## Cloudflare Tunnel
|
|
|
|
The tunnel module is `hosts/noisebell-do/public-gateway.nix`. It defines ingress for the three public hostnames and returns `404` for everything else.
|
|
|
|
The module reconciles Cloudflare through the API when enabled:
|
|
|
|
- creates a locally-managed tunnel named `noisebell-do` if it does not exist
|
|
- writes the tunnel credentials JSON to `/var/lib/noisebell-public-gateway/credentials.json`
|
|
- upserts proxied CNAME records for the public hostnames
|
|
- starts `cloudflared` with local Nix-managed ingress rules
|
|
|
|
Create two age secrets before enabling the module:
|
|
|
|
```sh
|
|
cd secrets
|
|
agenix -e cloudflare-api-token.age
|
|
nix shell nixpkgs#openssl -c openssl rand -base64 32
|
|
agenix -e cloudflare-tunnel-secret.age
|
|
```
|
|
|
|
Paste the generated base64 value into `cloudflare-tunnel-secret.age`.
|
|
|
|
Set `services.noisebell-public-gateway.accountId` and `services.noisebell-public-gateway.zoneId` in `hosts/noisebell-do/configuration.nix`, then flip `services.noisebell-public-gateway.enable = true`.
|
|
|
|
Required Cloudflare API token scopes:
|
|
|
|
| Resource | Scope |
|
|
|---|---|
|
|
| Account | `Cloudflare Tunnel:Edit` or `Cloudflare One Connector: cloudflared:Edit` |
|
|
| Zone | `DNS:Edit` for `extremist.software` |
|
|
|
|
The token should be restricted to the Noisebell Cloudflare account and the `extremist.software` zone.
|
|
|
|
## Grafana
|
|
|
|
Grafana listens on `127.0.0.1:3030` on the DO host. Public access is through `https://grafana-noisebell.extremist.software/` and requires the Grafana login form.
|
|
|
|
The admin user is `admin`. The password is generated on the DO host at first start and stored in `/var/lib/grafana/admin_password`.
|
|
|
|
```sh
|
|
ssh jet@noisebell-do sudo cat /var/lib/grafana/admin_password
|
|
```
|
|
|
|
Two dashboards are provisioned from `hosts/noisebell-do/observability.nix`:
|
|
|
|
| Dashboard | Audience | Datasources |
|
|
|---|---|---|
|
|
| `Noisebell Full Debug` | authenticated operators | Prometheus and Loki |
|
|
| `Noisebell Public` | anyone with the shared link | Prometheus only |
|
|
|
|
Use Grafana externally shared dashboards for the public-safe view. `noisebell-grafana-public-dashboard.service` creates or refreshes the public share on boot/deploy with a deterministic token.
|
|
|
|
The public-safe URL is:
|
|
|
|
```text
|
|
https://grafana-noisebell.extremist.software/public-dashboards/6e6f69736562656c6c7075626c696330
|
|
```
|
|
|
|
The RSS and Grafana hostnames use one label under `extremist.software` so they are covered by Cloudflare Universal SSL. Nested names like `grafana.noisebell.extremist.software` require additional Cloudflare certificate setup.
|
|
|
|
The helper script `scripts/share-grafana-public-dashboard jet@noisebell-do` can still be used to repair or print that URL manually. The public dashboard intentionally avoids Loki/raw journal panels and uses stored Prometheus queries only.
|
|
|
|
## Pi Hardening
|
|
|
|
`scripts/deploy-pios-pi.sh` configures the Raspberry Pi OS host. It now uses `NOISEBELL_ENDPOINT_URL=http://noisebell-do:3000/webhook` by default, so state changes go to the cache over Tailscale instead of the public domain.
|
|
|
|
The deploy script applies a persistent firewall service, `noisebell-tailscale-only-firewall.service`, that drops non-Tailscale TCP traffic to `22`, `80`, `8090`, and `9100`. Existing SSH sessions survive because established connections are allowed. New SSH, app, relay, and node exporter access must use Tailscale.
|
|
|
|
Deploy the Pi over Tailscale after the first bootstrap:
|
|
|
|
```sh
|
|
HOME_ASSISTANT_BASE_URL=http://10.21.0.43:8123 scripts/deploy-pios-pi.sh pi@100.66.45.36
|
|
```
|
|
|
|
Override the cache webhook only if needed:
|
|
|
|
```sh
|
|
NOISEBELL_CACHE_WEBHOOK_URL=http://noisebell-do:3000/webhook scripts/deploy-pios-pi.sh pi@100.66.45.36
|
|
```
|