Files
velox-bot/docs/self-hosting.md
T
FernandoJVideiraandClaude Sonnet 5.5 02b7db1813 Docs: say plainly that only the bot is open source; the dashboard and API are proprietary
- README, license section and architecture no longer point to the dashboard repositories
- schema.sql is the schema for contributors; database changes only need schema.sql and a note in the PR
- self-hosting: settings without a dashboard (SQL for security thresholds, beta settings, opted-in servers)
- beta features, deployment and troubleshooting reworded for people who don't have the dashboard

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
2026-10-23 01:54:08 +01:00

9.4 KiB

Host your own bot

This guide takes you from a clean server to your own Velox running under your own Discord application. It uses Docker Compose, which is the simplest way. For the Discord side in more detail, see Getting started. For a short run on your own machine while developing, see that page too.

You will run:

  • The bot (this repository). It needs PostgreSQL.
  • PostgreSQL, started by the same Compose file.
  • Optionally Lavalink, if you want music.

The hosted Velox also has a web dashboard. It is proprietary and not part of this repository, so it is not something you can host. You do not need it. See Settings without a dashboard.

Before you start

You need:

  • A Linux server (or any machine that is always on) with Docker and Docker Compose. The bot itself is a small static Go binary and needs little. Lavalink is a Java program and needs noticeably more memory, so size the server for it if you want music.
  • A Discord account that can create an application.
  • A way to reach the server over SSH, and a firewall that does not expose PostgreSQL.

You do not need a domain name or an open port. The bot only makes outgoing connections to Discord (and to Lavalink and Twitch if you use them).

1. Create your Discord application

Follow step 1 of Getting started. You end up with:

  • an application ID (APP_ID),
  • a bot token (BOT_TOKEN), which is a password: never commit it or paste it anywhere public,
  • the Server Members and Message Content privileged intents switched on.

Invite your bot with this link, replacing YOUR_APP_ID:

https://discord.com/oauth2/authorize?client_id=YOUR_APP_ID&scope=bot%20applications.commands&permissions=1460577627318

The number is the set of permissions the bot uses across all its modules: View Channels, Send Messages, Embed Links, Attach Files, Read Message History, Use External Emojis, Manage Messages, Manage Roles, Manage Channels, Manage Server, Kick Members, Ban Members, Moderate Members, View Audit Log, Create Private Threads, Send Messages in Threads, Manage Threads, Connect, Speak and Move Members. If you never use a module you can leave its permissions out. The permission table says which module needs which.

After inviting, drag the bot's role above the roles it should manage and the members it should moderate. Discord does not let a bot change anyone whose highest role is above its own.

2. Get the code

git clone <this repository> velox-bot
cd velox-bot

3. Configure

Create a file called .env next to docker-compose.yml:

BOT_TOKEN=paste-your-bot-token
APP_ID=paste-your-application-id
# Register commands in one server (appear at once). Leave empty to register
# them globally, which Discord can take up to an hour to show.
GUILD_ID=paste-a-server-id
# Used for Twitch live alerts. Required to start, even if you never use them
# (any value works then). See "Twitch" below.
TWITCH_CLIENT_ID=unused

