Links

24/7 Bot Hosting (Free Credit!)

Here's a tutorial on how to get started with hosting your bot on Linode for free by claiming $100 in credit for free, and enjoy enterprise-grade hosting for bots of all sizes!

Introduction

Linode's powerful datacenters have been hosting DeGore's core infrastructure with an impressive 99.99% uptime, and we can confirm that Linode is amongst the best choices for cloud server hosting, to power your discord bot of any size.

Have you been looking for an intuitive and reliable host for your Discord bot? Then you've come to the right place. Read along and we'll get your bot hosted 24/7 on Linode's servers for no initial cost. This tutorial will focus on how to host your NodeJS bot, however it can be easily adapted for all other languages.

Why Linode?

Linode offers impeccable value when it comes to virtual private servers. For just $5 a month, you can utilize their high performance cloud computing infrastructure with free bundled support, transfer, DDoS Protection and much more for the most affordable prices. The best part is that once your product or service becomes super popular and you may need to upgrade your server, with Linode you can upgrade your system's hardware and scale with just a few clicks. The servers also come bundled with many great useful features, such as automatic backups, automatic server re-starts in the case of a crash and even more. I've been using Linode and my experience with them so far has been excellent. Their support team is also notably incredibly fast and helpful, ready to support you 24/7.

Step 1: Create an account on Linode

Let's get started! To begin, visit Linode's site at https://linode.com/ and click on Sign Up. Ensure to use the link above so you can claim $100 in free credit, to get you started. Plus, when you use that link it helps us out too :D
Linode's landing page, where you can sign up to get started!
Once you've signed up, congratulations! You're set to get your server up and running.

Step 2: Create a Linode Server

We'll be utilizing Docker in order to streamline the process of sending updates to your server. To make our lives easier, we'll be creating a server with docker pre-installed, thanks to Linode's nifty Marketplace.

The Marketplace

Make sure you're currently logged in at Linode's dashboard, at https://cloud.linode.com/
Start by selecting Marketplace on the sidebar of Linode's dashboard.
Where to find the marketplace

Choosing the Docker App

The Docker App consists of a ready-to-go server with Docker pre-installed. This'll save us the trouble of installing Docker manually, as it's all set-up.
In the Marketplace, look for the Docker App and click on it.
Selecting the Docker App in the Marketplace
You'll notice that at the top-left of the panel, we're actually Creating a Linode. Linodes are pretty much Virtual Private Servers.

Configuring the Server

