How to deploy Django project on fly.io for free
• • ☕️ 7 min readIf you just want to try it yourself without reading about my experience, clone the repo and follow the readme.
https://github.com/tomwojcik/django-fly.io-example-project
Why I’ve decided to give Fly.io a shot
On August 25th 2022 Heroku announced they’re removing the free tier. There are a few great and cheap PaaS alternatives, but Fly is the only one that comes close to Heroku feature parity and is the only one with free tiers for a simple fullstack project (that I know of).
A few months earlier, on January 20th 2022, Fly.io announced Postgres (and SQLite) free tier. That was the day I considered them to be my next PaaS provider for the first time. It’s a great feeling to “just click” and have a database provisioned for free, which used to be the killer feature of Heroku. There are a few differences though.
In the Free Postgres databases for small projects
Fly announcement post on HN, jamiegreen asked
Not sure if this is a dumb question but is this basically the same as Heroku? What’s the difference?
Kurt Mackey, the CEO of Fly.io, answered:
We’re different, but only because we were builtin 2020 instead of 2008. Notably:
- You get your own Postgres process and disk, no shared database instances
- Private networking is baked in. Your app talks to postgres over an encrypted private network
- You can provision persistent disks and run basically anything you want
- We support arbitrary TCP and UDP services, not just HTTP. We’re also substantially cheaper.
Sounds great. On the other hand, Heroku is superior when it comes to WAL based restore system. It allows you to restore the DB to a specific point in time. For a side project it’s usually not a requirement, but if it’s something you need and you still want to use Fly.io, it’s better to use another, external DB provider.
Note, you were able to host a DB for free on their infrastructure even before that and you still can. All you have to do is launch a fly app using postgres docker image. That’s probably what they do themselves anyway, but chances are you’d rather hand over the provisioning part entirely to 3rd party.
Running hello_django
project on Fly.io
To validate that Fly works as expected, I wanted to set up a free service myself. Even though Fly has a special org on GitHub whose sole purpose is to set up examples of projects using different frameworks, the one with Django is rather empty (at the time of writing this).
I don’t think it makes sense to copy-paste the project setup steps from the repository readme file to this blogpost. Just follow the readme.
https://github.com/tomwojcik/django-fly.io-example-project#want-to-try-it-yourself
Some observations
I can’t 100% confirm that, but I remember running a medium-sized project on Heroku and both Django and Celery dynos with 2.5GB RAM (Performance M) were using ~500MB when idle. This minimal Django project on Fly uses only 100MB-200MB of memory. Again, it’s not exactly apples to apples, but I’m surprised anyway. I think Fly doesn’t include docker memory footprint. Or maybe there was additional penalty when running a dockerized app on Heroku… I don’t know. Just my observation.
A few years ago I tried to set up Django and Celery on a single dyno and IIRC it’s not possible on Heroku, but you can do that on Fly. If you’re thinking about running both on a single instance, see Running Multiple Processes Inside A Fly.io App . Though I can’t say that’s a good idea…
Heroku runs on AWS. Fly runs on their own infra. One could say that AWS is so big that it’s better to rely on them but the truth is you can rely on both. When it comes to pricing though… you pay premium on Heroku, because they need to use 3rd party for infra. That’s why Fly pricing is more appealing.
Problems I run into when experimenting with Fly
I run into a few small problems with Fly. It’s entirely possible that some of them would be gone if I tried doing the same thing while being a paid customer. It’d make perfect sense if they had different limits for free tier.
~ flyctl version
flyctl v0.0.398 linux/amd64 Commit: 34b4b13d BuildDate: 2022-09-27T18:19:47Z
1. Command flyctl launch
doesn’t work well for Django projects
Maybe I wasn’t able to make it work because I already had fly.toml
file populated as well as Dockerfile
, but I kept running into different problems, depending on the state of my project locally.
~ flyctl launch
An existing fly.toml file was found for app hello-django
? Would you like to copy its configuration to the new app? Yes
Creating app in /home/tom/PycharmProjects/django-fly.io-example-project
Scanning source code
Detected a Django app
? Overwrite "/home/tom/PycharmProjects/django-fly.io-example-project/Dockerfile"? No
? App Name (leave blank to use an auto-generated name): hello-django
Automatically selected personal organization: Tomasz Wójcik
? Select region: fra (Frankfurt, Germany)
Created app hello-django in organization personal
Set secrets on hello-django: SECRET_KEY
Creating database migrations
Error failed running /home/tom/PycharmProjects/django-fly.io-example-project/venv/bin/python manage.py makemigrations: exit status 2
I have no idea why would it try to run makemigrations
. I grepped over the entire project and found no makemigrations
in docker entrypoints or the Dockerfile.
The above launch
command identified the framework
Scanning source code
Detected a Django app
I’d assume that flyctl launch
would be framework agnostic, so maybe the problem was somewhere else? I don’t know and I don’t care as I found a more suitable workaround. Even though the docs recommend to start with launch
, you can split it into two steps.
- First create the placeholder for your app
flyctl apps create
. - Then deploy using
fly.toml
flyctl deploy
.
2. I might have run into some limits when deleting and creating free apps, although there was no meaningful error
When I was experimenting with the most suitable combination of yaml.toml
, flyctl
commands and the Dockerfile
, I kept deleting apps over and over.
At one point I’ve had one DB that I haven’t touched in a longer moment (haven’t deleted the instance) and a Django app that I kept deleting and recreating from scratch. Sometimes I was reusing the old name, sometimes I was just appending -<number>
to the name.
After a few consecutive delete-create repetitions, I wasn’t able to attach my DB to the app. Sadly, I didn’t save flyctl
output and I don’t remember the exact steps, but it’s something to have in mind. My assumption is that they have a pretty low caps for free tier, or they don’t remove apps instantly. Maybe if you click delete
and the app is no longer visible in the UI, it’s still there somewhere with an active attachment to the DB and there’s a cap on the attachments? I don’t know.
The next day I went through this process again and it was working fine.
3. Remote builder is very fragile.
When running Github action, I run into
Error failed to fetch an image or build from source: error connecting to docker: remote builder app unavailable
Apparently it’s not a new issue. Under some circumstances fly api can’t make the remote worker do the actual work. You need to manually remove the free worker app and rerun the deployment. That’s what they recommend on the forum and that’s what fixed it for me.
I deployed the app using github actions a few times. It was always failing (at least 3 times) when the worker was idle, and it hasn’t failed once when the worker app didn’t exist (it had to be recreated).
Conclusions
My experience with Fly.io is still very limited, but for me, they are far superior to Heroku.
I don’t care about the Heroku plugins marketplace, which is the only “feature” Fly doesn’t have, that could be considered a killer feature (IMO). These days you either use a Docker image and self-provision a solution or buy a solution from another vendor without a crazy markup fee.
I run everything I can using Docker and it shows that Fly.io is built with Docker in mind. I sure hope this platform matures over time and they become a Heroku replacement for most.