前言
这是一篇手动创建Hugo博客的教程,跟着教程一步一步的进行,最终你将会得到一个类似我这样的博客,在这个过程中,如果你能用心思考,善用搜索,你将会理解,这些服务彼此是如何连接的,每一项服务的功能是什么,以及如何修改它们的配置文件。理解这些后,你就可以根据自己的需求,创建自己的博客组合了。如果不想手动创建,你也可以使用 Stackbit来自动创建博客。它支持Hugo,Gatsby和Jekyll,后台管理支持Netlify CMS,Forestry和Contentful。关于Stackbit的教程,以后会写,先挖坑。
一、技术总结
经过一周的摸索和实践,终于把这个博客搭建成功了。简单总结一下本博客所使用的技术。
上面提到的这些服务,除了购买域名需要花钱,其他服务都是免费的,购买域名也不是必要条件, Netlify 可以提供的二级域名。
二、必要条件
- 注册 GitHub
- 注册 Netlify
- 注册 CloudFlare
- 一台可以访问网络的计算机
三、博客使用的服务简介
- Hugo 是使用 Go 语言编写的,静态博客生成平台。使用Hugo平台,你可以快速的生成博客页面,因为是静态博客,所以访问者的载入速度是非常快的,静态博客对爬虫是很友好的,这样就利于被搜索引擎抓取网站。
- Netlify 提供免费的静态博客托管服务和免费二级域名:https://suan.netlify.com。
- GitHub提供免费代码托管服务,Hugo 生成的代码,会存在这里里。
- Netlify CMS是一套开源的后台管理平台,支持 Markdown 语法,给习惯在后台编辑文章的人使用。
- 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 系统:
如果你没有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
|
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.启动本地博客服务器
点击访问你的博客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 需要的配置文件
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仓库
2.创建新的站点
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对初学者还是很友好的。