Discord Bot & Cloud Relay
Saba-chan Discord bot configuration and the cloud relay pairing flow that lets you control your server without port forwarding.
Discord Bot & Cloud Relay
The Saba-chan Discord bot is an official bot operated on the cloud relay server. You don't need to run a bot process or manage a Discord token yourself — just invite the official bot to your guild and pair it once with a code issued from the Saba-chan GUI.
This document is based on the bot implementation in server-chan/relay-server.
1. How It Works
┌────────────┐ ┌──────────────────┐ ┌────────────┐
│ User │ slash command │ Official bot │ HMAC-signed │ User PC │
│ (Discord) │ ──────────────▶│ (in relay server)│ ──────────────▶│ Saba-chan │
└────────────┘ └──────────────────┘ long-poll │ daemon │
▲ └────────────┘
└──────────── result ──────────────┘
- The bot itself runs inside the relay server process. Nothing bot-related is installed on the user PC.
- The Saba-chan daemon attaches to the relay server with long-polling to fetch commands.
- All bot ↔ relay ↔ daemon traffic uses outbound HTTPS only. No router port forwarding is required.
2. Pairing
Pairing registers a host (the Saba-chan daemon) and nodes (Discord guilds) on the relay server. It finishes with a single code entry.
2.1 Flow Diagram
(1) GUI (2) Relay Server
│ POST /api/relay/pair/initiate │
│ ──────────────────────────────────────────────────────────▶ │
│ │ generates a 32-char code + 48-char pollSecret
│ ◀────────────────────────────────────────────────────────── │ (5-min TTL)
│ { code, pollSecret } │
│ │
│ user types the code in Discord chat │
│ │
│ (3) Discord Bot │
│ POST /api/pair/{code}/claim
│ (includes the guild ID)
│ │
│ creates host/node │
│ + issues token │
│ │
│ (4) GUI polls every 3 seconds │
│ GET /api/relay/pair/{code}/status?secret={pollSecret} │
│ ──────────────────────────────────────────────────────────▶ │
│ ◀────────────────────────────────────────────────────────── │ atomic swap: token is returned exactly once
│ { status: "claimed", token: "sbn_{hostId}.{secret}" } │
│ │
│ GUI → saves to %APPDATA%\saba-chan\.node_token │
- The pairing code is 32 characters;
pollSecretis 48 characters. TTL is 5 minutes. - The token is returned exactly once (atomic swap). The GUI must persist it to
.node_tokenimmediately upon receipt. Even if it leaks in transit, it can't be reused before re-issuance.
2.2 GUI-side Steps
- On the GUI's "Cloud Mode" screen, click Issue code.
- Copy the 32-character code that appears.
- Make sure the official Saba-chan bot is invited to your Discord guild (the GUI links to the invite).
- Pass the code to the bot via the
/사바쨩 연결 <code>slash command in Discord. - The GUI screen, polling every 3 seconds, switches to "Connected." At the same time
.node_tokenis persisted.
Once paired, the daemon keeps a long-poll connection to the relay server automatically. There is no separate bot start/stop step.
2.3 Unpairing
- Click "Unpair" in the GUI → the daemon deletes
.node_tokenand notifies the relay server to release the host. - Alternatively, manually deleting
.node_tokenand restarting Saba-chan has the same effect.
3. Bot Slash Commands
Key slash commands exposed by the official bot:
| Command | Action |
|---|---|
/사바쨩 연결 <code> | Register the pairing code → bind the guild as a node and the daemon as a host |
/사바쨩 상태 | Show which host the current guild is bound to and what instances are active |
/사바쨩 권한부여 <user> | Grant the given Discord user permission to use bot commands |
/사바쨩 권한해제 <user> | Revoke the permission |
4. Chat Commands (prefix)
Once paired, you can drive servers from any Discord text channel using prefix-based commands.
사바쨩 <command> <module_or_alias> [args…]
The default prefix is 사바쨩 (it literally means "Saba-chan"). It can be changed per host from the GUI; changes are propagated to the bot immediately.
Default built-in commands:
| Command | Description |
|---|---|
start | Starts the instance for the given module. Example: 사바쨩 start minecraft |
stop | Stops the instance |
status | Queries status (Running / Stopped / Crashed, etc.) |
Aliases (moduleAliases / commandAliases) are defined on the GUI's Bot settings screen. Saba-chan syncs them to the relay server, and the bot picks them up immediately. See the Commands document for the full command list.
5. Music Features
Music playback is handled by the official music server (music-server) running alongside the relay server.
- When you run a command like
사바쨩 음악 재생 …, the bot delegates to the music server, which streams audio into the Discord voice channel. - You don't need to install ffmpeg/yt-dlp on your PC.
- If
musicChannelIdis configured, music commands are only accepted in that text channel.
6. Security Model
Every bot ↔ user-daemon request is signed with the following headers:
Authorization: Bearer sbn_{hostId}.{secret}
X-Request-Timestamp: <unix epoch>
X-Request-Nonce: <UUID>
X-Request-Signature: HMAC_SHA256(
METHOD + "\n" + PATH + "\n" +
TIMESTAMP + "\n" + NONCE + "\n" +
BODY,
secret
)
The relay server compares the secret against an Argon2 hash and verifies the timestamp window (±30s), nonce uniqueness, and the signature. All checks must pass for the request to be accepted.
7. Troubleshooting
| Symptom | Cause / Resolution |
|---|---|
| Bot doesn't respond | Check the prefix (default 사바쨩) and that there is a space after it. Make sure the bot is invited to the guild and pairing has completed |
사바쨩 start … → "module not found" | Check moduleAliases settings, or the actual module_name. Note that the argument is the module name, not an instance |
| Pairing code expired | The 5-minute TTL elapsed. Re-issue from the GUI |
Polling status stays pending | The /사바쨩 연결 slash command never reached the bot. Verify the bot is online in your guild |
| Relay request 401 | .node_token is empty, or the signed timestamp is off by more than 30 seconds (check the system clock) |
| Relay request 409 (nonce duplicate) | Local clock skew / replay-attack protection triggered. Verify time synchronization |
For more detailed troubleshooting flows, see the Troubleshooting document.