构建和托管静态网站

2024-09-25#Hugo#Cloudflare#静态网站

对于简单的内容呈现站点,比如着陆页、博客等,可以将站点提前转换为静态页面,通过HTTP服务器对外呈现内容。这样的好处是易于部署、对服务器资源要求很低,同时对SEO更友好。在市面上,已经有很多围绕静态站点的工具。对于最终用户而言,最好的体验就是:在编写了文本内容(比如以Markdown编写的文章)后,就会自动化地构建,再自动化地部署到服务器,然后即可通过浏览器访问。附加的基础能力,还包括版本控制等。

工具和服务 🔗

静态网站生成器 🔗

术语 JAMstack 是一种前端 Web 开发方法(构建用户与之交互的内容和界面)。JAM 分别代表 JavaScript、APIs、Markup;stack(堆栈)指的是将所有这些内容以一种方式结合起来,使开发人员能够构建应用程序和网站。它允许开发人员快速创建并有效地为用户提供静态网站。在 JAMstack 的Site Generators 页面,包含了一个 JAMstack 站点生成工具的清单。这些又被称为“静态网站生成器”(Static Site Generator,简称 SSG)。与传统的动态网站不同,静态网站在服务器上不需要运行复杂的服务器端脚本,而是直接提供预先生成好的网页文件给用户访问。

比较知名的静态网站生成器有:

  • Hugo:一个使用 Go 编写的命令行工具,下载可执行文件后即可使用。可使用 Markdown 编写内容,使用 Go 标准库的模板语言编写 HTML 布局模板。功能强大,且社区活跃。
  • Zola:一个使用 Rust 编写的命令行工具,无其他依赖,下载了可执行文件后即可使用。其最大的特色就是“快”,在修改了内容或者布局模板后,会立即生效。它使用了与 Jinja 类似的模板引擎 tera。不过 zola 的完成度比 Hugo 少很多。
  • Gatsby:一个使用 React 来构建快速和现代站点的工具,支持服务器端渲染。它由 Javascript 和 Typescript 编写,因此需要安装 NodeJS 等工具才可以构建站点。
  • jekyll:一个老牌的静态网站生成器,诞生于 2008 年。它由 Ruby 编写,使用 Liquid 模板。需要安装 Ruby 才可以构建站点。

站点托管 🔗

任何的 HTTP 服务器都可以托管静态站点。但还应该考虑其他的方面:

  • 费用:免费还是付费?对于免费服务,是否有用量限制?超出免费额度后,如何收费?
  • 域名:是否支持自定义域名?
  • HTTPS:是否支持HTTPS访问,是否支持免费的SSL证书?
  • 易用性:是否可以与第三方工具集成,自动化地部署?访问速度如何,是否有 CDN 加速?

几个比较知名的选项有:

  • AWS:AWS 作为云服务,尤其是 IaaS 的领导,提供了多种云服务供用户组合使用。比如:可使用 AWS S3 托管内容,使用 AWS Cloudfront 作为 CDN 对外提供服务,AWS Certificate Manager 提供 SSL 证书,同时还需要使用 AWS IAM 服务管理权限。同时可能还需要使用一些 IaC(Infrasture as Code,基础设施即代码) 工具,比如 Terraform 管理基础设施。可以看出,AWS 尽管有一切你能想到的服务,但有一定的技术门槛,需要非常熟悉相关的多个服务。AWS 对各种服务有免费额度,超出后按量收费。
  • Github Pages:使用 Github 管理站点内容,然后将其推送到代码仓库,即可使用 http://username.github.io/repository 这样的地址进行访问。Github 还允许配置自定义域名。尽管使用起来很简单,但需要注意,不同的物理位置,访问站点的速度和稳定性是不一样的,也可能出现无法访问的情况。
  • Cloudflare Pages: Cloudflare Pages 是一个 JAMstack 平台,用于前端开发者构建和部署网站。它既能与 Git(GitHub 或者 GitLab) 无缝集成,也提供了API与其他工具集成。Cloudflare Pages 提供了免费计划,包括每月500次的构建,无限静态请求与无限带宽等。当然,Cloudflare 本身就是 CDN 提供商,也就提供了 CDN 加速服务。支持自定义域名和SSL证书。

除此之外,还有 VercelRender 等。

https://bejamas.io/compare 里列出了一些托管工具的比较。比如 Cloudflare Pages 和 GitHub Pages 的比较

自动化的构建和部署工具 🔗

尽管可在本机构建站点,然后在浏览器里上传内容到托管平台,但生成HTML站点和部署,毕竟是一个重复和无聊的事情。如果有工具自动做这件事,岂不美哉?对于有技术背景的开发者而言,Git 是管理文本内容极其版本的不二之选。有些托管平台与Github等代码托管平台有深度集成,可以在提交了代码之后,自动生成和部署站点;有些托管平台提供了鉴权和内容管理的API,可以通过命令行工具进行部署。

实现 🔗

以 Hugo、Cloudflare 和 Github Actions 为例,介绍构建和部署静态站点的方法。

使用 Hugo 构建站点 🔗

参考 Hugo 的官方文档,创建项目,添加内容。并使用 Git 进行版本控制。

在 Github 管理站点内容 🔗

在 Github 创建代码仓库(公开和私有仓库均可)。然后将项目内容推送到代码仓库中。

在 Cloudflare 创建 Pages 🔗

创建项目 🔗

