Deploying miniflux to fly.io with machines
a low-cost alternative to traditional hosting with minimal deployment steps
9 min read
miniflux is a great, minimal feed-reader that you can self-host in the cloud. But we don't want to just put it on any ordinary cloud server.
Today we will look at how we can get it deployed to
fly.io using something called machines. Under the hood, these are Firecracker VMs that start under 300ms. If you never used
fly.io before, this could be your starting point to try it out and see how operations and especially deployment can be reduced to a minimum.
At the end of this article, you will have a working miniflux installation along with a Postgres database that is hosted on
fly.io as a private instance. The docs suggest that you can run a basic 256MB Postgres Database with 1GB persistent storage in the free tier. There is also a hobby tier, when you link a credit card to your account. A fun story is that they don't bill you for costs below $5, which is convenient because my gitea instance costs me around $2 per month. But what we are building today will not incur costs for you.
Free Allowances Resources included for free on all plans: Up to 3 shared-cpu-1x 256mb VMs 3GB persistent volume storage (total) 160GB outbound data transfer
Please be aware that you might incur costs when we move past the free tier. That's also why we mostly use 256MB instances. You could easily scale these up but I don't think miniflux needs a lot more than that.
Before we begin, let's make sure that we have the flyctl command line tool installed. Please refer to this page to install it for your OS.
curl -L https://fly.io/install.sh | sh)
Please make sure after installation that you put the relevant snippets into your
.zshrc and also have the
flyctl in your
$PATH. But the install script will tell you what to do, so don't skip its output.
I am using
flyctl v0.0.393 at the time of writing this article, so when you have a
flyctl that is newer than that, you should be okay.
The next step is creating an account at fly.io. You can easily sign in with your GitHub account. They flagged my account in the beginning and I had to add a credit card to unblock it, just a heads-up that you might run into this as well.
Once we have an account, we can link the
flyctl to our account by running
flyctl auth login
This will put a magic link into your terminal that you can click and that will create a token for your flyctl account to consume. You are now fully set up for deploying miniflux to
One more thing I wanted to mention,
fly.io has no hard requirement of running docker on your local machine. They provision a remote builder if you don't run docker locally. This allows me to also play around with fly on windows / wsl, which I found pretty neat. Yes, I know there is Docker for Windows, but I have run into problems there. That's why I doubly appreciate the remote builder.
Creating a database on fly
Without a database, we don't have any persistence. And miniflux refuses to run without a database, so let's create a Postgres database within
fly.io. You might be wondering before creating any database if this is a good idea, putting it out there into the wild. Rest assured, the database instance is created in a private namespace, only accessible by apps in your organization. Your personal account counts as some sort of organization. If you want to make it available to the public, you have to jump through a few more hoops, but we don't need that here. Open your terminal, which has flyctl in its path and is all set up, and run this command:
flyctl postgres create
This command will prompt you for an app name, a region, and what kind of cluster you want to set up. We will go for an easily rememberable name for the database, you can choose it. And for the region, just pick one that is close to you. I will be going with fra for Frankfurt. When it asks for the configuration, choose
Development - Single node, 1x shared CPU, 256MB RAM, 1GB disk.
To give some context,
fly.io is also offering persistent volumes that you can attach to apps. The 1 GB disk here is a persistent volume managed by
fly.io. If you have any persistence needs for the apps you are building yourselves, you can also make use of the volumes. For the rest of this article, we won't be leveraging this though. Just good to know that these exist. They are also snapshotted/backed up behind the scenes. Check the reference if you want to know more https://fly.io/docs/reference/postgres/
Fly will take a short moment to create our database and then we are all set to continue on our miniflux deployment journey.
Creating the app, or the machine?
What we want to do next is create the app for miniflux. An app is like a namespace for the machines you want to run. An app could also just be the
fly.io app that you deployed with your
fly.toml. But what are machines then? A machine is a firecracker VM that starts up very fast with an image that you specified or built. One common thing at fly is that things are developing very fast and thus terminology and functionality is shifting. I didn't know about machines when I started out with fly but they are getting more into the foreground here.
I might have confused you with the app and machine talk. One takeaway here might be that there are (currently) multiple routes to deploy workload on fly. It is perfectly reasonable to deploy a fly app with a fly.toml, like they showcase on the website and in the guides. But this would rather be using what they call Apps V1 which is not a firecracker VM but an underlying nomad deployment. If you wanna read up more about the specifics, you can find them here: https://fly.io/docs/reference/apps/#apps-v1
Back to your terminal: let's create our app, or rather our app namespace.
flyctl apps create your-miniflux-app --machines
your-miniflux-app with a randomly chosen name. See the
--machines flag here? That's where we are telling fly that we want to use machines and not use the usual app route (which is marked as Apps V1 in the documentation).
Next up is an extra step we need to do, because fly-machines themselves don't come with a public ipv4 address. No worries now! We don't need to jumble with ip-addresses and subnets now.
flyctl ips allocate-v4 -a your-miniflux-app
Now our app has an ip-address, that's great! fly generates certificates for the domain
$yourAppName.fly.dev automatically. But we haven't deployed anything yet. We will do that in a second. Remember the Postgres database we created earlier? Now is the time that we need to attach it to our miniflux app. Let's head to the terminal again and attach it.
flyctl postgres attach your-database-name -a your-miniflux-app
Told you to keep the name you specified for the database in the beginning handy. Use it in this script instead of
your-database-name also make sure to adjust the name of the app of your miniflux app at the end of the command. Now we are entering a trickier part of our deployment adventure. Behind the scenes, when we attach a Postgres from fly, it creates a database and credentials for our app. You should see the output of that in your terminal right now. This allows our miniflux app to access the Postgres database.
Sadly, miniflux doesn't work out of the box like this. You would be seeing SSL database connection errors in the
fly.io console if you would continue with the deployment.
Fly.io has something called secrets, which are environment variables you can set on the terminal, but not read after it's written. When you attach your database to your app, it will write a secret called
DATABASE_URL to your app. We will need to set that secret to the existing secret and add
?sslmode=disable at the end of it.
Before doing anything else, search for the
DATABASE_URL=.... line in the terminal output to your Postgres attach command. Copy that string to the end, including your database. Let's adjust the secret in our app before we continue with the deployment:
flyctl secrets set DATABASE_URL=postgres://your-app:firstname.lastname@example.org:5432/your-app?sslmode=disable -a your-miniflux-app
**Don't blindly copy and paste this. This portion of the script must be altered to have the DATABASE_URL that your
postgres-attach-command returned. **
Also, don't be startled that this command fails. Because there's nothing yet to deploy. Or in this case, redeploy. fly will trigger a new deployment of your app when you change the secrets or any secret of the app. But since we don't have anything yet there, it fails. I am very proud of you, you made it through most of the configuration part and even mastered the tricky database secret part. Now there's one thing left to do, and that is to deploy our miniflux instance.
Finally starting our fly-machine
Return to your trusted terminal and run miniflux on fly machines using the following command:
flyctl machine run miniflux/miniflux:2.0.38 \ -p 443:8080/tcp:tls \ --memory 256 \ --region your-region \ --env RUN_MIGRATIONS=1 \ -a your-miniflux-app
We are using the fly machine run command with the designated docker image for miniflux. In another scenario, you could also use a
. to point it to a local Dockerfile. But lucky for us, miniflux is hosting docker images on Dockerhub. Thus we can just reference the image with the tag 2.0.38, which is the latest version miniflux as of today. Please adjust the app-name and the region before you run the command. You will find that a 9MB docker image deploys quite fast.
After the deployment, you can browse to https://$your-app-name.fly.dev to see the miniflux instance online.
Unfortunately, there is still one more thing we need to do. You most likely don't want to stare at the login screen and login. You need to create an admin account and this is a console command that has to happen on the machine itself. This is a good moment to find out about another command you can issue for your fly apps. Run this in your terminal to start a terminal session on your machine:
flyctl ssh console -a your-miniflux-app
This takes a little while, once we finish, we can create a miniflux admin user. Run this on the console that you just got:
This will prompt you for a username and password and then we are done.
And now I am happy to congratulate you on your new miniflux instance. Let me know if everything was clear and if this helped you get a quick glimpse at fly and machines. It's just the tip of the iceberg and I am sure you already have another service in mind that you could deploy with fly.io right now.
Thanks for reading and have a fantastic day.