前言

这是一篇手动创建Hugo博客的教程,跟着教程一步一步的进行,最终你将会得到一个类似我这样的博客,在这个过程中,如果你能用心思考,善用搜索,你将会理解,这些服务彼此是如何连接的,每一项服务的功能是什么,以及如何修改它们的配置文件。理解这些后,你就可以根据自己的需求,创建自己的博客组合了。如果不想手动创建,你也可以使用 Stackbit来自动创建博客。它支持Hugo,Gatsby和Jekyll,后台管理支持Netlify CMS,Forestry和Contentful。关于Stackbit的教程,以后会写,先挖坑。

一、技术总结

经过一周的摸索和实践,终于把这个博客搭建成功了。简单总结一下本博客所使用的技术。

上面提到的这些服务,除了购买域名需要花钱,其他服务都是免费的,购买域名也不是必要条件, Netlify 可以提供的二级域名。

二、必要条件

  1. 注册 GitHub
  2. 注册 Netlify
  3. 注册 CloudFlare
  4. 一台可以访问网络的计算机

三、博客使用的服务简介

  1. Hugo 是使用 Go 语言编写的,静态博客生成平台。使用Hugo平台,你可以快速的生成博客页面,因为是静态博客,所以访问者的载入速度是非常快的,静态博客对爬虫是很友好的,这样就利于被搜索引擎抓取网站。
  2. Netlify 提供免费的静态博客托管服务和免费二级域名:https://suan.netlify.com
  3. GitHub提供免费代码托管服务,Hugo 生成的代码,会存在这里里。
  4. Netlify CMS是一套开源的后台管理平台,支持 Markdown 语法,给习惯在后台编辑文章的人使用。
  5. CloudFlare拥有全球最大的网络之一,提供 CDN,DNS,ssl证书等服务,远不止这些。

四、安装 Hugo

1.Ubuntu系统:

先去 Hugo release查看 Hugo的最新版本,用最新版本号替代下面代码里面的0.59.1,你也可以直接复制下面的代码,进行下载和安装。

1
2
3
4
#使用 wget 下载 hugo
wget https://github.com/gohugoio/hugo/releases/download/v0.59.1/hugo_0.59.1_Linux-64bit.deb
#使用 dpkg 安装 .deb 文件
sudo dpkg -i hugo_0.59.1_Linux-64bit.deb

2.MacOS 系统:

1
brew install hugo

如果你没有brew包工具,你可以用下面的命令安装brew包工具

1
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

五、使用 Hugo创建静态博客

1.创建网站存放目录

1
2
3
4
5
6
# 使用 mkdir命令,创建网站目录
mkdir -p /var/www
# 使用 cd命令,进入创建的目录
cd /var/www
# 新建站点,名字以3cho为例,你可以替换成自己的名字
hugo new site 3cho

2.安装主题,主题可以去Hugo官方主题库下载,本文以 even 主题为例

1
2
3
4
5
6
# 进入新建好的3cho目录
cd /var/www/3cho
# 安装主题(不同主题安装方式不同)
git clone https://github.com/olOwOlo/hugo-theme-even themes/even
#复制主题自带的 config.toml文件到当前根目录
cp themes/even/exampleSite/config.toml ./config.toml

3.创建一篇测试新文章

1
2
#生成一篇新文章
hugo new post/hello.md

4.生成博客静态博客

1
2
# 生成静态网页,包括草稿,生成好的内容在public目录中
hugo -D

5.启动本地博客服务器

1
hugo server

点击访问你的博客http://localhost:1313

到这里,博客搭建工作已经完成了,接下来是把这个博客,部署到网络上,这样其他人才可以访问你的博客了。

6.关闭本地博客服务器

使用快捷键 ctrl+c 关闭本地博客服务器

六、GitHub使用

1.创新一个新的Github仓库

Create a new repository repository在 GitHub点击查看官方教程,你不需要看文字,跟着图走就行。repository名字是什么很重要,下面我们要用它来替换3cho。

2.初始化 GitHub,初始化意思是初次建立本地目录和 GitHub远程仓库的连接

