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

**URL:** <https://forum.ghost.org/t/tutorial-host-ghost-5-mysql-8-on-fly-io-free-tier/33095>\
**Category:** Self-hosting\
**Created:** [September 28, 2022, 7:52pm UTC](https://forum.ghost.org/t/tutorial-host-ghost-5-mysql-8-on-fly-io-free-tier/33095 "2022-09-28T19:52:43Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![curiositry](https://sea1.discourse-cdn.com/flex015/user_avatar/forum.ghost.org/curiositry/32/1084_2.png) [@curiositry](https://forum.ghost.org/u/curiositry)\
**Post date:** [September 28, 2022, 7:52pm UTC](https://forum.ghost.org/t/tutorial-host-ghost-5-mysql-8-on-fly-io-free-tier/33095/1 "2022-09-28T19:52:43Z")

</div>

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:

> **[Host a Ghost 5 + MySQL 8 Site on Fly.io Free Tier — In 2 Minutes](https://www.autodidacts.io/host-ghost-mysql8-on-fly-io-free-tier/)**
>
> Not long ago, I wrote a post on how to deploy a Ghost 5 blog on Fly.io without paying a dime. Shortly after, Ghost removed support for SQLite in production, in favour of MySQL.
> 
> 
> However, hosting Ghost + MySQL 8 on Fly turned out to be a bit gnarly....

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 🙂

---

<div class="post-metadata">

**Author:** ![eexit](https://sea1.discourse-cdn.com/flex015/user_avatar/forum.ghost.org/eexit/32/15583_2.png) [@eexit](https://forum.ghost.org/u/eexit)\
**Post date:** [November 5, 2022, 6:56pm UTC](https://forum.ghost.org/t/tutorial-host-ghost-5-mysql-8-on-fly-io-free-tier/33095/2 "2022-11-05T18:56:47Z")

</div>

Pretty cool, thanks!

I just switched to [Fly.io as well](https://blog.eexit.net/digitalocean-to-fly-io/) (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](http://Fly.io) is pretty neat but really too tight to ensure decent stability.

---

<div class="post-metadata">

**Author:** ![curiositry](https://sea1.discourse-cdn.com/flex015/user_avatar/forum.ghost.org/curiositry/32/1084_2.png) [@curiositry](https://forum.ghost.org/u/curiositry)\
**Post date:** [November 9, 2022, 11:49pm UTC](https://forum.ghost.org/t/tutorial-host-ghost-5-mysql-8-on-fly-io-free-tier/33095/3 "2022-11-09T23:49:47Z")

</div>

Thanks for your reply @eexit.

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

> **[A few more things I've learned about self-hosting Ghost on Fly’s free tier](https://www.autodidacts.io/things-ive-learned-self-hosting-ghost-on-fly-io-free-tier/)**
>
> Following on from my previous two posts on the topic, here are some additional things I’ve learned running this blog for free on Fly:
> 
> 
> 
> 1. 
>     
>     
> You can survive a HackerNews traffic spike, without scaling. However, your access logs will...

**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](https://www.autodidacts.io/host-a-ghost-blog-free-on-fly-io/) 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.

---

<div class="post-metadata">

**Author:** ![curiositry](https://sea1.discourse-cdn.com/flex015/user_avatar/forum.ghost.org/curiositry/32/1084_2.png) [@curiositry](https://forum.ghost.org/u/curiositry)\
**Post date:** [November 9, 2022, 11:58pm UTC](https://forum.ghost.org/t/tutorial-host-ghost-5-mysql-8-on-fly-io-free-tier/33095/4 "2022-11-09T23:58:34Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![curiositry](https://sea1.discourse-cdn.com/flex015/user_avatar/forum.ghost.org/curiositry/32/1084_2.png) [@curiositry](https://forum.ghost.org/u/curiositry)\
**Post date:** [November 10, 2022, 12:02am UTC](https://forum.ghost.org/t/tutorial-host-ghost-5-mysql-8-on-fly-io-free-tier/33095/5 "2022-11-10T00:02:49Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![Georgi\_Pehlivanov](https://sea1.discourse-cdn.com/flex015/user_avatar/forum.ghost.org/georgi_pehlivanov/32/11733_2.png) [@Georgi\_Pehlivanov](https://forum.ghost.org/u/Georgi_Pehlivanov)\
**Post date:** [November 27, 2022, 9:04pm UTC](https://forum.ghost.org/t/tutorial-host-ghost-5-mysql-8-on-fly-io-free-tier/33095/6 "2022-11-27T21:04:00Z")

</div>

I used another tutorial with sqlite working:  
[How to Host a Ghost Blog for Free on Fly.io (blixtdev.com)](https://blixtdev.com/how-to-host-a-ghost-blog-for-free-on-fly-io/)  
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.

---

<div class="post-metadata">

**Author:** ![curiositry](https://sea1.discourse-cdn.com/flex015/user_avatar/forum.ghost.org/curiositry/32/1084_2.png) [@curiositry](https://forum.ghost.org/u/curiositry)\
**Post date:** [November 28, 2022, 10:57pm UTC](https://forum.ghost.org/t/tutorial-host-ghost-5-mysql-8-on-fly-io-free-tier/33095/7 "2022-11-28T22:57:01Z")

</div>

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:

```auto
fly deploy

```

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

---

<div class="post-metadata">

**Author:** ![curiositry](https://sea1.discourse-cdn.com/flex015/user_avatar/forum.ghost.org/curiositry/32/1084_2.png) [@curiositry](https://forum.ghost.org/u/curiositry)\
**Post date:** [November 28, 2022, 11:06pm UTC](https://forum.ghost.org/t/tutorial-host-ghost-5-mysql-8-on-fly-io-free-tier/33095/8 "2022-11-28T23:06:43Z")

</div>

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](https://www.autodidacts.io/things-ive-learned-self-hosting-ghost-on-fly-io-free-tier/) (`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.

---

<div class="post-metadata">

**Author:** ![curiositry](https://sea1.discourse-cdn.com/flex015/user_avatar/forum.ghost.org/curiositry/32/1084_2.png) [@curiositry](https://forum.ghost.org/u/curiositry)\
**Post date:** [November 28, 2022, 11:08pm UTC](https://forum.ghost.org/t/tutorial-host-ghost-5-mysql-8-on-fly-io-free-tier/33095/9 "2022-11-28T23:08:41Z")

</div>

More in depth info here:

> **[How to backup your self-hosted Ghost install - Ghost Developers](https://ghost.org/docs/faq/manual-backup/)**
>
> Find out how tobackup your self-hosted Ghost install using Ghost CLI, or by performing a manual backup.

---

<div class="post-metadata">

**Author:** ![Georgi\_Pehlivanov](https://sea1.discourse-cdn.com/flex015/user_avatar/forum.ghost.org/georgi_pehlivanov/32/11733_2.png) [@Georgi\_Pehlivanov](https://forum.ghost.org/u/Georgi_Pehlivanov)\
**Post date:** [November 28, 2022, 11:34pm UTC](https://forum.ghost.org/t/tutorial-host-ghost-5-mysql-8-on-fly-io-free-tier/33095/10 "2022-11-28T23:34:59Z")

</div>

Thank you! I’m not sure how many apps I can deploy in [Fly.io](http://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.

---

<div class="post-metadata">

**Author:** ![Georgi\_Pehlivanov](https://sea1.discourse-cdn.com/flex015/user_avatar/forum.ghost.org/georgi_pehlivanov/32/11733_2.png) [@Georgi\_Pehlivanov](https://forum.ghost.org/u/Georgi_Pehlivanov)\
**Post date:** [November 28, 2022, 11:39pm UTC](https://forum.ghost.org/t/tutorial-host-ghost-5-mysql-8-on-fly-io-free-tier/33095/11 "2022-11-28T23:39:55Z")

</div>

I have

```auto
[build]
  image = "ghost:5.23.0"

```

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

---

<div class="post-metadata">

**Author:** ![curiositry](https://sea1.discourse-cdn.com/flex015/user_avatar/forum.ghost.org/curiositry/32/1084_2.png) [@curiositry](https://forum.ghost.org/u/curiositry)\
**Post date:** [November 28, 2022, 11:56pm UTC](https://forum.ghost.org/t/tutorial-host-ghost-5-mysql-8-on-fly-io-free-tier/33095/12 "2022-11-28T23:56:56Z")

</div>

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)

---

<div class="post-metadata">

**Author:** ![curiositry](https://sea1.discourse-cdn.com/flex015/user_avatar/forum.ghost.org/curiositry/32/1084_2.png) [@curiositry](https://forum.ghost.org/u/curiositry)\
**Post date:** [November 28, 2022, 11:57pm UTC](https://forum.ghost.org/t/tutorial-host-ghost-5-mysql-8-on-fly-io-free-tier/33095/13 "2022-11-28T23:57:30Z")

</div>

Yes, that should work.

---

<div class="post-metadata">

**Author:** ![curiositry](https://sea1.discourse-cdn.com/flex015/user_avatar/forum.ghost.org/curiositry/32/1084_2.png) [@curiositry](https://forum.ghost.org/u/curiositry)\
**Post date:** [November 28, 2022, 11:59pm UTC](https://forum.ghost.org/t/tutorial-host-ghost-5-mysql-8-on-fly-io-free-tier/33095/14 "2022-11-28T23:59:14Z")

</div>

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 🙂

---

<div class="post-metadata">

**Author:** ![Georgi\_Pehlivanov](https://sea1.discourse-cdn.com/flex015/user_avatar/forum.ghost.org/georgi_pehlivanov/32/11733_2.png) [@Georgi\_Pehlivanov](https://forum.ghost.org/u/Georgi_Pehlivanov)\
**Post date:** [November 29, 2022, 1:21pm UTC](https://forum.ghost.org/t/tutorial-host-ghost-5-mysql-8-on-fly-io-free-tier/33095/15 "2022-11-29T13:21:55Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![Georgi\_Pehlivanov](https://sea1.discourse-cdn.com/flex015/user_avatar/forum.ghost.org/georgi_pehlivanov/32/11733_2.png) [@Georgi\_Pehlivanov](https://forum.ghost.org/u/Georgi_Pehlivanov)\
**Post date:** [December 1, 2022, 8:29pm UTC](https://forum.ghost.org/t/tutorial-host-ghost-5-mysql-8-on-fly-io-free-tier/33095/16 "2022-12-01T20:29:25Z")

</div>

@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?

---

<div class="post-metadata">

**Author:** ![curiositry](https://sea1.discourse-cdn.com/flex015/user_avatar/forum.ghost.org/curiositry/32/1084_2.png) [@curiositry](https://forum.ghost.org/u/curiositry)\
**Post date:** [December 1, 2022, 10:35pm UTC](https://forum.ghost.org/t/tutorial-host-ghost-5-mysql-8-on-fly-io-free-tier/33095/17 "2022-12-01T22:35:53Z")

</div>

@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?

 ![Certificates · Fly](https://us1.discourse-cdn.com/flex015/uploads/ghost2/original/3X/8/c/8cd87a2c51d50965b377deaa366326989fa17cbe.png)

---

<div class="post-metadata">

**Author:** ![Georgi\_Pehlivanov](https://sea1.discourse-cdn.com/flex015/user_avatar/forum.ghost.org/georgi_pehlivanov/32/11733_2.png) [@Georgi\_Pehlivanov](https://forum.ghost.org/u/Georgi_Pehlivanov)\
**Post date:** [December 1, 2022, 10:54pm UTC](https://forum.ghost.org/t/tutorial-host-ghost-5-mysql-8-on-fly-io-free-tier/33095/18 "2022-12-01T22:54:07Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![curiositry](https://sea1.discourse-cdn.com/flex015/user_avatar/forum.ghost.org/curiositry/32/1084_2.png) [@curiositry](https://forum.ghost.org/u/curiositry)\
**Post date:** [December 1, 2022, 11:12pm UTC](https://forum.ghost.org/t/tutorial-host-ghost-5-mysql-8-on-fly-io-free-tier/33095/19 "2022-12-01T23:12:38Z")

</div>

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:

```auto
flyctl secrets set url=https://yourdomain.com -a APPNAME

```

---

<div class="post-metadata">

**Author:** ![Georgi\_Pehlivanov](https://sea1.discourse-cdn.com/flex015/user_avatar/forum.ghost.org/georgi_pehlivanov/32/11733_2.png) [@Georgi\_Pehlivanov](https://forum.ghost.org/u/Georgi_Pehlivanov)\
**Post date:** [December 1, 2022, 11:26pm UTC](https://forum.ghost.org/t/tutorial-host-ghost-5-mysql-8-on-fly-io-free-tier/33095/20 "2022-12-01T23:26:05Z")

</div>

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.

[Next page](https://forum.ghost.org/t/tutorial-host-ghost-5-mysql-8-on-fly-io-free-tier/33095.md?page=2)
