从 Typecho 迁移到 Jekyll
由于腾讯云买的服务器明年到期,如果想要有优惠必定需要迁移到其他厂商,但是如果想要其他厂商就又需要走一遍备案流程,十分麻烦。考虑到过去3年,这台服务器除了搭建博客外,也没有什么其他用途(主要是国内服务器很多操作都比较繁琐),于是决定明年降配置,但是会继续考虑腾讯云。
其实以上种种原因都只是做出这个决定的其中几个因素,最重要的原因是这两年来(从2023年9月开始),在找工作的压力下,我实在无心维护这个博客。但是考虑到这也算作是我的作品之一,还是不忍放弃,我还时常回顾很多当时走过的路、踩过的坑,于是决定将全站迁移为静态网站。
至于为什么用 Jekyll,因为我找到一个名为 Chirpy 的主题,它功能实现完整,基本上可以做到“开箱即用”,于是决定就用它了。
安装 Jekyll
Jekyll 是一个简单的静态网站生成器,它采用 Ruby 编程语言编写,可以将 markdown 文本根据不同模板自动转换为网页。考虑到这个站点需要部署到国内服务器上,我们还是在本地安装一下环境,手动编译后再上传上去。
以下是本次安装用到的环境:
- Ubuntu 24.04.2 LTS
- Linux pve-testenv 6.8.0-55-generic #57-Ubuntu SMP PREEMPT_DYNAMIC Wed Feb 12 23:42:21 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux
我们参考官方教程,先安装需要的程序,使用 apt
安装即可,无需编译。
1
sudo apt-get install ruby-full build-essential zlib1g-dev
接下来我们验证一下环境,只要没报错应该就行。
1
2
3
4
5
ruby -v
gem -v
gcc -v
g++ -v
make -v
由于需要更改环境变量 ~/.bashrc
,根据官方的建议,我们新建一个用户,这个用户无需 sudo
权限。
1
sudo adduser jekyll
创建完成后切换到这个用户。
1
2
su jekyll
cd ~/
然后把下面的各种配置贴进去。
1
2
3
4
echo '# Install Ruby Gems to ~/gems' >> ~/.bashrc
echo 'export GEM_HOME="$HOME/gems"' >> ~/.bashrc
echo 'export PATH="$HOME/gems/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc
再安装 Jekyll 和 Bundler,理论上就能用了。
1
gem install jekyll bundler
导出文章
既然是迁移,那么肯定要把文章给导出来。这里我没找到 Typecho 直接导出为 Jekyll 格式的插件,但是找到了可以导出为 Hugo 格式的插件,由于两者较为相近,稍微改改就能用。
1
2
cd /path/to/typecho/usr/plugins
git clone https://github.com/lizheming/typecho-export-hugo.git Export2Hugo
启用插件后,上方菜单栏-控制台-导出至Hugo,开始导出。但下载后无法解压,尝试修改 Action.php
里第 69-73 行,改为 tar 打包:
1
2
3
4
5
$filename = "hugo.".date('Y-m-d').".tar.gz";
$outputFile = $dir."/".$filename;
exec("cd $dir && tar -czf $outputFile content");
header("Content-Type:application/tar+gzip");
但仍然提示文件错误,最后在服务器临时文件目录下 /tmp/Export2Hugo
直接下载回了本地,可以正常解压。
不过这只是意味着所有文章成功导出了,但我们还需要修改一下插件以匹配 Jekyll 的格式要求。
由于我们需要文章的更新时间,这里需要在最开始的 select
中添加 modified
,因此需要改一下 SQL 查询语句,找到 $sql=<<<TEXT
,然后修改:
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
select
u.screenName author,
url authorUrl,
title,
type,
text,
created,
modified,
c.status status,
password,
t2.category,
t1.tags,
slug
from
{$prefix}contents c
left join (
select
cid,
CONCAT(
'"',
group_concat(m.name SEPARATOR '","'),
'"'
) tags
from
{$prefix}metas m,
{$prefix}relationships r
where
m.mid = r.mid
and m.type = 'tag'
group by
cid
) t1 on c.cid = t1.cid
left join (
select
cid,
CONCAT(
'"',
GROUP_CONCAT(m.name SEPARATOR '","'),
'"'
) category
from
{$prefix}metas m,
{$prefix}relationships r
where
m.mid = r.mid
and m.type = 'category'
group by
cid
) t2 on c.cid = t2.cid
left join (
select
uid,
screenName,
url
from
{$prefix}users
) as u on c.authorId = u.uid
where
c.type in ('post', 'page');
然后我们要修改一下 foreach
里面的内容,首先为发布日期添加时区:
1
$time = date('Y-m-d H:i:s O', $content["created"]);
然后新增更新日期变量:
1
$updated_time = date('Y-m-d H:i:s O', $content["modified"]);
接下来我们修改一下写入 markdown
文件的头内容,根据自己的需求修改就好:
1
2
3
4
5
6
7
8
9
---
title: "$title"
author: "Dan"
categories: [ $categories ]
tags: [ $tags ]
slug: "$slug"
date: "$time"
last_modified_at: "$updated_time"
---
由于原文件名不符合 Jekyll 规范,还需要修改一下导出的文件名格式:
1
2
#$filename = str_replace(array(" ","?","\\","/" ,":" ,"|", "*" ),'-',$title).".md";
$filename = date('Y-m-d', $content["created"]) . '-' . str_replace(array(" ","?","\\","/" ,":" ,"|", "*" ), '-', $slug) . ".md";
总之由于每个人的设置有所不同,可能需要尝试多次才能导出自己满意的一份。
导入文章
由于我正式因为看上了 Chirpy 主题才决定使用 Jekyll,因此这里用它做演示。
我们需要先下载一个主题的仓库,然后修改一下文件夹的名字:
1
2
git clone git@github.com:cotes2020/chirpy-starter.git
mv chirpy-starter chirpy
接下来先不导入任何文章,直接运行一下看能不能跑起来,这里开发者非常贴心了帮我们写了一个 shell 脚本,因此我们直接运行它就行:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
jekyll@pve-testenv:~/blog/chirpy$ tools/run.sh
> bundle exec jekyll s -l -H 127.0.0.1
Configuration file: /home/jekyll/blog/chirpy/_config.yml
Source: /home/jekyll/blog/chirpy
Destination: /home/jekyll/blog/chirpy/_site
Incremental build: disabled. Enable with --incremental
Generating...
done in 5.473 seconds.
Auto-regeneration: enabled for '/home/jekyll/blog/chirpy'
LiveReload address: http://127.0.0.1:35729
Server address: http://127.0.0.1:4000/
Server running... press ctrl-c to stop.
如果没问题就可以关闭了,将所有导出的文件都放到 _posts
文件夹目录,修改一下 _config.yml
文件。这里因为每个人应该有所不同,因此只挑几个来讲。
为了保证迁移后的链接与原来的链接保持一致,我们找到 permalink
参数,将它配置为与你原来博客差不多的样子,这里可以参考官方文档查看可配置选项:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
defaults:
- scope:
path: "" # An empty string here means all files in the project
type: posts
values:
layout: post
comments: true # Enable comments in posts.
toc: true # Display TOC column in posts.
# DO NOT modify the following parameter unless you are confident enough
# to update the code of all other post links in this project.
permalink: /:categories/:slug.html
- scope:
path: _drafts
values:
comments: false
- scope:
path: ""
type: tabs # see `site.collections`
values:
layout: page
permalink: /:slug/
由于开启 PWA 功能后会导致网站不会立即刷新,我们这里直接关闭掉它:
1
2
3
4
5
6
7
8
9
pwa:
enabled: false # The option for PWA feature (installable)
cache:
enabled: false # The option for PWA offline cache
# Paths defined here will be excluded from the PWA cache.
# Usually its value is the `baseurl` of another website that
# shares the same domain name as the current website.
deny_paths:
# - "/example" # URLs match `<SITE_URL>/example/*` will not be cached by the PWA
由于本站是要放到国内部署,使用任何国外的 CDN 都算是为了加速而背道而驰,因此我们需要自己托管静态资源,这里我们修改这一段配置:
1
2
3
4
5
6
7
# Self-hosted static assets, optional › https://github.com/cotes2020/chirpy-static-assets
assets:
self_host:
enabled: true
# specify the Jekyll environment, empty means both
# only works if `assets.self_host.enabled` is 'true'
# env: # [development | production]
然后还需要下载所有静态资源:
1
2
git submodule init
git submodule update
最后我们再部署一下试试:
1
tools/run.sh
部署
如果看起来都没什么问题,我们需要以 production 模式运行一次,在 _site
得到编译好的文件:
1
tools/run.sh -p
最后把这个文件打个包,部署到国内服务器就可以了:
1
tar -cvf _site.tar _site/