Hugo养成记(1)-安装与部署

本文记录 Hugo 的安装与部署入门笔记。

Hugo 安装

Hugo 是一个基于 Go 语言的静态网站生成工具(框架),特点是页面生成速度快,主题丰富,文档详细(英文)。

安装

1、到 Hugo Release 下载所需版本。推荐下载 Extended 版本,解压后应该得到3个文件,其中一个是 hugo.exe。

2、新建 D:\hugo\sites 作为 hugo 站点仓库,仓库可以存放多个站点。

3、新建 D:\hugo\bin 作为 hugo 执行目录,将前面解压得到的 hugo.exe 放到 bin 目录下。

4、将 D:\hugo\bin 加入到系统环境变量 Path 中,这样就可以通过 PowerShell 或 Git Bash 直接执行 hugo 命令。

验证安装是否成功:hugo help,如果有 Hugo 的提示信息表明安装成功。hugo version命令可以查看 hugo 版本。若提示未找到命令,则是环境变量未生效,需要寻求促使新增环境变量生效的方案(具体请求助搜索引擎)。

生成站点结构

使用 hugo new site 命令可以快速生成一个空的站点结构。假如希望在 D:\hugo\sites 目录下生成站点 migchar.com,则切换到 sites 目录下,执行:

$ hugo new site migchar.com 

hugo 为我们生成的默认站点目录如下:

.
 └── content
     └── about
     |   └── _index.md       // <- https://migchar.com/about/
     ├── post
     |   ├── _index.md       // <- https://migchar.com/post/
     |   ├── firstpost.md    // <- https://migchar.com/post/firstpost/
     |   ├── happy
     |   |   └── ness.md     // <- https://migchar.com/post/happy/ness/
     |   └── secondpost.md   // <- https://migchar.com/post/secondpost/
     └── quote
         ├── first.md        // <- https://migchar.com/quote/first/
         └── second.md       // <- https://migchar.com/quote/second/

安装主题

Hugo默认是没有主题的,需要先安装主题才能正常显示我们的网站内容。

# 切换到 migchar.com 站点根目录
$ cd migchar.com
# 下载主题到 themes 目录,更多主题到 hugo 官网下载
$ git submodule add https://github.com/budparr/gohugo-theme-ananke.git themes/ananke

一般情况下下载的主题都会带有 exampleSite 目录,这里面包含了主题需要的一些默认内容和结构,如果你希望自己的网站看起来跟主题预览显示的一样,可以将 exampleSite 目录里的内容复制到 站点根目录(migchar.com 目录),并根据需要修改 config.toml 文件。要使用哪个主题需要在 config.toml 里设置,也可以随时更换主题。

写作

content

在 migchar.com 目录下执行以下命令,就在 migchar.com/content/posts 下生成了文章。以后都在 content/ 下写作。推荐使用 Typora 编辑 md 文件。

hugo new posts/my-first-post.md

我们可以自己组织 content/ 目录,Hugo 会自动将我们自己组织的结构反映到生成的静态页面结构中。

.
 └── content
     └── about
     |   └── _index.md       // <- https://migchar.com/about/
     ├── post
     |   ├── _index.md       // <- https://migchar.com/post/
     |   ├── firstpost.md    // <- https://migchar.com/post/firstpost/
     |   ├── happy
     |   |   └── ness.md     // <- https://migchar.com/post/happy/ness/
     |   └── secondpost.md   // <- https://migchar.com/post/secondpost/
     └── quote
         ├── first.md        // <- https://migchar.com/quote/first/
         └── second.md       // <- https://migchar.com/quote/second/

front matter

对于一篇 Hugo 文章来说,front matter 的作用是告诉 Hugo 如何处理我们的文章。下面是一些可选的 front matter 属性:

---
 title: "文章标题"
 description: "文章的描述信息"
 tags: [ "标签1", "标签2", "标签3" ]
 categories: [ "分类1", "分类2" ]
 keywords: [ "Hugo", "keyword" ]
 date: 2019-01-01
 lastmod: 2019-01-02
 # CJKLanguage: Chinese, Japanese, Korean
 isCJKLanguage: true
 ​
 # 如果draft为true,除非使用 --buildDrafts 或 -D 参数,否则不会发布文章
 draft: false
 ​
 # 设置文章的过期时间,如果是已过期的文章则不会发布,除非使用 --buildExpired 或 -E 参数
 expiryDate: 2020-01-01
 ​
 # 设置文章的发布时间,如果是未来的时间则不会发布,除非使用 --buildFuture 或 -F 参数
 publishDate: 2020-01-01
 ​
 # 排序你的文章
 weight: 40
 ​
 # 使用这两个参数将会重置permalink,默认使用文件名
 url: 
 slug: 
 ​
 # 别名将通过重定向实现
 aliases:
   - 别名1
   - /posts/my-original-url/
   - /2010/01/01/another-url.html
 ​
 # type 与 layout 参数将会改变 Hugo 寻找该文章模板的顺序,将在下一节细述
 type: review
 layout: reviewarticle
 ​
 # 三个比较复杂的参数
 taxonomies:
 linkTitle: 
 outputs:
 # 实验性的参数
 markup: "md"
 ​
 # 你还可以自定义任何参数,这些参数可以在模板中使用
 include_toc: true
 show_comments: false
 ---
---
 title: "文章标题"
 description: "文章的描述信息"
 tags: [ "标签1", "标签2", "标签3" ]
 categories: [ "分类1", "分类2" ]
 keywords: [ "Hugo", "keyword" ]
 date: 2019-01-01
 lastmod: 2019-01-02
 # CJKLanguage: Chinese, Japanese, Korean
 isCJKLanguage: true
 ​
 # 如果draft为true,除非使用 --buildDrafts 或 -D 参数,否则不会发布文章
 draft: false
 ​
 # 设置文章的过期时间,如果是已过期的文章则不会发布,除非使用 --buildExpired 或 -E 参数
 expiryDate: 2020-01-01
 ​
 # 设置文章的发布时间,如果是未来的时间则不会发布,除非使用 --buildFuture 或 -F 参数
 publishDate: 2020-01-01
 ​
 # 排序你的文章
 weight: 40
 ​
 # 使用这两个参数将会重置permalink,默认使用文件名
 url: 
 slug: 
 ​
 # 别名将通过重定向实现
 aliases:
   - 别名1
   - /posts/my-original-url/
   - /2010/01/01/another-url.html
 ​
 # type 与 layout 参数将会改变 Hugo 寻找该文章模板的顺序,将在下一节细述
 type: review
 layout: reviewarticle
 ​
 # 三个比较复杂的参数
 taxonomies:
 linkTitle: 
 outputs:
 # 实验性的参数
 markup: "md"
 ​
 # 你还可以自定义任何参数,这些参数可以在模板中使用
 include_toc: true
 show_comments: false
 ---

运行与部署

1、启动 Hugo 内置服务器。

hugo server -D

通过本地 http://localhost:1313 就可以访问站点,每当站点内容有所修改时服务会实时编译并刷新浏览器,不需要每次修改都重启本地服务器。

2、生成静态页面

hugo

在站点根目录 migchar.com / 下执行 hugo 命令,默认会在站点根目录下生成 public 文件夹,里面是 hugo 生成的静态页面,只需要将 public/ 里的内容分发布到自己的服务器即可。如果要修改静态页面存放的目录,可以在 config.toml 里设置publishdir节点,或者使用 hugo /static-dir命令指定静态页面生成路径。

如果一篇 md 文章在 fromt matter 设置了以下属性之一,则 hugo 命令不会编译这篇文章。

publishdate: 
expirydate: 
draft: true

写作流程

假设你已经熟悉前面的工作,以后当你要写新的文章时,大概的流程是这样子的:

