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!
Last updated
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!
Last updated
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.
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.
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
Once you've signed up, congratulations! You're set to get your server up and running.
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.
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.
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.
You'll notice that at the top-left of the panel, we're actually Creating a Linode. Linodes are pretty much Virtual Private Servers.
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.
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.
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.
Set a label and Tag(s) for your Linode. These don't really matter - it's just to keep everything clean and organised.
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.
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 😅
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.
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.
Congratulations on creating your first Linode! You should now see that your Linode is being Provisioned and will shortly start Booting!
Once your server is ready, you should see the RUNNING status on your Linode's overview
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.
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:
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.
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.
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.
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.
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.
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.
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:
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.
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.
Here's what our final dockerfile should look like:
Start by opening a terminal in your favorite code editor, and enter the command below to build a Docker Image:
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]
.
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.
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
.
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:
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.
It's time to finally Push the Image to the Docker Registry.
Simply enter and run the command 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.
Now that the image is safely on the Docker Registry, we're ready to pull it and download it 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:
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:
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.
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).
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.
Once logged in, you may get a security warning about your password being stored unencrypted, but you can safely ignore it.
To pull the Image from our private Docker Repository, simply enter the command docker pull yourUsername/coolbot:latest
You should now see all the different layers of our Image download, after which the Pull will Complete.
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.
To get our Docker Image's ID, simply enter the command docker images
and copy the IMAGE ID.
Finally, to run the Image and configure it to run automatically on boot, execute this command:
docker run -d --restart always [IMAGE ID]
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:
...and that's all - your bot should be online and ready to go! Congrats!
To logout of your server, simply enter the command logout
.
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
.
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/