# 24/7 Bot Hosting (Free Credit!)

## 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/](https://www.linode.com/lp/free-credit-short/?utm_source=google\&utm_medium=cpc\&utm_campaign=11178784489_109179215203\&utm_term=g_kwd-4269612793_p_linode) 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!](/files/-MhnSqGfTW07BRgJjPFs)

{% hint style="success" %}
Once you've signed up, congratulations! You're set to get your server up and running.
{% endhint %}

## 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

{% hint style="info" %}
Make sure you're currently logged in at Linode's dashboard, at <https://cloud.linode.com/>
{% endhint %}

Start by selecting **Marketplace** on the sidebar of Linode's dashboard.

![Where to find the marketplace](/files/-MhnVRYc6fx9pNFFMS-x)

### 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](/files/-MhnWUb9PyV7p8GrNyFw)

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](/files/-MhowwiHlCNfKTtq9MDu)

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](/files/-MhoxweMCZf_LtcW-OM4)

{% hint style="info" %}
It's a good idea to use Linode's [speedtest page](https://www.linode.com/speedtest) to determine which datacenters would be most suitable with the lowest ping, based on your location.
{% endhint %}

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](/files/-MhozYx1ulzmI8lZejyN)

#### 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](/files/-Mhp-hDVlErP_Lk089Zg)

#### 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](/sponsorships/linode-bot-hosting/creating-an-ssh-key.md).

![Setting a Root Password and Adding an SSH Key](/files/-Mhp0VwJKmjxbGz7KkSt)

#### (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)](/files/-Mhp4E98lGWD0Mt6hUot)

{% hint style="info" %}
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.
{% endhint %}

#### Private IP

It's recommended to enable the Private IP for no additional cost.

![](/files/-Mhp5JtFoalNFEaZaxmR)

{% hint style="success" %}
That's all! Finally, click on **Create Linode** to start provisioning your server.
{% endhint %}

![Click on Create Linode to get your server up and running](/files/-Mhp69byu8FQc_2Aalyi)

{% hint style="success" %}
Congratulations on creating your first Linode!\
You should now see that your Linode is being Provisioned and will shortly start Booting!
{% endhint %}

![Linode Provisioning and Booting the Server](/files/-Mhp6cUrmPaNsUEe7laQ)

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](/files/-Mhr6sG61zNPMQDC-hFi)

## 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**](/sponsorships/linode-bot-hosting.md#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](https://www.docker.com/products/docker-desktop) 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](/files/-Mhr8n450_PIwuGvfmOP)

### 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](/files/-MhtnaFeXxN7-yNn0c9H)

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.**

{% code title="dockerfile" %}

```javascript
FROM node:slim
```

{% endcode %}

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.**

{% code title="dockerfile" %}

```javascript
FROM node:slim

WORKDIR /app
```

{% endcode %}

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.**

{% code title="dockerfile" %}

```javascript
FROM node:slim

WORKDIR /app

COPY package*.json ./
```

{% endcode %}

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.**

{% code title="dockerfile" %}

```javascript
FROM node:slim

WORKDIR /app

COPY package*.json ./

RUN npm install
```

{% endcode %}

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.**

{% code title="dockerfile" %}

```javascript
FROM node:slim

WORKDIR /app

COPY package*.json ./

RUN npm install

COPY . .
```

{% endcode %}

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:

{% code title=".dockerignore" %}

```javascript
node_modules
.env
```

{% endcode %}

{% hint style="warning" %}
Add .env in .dockerignore only if you use dotenv for secret management!
{% endhint %}

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.**

{% code title="dockerfile" %}

```javascript
FROM node:slim

WORKDIR /app

COPY package*.json ./

RUN npm install

COPY . .

CMD [ "npm", "start" ]
```

{% endcode %}

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:

<figure><img src="/files/9HU7AOuwm4uMX4OGtaHU" alt=""><figcaption><p>Here's what our completed dockerfile should look like.</p></figcaption></figure>

### Creating a Docker Image

Start by opening a terminal in your favorite code editor, and enter the command below to build a Docker Image:

```javascript
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**](https://hub.docker.com/) **> Account Settings > Default Privacy, then select Private as your Default Repository Visibility. Lastly, click on Save.**

![Setting the Default Repository Visibility to Private](/files/-MiNqo4Eq31WDz3J_65N)

{% hint style="warning" %}
**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](https://docs.docker.com/registry/deploying/), or by using alternatives to Docker Hub, such as the [GitLab container registry](https://docs.gitlab.com/ee/user/packages/container_registry/).
{% endhint %}

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`.

```javascript
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.**

{% hint style="info" %}
Once logged in, you may get a security warning about your password being stored unencrypted, but you can safely ignore it.
{% endhint %}

#### Tagging the Image as Latest Release \[Recommended]

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:

```javascript
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`

```javascript
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).

{% hint style="success" %}
Nice job! We're almost there. Feel free to enjoy your favorite drink and take a quick break.
{% endhint %}

## 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](https://cloud.linode.com/linodes). Select your newly created Linode server (from [Step 2](/sponsorships/linode-bot-hosting.md#step-2-create-a-linode-server)), and in the overview copy the Server's IPv4 Address:

![Copying our server's IPv4 Address](/files/-MiO-4Y-6P0Km6B8aMRX)

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:

```bash
ssh root@172.104.133.229

(make sure to replace 172.104.133.229 with your server's IPv4 Address)
```

{% hint style="warning" %}
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.
{% endhint %}

![Authenticity of host warning](/files/-MiO1u5l7GhqYhmZqdzD)

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](/sponsorships/linode-bot-hosting.md#configuring-the-server)).

### 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.**

```bash
docker login
```

![Logging in to Docker](/files/-MiO4BQSMKXn8AYLhW8x)

{% hint style="info" %}
Once logged in, you may get a security warning about your password being stored unencrypted, but you can safely ignore it.
{% endhint %}

### Pulling the Image

To pull the Image from our private Docker Repository, simply enter the command `docker pull yourUsername/coolbot:latest`

```bash
docker pull yourUsername/coolbot:latest
```

![Pulling the Image from our private Docker Repository](/files/-MiO5-QxpIoRIeoe00nC)

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.

```bash
docker images
```

![Copy the Image ID, as underlined.](/files/-MiO73qSPAWb_OfVQTkL)

**Finally, to run the Image and configure it to run automatically on boot, execute this command:**\
\&#xNAN;**`docker run -d --restart always [IMAGE ID]`**

{% code title="(make sure to replace 7ea5c0aa7ab5 with your IMAGE ID)" %}

```bash
 docker run -d --restart always 7ea5c0aa7ab5
```

{% endcode %}

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:

| <p>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.<br><strong>Source:</strong> <a href="https://docs.docker.com/config/containers/start-containers-automatically/"><strong><https://docs.docker.com/config/containers/start-containers-automatically/></strong></a></p> |
| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |

{% hint style="success" %}
**...and that's all - your bot should be online and ready to go! Congrats!**\
**To logout of your server, simply enter the command `logout`.**
{% endhint %}

## 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:**\
  \&#xNAN;**`docker run -d --restart always [IMAGE ID]`.**
* **To logout of your server, simply enter the command `logout`.**


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://degore-docs.unitedweco.de/sponsorships/linode-bot-hosting.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
