Some checks failed
CI / skinny-install (aco) (push) Successful in 1m18s
CI / skinny-install (api) (push) Successful in 40s
CI / skinny-install (bcda) (push) Successful in 35s
CI / skinny-install (bib) (push) Successful in 38s
CI / skinny-install (cli) (push) Successful in 46s
CI / skinny-install (conf) (push) Successful in 36s
CI / skinny-install (opps) (push) Successful in 38s
CI / skinny-install (pfs) (push) Successful in 47s
CI / skinny-install (rex) (push) Successful in 35s
Infra CI / notebooks (push) Successful in 3m17s
CI / lint-test (push) Failing after 3m30s
CI / skinny-install (bls) (push) Successful in 34s
CI / skinny-install (ccw) (push) Successful in 45s
CI / skinny-install (cms) (push) Successful in 32s
CI / skinny-install (perf) (push) Successful in 43s
Deploy / build-scan-report (push) Has been cancelled
Infra CI / docs (push) Failing after 20s
Infra CI / api (push) Successful in 16s
Infra CI / mc (push) Successful in 12s
Package Supply Chain / pkg-supply-chain (push) Successful in 1m27s
Infra CI / zotero (push) Successful in 6m10s
252 lines
7.2 KiB
Markdown
252 lines
7.2 KiB
Markdown
# Cloudflare Tunnel + Certs Setup for rig.fhirworx.io
|
|
|
|
## Architecture
|
|
|
|
```
|
|
Internet Your Server (rig)
|
|
┌──────────────────────────────┐
|
|
Users ──→ Cloudflare Edge │ │
|
|
(TLS termination) │ cloudflared ←──outbound──→ CF Edge
|
|
*.rig.fhirworx.io │ │ │
|
|
│ ├─→ rustfs:9000 (S3 API)│
|
|
│ └─→ rustfs:9001 (Console)│
|
|
│ │
|
|
Cloudflare WARP │ warp-svc (DNS/Zero Trust) │
|
|
└──────────────────────────────┘
|
|
```
|
|
|
|
All connections are OUTBOUND from your server. No inbound ports needed
|
|
except SSH (22) for YubiKey management.
|
|
|
|
## Step 1: Cloudflare Dashboard — DNS
|
|
|
|
1. Log into https://dash.cloudflare.com
|
|
2. Select **fhirworx.io** zone
|
|
3. Go to **DNS → Records**
|
|
4. You do NOT need to add A/AAAA records manually — the tunnel creates
|
|
CNAME records automatically. But verify the zone exists and is active.
|
|
|
|
## Step 2: Create the Tunnel
|
|
|
|
1. Go to https://one.dash.cloudflare.com (Zero Trust dashboard)
|
|
2. **Networks → Tunnels → Create a tunnel**
|
|
3. Tunnel name: `rig`
|
|
4. Choose **Cloudflared** connector
|
|
5. You'll get a tunnel token — it looks like:
|
|
```
|
|
eyJhIjoiNGY4...very-long-base64-string
|
|
```
|
|
6. **Copy this token** — you'll need it in Step 4
|
|
|
|
## Step 3: Configure Tunnel Routes (Public Hostnames)
|
|
|
|
Still in the tunnel config, add these public hostnames:
|
|
|
|
| Public Hostname | Service | Notes |
|
|
|----------------|---------|-------|
|
|
| `s3.rig.fhirworx.io` | `http://rustfs:9000` | S3 API endpoint |
|
|
| `console.rig.fhirworx.io` | `http://rustfs:9001` | Web console |
|
|
| `rig.fhirworx.io` | `http://rustfs:9000` | Default/root domain → S3 |
|
|
|
|
For each route:
|
|
- **Type**: HTTP (not HTTPS — cloudflared handles the tunnel encryption,
|
|
the local connection to the container is plaintext over Docker network)
|
|
- **TLS → Origin Server Name**: leave blank
|
|
- **No TLS Verify**: Yes (local traffic, no cert needed)
|
|
|
|
### Optional: Add SSH access through tunnel
|
|
|
|
| Public Hostname | Service | Notes |
|
|
|----------------|---------|-------|
|
|
| `ssh.rig.fhirworx.io` | `ssh://localhost:22` | Browser SSH or cloudflared access |
|
|
|
|
For SSH through tunnel, on the **Access** tab:
|
|
- Create an Access Application for `ssh.rig.fhirworx.io`
|
|
- Add an Access Policy (e.g., email allowlist, one-time PIN)
|
|
- This gives you browser-based SSH as a backup to direct SSH
|
|
|
|
## Step 4: Install the Token on Your Server
|
|
|
|
After `yubikey-unlock`, edit the env file:
|
|
|
|
```sh
|
|
rw
|
|
nano /opt/rustfs/.env
|
|
```
|
|
|
|
Replace `PASTE_YOUR_TOKEN_HERE` with the actual token from Step 2:
|
|
|
|
```
|
|
TUNNEL_TOKEN=eyJhIjoiNGY4...
|
|
```
|
|
|
|
Save and:
|
|
|
|
```sh
|
|
ro
|
|
cd /opt/rustfs && docker compose up -d
|
|
```
|
|
|
|
Verify the tunnel connects:
|
|
```sh
|
|
docker logs cloudflared
|
|
# Should show: "Connection registered" and "Tunnel is connected"
|
|
```
|
|
|
|
## Step 5: SSL/TLS Mode
|
|
|
|
1. In Cloudflare dashboard → **fhirworx.io** → **SSL/TLS → Overview**
|
|
2. Set mode to: **Full**
|
|
- NOT "Full (Strict)" — unless you set up an origin cert (see below)
|
|
- NOT "Flexible" — that's insecure
|
|
- With tunnels, "Full" is fine because the tunnel itself is encrypted
|
|
|
|
If you want "Full (Strict)" (belt AND suspenders), do Step 6.
|
|
|
|
## Step 6: Origin Certificate (Optional)
|
|
|
|
Only needed if:
|
|
- You want Full (Strict) SSL mode, OR
|
|
- You want direct HTTPS access on your LAN to rig.fhirworx.io
|
|
|
|
### Option A: Cloudflare Origin CA (simplest, 15-year validity)
|
|
|
|
1. Dashboard → **fhirworx.io** → **SSL/TLS → Origin Server**
|
|
2. **Create Certificate**
|
|
3. Settings:
|
|
- Key type: **ECDSA**
|
|
- Hostnames: `rig.fhirworx.io`, `*.rig.fhirworx.io`
|
|
- Validity: **15 years**
|
|
4. Copy the PEM certificate and private key
|
|
|
|
On the server:
|
|
```sh
|
|
rw
|
|
|
|
# Paste the certificate
|
|
nano /opt/certs/origin.pem
|
|
|
|
# Paste the private key
|
|
nano /opt/certs/origin-key.pem
|
|
|
|
chmod 644 /opt/certs/origin.pem
|
|
chmod 600 /opt/certs/origin-key.pem
|
|
|
|
ro
|
|
```
|
|
|
|
These certs are ONLY trusted by Cloudflare's edge — browsers connecting
|
|
directly will see a cert warning. That's expected and correct for origin certs.
|
|
|
|
### Option B: Let's Encrypt (trusted everywhere, auto-renews)
|
|
|
|
Use this if you also want trusted HTTPS directly on your LAN.
|
|
|
|
1. Create a Cloudflare API token:
|
|
- https://dash.cloudflare.com/profile/api-tokens
|
|
- **Create Token → Edit zone DNS** template
|
|
- Zone: `fhirworx.io`
|
|
- Copy the token
|
|
|
|
2. On the server:
|
|
```sh
|
|
rw
|
|
|
|
# Save the API token
|
|
cat > /opt/certs/cf-credentials.ini << EOF
|
|
dns_cloudflare_api_token = YOUR_TOKEN_HERE
|
|
EOF
|
|
chmod 600 /opt/certs/cf-credentials.ini
|
|
|
|
# Request the cert
|
|
apk add certbot-dns-cloudflare
|
|
|
|
certbot certonly \
|
|
--dns-cloudflare \
|
|
--dns-cloudflare-credentials /opt/certs/cf-credentials.ini \
|
|
-d "rig.fhirworx.io" \
|
|
-d "*.rig.fhirworx.io" \
|
|
--preferred-challenges dns-01 \
|
|
--non-interactive \
|
|
--agree-tos \
|
|
-m you@fhirworx.io
|
|
|
|
ro
|
|
```
|
|
|
|
Certs land at:
|
|
- `/etc/letsencrypt/live/rig.fhirworx.io/fullchain.pem`
|
|
- `/etc/letsencrypt/live/rig.fhirworx.io/privkey.pem`
|
|
|
|
Auto-renewal cron (add after setup):
|
|
```sh
|
|
rw
|
|
echo "0 3 * * * root mount -o remount,rw / && certbot renew --quiet && mount -o remount,ro /" >> /etc/crontabs/root
|
|
ro
|
|
```
|
|
|
|
## Step 7: Cloudflare WARP (Zero Trust DNS/VPN)
|
|
|
|
The WARP container gives you:
|
|
- DNS-over-HTTPS for all container traffic
|
|
- Option to route through Cloudflare's network
|
|
- Zero Trust device posture (if configured)
|
|
|
|
First run enrollment:
|
|
```sh
|
|
docker exec -it warp-svc warp-cli registration new
|
|
docker exec -it warp-svc warp-cli connect
|
|
```
|
|
|
|
To use WARP as the default DNS for the host:
|
|
```sh
|
|
rw
|
|
echo "nameserver 127.0.0.1" > /etc/resolv.conf
|
|
ro
|
|
```
|
|
|
|
## Step 8: Verify Everything
|
|
|
|
```sh
|
|
# Tunnel status
|
|
docker logs cloudflared
|
|
|
|
# Test S3 endpoint externally
|
|
curl -I https://s3.rig.fhirworx.io
|
|
# Should return 403 (no auth) or 200 with health check
|
|
|
|
# Test console
|
|
curl -I https://console.rig.fhirworx.io
|
|
# Should return 200 or 302 redirect to login
|
|
|
|
# Test from server locally
|
|
curl http://127.0.0.1:9000/minio/health/live
|
|
curl http://127.0.0.1:9001
|
|
|
|
# WARP status
|
|
docker exec warp-svc warp-cli status
|
|
```
|
|
|
|
## DNS Records (auto-created by tunnel)
|
|
|
|
After the tunnel connects, Cloudflare automatically creates:
|
|
```
|
|
s3.rig.fhirworx.io CNAME <tunnel-id>.cfargotunnel.com
|
|
console.rig.fhirworx.io CNAME <tunnel-id>.cfargotunnel.com
|
|
rig.fhirworx.io CNAME <tunnel-id>.cfargotunnel.com
|
|
```
|
|
|
|
You don't need to create these manually.
|
|
|
|
## Summary: What Needs a Cert and What Doesn't
|
|
|
|
| Connection | Encrypted By | Cert Needed? |
|
|
|-----------|-------------|-------------|
|
|
| User → Cloudflare Edge | Cloudflare Universal SSL | No (automatic) |
|
|
| Cloudflare Edge → cloudflared | Tunnel encryption (built-in) | No |
|
|
| cloudflared → RustFS container | Docker internal network (localhost) | No |
|
|
| Direct LAN → RustFS | Nothing (HTTP) or your own cert (HTTPS) | Only if you want LAN HTTPS |
|
|
|
|
**For your setup: you need ZERO certificates.** The tunnel handles everything.
|
|
Origin certs are a nice-to-have for defense in depth or direct LAN access.
|