# Cloudflare Load Balancer + Origin Certificate Setup ## Architecture ``` Internet │ HTTPS (Cloudflare proxied) ▼ Cloudflare Load Balancer ──health check: /v1/health──► Server 1 (Primary) └──► Server 2 (Secondary) Both servers: Traefik → Appwrite ``` --- ## 1. Cloudflare SSL/TLS Mode Dashboard → your domain → **SSL/TLS → Overview** Set mode to: **Full** Traefik on each server uses Let's Encrypt automatically (same as your current setup). Cloudflare "Full" mode accepts these valid LE certificates. No manual certificate management needed. --- ## 3. Create the Load Balancer Requires Cloudflare **Pro** plan or higher (Load Balancing is a paid add-on). ### Create Origin Pool — Pool 1 (Server 1) Dashboard → **Traffic → Load Balancing → Manage Pools → Create Pool** | Field | Value | |---|---| | Pool name | `appwrite-node1` | | Origin Address | `` | | Weight | 1 | | Health Check | (create new, see below) | ### Create Origin Pool — Pool 2 (Server 2) | Field | Value | |---|---| | Pool name | `appwrite-node2` | | Origin Address | `` | | Weight | 1 | | Health Check | same health check | ### Health Check Configuration | Field | Value | |---|---| | Name | `appwrite-health` | | Monitor Type | HTTPS | | Path | `/v1/health` | | Port | 443 | | Interval | 60 seconds | | Retries | 2 | | Expected status codes | 200 | ### Create Load Balancer Dashboard → **Traffic → Load Balancing → Create Load Balancer** | Field | Value | |---|---| | Hostname | `hostsuite.teamhup.com` | | Fallback Pool | `appwrite-node1` | | Traffic Steering | **Random** (both servers active simultaneously) | Add both pools. With Random steering: - Both servers receive traffic normally - If one fails health checks, all traffic goes to the healthy one automatically --- ## 4. WebSocket / Realtime Considerations Appwrite realtime uses WebSockets (`/v1/realtime`). Cloudflare supports WebSockets by default on proxied records — no extra config needed. However, if a user's WebSocket connection is on Server 1 and the next HTTP request goes to Server 2, that's fine — WebSocket sessions are stateless (backed by Redis). No sticky sessions needed. --- ## 5. Firewall Rules on Both Servers Allow inbound traffic **only from Cloudflare IP ranges** on ports 80 and 443. This prevents direct access bypassing Cloudflare. ```bash # Get current Cloudflare IPs # IPv4: https://www.cloudflare.com/ips-v4 # IPv6: https://www.cloudflare.com/ips-v6 # Example with ufw: ufw default deny incoming ufw allow ssh # Allow Cloudflare IPv4 ranges (update these periodically) for ip in \ 173.245.48.0/20 \ 103.21.244.0/22 \ 103.22.200.0/22 \ 103.31.4.0/22 \ 141.101.64.0/18 \ 108.162.192.0/18 \ 190.93.240.0/20 \ 188.114.96.0/20 \ 197.234.240.0/22 \ 198.41.128.0/17 \ 162.158.0.0/15 \ 104.16.0.0/13 \ 104.24.0.0/14 \ 172.64.0.0/13 \ 131.0.72.0/22; do ufw allow from $ip to any port 80,443 proto tcp done ufw enable ``` --- ## 6. Deployment Checklist ### On current server (before cutover) - [ ] Fill in `MANAGED_DB_HOST`, `MANAGED_DB_USER`, `MANAGED_DB_PASS` in `migrate.sh` - [ ] Stop Appwrite: `docker compose down` - [ ] Run migration: `./migrate.sh` - [ ] Verify managed DB has all tables and S3 has all files ### On Server 1 (Primary) - [ ] Copy project files: `compose-node1.yml`, `.env.ha` (rename to `.env`), `certs/` - [ ] Fill in `CHANGE_ME` values in `.env` - [ ] Create `traefik-tls.yml` in config volume (see section 1) - [ ] Install Cloudflare Origin Certificate in `certs/` - [ ] `docker compose -f compose-node1.yml up -d` - [ ] Verify: `curl -k https://localhost/v1/health` ### On Server 2 (Secondary) - [ ] Copy same files: `compose-node2.yml`, `.env` (identical to Server 1), `certs/` - [ ] `docker compose -f compose-node2.yml up -d` - [ ] Verify: `curl -k https://localhost/v1/health` ### Cloudflare - [ ] Create origin pools pointing to both server IPs - [ ] Create health check on `/v1/health` - [ ] Create load balancer for `hostsuite.teamhup.com` - [ ] Set SSL mode to Full (strict) - [ ] Test failover by stopping one server and confirming traffic continues --- ## 7. DNS Update Once the load balancer is created, Cloudflare manages the DNS automatically (the LB hostname replaces the A record). You don't need to manually update DNS. If you previously had `hostsuite.teamhup.com` as an A record pointing to `51.38.129.81`, the load balancer creation will replace it.