1、在 content/posts/ 或其他你自定义的目录创建新文章。

hugo new posts/my-new-post.md

以上命令创建了默认 front matter 的文章,自动生成的 front matter 的取决于\hugo\sites\migchar.com\archetypes\default.md ,在我们执行 hugo new的时候 Hugo 会使用 default.md 作为模板,如果你不希望每次生成的 md 文件默认 draft: true,可以自己修改 default.md 文件。

# default content of default.md
title: "{{ replace .Name "-" " " | title }}"
date: {{ .Date }}
draft: true
# default content of default.md
title: "{{ replace .Name "-" " " | title }}"
date: {{ .Date }}
draft: true

2、启动内置 web 服务器,这样就可以在浏览器实时预览文章。如果不加上 -D 标识则 Hugo 不会编译标记为 draft 的文章。

hugo server -D

3、文章完成后运行 hugo 命令,生成静态页面,便于部署。

建议使用 hugo –minify 命令生成压缩的静态页面,减少页面体积

常用命令

用法:
  hugo
  hugo [flags]
  hugo [command]
  hugo [command] [flags]

可选的 Commands:
  config      打印站点配置信息
  deploy      部署站点(前提是配置了部署信息)
  help        帮助信息
  list        打印文章列表
  new         为站点创建新的内容
  server      一个高性能的web服务器

可选的 Flags:
  -b, --baseURL        指向服务器部署地址,部署必选,否则相关资源会404,推荐在config.toml中指定
  -D, --buildDrafts    包括被标记为draft的文章
  -E, --buildExpired   包括已过期的文章
  -F, --buildFuture    包括将在未来发布的文章
用法:
  hugo
  hugo [flags]
  hugo [command]
  hugo [command] [flags]

可选的 Commands:
  config      打印站点配置信息
  deploy      部署站点(前提是配置了部署信息)
  help        帮助信息
  list        打印文章列表
  new         为站点创建新的内容
  server      一个高性能的web服务器

可选的 Flags:
  -b, --baseURL        指向服务器部署地址,部署必选,否则相关资源会404,推荐在config.toml中指定
  -D, --buildDrafts    包括被标记为draft的文章
  -E, --buildExpired   包括已过期的文章
  -F, --buildFuture    包括将在未来发布的文章
Hugo 常用命令

以下命令默认你已经切换到站点根目录 migchar.com/

# 例子
hugo new posts/my-post.md 在content/posts/目录下创建文章
hugo 生成静态文件
hugo -D 生成静态文件,包括在frontmatter中draft为true的文章
hugo --minify 生成压缩的静态文件(html)
hugo server -D 生成静态文件(包括draft)并启动内置web服务器

参考文档:

在 Hugo 中使用 Sass – kok的笔记本
https://wocai.de/post/2019/03/%E5%9C%A8-hugo-%E4%B8%AD%E4%BD%BF%E7%94%A8-sass/

支持编译 scss,必须使用extended版本。

sass-如何使用Hugo设置SCSS-代码日志
https://stackoverflow.com/questions/54057291/how-to-setup-scss-with-hugo

部署到 Github Pages

通过 Github 客户端部署

前提:安装了 Git Bash(或 Github Desktop),拥有 Github 账号

Github官方已经有详细的 Github Pages 教程:https://pages.github.com/。需要注意的是Github Pages有两种类型,一种是 User or organization site,一种是 Project site,这里我们选择创建 User site,方法是创建一个仓库命名为 username.github.io ,username 需要替换为 Github 账户名,然后将网页上传到这个仓库即可,通过 username.github.io就可以访问上传的网页。hugo官方有自动化部署的教程:https://gohugo.io/hosting-and-deployment/hosting-on-github/

我比较喜欢手动部署,以下介绍我的部署过程:

1、安装 Github 客户端:https://desktop.github.com/ ,登录 Github 账户。

2、通过客户端将 migchar/migchar.github.io 克隆到本地。

github desktop clone
Github 客户端 Clone

