Skip to content

Commit 41847b6

Browse files
committed
Publish logviewer via Cloudflare Tunnel
Add a cloudflared service to the Oracle deployment so the logviewer is served on a custom domain over HTTPS with no inbound ports. Drop the public logviewer port mapping, add TUNNEL_TOKEN config, and rewrite the guide for the Cloudflare Zero Trust tunnel flow. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013vqQJQAud7rmfykwWKJACY
1 parent 33a5085 commit 41847b6

3 files changed

Lines changed: 66 additions & 33 deletions

File tree

deploy/oracle/.env.example

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ OWNERS=Owner1ID,Owner2ID
1515
CONNECTION_URI=mongodb+srv://user:pass@cluster.mongodb.net/modmail
1616

1717
# Public URL where the logviewer is reachable, used in generated log links.
18-
# Set this to your VM's public IP (or domain) on port 8000, e.g.:
19-
# http://123.45.67.89:8000
20-
LOG_URL=http://YOUR_VM_PUBLIC_IP:8000
18+
# With Cloudflare Tunnel this is your domain over HTTPS, e.g.:
19+
# https://logs.yourdomain.com
20+
LOG_URL=https://logs.yourdomain.com
21+
22+
# Cloudflare Tunnel token. Create a tunnel in the Cloudflare Zero Trust
23+
# dashboard (Networks -> Tunnels), route your hostname to http://logviewer:8000,
24+
# then copy the connector token here. See deploy/oracle/README.md.
25+
TUNNEL_TOKEN=your-cloudflare-tunnel-token

deploy/oracle/README.md

Lines changed: 40 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
# Deploying Modmail to Oracle Cloud
22

33
This guide moves your Modmail bot (this fork) and the Logviewer onto an Oracle
4-
Cloud **Always Free** VM, while continuing to use your **existing MongoDB**.
4+
Cloud **Always Free** VM, while continuing to use your **existing MongoDB**. The
5+
logviewer is published on your own domain via a **Cloudflare Tunnel**, so no
6+
inbound ports are exposed.
57

68
What you get:
79
- `bot` — built from this repo's `Dockerfile`, so your fork's changes are
8-
included and the image is native to the VM's ARM64 architecture.
9-
- `logviewer` — the web UI for closed-thread log links, served on port `8000`.
10+
included and the image is native to the VM's architecture.
11+
- `logviewer` — the web UI for closed-thread log links.
12+
- `cloudflared` — a Cloudflare Tunnel that serves the logviewer at your domain
13+
over HTTPS, with no open ports on the VM.
1014
- No database container — the bot and logviewer both point at your current
1115
`CONNECTION_URI`.
1216

