Even though I’ve used Discord as a platform for many years, and been interested in possibly creating a bot, I had never properly looked into it. That recently changed when one of my most-used bots, Passel, was announced to be discontinued. I discovered that one of the users of the bot had created a fork called
The first important thing I learned about how Discord bots work is that they only serve as an interface with the Discord API. This means that there’s no port-forwarding necessary when trying to host one; all you need is the process to be running constantly, and the bot will work fine. Knowing that, and also knowing that this bot would only be hosted on one server (and therefore not very resource-intensive), I elected to skip on paying DigitalOcean to host the bot and used my Raspberry Pi 3B instead.
passel-js and seeing that it was attempting to be a one-to-one copy of
passel_public rather than adding any new features, I forked the repo and made my own bot with some modifications. I called it Pinsir, with added support for the
dotenv Node module and a few changes to embeds. Using
dotenv was particularly important because the Discord bot token needs to be hidden from the code available on GitHub to prevent bad actors from taking control of your application.
Running the bot on the Pi #
Once I added my code onto the Pi, it was a relatively straightforward process to test the bot and make sure it worked. Using
npm start to test resulted in everything working fine as it should. What took me some time to figure out is how I was to run the bot 24/7.
The answer is a Node module called
pm2, which is a process manager for Node apps. Effectively,
pm2 can be used to “daemonize” an application: make it so that the app only shuts down when the system does, and comes right back online with the system as well. This is accomplished automatically without any manual interference.
I started off with installing the
npm install -g pm2
Then, I run this command to start the application with
pm2 start npm --name "pinsir" -- start
This command uses the
npm start command to run the application while also assigning it a process name of “pinsir”. So, when I run
pm2 list to list all active
pm2 processes, I see this:
$ pm2 list
│ id │ name │ namespace │ version │ mode │ pid │ uptime │ ↺ │ status │ cpu │ mem │ user
│ watching │
│ 0 │ pinsir │ default │ 0.39.1 │ fork │ 31366 │ 21s │ 0 │ online │ 0% │ 48.5mb │ mogg
│ disabled │
To configure the app to start on boot, a few more steps are needed. First,
pm2 startup systemd
which gives the following output:
[PM2] Init System found: systemd
[PM2] To setup the Startup Script, copy/paste the following command:
sudo env PATH=$PATH:/home/malc/.nvm/versions/node/v18.9.0/bin /home/malc/.nvm/versions/node/v18.9.0/lib/node_modules/pm2/bin/pm2 startup systemd -u malc --hp /home/malc
If you run the command that the output gives you,
pm2 will run on boot and immediately start your application. More information on this step can be found on this DigitalOcean tutorial page.
Finishing up #
As I’m still working on Pinsir, I’ll need to roll out updates to it by restarting the process. I can accomplish this with
pm2 restart pinsir
and the bot will start up with the updated code.
Using a Pi beats a subscription fee by far #
If you’re not hosting anything particularly resource-intensive, I found this process to be far better than paying DigitalOcean or some other VPS service. As long as my Raspberry Pi maintains a stable power source and Internet connection, uptime will be solid and the bot will be quite responsive.