This article introduce how to install, backup and restore ghost on fly.io for free. Backing up and restoring data is a reference for use cases on other servers. With the use of cron, the full site data is regularly backed up to github, so to speak, you can really feel at ease with ghost and give up static blogs.
1. Pre-requisites
- To register for a fly.io account,install flyctl command line, you need a credit card. (required)
- be familiar with basic git commands. (not required)
- Understand fly.io’s pricing. (not required)
- Understand Mailgun. (not required)
Install the command line
curl -L https://fly.io/install.sh | sh
For Windows,run
iwr https://fly.io/install.ps1 -useb | iex
2. Install Ghost
The following command is common on Linux and Mac.
Open a terminal and execute.
mkdir blog #Create a directory
cd blog #Enter this directory
flyctl auth login #Log in, then the browser will pop up the login session
flyctl launch --image=ghost:5 -r hkg --name=<AppName> --no-deploy
An explanation of the last command:
The docker image used is
ghost:5
, indicating that the 5.x major version will be updated automatically on every deployment, and if you intend to check a specific version, such as 5.36.0, then replace 5 with it. The official image is here.- r hkg
means that the node of the selected server is Hong Kong (the node closest to us). The region code of fly.io is here.--name=<AppName>
means the name of the created app, replace<AppName>
with your own, and note that the default URL generated in the future is<AppName>.fly.dev
, so please take a unique name.--no-deploy
means don’t deploy for now.
This will create a fly.toml file in the blog directory. Open it with a text editor and overwrite it with the following code.
app = "<AppName>"
kill_signal = "SIGINT"
kill_timeout = 5
processes = []
[build]
image = "ghost:5"
[env]
url = "https://<AppName>.fly.dev"
database__client = "sqlite3"
database__connection__filename = "content/data/ghost.db"
database__debug = "false"
database__useNullAsDefault = "true"
mail__from = "noreply@example.com"
mail__options__auth__pass = "<YourMailgunPassword>"
mail__options__auth__user = "postmaster@example.com"
mail__options__host = "smtp.mailgun.org"
mail__options__port = "465"
mail__transport = "SMTP"
[experimental]
auto_rollback = true
[mounts]
destination = "/var/lib/ghost/content"
source = "data"
[[services]]
http_checks = []
internal_port = 2368
processes = ["app"]
protocol = "tcp"
script_checks = []
[services.concurrency]
hard_limit = 25
soft_limit = 20
type = "connections"
[[services.ports]]
force_https = true
handlers = ["http"]
port = 80
[[services.ports]]
handlers = ["tls", "http"]
port = 443
[services.ports.http_options.response.headers]
Referrer-Policy = "strict-origin"
Strict-Transport-Security = "max-age=63072000; includeSubDomains; preload"
X-Content-Type-Options = "nosniff"
X-Frame-Options = "SAMEORIGIN"
x-xss-protection = "1; mode=block"
Permissions-Policy = "camera=(), microphone=(), geolocation=(), browsing-topics=()"
[[services.tcp_checks]]
grace_period = "1s"
interval = "15s"
restart_limit = 0
timeout = "2s"
Please replace <AppName>
with your own, and, if you don’t use Mailgun, please remove all code starting with mail__
below [env]
.
The [services.ports.http_options.response.headers]
section is optional and is used to set the http header. You can search item by item, Strict-Transport-Security
, for example, to determine if you want to add them. After the deployment, you may go to the http header test site.
When you are done checking, save and close the fly.toml file. Then go back to the terminal and continue executing.
flyctl volumes create data -r hkg --no-encryption --size 1 # Create a volume of size 1Gb with region hkg and no encryption (helps improve performance). The free amount is 3GB in total.
flyctl deploy #deploy
Wait a few moments, the deployment is successful! It will show successful
.
3. Initialize Ghost
Visit
https://<AppName>.fly.dev/ghost/
to initialize ghost. After this, you are free to use ghost to publish content. Binding domain names, backing up and restoring data are optional operations.
4. Bind the domain name
Run
flyctl ips list
to see the IP address of your app. Then create A records for ipv4 and AAAA records for ipv6 on your DNS server, pointing to your domain name example.com
(required). Create CNAME, <AppName>.fly.dev
, pointing to your www.example.com
(not required). Also known as
type | record | value |
---|---|---|
A | @ | ipv4 address |
AAAAA | @ | ipv6 address |
CNAME | www | <AppName>.fly.dev |
Note: Before binding the domain name, make sure to create the DNS records correctly.
Then run
flyctl certs create example.com
flyctl certs create www.example.com
wait a moment and run
flyctl certs check example.com
flyctl certs check www.example.com
to check the certificate enactment, which usually takes about a minute or two as long as the DNS advance configuration is correct. Run
flyctl ips list
to check the certificate issuance status.
Note: Don’t install certificates repeatedly because there is a limit, only 5 certificates can be issued every 7 days. It is recommended to bind them after debugging the app.
5. Redeploy
Notice that in the fly.toml,
[env]
url = "https://<AppName>.fly.dev"
is the address assigned by fly.io, and if you click on the home page title of the ghost site, it will redirect to this address, so when you bind your own domain, change it to
[env]
url = "https://example.com"
Save and close, then run flyctl deploy
.
6. Back up and restore
Every time in the future you need to go into your local configuration directory to use flyctl correctly.
6.1 Method 1: Use SFTP to bacup Ghost
The advantage is that no complicated configuration is needed, but the copy speed is slow.
6.1.1 Back up
First login (assuming you need to back up later).
cd blog
flyctl auth login
Then run
flyctl ssh sftp shell -r -a <AppName>
When it succeeds, it will show >>
(red), then run
get /var/lib/ghost/content/
This will backup the whole site data, including themes, images, videos, articles, etc. It’s very slow, please be patient.
You can also backup only images and videos by running
get /var/lib/ghost/content/images/
get /var/lib/ghost/content/media/
This will generate a content.zip
, or, images.zip
and media.zip
in the blog directory. back them up elsewhere, or name them content-YYYY-MM-DD.zip
.
6.1.2 Restore
Now suppose you reinstall a new ghost, assuming it is still on fly.io, then the installation directory will remain as /var/lib/ghost/content/
. If you install ghost somewhere else in the future, like on AWS, make sure you create this directory instead of the usual tutorial /var/www/ghost/content/
, otherwise you will have trouble recovering your data by first method.
Still run
cd blog
flyctl auth login
flyctl ssh sftp shell -r -a <AppName>
Then run
put content.zip /var/lib/ghost/content.zip
After success, create a new tab in the terminal and run
flyctl ssh console
again, in ssh, run
apt-get update && apt-get upgrade && apt-get install unzip
to install unzip
. Then run
cd /var/lib/ghost/
unzip content.zip
It will overwrite the content folder directly.
To verify that the unzip was successful, run
cd /var/lib/ghost/content/images/
ls #List all the files in the current folder
to see if there is any new data.
To fix permissions, run
chown -R node:node /var/lib/ghost/content/
Note: Possible scenario, can’t overwrite the content folder correctly, then try to backup only /var/lib/ghost/content/images/
and /var/lib/ghost/content/media/
instead. At this point run
put images.zip /var/lib/ghost/content/images.zip
put media.zip /var/lib/ghost/content/media.zip
rm -rf /var/lib/ghost/content/images/
rm -rf var/lib/ghost/content/media/
unzip /var/lib/ghost/content/images.zip
unzip /var/lib/ghost/content/media.zip
this may break the permissions of the content folder, so run
ls -l /var/lib/ghost/content/
to check the user and permissions of the images and media folders, if their permissions belong to root, then you can’t upload images and videos anymore, then run
chown -R node:node /var/lib/ghost/content/
chown -R node:node /var/lib/ghost/content/images/
chown -R node:node /var/lib/ghost/content/media/
to fix it, note that node
is the ghost user in the fly.io case, depending on the result of the ls -l /var/lib/ghost/content/
command,, in any case make sure that the user of the images and media folders is the same as the user of the other files under /content/
.
6.2 Method 2: Use Github to backup Ghost
The advantage is that it is fast to replicate data, but the disadvantage is that the installation and configuration is relatively complicated.
6.2.1 Back up
- Login and enter ssh
cd blog
flyctl auth login
flyctl ssh console
- Install git
apt-get update && apt-get upgrade && apt-get install git
Create a private (recommended) repository on the github web side , assuming it is called
<YourRepository>
.Generate the key
ssh-keygen -t rsa -C "<GithubEmail>" # Press the Enter key continuously
- Terminal new tab, run
flyctl ssh sftp shell -r -a <AppName>
get /root/.ssh/id_rsa.pub
Go back to the blog folder and find the id_rsa.pub
file, open it with a text editor, and copy the key from it. Add it to setting→SSH and GPG keys→SSH keys
in github and save it.
Test the connection with github
ssh git@github.com
Pay attention to the word successful
.
- Initialize the content git
cd /var/lib/ghost/content/
git init
git config --global user.name "<GithubUsername>"
git config --global user.email <GithubEmail>
git config --global --add safe.directory /var/lib/ghost/content
git remote add origin git@github.com:<GithubUsername>/<YourRepository>.git
git add .
git commit -m "auto backup"
git push -u origin master --force
Make sure you successfully push to github.
- Create a new script
apt-get update && apt-get upgrade && apt-get install nano
cd /var/lib/ghost/content/
nano auto_run.sh
Copy the following code into auto_run.sh
#! /bin/sh
cd /var/lib/ghost/content # Switch to the directory
git config --global init.defaultBranch master
git config --global --add safe.directory /var/lib/ghost/content
git pull # Pull the repository
git add . # Add a staging
git commit -m "auto backup" # Commit
git push --force
Press ctrl
+O
followed by enter
to write; press ctrl
+x
to exit nano.
Give the file permission to run
chmod a+x auto_run.sh
Later, after logging into ssh, you can directly run
sh /var/lib/ghost/content/auto_run.sh
to execute a new push.
6.2.2 Restore
Log in to shh, reinstall git and add the key without further ado.
Empty the content folder
cd /var/lib/ghost/
rm -rf content
It will return that the folder can’t be deleted because its busy
, it doesn’t matter, it has been emptied, but not deleted.
- Initialize the git in the content file and force a pull
cd /var/lib/ghost/content/
git init
git config --global user.name "<GithubUsername>"
git config --global user.email <GithubEmail>
git pull --force git@github.com:<GithubUsername>/<YourRepository>.git
- Verify that the pull was successful
ls
- Make sure the data is successfully pulled, then restart the app
fly apps restart <AppName>
As of now, restarting or redeploying will clear the installed environment and software, but will not delete the ghost data.
- It is really difficult to run cron in docker, so don’t try it. In a normal virtual machine, you can set up cron to run at regular intervals
sh /var/lib/ghost/content/auto_run.sh