私有化 Git Pages 源码仓库

1. 前言

被一件事儿恶心到了, 发现最开始发在博客园上的文章被爬到了一个不知名的小网站, 没有署名, 没有注明来源。 真的对这种侵犯个人权利的事情感到恶心, 至少引用和转载文章需要注明来源。 国内互联网的内容同质化严重, 优质内容也逐渐减少不是没有道理的。

一气之下把 cnblogs 的内容都删掉了。

后来又想了想什么地方造成了数据外泄, 毕竟 markdown 数据也是保存在自己的私有仓库中, 估计 content 部分的内容被精准地洗劫了, 而且图片是上传在博客园的服务器上的, 被爬走还能正常显示, 这和在 Git Pages 中用相对地址引用还有区别。

感觉自己的 Git Pages 把源码都泄露在外头无异于数据裸奔, 另外 sitemap.xml 每次都需要自己去手动更新, 明明 jekyll-sitemap 插件能够将这件事情自动化处理, 于是产生了分离源码仓库和展示仓库的想法。

2. 私有化与自动化部署

实现的思路很清晰, 通过 Github Action 实现私有仓库的数据编译, 再将编译后的内容推送到目标公有仓库中, 所有的内容均对外不可见就完成了源码的私有化和部署的公有化。

flowchart LR p1(Private Repository) p2(Git Action) p3(Public Repository) style p1 fill:#4F94CD,stroke:#363636,stroke-width:2px,color:#F5F5F5 style p2 fill:#DCDCDC,stroke:#363636,color:#8B8B7A,color:#696969 style p3 fill:#FF6A6A,stroke:#363636,stroke-width:2px,color:#F5F5F5 p1 --> p2 p2 -->|Compile/Push| p3

需要在自己的源码仓库中创建 .github/workflows/jekyll.yml 文件, 当然文件名可以自定义。 这样 Git Action 就可以识别这个配置文件的内容, 这个仓库就能执行配置文件定义的各个步骤。 在其中复制粘贴如下代码, 将其中带有提示性的大写的字符都替换为自己的配置。 但需要注意的是, 我们需要通过 ssh-keygen -t rsa 生成用于该仓库推送的一对密钥, 将私有密钥填写在私有仓库的 Settings->Actions secrets and variablesSecrets 中, 并将这个 secret 命名为 DEPLOY_KEY。 之后需要将公有密钥添加到 Github 账号的 Settings->SSH and GPG keys 中。

# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.

# Sample workflow for building and deploying a Jekyll site to GitHub Pages
name: Deploy Jekyll site to Pages

on:
  # Runs on pushes targeting the default branch
  push:
    branches: ["YOUR_PRIVATE_REPO_SOURCE_BRANCH"]

  # Allows you to run this workflow manually from the Actions tab
  workflow_dispatch:

# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
permissions:
  contents: read
  pages: write
  id-token: write

# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
concurrency:
  group: "pages"
  cancel-in-progress: false

env:
  TZ: Asia/Shanghai

jobs:
  # Build job
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3
        with:
           persist-credentials: true # false 是用 personal token,true 是使用 GitHub token
           fetch-depth: 0
      - name: Setup Ruby
        uses: ruby/setup-ruby@55283cc23133118229fd3f97f9336ee23a179fcf # v1.146.0
        with:
          ruby-version: '3.1' # Not needed with a .ruby-version file
          bundler-cache: true # runs 'bundle install' and caches installed gems automatically
          cache-version: 0 # Increment this number if you need to re-download cached gems
      - name: Build with Jekyll
        # Outputs to the './_site' directory by default
        run: bundle exec jekyll build --baseurl "$" --config ./_config.yml
        env:
          JEKYLL_ENV: production
          TZ: Asia/Shanghai
      - name: Upload artifact
        # Automatically uploads an artifact from the './_site' directory by default
        uses: actions/upload-pages-artifact@v1
      - name: Set SSH Environment
        env:
          # 1. Add this private key and title as DEPLOY_KEY in this repo -> settings/secrets
          # 2. Add corresponding public key and named as any text to the github page repo -> settings/deploy keys
          DEPLOY_KEY: $
          USER_NAME: YOUR_USER_NAME
          USER_EMAIL: YOUR_USER_EMAIL
        run: |
          mkdir -p ~/.ssh/
          echo "$DEPLOY_KEY" | tr -d '\r' > ~/.ssh/id_rsa
          chmod 600 ~/.ssh/id_rsa
          chmod 700 ~/.ssh && chmod 600 ~/.ssh/*
          ssh-keyscan github.com >> ~/.ssh/known_hosts
          git config --global user.name $USER_NAME
          git config --global user.email $USER_EMAIL
      - name: Commit and Push to Git Pages
        env:
          USER_NAME: YOUR_USER_NAME
          USER_EMAIL: YOUR_USER_EMAIL
        working-directory: ./
        run: |
          git clone -b PUBLIC_REPOSITORY_BRANCH git@github.com:YOUR_USER_NAME/YOUR_USER_NAME.github.io.git gitpage_repo
          cd gitpage_repo
          cp robots.txt ../_site/robots.txt
          rm -rf *
          cp -r ../_site/* .
          git add -A
          git -c user.name="$USER_NAME" -c user.email="$USER_EMAIL" commit -am "Site Updated: `date +'%Y-%m-%d %H:%M:%S'`"
          git push origin master -f -q

简化了个人摸索这个自动化配置的过程, 若对以上配置有所疑惑之处, 可以参考以下文章加深个人理解。 如有问题欢迎留言询问~

GitHub 私有仓库免费开启 GitHub Pages 的可行性方案
通过Github Action自动部署Hexo
Hexo Deploy with Github Actions workflow
使用 GitHub Actions 自动部署 Hexo 博客
github actions中如何判断仓库是否有变更

3. 爬虫与目录结构保护

更改网站的 robots.txt 为如下形式

---
layout: null
---

User-agent: *

Disallow: /assets/   # /assets/ 是常规资源目录,不怕暴露路径
Disallow: /norobots/ # 零碎敏感文件、目录等放置在此

Sitemap: https://hangx-ma.github.io/sitemap.xml

出于安全考虑,站点的某些目录结构,譬如 /norobots/, 不希望被外部访问, 所以需要使用重定向来保护目录, 可以使用 GitHub 推荐的 Jekyll 重定向插件 Jekyll Redirect From

GitHub Pages 默认支持该插件,在项目的 Gemfile 里添加引用:

gem "jekyll-redirect-from"

接着运行 bundle install 命令安装插件,安装完成后,在站点 404 页面的 YAML 头部添加跳转规则:

---
redirect_from:
  - /norobots/
---

具体的目录可以更具自己站点的实际情况定义, 按照上述定义, 访问 {SITE_URL}/norobots/ 会直接返回 404 页面, 从而保护了敏感目录。

Jekyll 的 SEO 优化