更多 Hugo 迁移技巧





5.00/5 (2投票s)
这篇博文继续我关于如何从 Medium 迁移到 Hugo 系列的文章。
这篇博文继续我关于如何从 Medium 迁移到 Hugo 系列的文章。您可以在此处阅读第一部分。

2019 年 6 月,我将我的博客从 Medium 托管解决方案迁移到了使用 Hugo 的自托管静态网站。这篇博文将介绍我的旅程中的步骤,包括创建自定义嵌入、添加内容安全策略以及如何配置我的 Azure 存储静态网站并设置从 GitHub 的持续部署来发布我的博客。
在这篇博文中,我将介绍如何集成广告、包含静态图片、将其托管在 Azure 存储静态网站上,并使用 Azure Pipelines 构建了持续部署管道。
致富之路
我不指望通过我的博客发家致富。我投入大量时间和精力来撰写、编辑和发布内容,因为我热衷于教学。我希望内容保持免费,并且我乐于为我的努力赚取一点收入。我没有选择将文章隐藏在付费墙后面或烦人的“立即订阅”弹窗,而是选择了一种侵扰性较小的方法。当我链接到我购买和试用过的产品时,我一直使用亚马逊推荐链接。对于新博客,我决定添加 Google AdSense。我在两个地方使用它:搜索和横幅广告。
集成搜索
使用 Google AdSense 进行搜索为我解决了一些问题。首先,由于博客是静态网站,没有交互式搜索功能。Google 提供了一个动态表单,可以搜索您的域,显示缩略图(我将在未来的文章中详细介绍如何创建缩略图),并提供快速的“即插即用”体验。其次,它集成了广告,使我有机会产生适度的收入(为了透明起见,我每月赚取的收入足以购买一顿饭或租几部视频)。
搜索组件包含搜索表单的代码和结果的代码。我创建了两个短代码。第一个是 gsearch.html
,用于捕获查询。
<script async src='https://#/cse.js?cx=partner-pub-#######:#####'></script>
<div class="gcse-searchbox-only"></div>
<p> </p>
第二个是 gresults.html
,用于渲染结果。
<script async src='https://#/cse.js?cx=partner-pub-########:#####'></script>
<div class="gcse-searchresults-only"></div>
在 content/static
路径下,我创建了 search.md
。
---
title: "Search Developer for Life"
author: "Jeremy Likness"
date: 2003-06-13T0000.000Z
lastmod: 2019-06-24T1010-07:00
description: "Search across blog posts."
aliases:
- "/search"
---
Enter your search terms below to find content on this blog.
{{<gsearch>}}
### Search Results
{{<gresults>}}
生成的代码是响应式的。这是在 Galaxy S5 上搜索 WebAssembly 的搜索结果。
这就是我完成博客搜索体验所需的一切!
横幅广告
我选择使用单个横幅广告。如果您对广告有所了解,“首屏”或更高位置的横幅广告通常效果更好。我决定不想让第一印象是迎面而来的广告,而是您所寻找的内容,所以我将其放在文章底部(并且,没有恼人的对话框乞求您禁用广告拦截器)。Google 有一个响应式广告单元,可以自动适应提供的空间。
为了创建一个可重用的单元,我在 layouts/partials/_shared
下放置了一个名为 banner.html
的文件。这样,如果我选择移除代码或使用不同的广告,就可以轻松地进行更换。此部分仅包含 Google 生成的嵌入广告的代码。
<script async src="https://#/pagead/js/adsbygoogle.js"></script>
<!-- Blog Below the Fold Display Ad -->
<ins class="adsbygoogle"
style="display:block"
data-ad-client="ca-pub-#######"
data-ad-slot="#####"
data-ad-format="auto"
data-full-width-responsive="true"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>
我将其插入到 single.html
模板的底部,如下所示。
{{ if not .Params.noads }}
{{ partial "_shared/banner.html" }}
{{ end }}
我将在下一节中解释 noads
(无广告)参数以及在引入广告后我如何处理隐私问题。
静态页面和文件
在静态资源方面,我经历了一些学习过程。理想情况下,像我的“关于页面”这样的内容应该位于网站的根目录 /about
下,但我将其放在了 content/static/about.md
下,所以它最终会生成一个从 /about
到 /static/about
的重定向。后来我发现了一个更好的方法,但选择保持现有的路径“原样”。在我实施我的 隐私政策时,我在 content/privacy/index.md
创建了一篇文章。这会在 /privacy
创建一个页面,没有任何重定向。前置 matéria 和文章的撰写方式与其他条目相同。我甚至可以用我的相对文章短代码来引用它。
这是 Developer for Life 的完整隐私政策。了解我们使用的确切服务以及我们跟踪的内容。
我没有给它设置标签、系列或年份,所以它不会出现在分类中。我还引入了 noads
设置,以便通过在前置 matéria 中将其设置为 true
来隐藏隐私页面上的广告。
其他静态资源包括我的签名的全局图片、自定义 CSS 和一个 ads.txt
文件。这些都直接放在 /static
下(而不是 content/static
),并在生成的网站中“原样”构建。
托管在 Azure 上
Hugo 生成的是静态网站。还有什么比使用 Azure 存储静态网站更好的托管方式呢?实际上,我会考虑两种选择。我听说过 Netlify 的很多好处,特别是它易于使用和集成。Netlify 的部署过程是内置的。
选择 Azure 存储,我知道我需要构建自己的管道。由于我作为一名 云开发倡导者的角色,我想 自己体验我谈论的服务。我还考虑过容器、应用服务,甚至虚拟机,但归根结底,我选择 Azure 存储有三个原因。
- 成本
- 成本
- 成本
当我提到成本时,我指的是低。有多低?根据 Google 的数据,我平均每月有 7,500 名访客和 15,000 次页面浏览量。预计我的月成本是...不到 1 美元。
(您可以看到在我第一次上传网站时成本的“激增”。)这不仅仅是一个存储东西的存储桶。我将其设置为 区域冗余存储,它将文件分布在区域内的三个存储集群中,并提供 12 个 9 的持久性。这可能有点过头,因为我将网站保存在源代码管理中,可以随时从头开始重建它。
配置网站很简单。我创建了我的账户,打开了静态网站功能,指定 index.html
作为默认文档,404.html
作为我的“未找到”页面,然后上传了内容。该服务会自动提供一个 Azure 托管的域名和一个 SSL 证书,但我需要将其放在我自己的自定义域名下,所以我转向 Cloudflare 获取他们的免费服务。
Cloudflare
Cloudflare 提供多种服务,包括防攻击保护、网站免费 SSL 证书和自动缓存。我已经在我的旧博客和链接缩短工具上使用 Cloudflare,所以只是将其扩展到覆盖我的新博客。我在 DNS 中添加了一个 CNAME
记录来别名 Azure 存储端点,并设置了一个安全连接。我还启用了缓存和 JavaScript/CSS 自动最小化等功能。
上个月有超过 3GB 的数据是从缓存提供的,这降低了我的存储成本,并为您提供了更快的用户体验。我对存储和 CloudFlare 的组合非常满意,以至于我将我的主域名也迁移了过去,并将在下一个计费周期取消我的托管服务,每年节省约 100 美元。
打破束缚
那我现有的 Medium 存在怎么办?我为其他出版物撰写文章,所以我不想删除我的账户或任何故事。事实证明,这种方法对我的博客上的故事“效果很好”。以前,我为我的博客出版物设置了自定义域名。Medium 知道这一点,所以任何请求都会被重定向到我的博客。我保留了带有别名的原始 Medium 链接,所以一切连接都很好。我丢失了现有的评论,并且不再在发布新内容时通知关注者,但我的大部分流量来自搜索引擎和其他社交媒体网站。我怀疑将来如果 Medium 不再重定向,我可以去停用旧文章。
Azure Pipelines
我理想的工作流程是在 GitHub 中编辑文章,进行检查,一旦 draft
标志被关闭,就自动将其部署到网站。我通过两个阶段实现这一点:构建和部署。
构建
最初,我在 Windows 上设置了一个 Azure Pipelines 构建代理,并使用 Chocolatey 安装 Hugo,然后生成网站。这个过程花了大约几分钟,大部分时间都花在了安装 Hugo 上。我的同事 Shayne Boyer 建议我通过创建 Docker 容器来简化这个过程。
我创建了这个 🐳 Docker 文件。
FROM alpine:3.5 as build ENV HUGO_VERSION 0.55.6 ENV HUGO_BINARY hugo_${HUGO_VERSION}_Linux-64bit.tar.gz # Certificates RUN apk update \ && apk upgrade \ && apk add --no-cache ca-certificates \ && update-ca-certificates # Install Hugo RUN set -x && \ apk add --update wget ca-certificates && \ wget https://github.com/spf13/hugo/releases/download/v${HUGO_VERSION}/${HUGO_BINARY} && \ tar xzf ${HUGO_BINARY} && \ rm -r ${HUGO_BINARY} && \ mv hugo /usr/bin
这将构建我正在使用的特定 Hugo 版本。当我升级本地 Hugo 版本时,我会更新 Docker 文件。为了托管该文件,我创建了一个 Azure 容器注册表(对我来说,预计每月约增加 1 美元,所以我们每月运营我的博客的成本是 2 美元)。我甚至不需要构建和上传镜像。ACR 支持 Azure 容器注册表任务,可以直接从我的本地命令行在 Azure 中构建镜像。有了在存储库中构建和存储的镜像,我创建了这个构建管道。
trigger: - master pool: vmImage: 'ubuntu-16.04' steps: - task: DockerInstaller@0 inputs: dockerVersion: '17.09.0-ce' displayName: 'Install Docker CLI' - task: Docker@2 inputs: containerRegistry: 'DeveloperforLifeRegistry' command: 'login' displayName: 'Login to registry' - script: git submodule init workingDirectory: '$(Build.Repository.LocalPath)/themes/mediumish-gohugo-theme' displayName: 'Init theme' - script: git submodule update workingDirectory: '$(Build.Repository.LocalPath)/themes/mediumish-gohugo-theme' displayName: 'Update theme' - script: docker run --rm -v $(Build.Repository.LocalPath):/usr/site -w /usr/site developerforlife.azurecr.io/dev4lifehugo:v2 hugo workingDirectory: $(Build.Repository.LocalPath) displayName: 'Generate website' - task: PublishBuildArtifacts@1 inputs: PathtoPublish: '$(Build.Repository.LocalPath)/public' ArtifactName: 'blog' publishLocation: 'Container'
步骤是
- 安装 Docker CLI
- 登录 ACR(我的镜像已安全,只有我才能访问它)。
- 下载生成网站所需的模板文件。
- 在容器内运行 Hugo,将源文件挂载到容器的
/usr/site
。 - 从生成的文件创建构件。
整个过程每次部署只需要几分钟(通过专用机器和文件比较,我相信可以缩短到几秒钟,但对我来说几分钟就足够了)。
发布
来自构建的构件需要部署到 Azure 存储帐户。我使用发布来实现这一点。我没有 QA 或暂存环境,所以只有一个步骤。
唯一的任务是Azure Blob 文件复制任务,该任务在几秒钟内将构件上传到 Blob 存储。
现在我可以编辑我的文章和模板,只需将更改推送到 GitHub,即可触发自动构建和部署。
摘要
这个设置对我来说非常棒,因为我现在可以完全控制我的网站源代码,可以随时构建它,并且几乎可以在任何地方托管它,同时只需很少的努力就能获得缓存和安全等功能。
故事还没有结束!在未来的博文中,我将介绍如何创建内容安全策略、动态生成缩略图的秘密以及如何创建用于链接到其他博客文章的预览短代码。
此致,