Tutorial: Host Ghost 5 + MySQL 8 on Fly.io Free Tier

After a lot of tinkering, I have found a way of running Ghost 5 in production with MySQL 8 on Fly’s free tier! Here is a tutorial with the script I used:

Let me know if you run into any issues following the tutorial; it’s brand new so there may still be bugs that need to be worked out :slight_smile:

1 Like

Pretty cool, thanks!

I just switched to Fly.io as well (using SQLite) and I found out that I faced an OOM error when the internal Ghost worker is seeking upgrades. Unfortunately, I believe there’s no way to disable this worker.

So, Fly.io is pretty neat but really too tight to ensure decent stability.

1 Like

Thanks for your reply @eexit.

I recently posted a few more tips here, and #2 might be helpful:

TL;DR = If you aren’t already making use of the fact, Fly forgives monthly bills under $5, which means you can double the amount of RAM to 512 MB without actually getting charged.

I have had a Ghost site running on Fly using SQLite (following my previous tutorial for development mode) with 256MB RAM for months without any OOM issues, but perhaps running SQLite in production (with a slightly more complex configuration) uses more RAM.

Ah, I see you are already making use of that from your post image :slight_smile: How much RAM does your instance have, 256MB or 512?

I’m assuming you’ve tried setting the privacy__useUpdateCheck environment variable to false and it didn’t disable the update worker… ?

I used another tutorial with sqlite working:
How to Host a Ghost Blog for Free on Fly.io (blixtdev.com)
Can you help me to transfer my ghost blog from sqlite3 to MySQL8 . Right now my blog is running on sqlite3 on ghost 5.23.0 with a message that says I run my ghost blog on unsupported database in production. Its working ok, but I’m not sure what may happened if I still use sqlite3. Also, can you tell me how to backup and update ghost to newer released version? I’m not sure how to do that from Fly command-line tools.

1 Like

If you used the Ghost 5 docker image without specifying the exact version number (ie, the tag 5-alpine or alpine rather than 5.24.1-alpine), updating your existing install (tutorial forthcoming) should be as simple as running:

fly deploy

… from the directory where your fly.toml is located; or running fly deploy -a YOURAPPNAME from anywhere.

1 Like

Probably the simplest and cleanest approach will be to deploy a second app using my MySQL 8 tutorial, and then migrate everything over.

As far as backup, you’ll want to export a JSON dump from the labs page of your admin panel, and a CSV of your members. (and your routes.yaml and redirects, if applicable).

I haven’t used the Ghost CLI backup comand on Fly; I just back up my content folder using using the FTP command in tip #7 (flyctl ssh sftp shell -a APPNAME, then get /var/lib/ghost/content/ GHOST-CONTENT-BACKUP-YYYY-MM-DD)

Then, import the JSON and restore the content folder (or the subdirectories that you need, like images + files). I didn’t do this step when I migrated, because I had my images hosted externally. I assume this would be done over SSH or SFTP. It also might be possible to clone the whole volume and attach it to the new app. I’ll look into it.

I hope this helps.

1 Like

More in depth info here:

1 Like

Thank you! I’m not sure how many apps I can deploy in Fly.io free tier. Also, my domain have dns records pointing to ip of the app, so I guess I will have to do new records in my domain for the new app.

I have

[build]
  image = "ghost:5.23.0"

in my fly.toml
I change it to ghost:5.24.1 and deploy it :)

AFAIK you can have 3 free apps per organization, so you should be able to deploy Ghost + MySQL in an app each, alongside your existing Ghost+SQLite app. You can have 3GBs of volume space free, so 3x 1gb volumes would be fine.

However, even if you exceed the free tier during the transition, it won’t be too expensive (and of course bills under $5, which it likely would be if you are fast, are forgiven)

1 Like

Yes, that should work.

1 Like

Yes, you will. I found it pretty straightforward, though, and managed to transition my DNS with zero downtime.

But I would recommend waiting until you have migrated everything to the new install, and checked that it’s all working :slight_smile:

1 Like

Unfortunately my current app have 3GB volume, so I need to delete it before create a new one without exceeding free tier.

btw, can you make tutorial for external image storage with ghost? Also will be great if progressive image loading is possible.

@curiositry I create new app using your tutorial and restore my content, everything is ok, but I have issue with my domain. I use cloudflare and when make new dns records pointing to new app my site dont open from my domain with error SSL handshake failed. Why is that? Do i need to point only ghost app, or db app too?

@Georgi_Pehlivanov Just the Ghost app. The Ghost connects to the MySQL app using Fly’s internal routing.

You added a certificate at https://fly.io/apps/APPNAME/certificates (or using fly CLI), and added the DNS records Fly told you to at the next step, correct? Does Fly show the domain as verified, and have checkmarks next to the certificates?

@curiositry I fixed it, but now I have some problems - how to change default app domain to my domain and not to fly.dev subdomain. When I open my site, everytime I click on the logo it open link in subdomain and not in my primary domain. My domain is in fly.toml
I also have trouble connecting stripe, it worked after I opened the site from fly.dev subdomain.

The two might be related. That’s odd, you should be able to set a “url” environment variable in your fly.toml. Fly secrets take precedence over environment variables, and aren’t as vulnerable to syntax errors. Does the problem persist after you run:

flyctl secrets set url=https://yourdomain.com -a APPNAME
1 Like

Thank you! This solved the issue. Now everything is working.
btw do you know how to setup Cloudinary as image storage? I tried but without success.