Scroll down past the Advanced Options (we won't need them for this tutorial), and select Debian 10 as your server's image. This will ensure that Docker will be installed on the latest supported Debian Operating system. If at the time that you're reading this, there's a newer version of Debian, then I'd highly suggest you choose that instead, to stay up-to-date.
Selecting the Debian 10 Server Image
Next, Select a Region. This depends on where you are located - it's often best to choose the server region closest to you, to reduce latency. In my case, since the Frankfurt datacenters are closest to me, I'll be selecting Frankfurt, DE.
Selecting your Linode's datacenter location
It's a good idea to use Linode's speedtest page to determine which datacenters would be most suitable with the lowest ping, based on your location.
Now, you can choose your plan. Linode offers a wide range of many server specifications, built so you can scale whenever necessary. We'll be choosing the $5/mo Shared CPU plan, to get started. Note that you can always upgrade/downgrade your plan and scale your server accordingly at any time, even after creating your server.
Choosing your Linode Plan

Server Customization

Set a label and Tag(s) for your Linode. These don't really matter - it's just to keep everything clean and organised.
Setting a Label and adding Tag(s) to your Linode

Server Security

Now's the time to set your Root Password and SSH key(s) to your Linode. You'll be using the Root Password to log in to your Linode, in case you lose access to your SSH Key. You'll also be prompted to enter this password if you're trying to perform any actions with sudo. SSH keys are optional, but recommended for additional security. To create an SSH Key, simply follow the quick guide here.
Setting a Root Password and Adding an SSH Key

(Optional) Server Backups

You can optionally enable server backups for your server for an additional $2/mo. I'd recommend enabling them, to ensure that your data is protected and backed up, should anything go wrong and you need to roll back your server. Better safe than sorry 😅
Enabling Backups (Optional)
There's no need to enable a Private IP yet, but it might come in handy if you're planning on scaling your bot between multiple servers - you won't have to connect to the internet to communicate if both servers are at the same datacenter location.

Private IP

It's recommended to enable the Private IP for no additional cost.
That's all! Finally, click on Create Linode to start provisioning your server.
Click on Create Linode to get your server up and running
Congratulations on creating your first Linode! You should now see that your Linode is being Provisioned and will shortly start Booting!
Linode Provisioning and Booting the Server
Once your server is ready, you should see the RUNNING status on your Linode's overview
Here's what your server should look like after a successful setup

Step 3: Creating a Docker Image

If you've already created a docker image, you can skip this part of the tutorial and go straight to Step 4: Pulling the Docker Image. If not, follow along as I show you how to create yourself a docker image and push it to the Docker Hub.

Installing Docker Desktop

Visit Docker's website to download Docker Desktop on your device. Once installed, launch Docker Desktop. It may take some time for the Docker Engine to startup for the first time. Make sure to signup to Docker Hub, and skip the Tutorial, if prompted. You should then see a screen similar to this one:
The Docker Desktop Client

Configuring the Dockerfile

In your favorite editor, create a new file called dockerfile in the root of your project's folder. We'll be using this file to provide Docker with instructions on what to do when building your Docker Image.
Creating your dockerfile
Let's start by specifying a docker baseImage. Think of this as a pre-built docker image from the Docker registry which we can use as a base for our project. Since our bot relies on NodeJS, we'll be using the officially supported node:slim NodeJS baseImage. Note that we use the slim node package, which is a more slimmed-down, optimized version of node ideal for production environments which takes up less storage too. Enter the code FROM node:slim in the first line of your dockerfile to specify our baseImage.
dockerfile
FROM node:slim
Next, we'll need to add our app's source code to the Image. To do this, we'll be using the WORKDIR working directory instruction. Enter the code WORKDIR /app on the next line of your dockerfile to specify our working directory. Any subsequent instructions in our dockerfile will start from this app directory.
dockerfile
FROM node:slim
WORKDIR /app
Let's install our dependencies next, so they can be cached. This will prevent the fuss of having to re-install all our node_modules every time we change our app's source code. Let's use the COPY instruction, which takes two arguments: Our local package.json location, and the place we want to copy it in the container (which is the current working directory). Enter the code COPY package*.json ./ in the next line of your dockerfile to do this.
dockerfile
FROM node:slim
WORKDIR /app
COPY package*.json ./
Now that we have a package.json, we can run the npm install command. This is just like opening a terminal session and running a command. Enter the code RUN npm install in the next line of your dockerfile.
dockerfile
FROM node:slim
WORKDIR /app
COPY package*.json ./
RUN npm install
When finished, the results will be committed to the docker image as a layer. Now that we have our modules in the image, we can then copy over our source code, which we'll do by copying all of our local files into our current working directory. Enter the code COPY . . in the next line of your dockerfile.
dockerfile
FROM node:slim
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
Now, you may be asking, won't that also copy over our node_modules folder? You're right. We don't want this, as the node_modules folder here in our local filesystem, that would also be copied over to the image and override the node_modules that we install there.
To avoid this, we'll be creating a .dockerignore file & add node_modules as well as .env to it. It works just like a .gitignore file, which you've probably seen before. Here's what your .dockerignore file should look like:
.dockerignore
node_modules
.env
Add .env in .dockerignore only if you use dotenv for secret management!
So at this point, we have our source code in the image. But in order to run it we'll be using the keyword COMMAND. there can only be one of these for every dockerfile, and it tells the container how to run the actual application. Enter the code CMD [ "npm", "start" ] in the next line of your dockerfile.
dockerfile
FROM node:slim
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
CMD [ "npm", "start" ]
You'll also notice that unlike RUN we've made this command an array of strings. This is known as exec form, and it's the preferred way to do things. Unlike a regular command, it doesn't start up a shell session.

Resulting Dockerfile

Here's what our final dockerfile should look like:
Here's what our completed dockerfile should look like.

Creating a Docker Image

Start by opening a terminal in your favorite code editor, and enter the command below to build a Docker Image:
docker build -t yourUsername/coolbot:1.0 .
The command is docker build, and we pass the option -t in order to add a nametag to your image that's easy to remember, so you can access it later. When defining the tag name, it's recommended to enter your username followed by /imagename:version.number . You should also add a version number, separated by a colon. From there you simply add the path to your dockerfile, which in our case is just a . for the current working directory.
Hit enter to run the command, and you'll notice that it starts with Step 1, which is to pull the node:slim image remotely. Then it goes through each step in our dockerfile, and it should finally say successfully built [image ID].

Pushing the Image

Before we begin, it's a good idea to set the default visibility of our Docker Repositories to private. This'll help keep our environment variables and any code which explicitly states our bot's token secure. To set our Default Repository Visibility to Private, go to the Docker Hub > Account Settings > Default Privacy, then select Private as your Default Repository Visibility. Lastly, click on Save.
Setting the Default Repository Visibility to Private
Note that the Docker Hub offers just one private repository on the free tier. To get more, you'll have to upgrade. However, you can always work around this in the future by either creating and hosting your own docker registry, or by using alternatives to Docker Hub, such as the GitLab container registry.
We're all set! Let's push this Image.
To push the Docker Image, let's first make sure you're logged in to the Docker Registry on the terminal. To login, open a new terminal and enter the command docker login.
docker login
You'll be prompted to enter your credentials (Username and Password). When entering the password, it may seem as though no text is being entered, but rest assured it's being entered (this is a security feature).
Once you've typed in your Username and Password, hit enter once more and you should be good to go.
Once logged in, you may get a security warning about your password being stored unencrypted, but you can safely ignore it.
In order to push our Image to the Docker Hub, it's always best practice to tag the image as the latest release of our program (in this case our bot). To do this, we'll use the docker image tag command:
docker image tag yourUsername/coolbot:1.0 yourUsername/coolbot:latest
You'll notice that we enter docker image tag followed by the same Image tag as we gave it in the previous step, after which we enter the new tag we want to assign to this Docker Image. In this case, it's the same [username]/[imagename], followed by a colon for the version number, where we enter latest. This'll allow us to easily push updates in the future, by assigning the :latest tag to newer versions of the bot when we want to publish changes / an update to our bot's code. In the future, we'll be able to pull and run just the latest version of the code, instead of having to manually pull each version separately, look for the latest version, and run that, again and again.

Let's Push

It's time to finally Push the Image to the Docker Registry. Simply enter and run the command docker push yourUsername/coolbot:latest
docker push yourUsername/coolbot:latest
The Docker Image should start pushing to the Registry. This'll take some time, depending on your network speed (usually takes around 5-10 minutes for my bot).
Nice job! We're almost there. Feel free to enjoy your favorite drink and take a quick break.

Step 4: Pulling the Docker Image

Now that the image is safely on the Docker Registry, we're ready to pull it and download it to our Linode server.

Logging in to our Linode Server

To begin, get your server's public IP Address via the Linode Cloud Dashboard. Select your newly created Linode server (from Step 2), and in the overview copy the Server's IPv4 Address:
Copying our server's IPv4 Address
Next, open a new terminal and enter the command ssh root@[your server IP]. Make sure to enter your server's IPv4 Address which you had just copied right after the @ symbol. Here's what my command looks like:
(make sure to replace 172.104.133.229 with your server's IPv4 Address)
You may receive a warning stating that the authenticity of the host can't be established. This is for security, and you must enter yes and hit enter to allow the connection to be established.
Authenticity of host warning
If your SSH key is detected, you should log in straight away into your Linode Server! If you haven't created an SSH key, you'll be prompted to enter your Linode Server's password (which you set here).

Logging in to Docker

In order to access our private Docker Registry, we'll need to login with our docker Username and Password. To login, we'll (once again) enter the command docker login, and follow the instructions prompted.
docker login
Logging in to Docker
Once logged in, you may get a security warning about your password being stored unencrypted, but you can safely ignore it.

Pulling the Image

To pull the Image from our private Docker Repository, simply enter the command docker pull yourUsername/coolbot:latest
docker pull yourUsername/coolbot:latest
Pulling the Image from our private Docker Repository
You should now see all the different layers of our Image download, after which the Pull will Complete.

Step 5: Running the Docker Image 24/7

When paired with Linode's Shutdown Watchdog (also known as Lassie), all we need to do is run our Docker Image and set it to start back up on boot, using two simple commands.

Getting our Image ID

To get our Docker Image's ID, simply enter the command docker images and copy the IMAGE ID.
docker images
Copy the Image ID, as underlined.
Finally, to run the Image and configure it to run automatically on boot, execute this command: docker run -d --restart always [IMAGE ID]
(make sure to replace 7ea5c0aa7ab5 with your IMAGE ID)
docker run -d --restart always 7ea5c0aa7ab5
This'll run your Image, and set it to always restart, regardless of the cause of the program stopping/crashing. As the Docker Docs say, using the flag always indicates to:
Always restart the container if it stops. If it is manually stopped, it is restarted only when Docker daemon restarts or the container itself is manually restarted. Source: https://docs.docker.com/config/containers/start-containers-automatically/
...and that's all - your bot should be online and ready to go! Congrats! To logout of your server, simply enter the command logout.

Handy Commands

  • To login to your server, simply enter ssh root@[IPv4].
  • To view your currently running containers, simply enter docker ps.
  • To view your currently pulled Images, simply enter docker images.
  • To stop a currently running container, simply enter docker stop [IMAGE ID].
  • To run an Image and configure it to run automatically on boot, execute this command: docker run -d --restart always [IMAGE ID].
  • To logout of your server, simply enter the command logout.