1
2
3
4
5
6
7
#仓库名字repository以3cho为例
echo "# 3cho" >> README.md
git init
git add README.md
git commit -m "first commit"
git remote add origin [email protected]:替换成你的 GitHub用户名/3cho.git
git push -u origin master

七、连接Netlify前的准备

1.删除主题下面的.git文件,主题以 even为例

1
2
cd /var/www/3cho/themes/even
rm -rf .git

2.创建 Netlify 需要的配置文件

1
nano netlify.toml

3.复制下面的文件粘贴进去,Hugo version后面的数字替换成,你安装的版本。不明白什么意思,可以不改。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
[build]
publish = "public"
command = "hugo --gc --minify"

[context.production.environment]
HUGO_VERSION = "0.59.1"
HUGO_ENV = "production"
HUGO_ENABLEGITINFO = "true"

[context.split1]
command = "hugo --gc --minify --enableGitInfo"

[context.split1.environment]
HUGO_VERSION = "0.59.1"
HUGO_ENV = "production"

[context.deploy-preview]
command = "hugo --gc --minify --buildFuture -b $DEPLOY_PRIME_URL"

[context.deploy-preview.environment]
HUGO_VERSION = "0.59.1"

[context.branch-deploy]
command = "hugo --gc --minify -b $DEPLOY_PRIME_URL"

[context.branch-deploy.environment]
HUGO_VERSION = "0.59.1"

[context.next.environment]
HUGO_ENABLEGITINFO = "true"

粘贴完成后,你需要同时按 ctrl+x来退出,再输入y确认保存,再按回车确认保存。

4.创建 Netlify CMS所需要的配置文件和目录

1
touch static/.keep data/.keep

5.创建Netlify CMS需要用的 admin 和 img文件夹

1
2
mkdir /var/www/3cho/static/admin
mkdir /var/www/3cho/static/img

6.创建Netlify CMS页面

1
nano /var/www/3cho/static/admin/index.html

7.复制下面的文件粘贴进去

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Content Manager</title>
    <!-- Include the script that enables Netlify Identity on this page. -->
    <script src="https://identity.netlify.com/v1/netlify-identity-widget.js"></script>
  </head>
  <body>
    <!-- Include the script that builds the page and powers Netlify CMS -->
    <script src="https://unpkg.com/netlify-cms@^2.0.0/dist/netlify-cms.js"></script>
  </body>
</html>

粘贴完成后,你需要同时按 ctrl+x来退出,再输入y确认保存,再按回车确认保存。

8.创建Netlify CMS配置文件

1
nano /var/www/3cho/static/admin/config.yml

9.复制下面的文件粘贴进去

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
backend:
  name: git-gateway
  branch: master