如果你的 public/ 是通过 hugo 命令生成的,那在 clone 之前需要先清空 public/ 文件夹中的内容。clone 完成后会在 public/ 中生成隐藏的 .git/ 文件夹,如果要保持这个 public/ 与你的 Github Pages 仓库相关联,便记得不要删除 .get/ 文件夹,如果误删,则要清空 public/ 后重新 clone 。

3、完成本地 public/ 与远程仓库 https://github.com/migchar/migchar.github.io 关联后,只要通过 hugo 命令在 public/ 生成静态页面,Github客户端都能实时监测到文件的改动,手动在客户端点击 Commit to master 并 Push origin 就可以完成部署。访问 migchar.github.io 可以看到最新部署的博客。

绑定个人域名

前面的部署使得我们可以通过 migchar.github.io 访问本博客,但这是 github 提供的二级域名,如果想通过自己的个人域名 migchar.com 访问到 Github Pages,需要进行域名解析。

1 创建站点CNAME

在本地 hugo 站点根目录(我的是 migchar/static/)新建 CNAME 文件,CNAME文件里只写入你的域名(我写入了一行 migchar.com),运行 hugo 命令重新生成 public/ 静态页面,commit 并 push 到 Github。这一步告诉 Github 我们要将这个 Pages 绑定到域名 migchar,而且任何 migchar.github.io 的访问将重定向到 migchar.com。也可以在 Github Pages 设置, 到 https://github.com/migchar/migchar.github.io/settings 设置页面找到 Github Pages 选项,将自己的域名填入 Custom domain 并保存,Github 会自动帮我们在站点根目录生成 CNAME 文件。

2 域名解析

到域名服务商进行域名解析,添加两条记录:

主机记录记录类型线路类型记录值
@A默认185.199.110.153
wwwCNAME默认yourusername.github.io

其中A 记录的记录值要填你 yourusername.github.io 站点对应的 IP 地址。注意这个 IP 值是 Github 提供的,在未来可能会改变,一旦改变就要重新解析。操作无误的话稍等一会就可以通过个人域名访问到 Github Pages 了。

开启 HTTPS

前两年 Github Pages 绑定个人域名后开启 HTTPS 比较麻烦,需要借助国外 Cloudflare 之类支持 SSL 的 CDN 服务才能完成,但是现在不用这么麻烦,因为 Github 已经与 Let’s Encrypt 合作,为自定义域名提供免费的 HTTPS 支持。

开启HTTPS很简单,到 https://github.com/migchar/migchar.github.io/settings 仓库设置页面找到 Github Pages 选项,如果 Enforce HTTPS 处于不可勾选状态,先清空 Custom domain 并保存,然后重新填入自定义域名再保存,最后勾选 Enforce HTTPS 选项即可。SSL 证书颁发需要一定时间,在证书生效之前访问自定义域名会提示证书问题,等生效就好了。如果证书生效后浏览器左侧还是提示不安全,需检查站点是否引用了 http 资源,替换成相应的 HTTPS 资源即可。

github pages setting
Github Pages 开启 HTTPS

自动部署到云服务器

hugo搭建个人博客-第三弹Github Actions自动部署到阿里云服务器 – 灰信网(软件开发博客聚合)
https://www.freesion.com/article/4704539398/

部署到 GAE

如果想要部署到 GAE,可以按照以下操作。个人觉得 GAE 没有 Github Pages 方便和灵活,但是 GAE 可以支持动态语言,也有够用的免费额度,根据需要取舍吧。

安装 Google Cloud SDK

下载并安装 Google Cloud SDK,根据安装程序提示完成安装。

1568103662701
GCP 安装界面

确保勾选上 Bundles Python 和 Cloud Tools for PowerShell。安装完成后应该会自动启动 Google Cloud SDK Shell 并执行 gcloud init 命令, 我一般会将d:\Program Files (x86)\Google\Cloud SDK\google-cloud-sdk\bin加入到系统的 Path 环境变量。

