Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Install PolarBot (manual)

This page installs PolarBot from source on one Linux server, step by step: every command, what it does and what you should see. It takes about an hour, most of it waiting for the build. The result is exactly what deploy/install.sh sets up; the Reference lists every file and setting by name.

Commands are for Debian/Ubuntu and Fedora; where they differ, both are shown. Lines starting with sudo change the system; the others run as your normal user.

Before you start: you need a Linux server with systemd 250 or newer (Debian 12+, Ubuntu 24.04+, Fedora 38+), about 2 GB of free RAM and 3 GB of disk for the build, and a Discord account that can add bots to your server.

1. Create the Discord application

  1. Open https://discord.com/developers/applications and choose New Application. Give it a name (members will see it as the bot’s name).

  2. On General Information, copy the Application ID. You need it for the invite link.

  3. On Bot:

    • choose Reset Token, copy the token and keep it somewhere safe for step 7. It is shown only once, and anyone with it controls your bot;
    • under Privileged Gateway Intents, enable Presence Intent, Server Members Intent and Message Content Intent. Without them Discord refuses the connection and the bot stops with exit status 78.
  4. Invite the bot to your server: open this link in a browser, with your application ID in it, and pick the server.

    https://discord.com/oauth2/authorize?client_id=<APPLICATION_ID>&scope=bot%20applications.commands&permissions=1099511721094
    

    The number grants exactly: Kick Members, Ban Members, View Audit Log, View Channels, Send Messages, Manage Messages, Embed Links, Read Message History and Timeout Members. Optionally add Manage Server to the bot’s role later so that joins can be attributed to invites at log level 5.

  5. In your server’s settings, drag PolarBot’s role above the roles of members it should be able to moderate. Discord does not let a bot act on members whose top role is above its own.

2. Check the server

systemd --version | head -n1
systemd-creds --version | head -n1

Both print systemd 250 or a higher number (for example systemd 252 (252.33-1~deb12u1)). If systemd-creds is missing or older than 250, this guide does not work on that system: the bot’s secrets are stored with it.

3. Install the build tools

PolarBot is written in Rust. The build also compiles some C code (SQLite and the crypto library), so it needs a C compiler.

Debian/Ubuntu:

sudo apt update
sudo apt install build-essential git curl ca-certificates

Fedora:

sudo dnf install gcc git curl

Then install Rust with rustup, the official installer (PolarBot needs Rust 1.90 or newer, which most distributions do not ship yet). Download the installer, look at it if you like, then run it:

curl --proto '=https' --tlsv1.2 -sSf -o rustup-init.sh https://sh.rustup.rs
sh rustup-init.sh -y --profile minimal
. "$HOME/.cargo/env"
cargo --version

cargo --version prints something like cargo 1.90.0 (…) or newer. (On Fedora you can instead run sudo dnf install rustup and then rustup-init -y --profile minimal.)

4. Get the source

git clone https://github.com/sergeantpolarbear/PolarSystems.git
cd PolarSystems
git checkout stable
git log -1 --oneline

stable is the branch with the released versions. The last command shows the commit you are about to build; the running bot will show the same commit in /about.

5. Build

export POLARBOT_CHANNEL=stable
export POLARBOT_GIT_REV="$(git rev-parse --short HEAD)"
export POLARBOT_BUILD_DATE="$(date -u +%Y-%m-%d)"
cargo build --release --locked -p polarbot
  • The three variables are baked into the binary and shown by /about and the first log line. They are optional; without them the bot reports unknown and channel dev.
  • --locked builds exactly the dependency versions in Cargo.lock.
  • The first build downloads the toolchain components named in rust-toolchain.toml and all dependencies, and takes several minutes.

It ends with a line like:

    Finished `release` profile [optimized] target(s) in 4m 31s

Check the binary:

./target/release/polarbot --help

prints the usage (and exits with status 2, which is expected for --help):

usage: polarbot [--config <path>]
       polarbot export-training --out <file.jsonl> [--config <path>]

6. Install the binary and the config file

