docs: add LAN HTTPS setup guide (nginx + certbot + Cloudflare DNS-01)

Documents the trusted-certificate setup used for local staff access,
needed because the Screen Capture API (Copy Agent screenshots) requires
a secure context.
This commit is contained in:
2026-07-12 17:34:12 -04:00
parent f712479882
commit 44dea49fd1

104
README.md
View File

@@ -508,6 +508,110 @@ Each office runs its own `cloudflared` tunnel on its own PC. Ports never conflic
--- ---
## LAN HTTPS Setup (Trusted Certificate for Local Access)
Some browser features — notably the Screen Capture API used by the Copy Agent's screenshot
tool — only work in a "secure context" (`https://`, or the literal hostname `localhost`). Plain
`http://<LAN-ip>:3000` doesn't qualify, so staff would see the feature report itself as
unsupported.
The fix used here: a real, publicly-trusted certificate (Let's Encrypt) for a subdomain whose
DNS record points at this office's private LAN IP. Since the cert is issued via a DNS-01
challenge (not a live connection to the server), staff PCs need zero configuration — no local CA
to install, unlike a self-signed/mkcert certificate.
**How it works:**
- DNS: `local-<office>.mydentalofficemanagement.com``A` record → this PC's LAN IP, **unproxied**
("DNS only" in Cloudflare — proxying doesn't work for private IPs)
- nginx terminates TLS using the Let's Encrypt cert and only accepts connections from the office
subnet (`allow <subnet>; deny all;`)
- Staff browse to `https://local-<office>.mydentalofficemanagement.com` instead of the raw IP
This is separate from the Cloudflare Tunnel above — the tunnel is for public access (e.g. Twilio
webhooks), this is for trusted HTTPS on the local network only.
---
### Step 1 — Create the DNS record (in Cloudflare, not the registrar)
In the Cloudflare dashboard for `mydentalofficemanagement.com` → DNS → Add record:
- Type: `A`, Name: `local-<office>` (e.g. `local-summit`), Content: this PC's LAN IP
- **Proxy status: DNS only** (grey cloud) — required, Cloudflare can't proxy a private IP
### Step 2 — Install nginx (if not already done in Step 12 above)
```sh
sudo apt update
sudo apt install -y nginx
```
> If another web server (e.g. Apache) is already bound to port 80/443, nginx will fail to start.
> Check with `sudo ss -tlnp | grep -E ':80|:443'` and disable the conflicting service first.
### Step 3 — Install certbot with the Cloudflare DNS plugin
```sh
sudo apt update
sudo apt install -y certbot python3-certbot-dns-cloudflare
```
### Step 4 — Create a scoped Cloudflare API token
Cloudflare dashboard → profile icon → **My Profile****API Tokens****Create Token** → use the
**"Edit zone DNS"** template, restricted to **Specific zone → mydentalofficemanagement.com**.
Save it in a credentials file, root-only:
```sh
sudo mkdir -p /etc/letsencrypt
sudo nano /etc/letsencrypt/cloudflare.ini
```
```ini
dns_cloudflare_api_token = <paste token here>
```
```sh
sudo chmod 600 /etc/letsencrypt/cloudflare.ini
```
> The same token can be reused across offices (Cloudflare tokens are scoped to the whole zone,
> not a single subdomain) — but issuing one token per server makes it easy to revoke just one if
> a machine is ever decommissioned.
### Step 5 — Issue the certificate
```sh
sudo certbot certonly --dns-cloudflare \
--dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini \
-d local-<office>.mydentalofficemanagement.com
```
Certbot adds a temporary DNS TXT record via the API to prove domain ownership, then removes it.
The cert lands at `/etc/letsencrypt/live/local-<office>.mydentalofficemanagement.com/` and
auto-renews via a systemd timer — no manual renewal steps.
### Step 6 — Point nginx at the new cert
Update the LAN server block in `nginx.conf` (`server_name`, `ssl_certificate`,
`ssl_certificate_key`, and the `allow <subnet>;` line) for this office, then reinstall and reload:
```sh
sudo cp nginx.conf /etc/nginx/sites-available/dental-app
sudo nginx -t && sudo systemctl reload nginx
```
### Step 7 — Allow the new hostname in Vite and backend CORS
- `apps/Frontend/vite.config.ts` → add the hostname to `server.allowedHosts`
- `apps/Backend/.env` → add `https://local-<office>.mydentalofficemanagement.com` to
`FRONTEND_URLS`
Staff can now use `https://local-<office>.mydentalofficemanagement.com` with a trusted padlock —
no certificate warnings, no CA install on any PC.
---
## Twilio In-Browser Calling Setup (Dial Pad) ## Twilio In-Browser Calling Setup (Dial Pad)
The dial pad on the Patient Connection page lets staff make real phone calls directly through the browser (mic + speaker) using Twilio Voice SDK. One-time setup is required in the Twilio Console. The dial pad on the Patient Connection page lets staff make real phone calls directly through the browser (mic + speaker) using Twilio Voice SDK. One-time setup is required in the Twilio Console.