media_folder: static/img
public_folder: /img
collections:
  - name: config
    label: Config
    files:
      - name: config
        label: Config
        file: config.toml
        fields:
          - widget: string
            name: title
            label: Title
            required: false
          - widget: string
            name: baseURL
            label: Base URL
            required: false
            hint: Hostname (and path)  to the root
          - widget: boolean
            name: enableRobotsTXT
            label: Enable Robots Text
            required: false
          - widget: boolean
            name: enableEmoji
            label: Enable Emoji
            required: false
          - widget: string
            name: theme
            label: Theme name
            required: false
          - widget: boolean
            name: hasCJKLanguage
            label: Has CJK Language
            required: false
          - widget: number
            name: paginate
            label: Paginate
            required: false
            hint: Number of articles displayed on the homepage
            valueType: int
          - widget: number
            name: rssLimit
            label: Rss Limint
            required: false
            hint: Limit Entry Count to Rss file
            valueType: int
          - widget: string
            name: disqusShortname
            label: Disqus Shortname
            required: false
          - widget: string
            name: googleAnalytics
            label: Google Analytics code
            required: false
          - widget: string
            name: copyright
            label: Copyright
            required: false
          - widget: string
            name: defaultContentLanguage
            label: Default Content Language
            required: false
          - widget: object
            name: languages
            label: Languages
            required: false
            fields:
              - widget: object
                name: en
                label: English
                required: false
                fields:
                  - widget: string
                    name: languageCode
                    label: Language code
                    required: false
          - widget: object
            name: author
            label: Author
            required: false
            fields:
              - widget: string
                name: name
                label: Name
                required: false
          - widget: object
            name: sitemap
            label: Sitemap
            required: false
            fields:
              - widget: string
                name: changefreq
                label: Change frequency
                required: false
              - widget: number
                name: priority
                label: Priority
                required: false
                valueType: float
              - widget: string
                name: filename
                label: Filename
                required: false
          - widget: object
            name: menu
            label: Menu
            required: false
            fields:
              - widget: list
                name: main
                label: Main Menu
                required: false
                fields:
                  - widget: string
                    name: name
                    label: Menu Name
                    required: false
                  - widget: number
                    name: weight
                    label: Page order weight
                    required: false
                    valueType: int
                  - widget: string
                    name: identifier
                    label: Identifier
                    required: false
                  - widget: string
                    name: url
                    label: Menu Link
                    required: false
          - widget: object
            name: params
            label: Site Parameters
            required: false
            fields:
              - widget: string
                name: since
                label: Since
                required: false
                hint: Site Creation Time
              - widget: boolean
                name: homeFullContent
                label: Home Full Content
                required: false
                hint: >-
                  if false, show post summaries on home page. Othewise show full
                  content.
              - widget: boolean
                name: rssFullContent
                label: Rss Full Content
                required: false
                hint: 'if false, Rss feed instead of the summary'
              - widget: string
                name: logoTitle
                label: Logo Title
                required: false
              - widget: list
                name: keywords
                label: Keywords
                required: false
                field:
                  label: String
                  name: string
                  widget: string
              - widget: string
                name: description
                label: description
                required: false
              - widget: string
                name: dateFormatToUse
                label: Date Format
                required: false
              - widget: boolean
                name: toc
                label: TOC
                required: false
              - widget: boolean
                name: photoswipe
                label: Photo Swipe
                required: false
              - widget: string
                name: contentCopyright
                label: Content Copyright
                required: false
              - widget: list
                name: customCSS
                label: Custom Css
                required: false
                hint: >-
                  if ['custom.css'], load '/static/css/custom.css' fileif
                  ['custom.css'], load '/static/css/custom.css' file
                field:
                  label: String
                  name: string
                  widget: string
              - widget: list
                name: customJS
                label: Custom JS
                required: false
                hint: 'if [''custom.js''], load ''/static/js/custom.js'' file'
                field:
                  label: String
                  name: string
                  widget: string
              - widget: object
                name: social
                label: Social
                required: false
                fields:
                  - widget: string
                    name: a-email
                    label: Email
                    required: false
                  - widget: string
                    name: b-stack-overflow
                    label: StackOverflow
                    required: false
                  - widget: string
                    name: c-twitter
                    label: Twitter
                    required: false
                  - widget: string
                    name: d-facebook
                    label: Facebook
                    required: false
                  - widget: string
                    name: e-linkedin
                    label: Linkedin
                    required: false
                  - widget: string
                    name: f-google
                    label: Google
                    required: false
                  - widget: string
                    name: g-github
                    label: Github
                    required: false
                  - widget: string
                    name: h-weibo
                    label: Weibo
                    required: false
                  - widget: string
                    name: i-zhihu
                    label: Zhihu
                    required: false
                  - widget: string
                    name: j-douban
                    label: Douban
                    required: false
                  - widget: string
                    name: k-pocket
                    label: Pocket
                    required: false
                  - widget: string
                    name: l-tumblr
                    label: Tumblr
                    required: false
                  - widget: string
                    name: m-instagram
                    label: Instagram
                    required: false
                  - widget: string
                    name: n-gitlab
                    label: Gitlab
                    required: false
                  - widget: string
                    name: o-goodreads
                    label: Goodreads
                    required: false
                  - widget: string
                    name: p-coding
                    label: Coding
                    required: false
                  - widget: string
                    name: q-bilibili
                    label: Bilibili
                    required: false
                  - widget: string
                    name: r-codeforces
                    label: Codeforces
                    required: false
                  - widget: string
                    name: s-mastodon
                    label: Mastodon
                    required: false
  - name: basicpage
    label: Basic pages
    folder: content/
    create: true
    extension: md
    slug: '{{slug}}'
    fields:
      - widget: string
        name: title
        label: Title
        required: false
      - widget: datetime
        name: date
        label: Publish Date
        required: false
      - widget: datetime
        name: lastmod
        label: Last Modified Date
        required: false
      - widget: string
        name: menu
        label: Menu
        required: false
      - widget: number
        name: weight
        label: Page Order weight
        required: false
        valueType: int
      - widget: boolean
        name: comment
        label: Comment
        required: false
      - widget: boolean
        name: mathjax
        label: Mathjax
        required: false
        hint: 'see https://www.mathjax.org/'
      - widget: markdown
        name: body
        label: Content
        required: false
        hint: Page content
  - name: post
    label: Blog postss
    folder: content/post
    create: true
    extension: md
    slug: '{{slug}}'
    fields:
      - widget: string
        name: title
        label: Blog Title
        required: false
      - widget: string
        name: description
        label: Description
        required: false
      - widget: string
        name: author
        label: Blog Author
        required: false
      - widget: datetime
        name: date
        label: Publish date
        required: false
      - widget: datetime
        name: lastmod
        label: Last Modified Date
        required: false
      - widget: list
        name: tags
        label: Tags
        required: false
        field:
          label: String
          name: string
          widget: string
      - widget: list
        name: categories
        label: Categories
        required: false
        field:
          label: String
          name: string
          widget: string
      - widget: boolean
        name: draft
        label: Draft
        required: false
      - widget: boolean
        name: comment
        label: Comment
        required: false
      - widget: boolean
        name: toc
        label: Toc
        required: false
      - widget: boolean
        name: autoCollapseToc
        label: Auto Collaps Toc
        required: false
      - widget: string
        name: contentCopyright
        label: Content Copyright
        required: false
      - widget: boolean
        name: reward
        label: Reward
        required: false
      - widget: boolean
        name: mathjax
        label: Mathjax
        required: false
        hint: 'see https://www.mathjax.org/'
      - widget: boolean
        name: katex
        label: Katex
        required: false
        hint: 'See https://github.com/KaTeX/KaTeX'
      - widget: string
        name: markup
        label: Markup
        required: false
        hint: 'See https://gohugo.io/content-management/formats/#mmark'
      - widget: number
        name: weight
        label: Weight
        required: false
        valueType: int
      - widget: object
        name: menu
        label: Menu
        required: false
        fields:
          - widget: object
            name: main
            label: Main
            required: false
            fields:
              - widget: string
                name: parent
                label: Parent Menu
                required: false
              - widget: number
                name: weight
                label: Weight
                required: false
                valueType: int
      - widget: markdown
        name: body
        label: Content
        required: false
        hint: Page content

