fly.toml for Ghost with MySQL

Ghost has had a breaking chance with a switch from sqlite3 to MySQL by default

I’m trying to get a totally new build to work but keep getting “ECONNREFUSED”

Should anyone have been able to make Ghost work with MySQL I’d appreciate to understand your setup.

For the sake of others :slight_smile:
MySQL is not part of Ghost’s docker image, so you need to install it separately, when doing that you realize the real issue: MySQl8 needs a lot more RAM than offers and what most hosting platforms offer. Bare minimum one seemingly needs 2GB RAM
Conclusion: Hosting Ghost on’s (free tier) is no longer an option (PlanetScale is NOT an option for Ghost)

you might want to try making the connection string use the appname as the host so change to your-mysql-app-name:3306

Thanks, but as per my comment above. Even if connections are fixed, the real issue is 's RAM offer does not allow for a MySQL8 deployment (one needs a minimum of 2GB RAM). Sadly. And PlanetScale is not an option for Ghost.
fly.toml for Ghost with MySQL - #2 by patfly

1 Like

Planet scale mysql won’t work for ghost? Does it also need mysql 8 instead of 5.7+?

I can’t find specific info on that - Just curious!

Here: PlanetScale does not work with Ghost. Mainly because Ghost makes heavy use of foreign key constraints, a feature PlanetScale does not support → How to run PlanetScale as database for Ghost CMS? · Discussion #88 · planetscale/discussion · GitHub

And yes using MySql8 is a breaking change for Ghost → When will MySQL 8 be mandated? Which ver? - Developer help - Ghost Forum

For this reason (mainly because of RAM requirements for MySQL8) a build can’t even be tried on the free tier. Let alone run in production which is sad given a bunch of ghost tutorials online are guiding people to only for one to realize later it won’t work. Conclusion: One can no longer host Ghost in’s free tier.


For anyone reading this thread, the problem of MySQL 8 on the Fly free tier has be solved by Chris & Will over in this thread:

Ghost can now be deployed in production on Fly’s free tier with MySQL 8! Here’s a tutorial with the script I used:


@Curiositry Hi there! Deployment worked. Thanks a ton for your tutorial!!

Wanted to ask: How to update Ghost with this setup?

1 Like

@patfly Just redeploy, and it pulls in the latest Ghost v5 docker image (currently v5.17.0, v5.17.1 hasn’t made it to the docker hub yet.)

1 Like


1 Like

Hi again, so I’m running the

flyctl launch --name $appname --image=ghost:5-alpine --region sea
(I have replaced $appname with my app name)

but I’m getting:

Error Validation failed: Name has already been taken

Would you have any pointers?

Scratch that, for others in future just run:

flyctl deploy --image=ghost:5-alpine --region sea

1 Like

Yeah, sorry, I wasn’t very clear. You can just run:

fly deploy

… from the directory with your fly.toml, or

fly deploy -a [APPNAME]

from anywhere else.

Many thanks for the clarity @Curiositry . I appreciate all help.

Got something else earlier today that I’m stuck with.

I’ve added a custom domain and all good with that, I’m having issues with the metadata passed on to Google, Twitter, Facebook (located in Settings → Site Meta settings). My custom domain is not beeing passed on in that case, everywhere meta data is passed on my url shows up as being the domain (and not my custom domain).

I’ve tried setting up an env url in fly.toml to deal with that but no luck so far.

Would you know how to modify that metadata?

You may just need to re-deploy in order to get Ghost to “restart” (which may make it recognize the domain). That guess is based on this.

Sometimes that kind of error is related to the app not picking up reverse-proxy related HTTP headers such a X-Forwarded-For but I don’t think the hostname is usually picked up incorrectly in those cases (usually it’s more like generated URL’s use http:// instead of https://).

1 Like

Thanks @fideloper-fly for the nudge.
The issue was with embedly’s cash. With time, the custom domain propagated.

Thanks again!

1 Like

Hi there, me again! Sorry.

Struggling to get the Ghost/Signup/transactional emails to work (working with the Mailgun integration since it is the default one), by only setting up Mailgun details in Ghost dashboard I get “Failed to send magic link email” See screenshot:

Then I understood the mailgun setup via the ui is for bulk newsletter emails (not for auth/login)

Quoting them from: Mailgun & – The 'What's New' page shows mail delivery as Direct despite entering Mailgun API key and domain - Self-hosting - Ghost Forum

There are two mail delivery setups:

  1. Transactional email - this is set via the config file and used for one-off emails like member signups, staff invites, etc
  2. Bulk email - only Mailgun is supported and is set through the UI, used for sending newsletters to members

You’ll need to configure both for a fully working setup.

So reading Ghost’s documentation I also need to add some Mailgun details to add credentials to config.production.json → See mail under Configuration - Adapt your publication to suit your needs

Since the only config file I have is fly.toml I’ve attempted the following under fly.toml’s [env]:

    transport = "SMTP"
    service = "Mailgun"
    host = "" 
    port = 587
      user = "xxxx"
      pass = "xxxxxx"

and for that I’m getting

Error unknown attribute 'mail' for AppConfig.

          raise, k.to_s)

Without making transactional emails (i.e. login, etc) work, Ghost is non-functional.

Unsure where to provide those additional credentials. Pointers welcome :slight_smile:

1 Like

I don’t think that’s a valid fly.toml.

What you probably want is migrate from just putting your image on fly.toml to using a Dockerfile because Ghost image doesn’t support mail variables (?).

I haven’t tried it but it could be a Dockerfile like:


COPY config.production.json /the/folder/ghost/stores/data

After that remove the image portion from your Dockerfile and flyctl would pick the Dockerfile for the build.


Thanks for the pointer! Appreciated.
For others reading this in the future: I’ve managed to get the mail variables through as environment variables via secrets (and not via fly.toml).
So, for those struggling, here they come:

flyctl secrets set mail__transport=SMTP

flyctl secrets set

flyctl secrets set mail__options__port=587

flyctl secrets set mail__options__auth__user=xxxxx

flyctl secrets set mail__options__auth__pass=xxxx


@patfly Sorry I didn’t see your post until you had figured it out.

Like you, I have my transactional mail config set via fly secrets, using the convention for environment variables described in the Ghost docs:

Technically, you should be able use env variables in the fly.toml, but I suspect it would need look like:

mail__transport = "SMTP"

I haven’t tried it, though, since fly secrets work well enough.

I am curious why Ghost’s direct mail doesn’t seem to work on fly.

1 Like