@@ -23,20 +27,26 @@ In the [OCI Console](https://cloud.oracle.com/) → **Compute → Instances →
2327
- `VM.Standard.E2.1.Micro` (x86, 1 OCPU / 1 GB RAM) — logviewer runs natively;
2428
`setup.sh` adds a swap file to handle the 1 GB limit during image builds.
2529
- **SSH keys:** upload/download a key pair so you can log in.
26-
- Note the instance's **public IP** after it boots.
2730

28-
## 2. Open the firewall (cloud side)
31+
With a Cloudflare Tunnel you do **not** need to open any ingress ports in the OCI
32+
Security List — the tunnel connects outbound. (Port `22` for SSH is open by
33+
default.)
2934

30-
The instance firewall is handled by `setup.sh`, but the cloud network is separate.
35+
## 2. Create the Cloudflare Tunnel
3136

32-
In the OCI Console → **Networking → Virtual Cloud Networks → your VCN → your
33-
subnetSecurity List → Add Ingress Rules**:
37+
In the [Cloudflare Zero Trust dashboard](https://one.dash.cloudflare.com/)
38+
**NetworksTunnels**:
3439

35-
| Source CIDR | Protocol | Dest. Port | Purpose |
36-
|-------------|----------|------------|---------------|
37-
| `0.0.0.0/0` | TCP | `8000` | Logviewer |
38-
39-
(Port `22` for SSH is usually open by default.)
40+
1. **Create a tunnel** → choose **Cloudflared** → give it a name (e.g. `modmail`).
41+
2. On the install screen, **copy the tunnel token** — it's the long string in the
42+
shown `cloudflared ... run <TOKEN>` command. You don't run that command; the
43+
`cloudflared` container uses the token. Save it for step 4.
44+
3. Add a **Public Hostname**:
45+
- **Subdomain / Domain:** e.g. `logs` + your Cloudflare-managed domain.
46+
- **Type:** `HTTP`
47+
- **URL:** `logviewer:8000` (the container name + port — they share the
48+
Docker network)
49+
4. Save. Cloudflare auto-creates the DNS record and HTTPS cert for that hostname.
4050

4151
## 3. Install Docker on the VM
4252

@@ -67,17 +77,19 @@ Fill in:
6777
- `TOKEN`, `GUILD_ID`, `OWNERS` — same values as your old host.
6878
- `CONNECTION_URI` — your **existing** MongoDB URI (nothing migrates; the bot
6979
just reconnects to the same database).
70-
- `LOG_URL``http://YOUR_VM_PUBLIC_IP:8000`
80+
- `LOG_URL` — your tunnel hostname, e.g. `https://logs.yourdomain.com`
81+
- `TUNNEL_TOKEN` — the token you copied in step 2.
7182

7283
## 5. Launch
7384

7485
```bash
7586
docker compose up -d --build
76-
docker compose logs -f bot # watch it connect to Discord
87+
docker compose logs -f bot # watch it connect to Discord
88+
docker compose logs cloudflared # should show "Registered tunnel connection"
7789
```
7890

79-
You should see the bot log in. Closed-thread log links will resolve at
80-
`http://YOUR_VM_PUBLIC_IP:8000`.
91+
Open `https://logs.yourdomain.com` in a browser — the logviewer should load.
92+
Closed-thread log links will now use that domain.
8193

8294
## 6. Decommission the old host
8395

@@ -96,15 +108,15 @@ cd deploy/oracle && docker compose up -d --build
96108
## Troubleshooting
97109

98110
- **Bot won't start / DB errors:** double-check `CONNECTION_URI` and that your
99-
MongoDB/Atlas network access list allows the VM's public IP.
111+
MongoDB/Atlas network access list (Atlas → Network Access) allows the VM's
112+
public IP.
113+
- **Logviewer domain shows Cloudflare error 502/1033:** the tunnel can't reach
114+
the logviewer. Confirm the Public Hostname URL is exactly `logviewer:8000`,
115+
and that `docker compose logs cloudflared` shows a registered connection.
116+
- **`cloudflared` keeps restarting:** the `TUNNEL_TOKEN` is wrong or missing —
117+
re-copy it from the tunnel's install screen.
100118
- **Logviewer container exits with "exec format error" on the ARM VM:** the
101-
upstream `logviewer` image may not publish an `arm64` variant. Two fixes:
102-
1. Add emulation, then retry:
103-
`sudo apt install -y qemu-user-static binfmt-support` and add
104-
`platform: linux/amd64` under the `logviewer` service in
105-
`docker-compose.yml`; **or**
106-
2. Use an x86 shape (`VM.Standard.E2.1.Micro`, also Always Free) for the VM so
107-
the upstream image runs natively.
108-
- **Can't reach the logviewer in a browser:** confirm both the OCI Security List
109-
rule (step 2) *and* the instance firewall (`setup.sh`) allow port `8000`.
110-
```
119+
upstream `logviewer` image may not publish an `arm64` variant. Either add
120+
`platform: linux/amd64` under the `logviewer` service (with
121+
`sudo apt install -y qemu-user-static binfmt-support`), or use the
122+
`VM.Standard.E2.1.Micro` x86 shape so the image runs natively.

deploy/oracle/docker-compose.yml

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,21 @@ services:
2828
environment:
2929
# Logviewer reads MONGO_URI; reuse the same database the bot writes to.
3030
- MONGO_URI=${CONNECTION_URI}
31-
ports:
32-
- "8000:8000"
31+
# No public port: Cloudflare Tunnel reaches the logviewer privately over the
32+
# Docker network at http://logviewer:8000. To test locally without the
33+
# tunnel, temporarily add: ports: ["8000:8000"]
34+
35+
# Cloudflare Tunnel: makes an OUTBOUND connection to Cloudflare, so the
36+
# logviewer is published at your domain with automatic HTTPS and no inbound
37+
# ports opened. Create the tunnel in the Cloudflare Zero Trust dashboard,
38+
# route your hostname to the service http://logviewer:8000, and paste the
39+
# tunnel token into TUNNEL_TOKEN in .env. See README.md.
40+
cloudflared:
41+
image: cloudflare/cloudflared:latest
42+
container_name: modmail-cloudflared
43+
restart: always
44+
command: tunnel --no-autoupdate run
45+
environment:
46+
- TUNNEL_TOKEN=${TUNNEL_TOKEN}
47+
depends_on:
48+
- logviewer

0 commit comments

Comments
 (0)