在Google App Engine部署Jekyll博客
这篇文章简单介绍了如何通过 Travis CI 自动构建 Jekyll 博客、发布到 GAE,并配置使用自定义域名和 Cloud Flare 代理。
Google App Engine 基于 Google Cloud Platform,是谷歌提供的搭建可伸缩 Web 应用和移动后端的平台,属于 PaaS 。
目前支持 Python、Java、PHP、Go,当然,也支持静态文件,因而是 Github Pages 的替代方案之一。
(插一句题外话,当时的选项有 Surge、PubStorm、Netlify 这样的静态文件托管服务和 GAE、Heroku 这样的 PaaS、CaaS。然而 Surge 的 HTTPS 要收不菲的钱、PubStorm 即将关门、其他 PaaS、CaaS 有限的免费配额拿来做静态博客托管又有点浪费,最后就选定了 Netlify 和 GAE。)
开始之前
首先你要有一个 Jekyll Site 的 Git Repository,也是你最终要部署的站点。
这个站点的源码应该托管在 GitHub,以使用 Travis CI。为了使用 Travis CI 的命令行客户端,一个 ruby 环境也是必须的 —— 不过既然你都在用 Jekyll,这个应该没问题。
然后你需要一个 Google 账号,激活云平台。
如果不想使用 GAE 的子域名,就需要有一个你自己的域名,至少你需要有配置域名 CNAME 记录的权限。
如果你需要在墙内访问你的站点,就需要域名的整个所有权,因为 Cloud Flare 要求 Free Plan 将 NS 记录指向他们的服务器。
创建 GAE 项目
在 GAE 中创建一个项目;根据需要设置项目的区域,比如我选择的就是亚洲东北部。
创建 GAE 的私钥
你需要为对应的GAE项目创建服务账户,这样 Travis CI 才能通过服务账户的私钥获得部署的权限。(理论上你可以直接下载项目默认服务账户的私钥,但是推荐创建一个专用的服务账户。)
打开 Google Cloud Platform 的控制台,确定上方项目列表中选中的项目是你刚创建的项目,展开控制台左侧主菜单,点击 IAM和管理员,在打开的页面左侧面板点击 服务账户,在右侧的面板中点击 创建服务账户。
在弹出的窗口中给服务账户起个名字,如 Travis-CI,角色选择 项目 - 编辑者,勾选 提供新的私钥,密钥类型选择 JSON,然后点击 创建。
妥善保存下载到的私钥文件,可以先存放在 Git Repository 的根目录,但是加密之前不要提交。通过这个私钥可以获取对你 GAE 项目的写权限。建议在执行过加密之后删除这个未加密的私钥文件。
配置 GAE 项目
首先配置 GAE,让 GAE 帮我们提供静态站点服务。
GAE 的配置通过 app.yaml
进行,这个文件需要放在 Git Repository 的根目录下,详细说明可以参考官方文档。大致地说明一下用到的一些配置:
runtime: python27
指定运行环境,使用 Python 2.7 。threadsafe: false
关闭线程安全,允许并行服务。skip_files:
指定不部署的文件。我跳过了除_sites
外的所有文件夹和根目录下的大部分文件。handlers
配置处理单元,可以配置多个,按照顺序匹配执行。 客户端的请求会按照url
进行匹配,使用static_dir
表示整个文件夹作为静态文件提供服务,使用static_files
表示指定的一个(或一组)文件作为静态文件提供服务。使用static_files
匹配一组文件时,要注意同时指定upload
的配置,告知 GAE 如何寻找对应的文件。libraries:
指定要引用的库。这里我们需要引用webapp2
。
完整的配置如下:
runtime: python27
api_version: 1
threadsafe: false
skip_files:
- ^(_drafts|_posts|assets|files|.sass-cache)/(.*)$
- ^[a-zA-z]+.(xml|txt|html|md|yml|ico)$
- Gemfile
- gae.json
- gae.json.enc
handlers:
- url: /
static_files: _site/index.html
upload: _site/index\.html
secure: always
- url: /((archives|atom|categories|favicon|index|rss|sitemap|tags)\.(xml|txt|html|ico))$
static_files: _site/\1
upload: _site/.*\.(xml|txt|html|ico)$
secure: always
- url: /assets
static_dir: _site/assets
secure: always
- url: /files
static_dir: _site/files
secure: always
- url: /(.+)/
static_files: _site/\1/index.html
upload: _site/.*/index\.html
secure: always
- url: /(.*)
static_files: _site/404.html
upload: _site/404\.html
secure: always
libraries:
- name: webapp2
version: "latest"
配置 Travis CI
然后配置 Travis CI,让 Travis CI 在我们 push 博客文章之后自动 build 并发布到 GAE。
Travis CI 的配置通过 .travis.yml
进行,这个文件同样需要放在 Git Repository 的根目录下,详细说明见官方文档。几个需要注意的配置如下:
language: ruby
使用 ruby 环境。rvm: - 2.2.5
使用 rvm,指定一个较新的 ruby 版本。branches: only: - master
只处理 master 分支。sudo: false
不需要 sudo 权限,Travis CI 会在 Docker 容器中执行构建,可以缩短构建的等待时间。script: - bundle exec jekyll build
构建 Jekyll 站点,不需要指定 JEKYLL_ENV。deploy:
指定部署方式。配置provider: gae
指定部署到 GAE,配置project: your-project-id
指定要部署的 GAE项目,配置skip_cleanup: true
不清理生成文件, 配置keyfile: your-service-account-key.json
指定 GAE 的私钥(注意是不加密的文件名,不带.enc
后缀)。before_install: - openssl ...
解密私钥文件,这条配置不需要手动写,会由下一步的加密过程自动加入。
完整配置如下:
language: ruby
rvm:
- 2.2.5
branches:
only:
- master
sudo: false
before_install:
- openssl aes-256-cbc -K $encrypted__key -iv $encrypted__iv -in gae.json.enc -out gae.json -d
script:
- bundle exec jekyll build
deploy:
provider: gae
skip_cleanup: true
keyfile: gae.json
project: blog-
加密 GAE 的私钥
安全起见,GAE 的私钥需要加密,才能添加到 Git Repository 中。
在站点根目录下执行如下命令,将私钥文件加密并将解密需要的信息加入 .travis.yml
:
travis encrypt-file your-service-account-key.json --add
加密会生成一个.enc
结尾的加密文件,安全起见,请删除未加密的原文件,并将源文件名加入 .gitignore
在提交时进行排除。
参考 Travis CI 加密相关的文档。
Jekyll 的排除设置
上述的这些配置文件,需要加入 _config.xml
的 exclude
节在构建时进行排除。
exclude:
- vendor
- Gemfile
- Gemfile.lock
- .gitignore
- .travis.yml
- app.yaml
- gae.json
- gae.json.enc
测试上述配置
至此,自动部署的基本配置已经完成了,现在可以提交并推送代码到 GitHub 了。稍候片刻,Travis CI 应该会自动触发 build,生成 Jekyll 站点并部署到 GAE。
如果一切顺利,你应该可以通过https://your-project-id.appspot.com
访问你的站点了。
配置 GAE 自定义域名和 SSL
GAE 默认提供一个子域名,并提供 SSL 支持。如果你不想使用 GAE 默认的子域名,可以添加自己的域名;为自己的域名上传证书之后,也可以开启 SSL 支持。官方文档中 使用自定义域名和SSL 一节详述了相关配置,这里我们简单介绍一下。
打开 Google Cloud Platform 的控制台,确定上方项目列表中选中的项目是你刚创建的项目,展开控制台左侧主菜单,点击 App引擎,在打开的页面左侧面板点击 设置,在右侧的面板中点击 自定义网域 标签,再点击下面的 添加 自定义网域 按钮。
在 选择要使用的网域 中,选择你需要绑定的自定义域名并点击 继续。如果以前没有添加过,则选择 验证新网域,输入自定义域名,点击 验证;网络管理员中心 的窗口会弹出,指引你进行下一步的验证域名所有权;在列表中选择你的域名提供商,根据提示操作,或者选择 其他 ,则有 TXT 记录和 CNAME 记录两种验证方式。完成验证之后,就可以将自定义域名添加到项目。
自定义域名添加之后,还需要在你的域名解析服务商处将域名指向谷歌,推荐直接配置 CNAME 记录到 ghs.google.com
;如果是根域名,推荐配置 A记录,可以在 自定义网域 标签下找到 IP地址列表。
刚添加的域名是没有 SSL 支持的,上传证书之后才能通过 HTTPS 访问。GAE支持下列几种证书(基本都支持):
- 单域名证书
- 自签名证书
- 泛域名证书
- 多域名证书
注意,Cloud Flare 的 Origin Certificate 是不被 GAE 支持的,你可以使用 Let’s Encrypt 的证书或者 自签名的证书。如何生成自签名证书可以参考这篇文章。
点击 自定义网域 标签右边的 SSL 证书 标签,点击 上传新证书 按钮,填写 名称,选择公钥证书、私钥证书文件或者直接粘贴文件内容,点击上传。点击刚刚上传的证书,在 为以下自定义网域启用 SSL 的列表中勾选对应域名,点击 保存,新证书即可应用于当前 GAE 项目的指定自定义域名。
配置 Cloud Flare 代理
现在你的站点还无法在墙内访问;如果使用自签名的证书,也无法被浏览器信任。Cloud Flare 的代理可以解决这两个问题,只需要把你的域名添加到 Cloud Flare 并开启 Proxy 和 SSL。
登陆 Cloud Flare 的账户,点击右上角的 + Add Site,按照向导添加域名,并在域名服务商处修改 NS 记录。在新建站点的过程中,确保你之前的 DNS 记录都正确地导入了,或者在新建站点之后重新添加漏掉的记录。
添加站点之后,在 DNS 页面下找到你添加到 GAE 的域名的对应记录,确保右边的 Status 是橘色的云朵标志(DNS and HTTP proxy),即代理已经开启。等待新的 DNS 记录生效,就可以在墙内访问站点了。
在 Crypto 页面,将 SSL 调整为 Full,即可启用 SSL 支持。如果你在 GAE 上传了正式的 SSL 证书(非自签名的证书,如 Let’s Encrypt 的证书),可以将 SSL 调整为 Full (strict),即严格模式,会验证源站点的SSL证书是否被信任(非严格模式只要求源站点支持SSL即可,因而自签名证书只能使用非严格模式),理论上更安全。
在 Crypto 页面,还可以启用 HSTS(HTTP严格传输层安全)。
至此,在 GAE 部署 Jekyll 博客的配置就完成了。目前本博客就在使用这个配置。每次 Push 新的文章到 GitHub,Travis CI就会自动进行构建,并发布到 GAE;通过 Cloud Flare,在墙内也可以访问,并且连接是 SSL 加密的。