初始化 Google Cloud SDK

打开 cmd 或 PowerShell 执行 gcloud init 命令,进行初始化工作,根据指示登录 Google 账号、授权访问 Google Cloud Platform 资源、选择 Cloud Platform Project 等,还可以指定 网络代理。

gcloud 命令:

gcloud auth list列出本地系统已有授权凭据的 Google 账号

gcloud config list 列出 gcloud sdk 的项目配置属性,包括 Google账号,已授权 Cloud Platform Project 列表等。

配置代理:

gcloud config set proxy/type PROXY_TYPE
gcloud config set proxy/address PROXY_IP_ADDRESS
gcloud config set proxy/port PROXY_PORT

部署应用

假设我们已经在 Google Cloud Platform 创建了 My First Project 项目,并在该项目下创建了一个 App Engine 应用,接下来要做的便是把我们的项目代码部署到这个 App Engine 实例上。

在项目根目录创建 app.yaml 文件,PowerShell 或 CMD 切换到项目根目录(app.yaml 文件所在目录)执行以下命令:

gcloud app deploy

对于中国网络,执行部署命令前要求你已经设置好网络代理,让你的计算机能够访问到 Google 服务器。

如果设置了 Path 环境变量,部署命令也可以通过 Git bash 执行,要注意的是在 Git bash 中 gcloud 命令加上文件的扩展名,即:gcloud.cmd app deploy

部署完成后执行以下命令,可以通过浏览器访问应用,默认

gcloud app browse

配置 app.yaml

app.yaml 是 Google App Engine 的应用配置文件,主要作用是指定 url 与静态文件之间的对应关系,当然还包括与应用代码相关的信息,比如运行时和服务版本等。

app.yaml 位于服务程序的根目录。通常来讲 GAE 服务的目录如下:

my-service
  app.yaml
  public
    index.html
    ...

我们希望访问 https://my-app-name.appspot.com 时对应的是 my-service/public/index.html 文件,同时访问其他 css、js 等静态文件时能自动对应上public中的文件。以下 app.yaml 能应付大多数情况。

