Host a Ghost blog on Fly.io for free

On this post, I’ll show you how to host a Ghost instance on Fly.io for free. If you don’t know yet, Fly.io is an application distribution platform that makes it super easy to deploy and scaling your application on multiple regions. Their free plan includes 3 VMs with 256MB RAM and 3GB of persistent storage, which is more than enough for hosting small blog, like the one you are reading right now.

Launching a new application

The first step is signup for a Fly.io account. After that we will need to install flyctl cli program.

Following commands are all the steps necessary for launching a new Ghost blog. We will use the official Ghost Docker image, that uses SQlite3 as database sytem.

Authentication

$ flyctl auth login

Launch a new Fly.io application. We use --no-deploy as we want to change some configurations before deploying.

$ mkdir my-blog
$ cd my-blog
$ flyctl launch --image=ghost:4.36.3-alpine --no-deploy

The previous command will generate the fly.toml file. In the example, the application name is red-sun-2406, your application name will be diferrent.

# fly.toml file generated for red-sun-2406 on 2022-02-28T20:21:37+07:00

app = "red-sun-2406"

kill_signal = "SIGINT"
kill_timeout = 5
processes = []

[build]
  image = "ghost:4.36.3-alpine"

[env]

[experimental]
  allowed_public_ports = []
  auto_rollback = true

[[services]]
  http_checks = []
  internal_port = 8080
  processes = ["app"]
  protocol = "tcp"
  script_checks = []

  [services.concurrency]
    hard_limit = 25
    soft_limit = 20
    type = "connections"

  [[services.ports]]
    handlers = ["http"]
    port = 80

  [[services.ports]]
    handlers = ["tls", "http"]
    port = 443

  [[services.tcp_checks]]
    grace_period = "1s"
    interval = "15s"
    restart_limit = 0
    timeout = "2s"

Create a volume to store the SQlite3 database. We set to volume size to 3 to stay within the free plan.

flyctl volumes create data --size 3

Change the fly.toml to:

  • set the URL of the blog to https://<application-name>.fly.dev
  • change internal service port to 2386 (Ghost default port)
  • mount the data volume
...
[env]
  url = "https://red-sun-2406.fly.dev"
...  
[[services]]
  http_checks = []
  internal_port = 2368
...
[mounts]
  source="data"
  destination="/var/lib/ghost/content"

Everything is ready! Time to launch:

flyctl deploy                      
==> Verifying app config
--> Verified app config
==> Building image
Searching for image 'ghost:4.36.3-alpine' remotely...
image found: img_nk3yvlndg29pome7
==> Creating release
--> release v2 created

--> You can detach the terminal anytime without stopping the deployment
==> Monitoring deployment

 1 desired, 1 placed, 1 healthy, 0 unhealthy
--> v0 deployed successfully

Your Ghost blog is now live at https://<application-name>.fly.dev.

Further Configuration

  • Go to https://<application-name>.fly.dev/ghost and register the admin account
  • Fly.io supports custom domain, and it is free!