60c1c8770e
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
135 lines
6.3 KiB
Markdown
135 lines
6.3 KiB
Markdown
# DiscordBot-CloudflareWarp
|
|
|
|
A small [discord.js](https://discord.js.org/) bot that runs **entirely inside Docker** and sends all of its
|
|
traffic through a **Cloudflare WARP** (Cloudflare One / Zero Trust client) tunnel. Every container runs its
|
|
own WARP client, so every bot gets its own VPN tunnel and its own Cloudflare egress IP. The bot proves it is
|
|
still on Cloudflare by logging the egress IP and `warp=on` flag on startup, on a timer and on demand.
|
|
|
|
Nothing runs on the host except Docker: `npm install` happens in the image build, and the lockfile was
|
|
generated inside a `node:22-bookworm-slim` container.
|
|
|
|
## How it works
|
|
|
|
```
|
|
+-------------------------------------------------------------+
|
|
| container: discordbot-warp |
|
|
| |
|
|
| dbus -> warp-svc (Cloudflare WARP daemon, TUN device) |
|
|
| ^ |
|
|
| entrypoint.sh: register -> mode warp -> connect -> verify |
|
|
| | |
|
|
| node src/index.js ---- all traffic ----> WARP tunnel ---> Cloudflare ---> Discord
|
|
+-------------------------------------------------------------+
|
|
```
|
|
|
|
1. `docker/entrypoint.sh` starts `dbus` and `warp-svc`, creates (or reuses) a WARP registration, sets
|
|
`mode warp`, connects and waits until `warp-cli status` says `Connected`.
|
|
2. It then calls `https://www.cloudflare.com/cdn-cgi/trace` and **refuses to start the bot** unless
|
|
Cloudflare reports `warp=on` (or `warp=plus`). The egress IP and colo are logged.
|
|
3. `bot/src/index.js` logs into Discord and every `WARP_CHECK_INTERVAL` seconds (default 60) asks
|
|
Cloudflare's edge over IPv4 (`1.1.1.1`) and IPv6 (`2606:4700:4700::1111`) what it sees, logging a line like:
|
|
|
|
```
|
|
[2026-09-08T00:20:15.123Z] [WARP] CONNECTED via Cloudflare (periodic) ipv4=104.28.x.x (warp=on) ipv6=2a09:bac1:xxxx::x:x (warp=on) colo=AMS loc=NL | warp-cli: Status update: Connected Network: healthy
|
|
```
|
|
|
|
If the tunnel drops it logs `NOT CONNECTED` and runs `warp-cli connect` to recover.
|
|
4. A Docker `HEALTHCHECK` performs the same `warp=on` check, so `docker ps` shows `unhealthy` if the
|
|
container ever falls off Cloudflare.
|
|
|
|
### Slash commands
|
|
|
|
| Command | What it does |
|
|
|---------|-------------------------------------------------------------------------------|
|
|
| `/ping` | Replies with round-trip and gateway latency. |
|
|
| `/warp` | Runs a live tunnel check and replies with the Cloudflare IP, colo and status. |
|
|
|
|
## Repository layout
|
|
|
|
```
|
|
bot/
|
|
package.json, package-lock.json Node project (discord.js 14)
|
|
src/index.js the bot
|
|
docker/
|
|
Dockerfile node:22-bookworm-slim + cloudflare-warp .deb
|
|
entrypoint.sh boots WARP, verifies, then execs the bot
|
|
docker-compose.yml one service per bot, each with its own WARP tunnel
|
|
scripts/deploy.sh ships the committed tree to the Docker host and restarts the stack
|
|
.env.example configuration template
|
|
CHANGELOG.md every change, newest first
|
|
```
|
|
|
|
## Requirements
|
|
|
|
* A Docker host (tested on Debian 12 with Docker 20.10 and Compose v5) with `/dev/net/tun` available.
|
|
* Containers need `NET_ADMIN` and the TUN device. Both are set in `docker-compose.yml`.
|
|
* A Discord bot token from the [Developer Portal](https://discord.com/developers/applications).
|
|
|
|
The Cloudflare WARP client is downloaded during the image build from
|
|
`https://downloads.cloudflareclient.com/v1/download/bookworm-intel/version/<WARP_VERSION>`
|
|
(`WARP_VERSION` defaults to `2026.7.1377.0`, the Debian 12 build).
|
|
|
|
## Quick start (on the Docker host)
|
|
|
|
```bash
|
|
git clone https://gitea.ikbengino.nl/ginoblij/DiscordBot-CloudflareWarp.git
|
|
cd DiscordBot-CloudflareWarp
|
|
cp .env.example .env # put your DISCORD_TOKEN in .env
|
|
docker compose up -d --build
|
|
docker compose logs -f
|
|
```
|
|
|
|
You should see the entrypoint report the tunnel, then the bot log in:
|
|
|
|
```
|
|
[entrypoint] warp-svc is up
|
|
[entrypoint] no registration found, creating a new one
|
|
[entrypoint] mode set to warp
|
|
[entrypoint] warp-cli status: Status update: Connected
|
|
[entrypoint] WARP tunnel verified: ip=104.28.x.x warp=on colo=AMS
|
|
[entrypoint] starting bot: node src/index.js
|
|
[bot] logged in as ... in 1 guild(s)
|
|
[WARP] CONNECTED via Cloudflare (startup) ipv4=104.28.x.x (warp=on) ipv6=2a09:bac1:xxxx::x:x (warp=on) colo=AMS loc=NL ...
|
|
```
|
|
|
|
## Configuration (`.env`)
|
|
|
|
| Variable | Default | Meaning |
|
|
|-----------------------|---------|----------------------------------------------------------------------|
|
|
| `DISCORD_TOKEN` | | Bot token. Required. |
|
|
| `WARP_CHECK_INTERVAL` | `60` | Seconds between tunnel checks logged by the bot. |
|
|
| `GUILD_ID` | | Register slash commands in one guild (instant) instead of globally. |
|
|
| `WARP_MODE` | `warp` | `warp-cli mode` to use (`warp`, `doh`, `warp+doh`, ...). |
|
|
| `WARP_CONNECT_TIMEOUT`| `60` | Seconds the entrypoint waits for `Connected` before giving up. |
|
|
|
|
## Running more than one bot (one VPN per container)
|
|
|
|
Each service in `docker-compose.yml` is an independent container with its own `warp-svc`, its own
|
|
registration volume and therefore its own tunnel and egress IP. To add a bot:
|
|
|
|
1. Create `.env.bot2` with the second token.
|
|
2. Uncomment the `bot2` service and the `warp-data-bot2` volume in `docker-compose.yml`.
|
|
3. `docker compose up -d --build`.
|
|
|
|
## Deploying from this repo
|
|
|
|
`scripts/deploy.sh` sends the **committed** tree (`git archive HEAD`) to the host over SSH, rebuilds the
|
|
image there and restarts the stack. The `.env` on the host is never touched or overwritten.
|
|
|
|
```bash
|
|
scripts/deploy.sh # defaults to root@192.168.5.67:/opt/discordbot-cloudflarewarp
|
|
scripts/deploy.sh user@host /some/dir
|
|
```
|
|
|
|
## Checking the tunnel by hand
|
|
|
|
```bash
|
|
docker compose exec bot warp-cli --accept-tos status
|
|
docker compose exec bot curl -s https://www.cloudflare.com/cdn-cgi/trace
|
|
docker compose logs -f | grep WARP
|
|
```
|
|
|
|
## Change history
|
|
|
|
See [CHANGELOG.md](CHANGELOG.md). Every change is committed and pushed with a changelog entry.
|