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
-
Open https://discord.com/developers/applications and choose New Application. Give it a name (members will see it as the bot’s name).
-
On General Information, copy the Application ID. You need it for the invite link.
-
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.
-
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=1099511721094The 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.
-
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
/aboutand the first log line. They are optional; without them the bot reportsunknownand channeldev. --lockedbuilds exactly the dependency versions inCargo.lock.- The first build downloads the toolchain components named in
rust-toolchain.tomland 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/polarbotis the program the service runs./etc/polarbot/config.tomlis the config file. The one fromdeploy/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 yetis 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:
/setup log_channel:#mod-logchooses the log channel for mod cards and logs. PolarBot checks it can post there./perms set role:@Moderators level:Moderator(andAdminfor your admins) gives your staff roles their levels. Members with Administrator and the server owner are always Owner./perms authorize(Owner, after command visibility is set up) so each role sees only its commands./scanner statusshows 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.