粘贴完成后,你需要同时按 ctrl+x来退出,再输入y确认保存,再按回车确认保存。

10.上传到GitHub

1
2
3
4
5
6
7
#仓库名字repository以3cho为例
echo "# 3cho" >> README.md
git init
git add .
git commit -m "install"
git remote add origin [email protected]:替换成你的 GitHub用户名/3cho.git
git push -u origin master

八、Netlify连接 GitHub仓库

1.使用Github帐号登录Netlify

2.创建新的站点

Netlfiy 创建新站点

3.连接 Github

4.选择博客说在的GitHub仓库

5.部署

等待完成,你的博客就已经成功创建了。Netlify 会提供一个二级域名。但是名字比较难记,你可以更改一个好记一些的。

6.更改二级域名名字

大功告成

九、Netlify CMS

1.开启身份验证功能

2.开启 Git Gateway

3.开启邮箱免验证功能

4.邀请自己成为管理员

5.填写自己的邮箱

6.去邮箱接收邀请邮箱

7.访问Netlify CMS后台

后台地址是,你的网站后面加 admin,以 https://suan.su 为例,后台管理登录地址应该是:https://suan.su/admin

后话

当我逐渐熟悉了Github和找到了喜爱的本地Markdown编辑器 Typora后,我已经不太想使用netlify cms了,但是 netlify cms对初学者还是很友好的。