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; pollSecret is 48 characters. TTL is 5 minutes.
  • The token is returned exactly once (atomic swap). The GUI must persist it to .node_token immediately upon receipt. Even if it leaks in transit, it can't be reused before re-issuance.

2.2 GUI-side Steps

  1. On the GUI's "Cloud Mode" screen, click Issue code.
  2. Copy the 32-character code that appears.
  3. Make sure the official Saba-chan bot is invited to your Discord guild (the GUI links to the invite).
  4. Pass the code to the bot via the /사바쨩 연결 <code> slash command in Discord.
  5. The GUI screen, polling every 3 seconds, switches to "Connected." At the same time .node_token is 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_token and notifies the relay server to release the host.
  • Alternatively, manually deleting .node_token and restarting Saba-chan has the same effect.

3. Bot Slash Commands

Key slash commands exposed by the official bot:

CommandAction
/사바쨩 연결 <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:

CommandDescription
startStarts the instance for the given module. Example: 사바쨩 start minecraft
stopStops the instance
statusQueries 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 musicChannelId is 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

SymptomCause / Resolution
Bot doesn't respondCheck 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 expiredThe 5-minute TTL elapsed. Re-issue from the GUI
Polling status stays pendingThe /사바쨩 연결 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.