You do not set DB_HOST here: the Compose file points the bot at its own database. Change the database password, though. In docker-compose.yml, replace velox_pwd in two places (the db service's POSTGRES_PASSWORD and the default DB_HOST of the bot service), or set DB_HOST in .env yourself:

DB_HOST=postgres://velox:A-LONG-RANDOM-PASSWORD@db:5432/velox?sslmode=disable

and set the same password for POSTGRES_PASSWORD. Then remove the ports: - "5432:5432" lines of the db service so the database is only reachable from the bot.

.env holds secrets. Keep it out of version control (it is already in .gitignore) and readable only by you: chmod 600 .env.

4. Start the database and load the schema

docker compose up -d db
docker compose exec -T db psql -U velox -d velox < schema.sql

The schema file can be run again at any time, it only creates what is missing.

5. Start the bot

docker compose up -d --build bot
docker compose logs -f bot

You should see the bot connect and no errors. In your server, type /ping. If the commands do not appear, see Troubleshooting.

The Compose file restarts the bot automatically (restart: unless-stopped), including after a reboot of the server, as long as Docker starts at boot (sudo systemctl enable docker).

6. Turn modules on

Nothing is on by default. Follow Turn modules on.

Music (optional)

Music needs a Lavalink server. Add it to docker-compose.yml:

  lavalink:
    image: ghcr.io/lavalink-devs/lavalink:4
    container_name: velox-lavalink
    restart: unless-stopped
    environment:
      LAVALINK_SERVER_PASSWORD: ${LAVALINK_PASSWORD}
    # Not published: only the bot, on the same Compose network, needs it.

and put the password in .env:

LAVALINK_PASSWORD=another-long-random-password

The Compose file already defaults LAVALINK_HOST to ws://lavalink:2333 for the bot, so the two find each other. Restart with docker compose up -d.

Two things to know:

  • Lavalink 4 does not play from every source out of the box. Playing from YouTube needs a source plugin configured in Lavalink. See Lavalink's own documentation for what is current, since it changes.
  • Members need a role named exactly DJ to use the music commands.

Twitch alerts (optional)

Twitch live alerts check streamers every 30 seconds, using Twitch's web GraphQL endpoint with the client ID you set in TWITCH_CLIENT_ID. That is not Twitch's official API and Twitch can change or block it without notice. If you do not use alerts, leave the value as is and never set a notification channel.

Keeping it running

Updates.

git pull
docker compose up -d --build bot

Read the release notes first. Releases that add tables need schema.sql run again (it only creates what is missing, and is safe to repeat) before the bot restarts, and a release that changes an existing table says so in its notes. Slash commands update themselves when the bot starts.

Backups. Everything the bot stores is in PostgreSQL:

docker compose exec -T db pg_dump -U velox velox > velox-backup-$(date +%F).sql

Run it on a schedule and keep copies off the server. To restore into an empty database, load the file with psql.

Logs. docker compose logs -f bot. Docker keeps logs without limit by default. Set a log size limit for the bot service (logging options in Compose) if the server is small.

Rotating the token. If the bot token ever leaks, reset it in the developer portal at once, put the new one in .env and run docker compose up -d bot.

Growing past 100 servers

Discord requires you to verify your application once the bot is in 100 servers, and to be approved for the privileged intents (Server Members, Message Content). Plan for that if you intend to run a public bot. For a bot in a few servers you manage yourself, nothing is needed.

Settings without a dashboard

The bot works fully on its own, and every command in the Command reference does. Most things are set with slash commands. A few settings that the hosted Velox sets on its dashboard have no command, so you set them in the database. They are plain rows, described in schema.sql.

Security thresholds and filters. The defaults are in security_settings. To change a server's settings, insert or update its row (the columns are documented in schema.sql, and invalid values are refused):

INSERT INTO security_settings (guild_id, raid_join_count, raid_join_seconds)
VALUES (123456789012345678, 15, 10)
ON CONFLICT (guild_id) DO UPDATE
SET raid_join_count = EXCLUDED.raid_join_count, raid_join_seconds = EXCLUDED.raid_join_seconds;

Protections are switched on with /security toggle, not with SQL.

Beta features. Beta features are off until you choose a beta server and a Beta Tester role. Run this once, with your own IDs (the bot reads it every 30 seconds):

INSERT INTO beta_settings (id, guild_id, role_id) VALUES (TRUE, 123456789012345678, 234567890123456789)
ON CONFLICT (id) DO UPDATE SET guild_id = EXCLUDED.guild_id, role_id = EXCLUDED.role_id;

To let another server's beta features on, add it (its owner's agreement is yours to arrange):

INSERT INTO beta_guilds (guild_id, enabled_by) VALUES (345678901234567890, 123456789012345678)
ON CONFLICT DO NOTHING;

See Beta features for what this does.

Queue and panel requests. The *_commands tables let another program ask the bot to skip a song, post the ticket panel or end a raid. See Database if you want to build something on them.

Making it your own

  • Change the bot's name and avatar in the developer portal.
  • /help is hand-written text in internal/commands/help/help.go. Its author link points at the original project, so change it to your own repository.
  • The name "Velox" in this code is just a name. You may rename it, and under the license you must keep the copyright notices (LICENSE, NOTICE) and say what you changed. Please do not present your fork as the original project.

Something went wrong

Troubleshooting covers the usual problems: the bot not starting, commands not appearing, permissions, and music.