Deploy a Ghost Blog on Fly.io
Fly.io is a platform allowing you to serve your apps closer to your user, for example you can use it to host a Ghost blog as it allows you to deploy from a Docker image, you can think of it as a "Serverless Container". You can read more about Fly's architecture design here.
Back to business, to start deploying, you need the Fly CLI installed first. On macOS, you can install it with Homebrew:
brew install superfly/tap/flyctl
Then create a new project:
mkdir my-site cd my-site
Now you can use Fly to initialize the project with a config file
fly.toml, or just grab the file I use to deploy Ghost below:
app = "ghost-fly" kill_signal = "SIGINT" kill_timeout = 5 processes =  [build] image = "ghost:4-alpine" [mounts] source="ghost_content" destination="/var/lib/ghost/content" [env] url="https://[app-name].fly.dev" [experimental] allowed_public_ports =  auto_rollback = true [[services]] http_checks =  internal_port = 2368 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"
You need to tweak the highlighted part to suit your needs:
- Change the
appname to something unique.
- By default we use the
- We mount
ghost_contentvolume to persistent data,
/var/lib/ghost/contentis the directory to store Ghost database (SQLite), themes and uploaded images, etc.
urlshould be your production website URL, you can add custom domain on Fly.io dashboard.
In order to create a volume to persist data in
/var/lib/ghost/content, you can use Fly CLI:
# Create a 10G volume (default) in the nrt (tokyo) region fly volumes create ghost_content --region nrt
There's many other regions you can choose too.
To actually deploy the project, run
fly deploy in the project directory. After that, you should be able to access your Ghost blog at
https://[app-name].fly.dev/ghost or your custom domain name.
By default this docker image uses SQLite as the database, it's perfectly fine for our use case (heavy-read, low-write), but if you want to use MySQL, you can use Fly Secrets to do so:
fly secrets set \ database__client=mysql \ database__connection__host=db \ database__connection__user=root \ database__connection__password=example \ database__connection__database=ghost
These secrets will be available as environment variables at runtime.
To get a MySQL database, check out PlanetScale, they offer a generous free plan for developers.