在 fly.io 免费运行 Ghost 博客:安装、备份和恢复
最近把论文交了后,手又痒痒,折腾了下 ghost。 fly.io 是一个 PaaS,现在可以在上面安装若干个 Ghost 博客,而且完全免费。
这篇文章介绍了在 fly.io 上免费安装、备份和还原 Ghost 的方法。备份和恢复数据对其他服务器上的用例具有参考意义。配合使用 cron,定时将全站数据备份到 Github,可以说,真的可以安心用 Ghost,舍弃静态博客了。
1.前置条件
- 注册 fly.io 账号,安装 flyctl 命令行,需要一张支持外币的信用卡。(必要)
- 熟悉基本的 git 命令。(非必要)
- 了解 fly.io 的 定价 。(非必要)
- 了解 Mailgun。(非必要)
安装命令行
curl -L https://fly.io/install.sh | sh
对于 Windows,运行
iwr https://fly.io/install.ps1 -useb | iex
2.安装 Ghost
下面的命令在 Linux 和 Mac 上通用。
打开终端,执行:
mkdir blog #创建一个目录
cd blog #进入这个目录
flyctl auth login #登录,之后浏览器会弹出登录会话
flyctl launch --image=ghost:5 -r hkg --name=<AppName> --no-deploy
对最后一条命令的解释:
-
--image=ghost:5
,表示 5.x 大版本会自动在每一次部署时更新,若打算选中一个具体的版本,比如 5.36.0,则把 5 换成它。 官方镜像在这里 。 -
- r hkg
表示选择服务器的节点为香港(离我们最近的节点)。 区域代码在这里 。 -
--name=<AppName>
表示创建的 app 名字,将<AppName>
替换成你自己的,并且注意,将来生成的默认网址是<AppName>.fly.dev
,所以请想一个独一无二的名称。 -
--no-deploy
表示暂时不部署。
这会在 blog 目录里生成一个 fly.toml 文件,使用文本编辑器打开它,使用如下代码覆盖。
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"
请将<AppName>
替换成你自己的,并且,如果不用
Mailgun
,请删除[env]
中mail__
开头的所有代码。
其中[services.ports.http_options.response.headers]
这一部分是可选的,用于设定 http header。可以逐项搜索Strict-Transport-Security
,比如,确定你是否要确定将这项加入。部署完毕之后,http header 检测地址在
这里
。
检查完毕后,保存并关闭 fly.toml 文件。然后回到终端,继续执行:
flyctl volumes create data -r hkg --no-encryption --size 1 #创建一个大小为1Gb的卷,区域为hkg,不加密(有助于提高性能)。免费额度共3GB。
flyctl deploy #部署
等待片刻,部署成功!会显示successful
.
3. 初始化 Ghost
访问
https://<AppName>.fly.dev/ghost/
以初始化 ghost。在这个之后,你就可以自由使用 ghost 来发布内容了。绑定域名、备份和恢复数据是可选的操作。
4. 绑定域名
运行:
flyctl ips list
以查看你的 app 的 IP 地址。然后在你的 DNS 服务器上为 ipv4 创建 A 记录,为 ipv6 创建 AAAA 记录,指向你的域名example.com
(必须)。创建 CNAME,<AppName>.fly.dev
,指向你的www.example.com
(非必须)。也就是
类型 | 记录 | 值 |
---|---|---|
A | @ | ipv4 address |
AAAA | @ | ipv6 address |
CNAME | www | <AppName>.fly.dev |
注意:在绑定域名之前,一定要确保正确创建 DNS 记录。
然后运行:
flyctl certs create example.com
flyctl certs create www.example.com
等待片刻,运行
flyctl certs check example.com
flyctl certs check www.example.com
以检查证书颁布的情况,一般只要 DNS提前配置正确,大约需要一两分钟。运行
flyctl ips list
以查看证书颁发情况。
注意:不要反复安装证书,因为有限额, 每 7 天只能颁布 5 张证书 。建议在调试完 app 后,再绑定。
5.重新部署
注意到 fly.toml 的
[env]
url = "https://<AppName>.fly.dev"
是 fly.io 分配的地址,如果你点击 ghost 网站的主页标题,就会转向这个地址,所以,当你绑定了自己的域名,将其换成
[env]
url = "https://example.com"
保存并关闭,然后运行flyctl deploy
。
6. 备份和恢复
以后每一次需要进入你本地的配置目录,才能正确使用 flyctl。
6.1 方法 1:使用 SFTP 备份 Ghost
优点是无需复杂配置,但复制速度极慢。
6.1.1 备份
首先登录(假设你以后需要备份);
cd blog
flyctl auth login
然后运行
flyctl ssh sftp shell -r -a <AppName>
成功后,会显示>>
(我这里是红色的),然后输入
get /var/lib/ghost/content/
这将备份全站数据,包括主题、图片、视频、文章等等。速度很慢,请耐心等待。
也可以只备份图片和视频,运行
get /var/lib/ghost/content/images/
get /var/lib/ghost/content/media/
这在 blog 目录里将生成一个 content.zip,或,images.zip 和 media.zip。将它们备份到其他地方,或命名为 content-YYYY-MM-DD.zip。
6.1.2 恢复
现在假设你重新安装了一个新的 ghost,假设还是在 fly.io,那么安装目录仍然保持为/var/lib/ghost/content/
,假设你今后在别的地方,比如 AWS 上安装 ghost,确保创建的目录为这个而不是一般教程所说的/var/www/ghost/content/
,否则恢复数据会遇到麻烦。
仍然运行
cd blog
flyctl auth login
flyctl ssh sftp shell -r -a <AppName>
然后运行
put content.zip /var/lib/ghost/content.zip
成功后,在终端新一个标签页,然后运行
flyctl ssh console
进入 ssh 后,运行
apt-get update && apt-get upgrade && apt-get install unzip
以安装unzip
。然后运行
cd /var/lib/ghost/
unzip content.zip
会直接覆盖原先的 content 文件夹。
为验证是否成功解压,运行
cd /var/lib/ghost/content/images/
ls #列出当前文件夹下的所有的文件
查看是否有新的数据。
为修复权限,运行
chown -R node:node /var/lib/ghost/content/
注意:可能的情况,无法正确覆盖 content 文件夹,那么请尝试只备份 /var/lib/ghost/content/images/
和 /var/lib/ghost/content/media/
。此时运行的是
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
可能会破坏 content 文件夹的权限,运行
ls -l /var/lib/ghost/content/
以查看 images 和 media 文件夹的用户和权限,若其权限为 root,则不能上传图片和视频了,则运行
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/
以修复,注意,其中的node
是在 fly.io 案例中的 ghost 用户,具体情况视ls -l /var/lib/ghost/content/
命令的结果为准,总之确保 images 和 media 文件夹的用户和 content 下的其他文件的用户一样。
6.2 方法 2:使用 Github 备份 Ghost
优点是复制速度快,但缺点是安装配置相对复杂。
6.2.1 备份
1.登录并进入 ssh
cd blog
flyctl auth login
flyctl ssh console
2.安装 git
apt-get update && apt-get upgrade && apt-get install git
3.在 github 网页端先创建一个私密仓库(推荐),假设名为<YourRepository>
。
4.生成密钥
ssh-keygen -t rsa -C "<GithubEmail>" #连续按回车键
5.终端新建标签,运行
flyctl ssh sftp shell -r -a <AppName>
get /root/.ssh/id_rsa.pub
回到 blog 文件夹里找到 id_rsa.pub 文件,用文本编辑器打开,并复制其中的密钥。将其添加到 github 的setting→SSH and GPG keys→SSH keys
中,保存。
测试与 github 的通信
ssh -T git@github.com
留意有没有 successful 的字眼。
ssh -T git@github.com
Hi Pathsis! You've successfully authenticated, but GitHub does not provide shell access.
6.初始化 content 的 git
cd /var/lib/ghost/content/
git init
git config --global user.name "<GithubUsername>"
git config --global user.email <GithubEmail>
git remote add origin git@github.
com:<GithubUsername>/<YourRepository>.git
git config --global --add safe.directory /var/lib/ghost/content
git add .
git commit -m "auto backup"
git push -u origin master --force
确保成功 push 到 github。
7.新建一个脚本
apt-get update && apt-get upgrade && apt-get install nano
cd /var/lib/ghost/content/
nano auto_run.sh
复制以下代码到其中
#!/bin/sh
cd /var/lib/ghost/content # 切换到目录
git config --global init.defaultBranch master
git config --global --add safe.directory /var/lib/ghost/content
git pull # 拉取仓库
git add . # 添加暂存
git commit -m "auto backup" # 提交
git push --force
按ctrl
+O
之后再回车,以写入;按ctrl
+x
,以退出 nano。
赋予该文件运行权限
chmod a+x auto_run.sh
以后,登录 ssh 后,可以直接运行
sh /var/lib/ghost/content/auto_run.sh
以执行新的 push。
6.2.2 恢复
1.登录 shh,重新安装 git,添加密钥,不再赘述。
2.清空 content 文件夹
cd /var/lib/ghost/
rm -rf content
会返回说,该文件夹无法删除,因为其busy
,没关系,它已经被清空,但没有被删除。
3.初始化 content 文件中的 git,并强制 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
4.验证是否成功拉取
ls
5.确保成功拉取数据后,重启 app
fly apps restart <AppName>
目前来看,重启或重新部署,会清除安装的环境和软件,但不会删除 ghost 的数据。
6.在 docker 中运行 cron 实在困难,不用尝试了。在普通虚拟机中,可以设置 cron,以定时运行
sh /var/lib/ghost/content/auto_run.sh