登录 Cloudflare 后,进入 Workers & Pages 菜单项,点击 Create 后,在 Create an application 页面选择 Pages。此时点击 Upload assets,在 Deploy a site by uploading your project 创建项目。创建好之后,可以上传一个临时的 HTML 页面,用于验证项目创建成功。Cloudflare 会给每个项目生成一个 pages.dev 的子域名,在创建项目后,可能需要等一段时间,这个域名才能生效。

绑定域名 🔗

在项目页面里的 Custom Domain 选项卡,创建自定义域名。需要注意的是,如果项目的域名是顶级域名,那么需要在域名提供商处将名字服务器(Name Server, NS)修改为 Cloudflare 的DNS;如果是二级域名,那么可以直接在域名提供商处,添加 DNS 记录即可。

在绑定域名后,可能需要等一段时间才能生效。

通过 Github Actions 构建和部署站点 🔗

Cloudflare 官方提供了用于部署 Pages 的 cloudflare/pages-action。查看其示例,就会发现,在部署时,需要指定 apiTokenaccountIdprojectName。其中 projectName 就是 Cloudflare Pages 的项目名。

获取 API Token 🔗

参考文档《Create API token 》,在 User API Tokens 页面创建 API Token。出于“最小权限原则”,创建一个 Custom Token(自定义 Token),而不使用 API token template。打开 Create Custom Token 页面后,在 Permissions 里选择 AccountCloudflare Pages,同时在 Account Resources 里选择 Include 和项目所在下账户。然后设置 Token 的有效期(TTL)。

获取 Account ID 🔗

参考文章 《Find zone and account IDs 》,找到 Account ID。

在 Github Actions 中设置环境变量 🔗

在 Github 中,进入项目的 Settings页面,打开 Security 下的 Secrets and variables - Actions 页面,添加两个 Repository Secret:CLOUDFLARE_API_TOKENCLOUDFLARE_ACCOUNT_ID,其内容分别为从 Cloudflare 里获取的 API Token 和 Account ID。

添加工作流定义 🔗

在代码仓库中,添加 .github/workflows/main.yaml 文档,作为构建和发布的工作流定义。内容如下:

on: [push]

jobs:
  build:
    runs-on: ubuntu-latest
    env:
      HUGO_VERSION: 0.134.2
    steps:
      - name: Install Hugo CLI
        run: |
          wget -O ${{ runner.temp }}/hugo.deb https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-amd64.deb \
          && sudo dpkg -i ${{ runner.temp }}/hugo.deb
      - name: Install Dart Sass
        run: sudo snap install dart-sass
      - name: Checkout
        uses: actions/checkout@v4
        with:
          submodules: recursive
          fetch-depth: 0
      - name: Install Node.js dependencies
        run: "[[ -f package-lock.json || -f npm-shrinkwrap.json ]] && npm ci || true"
      - name: Build with Hugo
        env:
          HUGO_CACHEDIR: ${{ runner.temp }}/hugo_cache
          HUGO_ENVIRONMENT: production
          TZ: Asia/Shanghai
        run: |
          hugo \
            --gc \
            --minify \
            --baseURL "${{ steps.pages.outputs.base_url }}/"
      - name: Upload artifact
        uses: actions/upload-artifact@v4
        with:
          name: public
          path: ./public
  publish:
    runs-on: ubuntu-latest
    name: Publish to Cloudflare Pages
    needs: build
    if: github.ref == 'refs/heads/main'
    permissions:
      contents: read
    steps:
      - uses: actions/download-artifact@v4
        with:
          name: public
          path: ./public
      - name: Publish to Cloudflare Pages
        uses: cloudflare/pages-action@v1
        with:
          apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
          accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
          projectName: "your project name"
          directory: public
          wranglerVersion: "3"

在这个工作流定义中,包含了2个作业(Job):buildpublish

  • build 作业构建了站点。它下载了 hugo 可执行文件,然后使用 hugo 构建站点,最后使用 actions/upload-pages-artifactpublic 目录作为“构件”(artifact)上传
  • publish 作业下载了“构件”之后,发布到 Cloudflare Pages 中。注意,此作业只在当前分支为 main 分支时执行。

注意,这里使用两个步骤略显复杂,但是将构件和发布解耦了。这个好处是,在使用 PR 或者分支添加站点内容时,会进行构建,但不会部署。

测试 🔗

.github/workflows/main.yaml 提交到代码库的 main 分支后,Github Actions 就会自动地构建,然后发布到 Cloudflare。

与 Github 集成的其他方法 🔗

在 Cloudflare 的 Create an application 页面创建 Pages 时,可以 Connect to Git 按钮。其实,Cloudflare 对于 Github 有内建的集成。将 Github 账号授权给 Cloudflare 之后,当有代码提交时,Cloudflare 就会自行构建和部署。Cloudflare 所支持的构建工具可见 Framework presets 列表,包括 Hugo、Zola等。但这样会把 将 Github 用户的所有代码仓库都授权给 Cloudflare。在某些情况下,可能不太适合,因此并没有使用这种方式。

结尾 🔗

Cloudflare是一家提供 CDN、网络安全、DDoS 防御和域名服务的美国公司。在中文互联网中,Cloudflare 被称为 “赛博菩萨”、“赛博活佛”、“大善人”等。它“慷慨”地提供了很多免费的服务,被众多网友“白嫖”。经过对 Cloudflare Pages 的一番测试,开发者体验确实很棒,值得进一步探索。


加载中...