docs: add Cloudflare tunnel setup guide and ports reference
Add step-by-step Cloudflare tunnel setup to README.md with Summit Dental Care as a multi-office example. Create docs/ports.md documenting all service hosts and ports. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
156
README.md
156
README.md
@@ -172,7 +172,7 @@ cd apps/SeleniumService
|
|||||||
## 📖 Developer Documentation
|
## 📖 Developer Documentation
|
||||||
|
|
||||||
- [Setting up server environment](docs/server-setup.md) — the first step, to run this app in environment.
|
- [Setting up server environment](docs/server-setup.md) — the first step, to run this app in environment.
|
||||||
- [Development Hosts & Ports](docs/ports.md) — which app runs on which host/port
|
- [Development Hosts & Ports](docs/ports.md) — which app runs on which host/port, and how to configure `.env` for LAN or single-device access
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -195,3 +195,157 @@ Each package/app is 100% [TypeScript](https://www.typescriptlang.org/) (except t
|
|||||||
- [TypeScript](https://www.typescriptlang.org/) for static type checking
|
- [TypeScript](https://www.typescriptlang.org/) for static type checking
|
||||||
- [ESLint](https://eslint.org/) for code linting
|
- [ESLint](https://eslint.org/) for code linting
|
||||||
- [Prettier](https://prettier.io) for code formatting
|
- [Prettier](https://prettier.io) for code formatting
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Cloudflare Tunnel Setup (Remote Access per Office)
|
||||||
|
|
||||||
|
This connects each office's local app to a public subdomain via a Cloudflare Tunnel — no port forwarding needed, local network access is unchanged.
|
||||||
|
|
||||||
|
**How it works:**
|
||||||
|
- Local network: other office PCs reach the app directly at `http://<machine-ip>:3000`
|
||||||
|
- Internet: anyone reaches the app via `https://<subdomain>.mydentalofficemanagement.com`
|
||||||
|
- Both paths hit the same app simultaneously with no conflict
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Step 1 — Add domain to Cloudflare (done once for all offices)
|
||||||
|
|
||||||
|
> Skip this step if the domain is already on Cloudflare.
|
||||||
|
|
||||||
|
1. Go to `dash.cloudflare.com` → **Add a site** → enter `mydentalofficemanagement.com` (free plan)
|
||||||
|
2. Cloudflare scans existing DNS records — review and keep them
|
||||||
|
3. Cloudflare gives you 2 nameservers (e.g. `holly.ns.cloudflare.com`, `amir.ns.cloudflare.com`)
|
||||||
|
4. Log into **Ionos** → replace the domain's nameservers with Cloudflare's two
|
||||||
|
5. Wait 10–30 min → Cloudflare emails you when active
|
||||||
|
6. DNSSEC: if not purchased on Ionos, it was never enabled — nothing to turn off
|
||||||
|
|
||||||
|
### Step 2 — Install `cloudflared` on the office PC
|
||||||
|
|
||||||
|
Run this in a terminal on the office machine:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -L https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb -o cloudflared.deb
|
||||||
|
sudo dpkg -i cloudflared.deb
|
||||||
|
cloudflared --version
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 3 — Authenticate with Cloudflare
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cloudflared tunnel login
|
||||||
|
```
|
||||||
|
|
||||||
|
A browser window opens → click `mydentalofficemanagement.com` → terminal shows success and saves a certificate to `~/.cloudflared/cert.pem`.
|
||||||
|
|
||||||
|
### Step 4 — Create a tunnel for this office
|
||||||
|
|
||||||
|
Use a unique tunnel name per office:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cloudflared tunnel create <office-tunnel-name>
|
||||||
|
# Example: cloudflared tunnel create summit-dental-app
|
||||||
|
```
|
||||||
|
|
||||||
|
Note the **tunnel ID** (UUID) printed — you need it in Step 5.
|
||||||
|
|
||||||
|
### Step 5 — Create the config file
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo mkdir -p /etc/cloudflared
|
||||||
|
sudo nano /etc/cloudflared/config.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
Paste (replace tunnel ID, credentials path, and subdomain for this office):
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
tunnel: <tunnel-ID>
|
||||||
|
credentials-file: /home/ee/.cloudflared/<tunnel-ID>.json
|
||||||
|
|
||||||
|
ingress:
|
||||||
|
- hostname: <subdomain>.mydentalofficemanagement.com
|
||||||
|
service: http://localhost:3000
|
||||||
|
- service: http_status:404
|
||||||
|
```
|
||||||
|
|
||||||
|
Save: `Ctrl+O` → Enter → `Ctrl+X`.
|
||||||
|
|
||||||
|
### Step 6 — Route DNS for this office's subdomain
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cloudflared tunnel route dns <office-tunnel-name> <subdomain>.mydentalofficemanagement.com
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 7 — Install as a system service (auto-starts on boot)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo cloudflared service install
|
||||||
|
sudo systemctl enable cloudflared
|
||||||
|
sudo systemctl start cloudflared
|
||||||
|
sudo systemctl status cloudflared
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 8 — Allow the subdomain in Vite
|
||||||
|
|
||||||
|
In `apps/Frontend/vite.config.js`, add the subdomain to `server.allowedHosts` so Vite does not block external requests.
|
||||||
|
|
||||||
|
### Step 9 — Allow the subdomain in backend CORS
|
||||||
|
|
||||||
|
In `apps/Backend`, add the subdomain URL to the allowed CORS origins so login and API calls work from the public URL.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Example — Adding Summit Dental Care
|
||||||
|
|
||||||
|
**Office subdomain:** `summitdentalcare.mydentalofficemanagement.com`
|
||||||
|
|
||||||
|
**Step 1:** Already done (domain is on Cloudflare).
|
||||||
|
|
||||||
|
**Step 2:** Install `cloudflared` on Summit Dental's PC.
|
||||||
|
|
||||||
|
**Step 3:** Run `cloudflared tunnel login` on Summit Dental's PC.
|
||||||
|
|
||||||
|
**Step 4:**
|
||||||
|
```bash
|
||||||
|
cloudflared tunnel create summit-dental-app
|
||||||
|
# Example output: Created tunnel summit-dental-app with id a1b2c3d4-...
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 5 — `/etc/cloudflared/config.yml`:**
|
||||||
|
```yaml
|
||||||
|
tunnel: a1b2c3d4-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||||
|
credentials-file: /home/ee/.cloudflared/a1b2c3d4-xxxx-xxxx-xxxx-xxxxxxxxxxxx.json
|
||||||
|
|
||||||
|
ingress:
|
||||||
|
- hostname: summitdentalcare.mydentalofficemanagement.com
|
||||||
|
service: http://localhost:3000
|
||||||
|
- service: http_status:404
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 6:**
|
||||||
|
```bash
|
||||||
|
cloudflared tunnel route dns summit-dental-app summitdentalcare.mydentalofficemanagement.com
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 7:**
|
||||||
|
```bash
|
||||||
|
sudo cloudflared service install
|
||||||
|
sudo systemctl enable cloudflared
|
||||||
|
sudo systemctl start cloudflared
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 8:** Add `summitdentalcare.mydentalofficemanagement.com` to `allowedHosts` in `vite.config.js`.
|
||||||
|
|
||||||
|
**Step 9:** Add `https://summitdentalcare.mydentalofficemanagement.com` to backend CORS allowed origins.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Multi-office overview
|
||||||
|
|
||||||
|
Each office runs its own `cloudflared` tunnel on its own PC. Ports never conflict because each PC is a separate machine.
|
||||||
|
|
||||||
|
| Office | Local access | Public access | Tunnel name |
|
||||||
|
|---|---|---|---|
|
||||||
|
| Community Dentists of Lowell | `http://192.168.1.236:3000` | `https://communitydentistsoflowell.mydentalofficemanagement.com` | `dental-app` |
|
||||||
|
| Summit Dental Care | `http://<its-ip>:3000` | `https://summitdentalcare.mydentalofficemanagement.com` | `summit-dental-app` |
|
||||||
|
| Next office | `http://<its-ip>:3000` | `https://<subdomain>.mydentalofficemanagement.com` | `<office>-app` |
|
||||||
|
|||||||
84
docs/ports.md
Normal file
84
docs/ports.md
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
# Development Hosts & Ports
|
||||||
|
|
||||||
|
This document defines the default **host** and **port** used by each app/service
|
||||||
|
in this turborepo.
|
||||||
|
Update this file whenever a new service is added or port is changed.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Frontend (React + Vite)
|
||||||
|
- **Host:** `localhost` (default)
|
||||||
|
- Use `0.0.0.0` if you need LAN access (phone/other device on same Wi-Fi).
|
||||||
|
- **Port:** `3000`
|
||||||
|
- **Access URLs:**
|
||||||
|
- Local: [http://localhost:3000](http://localhost:3000)
|
||||||
|
- LAN: `http://<your-ip>:3000` (only if HOST=0.0.0.0)
|
||||||
|
|
||||||
|
**Current setup:**
|
||||||
|
Frontend is running on `0.0.0.0` and is accessible via the device IP.
|
||||||
|
|
||||||
|
**`.env` file:**
|
||||||
|
```env
|
||||||
|
NODE_ENV=development
|
||||||
|
HOST=0.0.0.0
|
||||||
|
PORT=3000
|
||||||
|
VITE_API_BASE_URL_BACKEND=http://192.168.1.8:5000
|
||||||
|
```
|
||||||
|
|
||||||
|
`VITE_API_BASE_URL_BACKEND` must point to the backend's IP/port as seen from the browser.
|
||||||
|
Use `localhost` if only accessing from the same machine, or the machine's LAN IP for access from other devices.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Backend (Express.js)
|
||||||
|
- **Host:** `0.0.0.0` (all interfaces)
|
||||||
|
- **Port:** `5000`
|
||||||
|
- **Access URL:** [http://localhost:5000](http://localhost:5000)
|
||||||
|
|
||||||
|
**Current setup:**
|
||||||
|
Runs on all interfaces and allows configured frontend URLs via CORS. Change `FRONTEND_URLS` to match your setup.
|
||||||
|
|
||||||
|
**`.env` file:**
|
||||||
|
```env
|
||||||
|
NODE_ENV="development"
|
||||||
|
HOST=0.0.0.0
|
||||||
|
PORT=5000
|
||||||
|
FRONTEND_URLS=http://localhost:3000,http://192.168.1.8:3000
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Patient Data Extractor Service
|
||||||
|
- **Host:** `localhost`
|
||||||
|
- **Port:** `5001`
|
||||||
|
- **Access URL:** [http://localhost:5001](http://localhost:5001)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Selenium Service
|
||||||
|
- **Host:** `localhost`
|
||||||
|
- **Port:** `5002`
|
||||||
|
- **Access URL:** [http://localhost:5002](http://localhost:5002)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Payment OCR Service
|
||||||
|
- **Host:** `localhost`
|
||||||
|
- **Port:** `5003`
|
||||||
|
- **Access URL:** [http://localhost:5003](http://localhost:5003)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
- `HOST` controls binding: `localhost` = loopback only, `0.0.0.0` = all interfaces (LAN accessible).
|
||||||
|
- `PORT` controls the service's port. Ports never conflict across separate machines — two office PCs can both run on port 5000 with no issue.
|
||||||
|
- Frontend uses `VITE_` prefixed variables for client-side access (e.g. `VITE_API_BASE_URL_BACKEND`).
|
||||||
|
- In production, traffic is routed through Cloudflare Tunnel — see [Cloudflare Tunnel Setup](../README.md#cloudflare-tunnel-setup-remote-access-per-office) in the main README.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Action for developers:**
|
||||||
|
1. Copy `.env.example` → `.env` inside each app folder.
|
||||||
|
2. Adjust `HOST` / `PORT` if your ports are already taken.
|
||||||
|
3. Set `VITE_API_BASE_URL_BACKEND` to the backend's LAN IP if accessing from other devices.
|
||||||
|
4. Run `npm run dev` from the repo root.
|
||||||
Reference in New Issue
Block a user