runtime: python37
default_expiration: 1h
handlers:

  - url: /(.*\.(appcache|manifest))
    mime_type: text/cache-manifest
    static_files: public/\1
    upload: public/(.*\.(appcache|manifest))
    expiration: "0m"

  - url: /(.*\.atom)
    mime_type: application/atom+xml
    static_files: public/\1
    upload: public/(.*\.atom)
    expiration: "1h"

  - url: /(.*\.crx)
    mime_type: application/x-chrome-extension
    static_files: public/\1
    upload: public/(.*\.crx)

  - url: /(.*\.css)
    mime_type: text/css
    static_files: public/\1
    upload: public/(.*\.css)

  - url: /(.*\.eot)
    mime_type: application/vnd.ms-fontobject
    static_files: public/\1
    upload: public/(.*\.eot)

  - url: /(.*\.htc)
    mime_type: text/x-component
    static_files: public/\1
    upload: public/(.*\.htc)

  - url: /(.*\.html)
    mime_type: text/html
    static_files: public/\1
    upload: public/(.*\.html)
    expiration: "1h"

  - url: /(.*\.ico)
    mime_type: image/x-icon
    static_files: public/\1
    upload: public/(.*\.ico)
    expiration: "7d"

  - url: /(.*\.js)
    mime_type: text/javascript
    static_files: public/\1
    upload: public/(.*\.js)

  - url: /(.*\.json)
    mime_type: application/json
    static_files: public/\1
    upload: public/(.*\.json)
    expiration: "1h"

  - url: /(.*\.m4v)
    mime_type: video/m4v
    static_files: public/\1
    upload: public/(.*\.m4v)

  - url: /(.*\.mp4)
    mime_type: video/mp4
    static_files: public/\1
    upload: public/(.*\.mp4)

  - url: /(.*\.(ogg|oga))
    mime_type: audio/ogg
    static_files: public/\1
    upload: public/(.*\.(ogg|oga))

  - url: /(.*\.ogv)
    mime_type: video/ogg
    static_files: public/\1
    upload: public/(.*\.ogv)

  - url: /(.*\.otf)
    mime_type: font/opentype
    static_files: public/\1
    upload: public/(.*\.otf)

  - url: /(.*\.rss)
    mime_type: application/rss+xml
    static_files: public/\1
    upload: public/(.*\.rss)
    expiration: "1h"

  - url: /(.*\.safariextz)
    mime_type: application/octet-stream
    static_files: public/\1
    upload: public/(.*\.safariextz)

  - url: /(.*\.(svg|svgz))
    mime_type: images/svg+xml
    static_files: public/\1
    upload: public/(.*\.(svg|svgz))

  - url: /(.*\.swf)
    mime_type: application/x-shockwave-flash
    static_files: public/\1
    upload: public/(.*\.swf)

  - url: /(.*\.ttf)
    mime_type: font/truetype
    static_files: public/\1
    upload: public/(.*\.ttf)

  - url: /(.*\.txt)
    mime_type: text/plain
    static_files: public/\1
    upload: public/(.*\.txt)

  - url: /(.*\.unity3d)
    mime_type: application/vnd.unity
    static_files: public/\1
    upload: public/(.*\.unity3d)

  - url: /(.*\.webm)
    mime_type: video/webm
    static_files: public/\1
    upload: public/(.*\.webm)

  - url: /(.*\.webp)
    mime_type: image/webp
    static_files: public/\1
    upload: public/(.*\.webp)

  - url: /(.*\.woff)
    mime_type: application/x-font-woff
    static_files: public/\1
    upload: public/(.*\.woff)

  - url: /(.*\.xml)
    mime_type: application/xml
    static_files: public/\1
    upload: public/(.*\.xml)
    expiration: "1h"

  - url: /(.*\.xpi)
    mime_type: application/x-xpinstall
    static_files: public/\1
    upload: public/(.*\.xpi)

  # image files
  - url: /(.*\.(bmp|gif|ico|jpeg|jpg|png))
    static_files: public/\1
    upload: public/(.*\.(bmp|gif|ico|jpeg|jpg|png))

  # audio files
  - url: /(.*\.(mid|midi|mp3|wav))
    static_files: public/\1
    upload: public/(.*\.(mid|midi|mp3|wav))

  # windows files
  - url: /(.*\.(doc|exe|ppt|rtf|xls))
    static_files: public/\1
    upload: public/(.*\.(doc|exe|ppt|rtf|xls))

  # compressed files
  - url: /(.*\.(bz2|gz|rar|tar|tgz|zip))
    static_files: public/\1
    upload: public/(.*\.(bz2|gz|rar|tar|tgz|zip))

  # site root
  - url: /
    static_files: public/index.html
    upload: public/index.html
    expiration: "15m"

  # index files
  - url: /(.+)/
    static_files: public/\1/index.html
    upload: public/(.+)/index.html
    expiration: "15m"

  - url: /(.+)
    static_files: public/\1/index.html
    upload: public/(.+)/index.html
    expiration: "15m"

  - url: /(.*)
    static_files: public/\1
    upload: public/(.*)

需要注意的是 site root 跟 index files 的配置必须置于末尾。mime_type 描述文件的媒体类型,GAE 默认通过文件后缀来确认文件的 MIME 值。default_expiration 设置全局默认的浏览器缓存期限,expiration 为静态文件设置单独的浏览器缓存期限,GAE 在 Cache-Control 和 Expires HTTP响应头中发送缓存期限。如果静态文件改动频繁,最好设置一个较短的缓存期限。缓存期限默认为10min。

参考资料

[1] app.yaml 参考 | Google Cloud

[2] 在 Google App Engine 上托管静态网站 | Google Cloud

hugo博客
上一篇
下一篇