4.5 KiB
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 | <Server 1 IP> |
| Weight | 1 |
| Health Check | (create new, see below) |
Create Origin Pool — Pool 2 (Server 2)
| Field | Value |
|---|---|
| Pool name | appwrite-node2 |
| Origin Address | <Server 2 IP> |
| 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.
# 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_PASSinmigrate.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_MEvalues in.env - Create
traefik-tls.ymlin 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.