Hosting a Python Discord Bot for Free with Fly.io
Tags: python, discord, bot, cloud
Published: 2022-08-29 01:11:00

## Intro

As Heroku is no longer going to be free after November 28, 2022, I am sharing another way to host a Discord bot 24/7 for free.

You will be able to host any kind of bot on Fly.io with few limitations by following the steps below. You can also optionally attach a PostgreSQL database for storing data.

## Deploying a Python Discord Bot to [Fly.io](https://fly.io/)

This article was originally a video tutorial, which you can check out here:

{% youtube J7Fm7MdZn_E %}

### 1. Install the `flyctl` command line tool

#### Mac OS

If you have the [Homebrew](https://brew.sh) package manager installed, flyctl can be installed by running:

```cmd
brew install flyctl
```

If not, you can run the install script:

```cmd
curl -L https://fly.io/install.sh | sh
```

#### Windows

Run the Powershell install script:

```cmd
iwr https://fly.io/install.ps1 -useb | iex
```

#### Arch Linux

Run the package installer:

```bash
yay -S flyctl-bin
```

#### Linux

Run the install script:

```cmd
curl -L https://fly.io/install.sh | sh
```

More info: https://fly.io/docs/getting-started/installing-flyctl/

### 2. Create an account by running `flyctl auth signup` and finishing through the browser

After installing flyctl, you should now be able to use it in the command line. Use `flyctl auth signup` to launch your browser and complete the account creation steps. If you already have an account, you can use `flyctl auth login`.

### 3. Add a `Dockerfile` with the Python version and dependency install method
    
#### Method 1: requirements.txt

Create a list of your dependencies in a `requirements.txt`. You can find out what you have installed using `pip freeze`.

Discord.py example:

```
discord.py>=2.0.0,<3
python-dotenv==0.20.0
```

Nextcord example:

```
nextcord>=2.1.0,<3
python-dotenv==0.20.0
```

To tell Fly.io to install these dependencies, create a file called `Dockerfile` (no file extension) with the following contents:

```dockerfile
FROM python:3.11
WORKDIR /bot
COPY requirements.txt /bot/
RUN pip install -r requirements.txt
COPY . /bot
CMD python bot.py
```

In this case `python bot.py` is the command used to run the bot. If your bot starts in a different file, you should change that here.

#### Method 2: Using Poetry

If you are using Poetry for dependencies, your `Dockerfile` will look more like this:

```dockerfile
FROM python:3.11
RUN pip install poetry
WORKDIR /bot
COPY . /bot/
COPY poetry.lock pyproject.toml /bot/
RUN poetry config virtualenvs.create false && poetry install --no-interaction --no-ansi
CMD python bot.py
```
*Poetry Dockerfile is based on [this tutorial](https://replicate.com/blog/build-a-robot-artist-for-your-discord-server-with-stable-diffusion) by Replicate.com. Thanks Abraham Murciano for the correction.*

### 4. `flyctl launch`

In the project folder, run `flyctl launch`

Give your project a name, type Y or N depending on if you want a Postgresql database or not, type N to not have it deploy.

This will create a `fly.toml`, but you can delete most of it so that it looks similar to this:

```toml
app = "my-bot-name"  # your bot's app name
primary_region = "den"  # a region of your choice

[[services]]
  internal_port = 8080
  protocol = "tcp"
  auto_start_machines = true
  auto_stop_machines = false  # prevent automatic suspension
  min_machines_running = 1  # keep a machine running at all times
```

### 5. `flyctl deploy`

Type `flyctl deploy` to deploy the first version!

Once it is completed, your bot will be running on Fly.io!

### 6. Set the environment vars

If you will be deploying your bot without your `.env` or configuration files, you will need to set secrets for fly.io to know about.

This will include all environment variables, for example:
```cmd
flyctl secrets set DISCORD_TOKEN=My.TOken.3213.example LOG_CHANNEL_ID=1234567890
```

See https://fly.io/docs/reference/secrets/#setting-secrets

You're done!

To deploy further versions, you can run `flyctl deploy` or see below for automatic deploys from GitHub.

> **Note:** If your bot is responding to commands twice, this may mean your bot is running on multiple machines. To fix this, try running the command `fly scale count 1` in order to remove the extra machine(s). Also, you should ensure your bot is only running in one location; you should not run the bot on fly.io and locally or on another host at the same time.

---

## Continuous deployment from GitHub

You can find the video for this part here:

{% youtube 6u9BrDaSHJc %}

1. Run `flyctl auth token` to get a Fly API token
2. Go to your repo's `Settings > Secrets > Actions` and click `New repository secret`
3. Enter `FLY_API_TOKEN` as the name and your token from step 1 as the value
4. Create a folder, `.github/workflows/` and inside create a file that uses the flyctl action on push. You may name it what you like, for example, `fly.yml`.

Example `fly.yml`:
```yml
name: Fly Deploy
on:
  push:
    branches:
      - main

env:
  FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}

jobs:
  deploy:
    name: Deploy app
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: superfly/flyctl-actions/setup-flyctl@master
      - run: flyctl deploy --remote-only
```

Make sure the branch name is correct for your default branch.

More info: https://fly.io/docs/app-guides/continuous-deployment-with-github-actions/

---

## Conclusion

Thanks for reading!

I hope you found this tutorial useful.

Check out the full video for further explanations and be sure to like and subscribe!

Part 1 (Setup and Hosting) - https://youtu.be/J7Fm7MdZn_E

Part 2 (Continuous Deployment) - https://youtu.be/6u9BrDaSHJc

\- Jonah Lawrence

GitHub: [DenverCoder1](https://github.com/DenverCoder1)

YouTube: [Jonah Lawrence - Dev Pro Tips](https://www.youtube.com/channel/UCipSxT7a3rn81vGLw9lqRkg)

Discord server: https://discord.gg/fPrdqh3Zfu