sudo install -d -m 0755 /opt/polarbot
sudo install -m 0755 target/release/polarbot /opt/polarbot/polarbot
sudo install -d -m 0755 /etc/polarbot
sudo install -m 0644 deploy/config.toml /etc/polarbot/config.toml
  • /opt/polarbot/polarbot is the program the service runs.
  • /etc/polarbot/config.toml is the config file. The one from deploy/ only sets the log format; every other setting has a sensible default. It must never contain secrets (the bot refuses to start if it does).

If you will set up command visibility (next page), set your public URL now:

sudoedit /etc/polarbot/config.toml

and add:

[web]
public_url = "https://bot.example.org"

with your own host name instead of bot.example.org.

7. Store the secrets

The bot token is stored encrypted with systemd-creds: only systemd can decrypt it, and only for the running service. read -s reads it without showing it and without putting it in your shell history.

sudo -v
read -rsp "Bot token: " TOKEN; echo
printf '%s' "$TOKEN" | sudo systemd-creds encrypt --name=discord_token - /etc/polarbot/discord_token.cred
unset TOKEN
sudo chmod 0600 /etc/polarbot/discord_token.cred

Paste the token from step 1 at the prompt and press Enter. sudo -v asks for your password first, so the password prompt does not get in the way of the pipe. systemd-creds prints nothing, or on its very first use a note that it created the machine’s credential key.

The unit also loads the two OAuth credentials for command visibility. Set them up now with Command visibility: OAuth and nginx (recommended), or, to run without command visibility for now, remove those two lines from the unit in the next step.

8. Install and start the service

sudo install -m 0644 deploy/polarbot.service /etc/systemd/system/polarbot.service

Only if you skip command visibility for now:

sudo sed -i '/^LoadCredentialEncrypted=\(discord_client_secret\|oauth_key\):/d' /etc/systemd/system/polarbot.service

Then:

sudo systemctl daemon-reload
sudo systemctl enable --now polarbot
systemctl status polarbot --no-pager

status shows Active: active (running). The unit runs the bot as a throw-away system user in a strict sandbox and creates the data directory /var/lib/polarbot on first start (see the security model).

9. Check the log

sudo journalctl -u polarbot -n 30 --no-pager

A good start looks like this (shortened):

INFO polarbot: starting polarbot version="0.3.1" rev="1a2b3c4" built="2026-10-22" channel="stable" config=/etc/polarbot/config.toml
INFO polarbot::app: authenticated application=1234… bot=1234…
INFO polarbot::threatlists: no cached list yet kind="threat" source=destroylist
INFO polarbot::app: shards started shards=1
INFO shard{id=[0, 1]}: polarbot::app: connected guilds=1
INFO polarbot::app: registered global commands count=17
INFO polarbot::threatlists: list updated kind="threat" source=destroylist bytes=…
  • no cached list yet is normal on the first start; the lists are downloaded within a minute (list updated) and cached for the next start.
  • Without OAuth credentials you also see OAuth credentials not configured; command visibility sync and the web server are disabled.
  • Global commands can take a few minutes to appear in Discord the first time.

If the service is not running, see Troubleshooting.

10. Set it up in Discord

In your server:

  1. /setup log_channel:#mod-log chooses the log channel for mod cards and logs. PolarBot checks it can post there.
  2. /perms set role:@Moderators level:Moderator (and Admin for your admins) gives your staff roles their levels. Members with Administrator and the server owner are always Owner.
  3. /perms authorize (Owner, after command visibility is set up) so each role sees only its commands.
  4. /scanner status shows the scanner settings. New servers start with the scanner on and actions enabled at the defaults (card from 60, delete from 90, 1 hour timeout from 97). Try it with /scanner analyze text:….

Configure explains the settings in detail.

Shortcut: the install script

Steps 6–8 (and the credentials of the next page) are what deploy/install.sh does in one go. Run it from a directory that contains the built binary as ./polarbot and the deploy/ folder:

cp target/release/polarbot ./polarbot
sudo ./deploy/install.sh

It asks for every missing secret with hidden input, never overwrites an existing config file, backs up the database and keeps the previous binary before it replaces anything. The maintainers use deploy/deploy.sh <ssh-host> from a workstation to copy the source to the server and build it there before running install.sh.