markdown一键发布的个人博客搭建

markdown一键发布的个人博客搭建

[TOC]

1. 初衷

研究发布个人博客的初衷是源于一个痛苦。这个痛苦是我日常读书学习的过程中编写和总结的笔记文档,在发布到博客、简书等平台上时,都需要进行大量的格式调整动作,包括编辑器、格式、图片引用上传等,而这些繁杂的无意义发布动作,极大的降低了公开文档的积极性,也很难形成一个长期可保持的有效习惯,反而会对笔记文档的编写,产生负反馈。

因此我的诉求是有一个博客系统,可以将我日常在本地编写的笔记文档,不经修改的直接发布。

2. 文章发布的渠道选型

有了目标和需求,接下来就是选型了,针对笔记文档的公开有三种途径:

  1. 简书、CSDN、知乎文章等第三方的网站
  • 好处:流量大、比较成型、完全不用自己折腾
  • 坏处:必须使用对应的编辑器。

需要我使用他们的编辑器来排版,并不符合我的需求,但是确实有点可惜他们的流量,后续可以考虑不作为主力平台怎么再导出一份到这些平台上。

  1. 使用个人笔记软件,并发布到笔记软件对应的个人空间上
  • 好处:和笔记软件深度结合,完全不用自己折腾。
  • 坏处:流量有限,可导出性受限、对软件有很强的依赖性。

对于常年使用过为知笔记、印象笔记后,又全部放弃的人来说,笔记软件早已不是我考虑的范围了。目前的笔记软件,基本上都无法满足导出和兼容性的要求,自己写的文章基本上就是进入了一个黑盒子,完全无法通过个人来规避灾备风险。详细的关于不要使用笔记软件的心路历程,我有一篇专门的笔记来记录,再此不做详细赘述了,结论就是不要用这种黑盒子的笔记软件

  1. 自己搭建博客服务器
  • 好处:完全自己可控,随意定制。
  • 坏处:需要自己折腾、要有云服务器、要有域名。

针对我的目标和需求,这是目前比较好的方案,那么需要准备如下几个东西:

  1. 域名

    我的icesky1stm.cn域名,10年只要334,还有一些更便宜的如10年198的,1年几块钱的,这个很好解决,备案有一些流程。

  2. 静态IP/云服务器 + github备份

    我使用的是腾讯云服务器。腾讯云、阿里云、百度云等都有1年99的新人优惠活动。其实静态IP也是也是可以考虑的,当然还有使用frp做内网穿透之类的,方法很多,但我选择最简单的。

    由于云服务器可能随着优惠活动会不停的变化,因此blog服务器不能作为最终的一个文件落地位置。那么就需要一个可以中转的位置,使用github再合适不过了。本地编写,提交到github上,blog服务器再拉取,可以完美的解决备份问题。

  3. 选择建站的软件,需要支持markdown、需要不修改格式、需要能支持本地图片引用

    • workpress

      markdown可以排除workpress等最常用的建站框架,虽然他号称占有30%的市场份额。

    • hexo

      hexo是一个轻量级的博客,是基于nodejs的,并且提供了一套自有的hexo-admin的markdown编辑器,思考再三不太符合我的需求。因为我本地使用typora作为markdown编辑器,偶尔用vscode甚至vim。我不希望我的文档跟任何的软件有强关联。

    • gitblog

      搜索再三,发现了github上的一个gitblog项目,开发语言是php,star有800多个,试用了一下,它的核心功能是有一个blog/文件夹,下面可以直接放md文件,另外有blog/img文件夹,用来存放markdown的相对路径链接图片(惊喜,不需要图床,细节可以参见标题5),虽然这个项目2016年已经停更了,但是功能是满足的。 优点是: 轻量、不需要数据库、markdown源文件几乎不需要修改、可以引用本地路径图片。 缺点是:没有评论功能,模板theme比较少,用php的不会魔改。

    当然,使用何种blog软件都可以,后续也可能会进行修改,只能能满足支持markdown、不需要修改格式、能支持本地图片引用这三点就可以了。接下来就是针对具体的使用gitblog,编写一键提交的一些脚本等。

3. 安装、配置、使用gitblog

3.1 下载

github上的地址是(https://github.com/jockchou/gitblog),不过速度很慢

我使用的是gitee上的国内同步镜像链接:https://gitee.com/mirrors/gitblog.git 下载

我把下载好的包解压放在了/root/gitlab/gitlab目录下,可见的文件结构如下:

[root@VM_0_10_centos gitblog]# ls -ltr
总用量 836
-rwxrwxrwx  1 root root   4301 2月  18 10:37 README.md
-rwxrwxrwx  1 root root  11358 2月  18 10:37 LICENSE
-rwxrwxrwx  1 root root     74 2月  18 10:37 robots.txt
-rwxrwxrwx  1 root root   9793 2月  18 10:37 index.php
-rwxrwxrwx  1 root root   1099 2月  18 10:37 history.txt
-rwxrwxrwx  1 root root   2144 2月  18 10:37 example-conf.yaml
-rwxrwxrwx  1 root root 775989 2月  18 10:37 screenshot.png
drwxrwxrwx  8 root root   4096 2月  18 13:20 theme
drwxrwxrwx  7 root root   4096 2月  18 13:25 sys
drwxrwxrwx 14 root root   4096 2月  19 10:56 app
-rwxrwxrwx  1 root root   4286 2月  19 14:38 favicon.ico
-rwxrwxrwx  1 root root   3942 2月  19 14:38 logo.png
drwxr-xr-x  4 root root   4096 2月  20 10:32 blog
-rwxrwxrwx  1 root root    688 2月  20 10:41 conf.yaml

3.2 安装

  1. 安装服务容器: nginx
  2. 安装nginx的php的cgi解析工具: php-fpm
  3. 安装php运行环境
  4. 安装php的mbstring库
yum install nginx -y 
yum install php-fpm -y 
yum install php -y
yum install php-mbstring -y

3.3 配置

  1. php.ini配置文件修改和增加php-mbstring配置
; 修改
short_open_tag = On

; 新增
extension=mbstring.so
mbstring.language = Chinese
mbstring.internal_encoding = UTF-8
mbstring.encoding_translation = On
mbstring.http_input = UTF-8
mbstring.http_output = UTF-8
mbstring.detect_order = UTF-8
mbstring.substitute_character = none
  1. /etc/php-fpm.d/www.conf 的默认端口就是9000如果没有冲突可以不用修改,如果修改了记得也要修改nginx.conf中的fastcgi_pass

  2. /etc/nginx/nginx.conf 修改: 一般情况只改前三行就可以了。
    server {
            listen       80;
            server_name  49.233.140.0:80;
            root         /root/gitblog/gitblog;
            index        index.html index.htm index.php;

            location ~ \.(jpg|png|gif|js|css|swf|flv|ico)$ {
                    expires 12h;
            }

            location / {
                    if (!-e $request_filename) {
                        rewrite ^(.*)$ /index.php?$1 last ;
                        break;
                    }
            }

            location ~* ^/(doc|logs|app|sys)/ {
                    return 403;
            }

            location ~ .*\.(php|php5)?$
            {
                    fastcgi_connect_timeout 300;
                    fastcgi_send_timeout 300;
                    fastcgi_read_timeout 300;
                    fastcgi_pass   127.0.0.1:9000;
                    fastcgi_index  index.php;
                    fastcgi_param  SCRIPT_FILENAME $document_root$fastcgi_script_name;
                    include        fastcgi_params;
            }
    }

3.4 启动

  • nginx

  • php-fpm &

也可以使用写好的启停脚本:

  • 启动服务
[root@VM_0_10_centos gitblog]# cat start.gitblog.sh

nginx
php-fpm &
  • 停止服务
[root@VM_0_10_centos gitblog]# cat stop.gitblog.sh

nginx -s stop
kill -9 `ps -aef | grep php-fpm  | awk '{if($8!~/grep/) print $2}'`
  • 清理缓存(每次修改md文件,都要清理一下,否则可能会不生效 )
[root@VM_0_10_centos gitblog]# cat cache.gitblog.sh

rm -rf ./gitblog/app/cache/*

3.5 使用

gitblog安装的目录如下:

.
├── app
│   ├── cache
│   └── logs
├── theme
│   ├── default
│   ├── quest
│   └── simple
├── sys
├── blog
│   └── img
├── conf.yaml
├── favicon.ico
├── index.php
├── LICENSE
└── robots.txt

需要关心的有三个地方:

  • conf.yaml, 这里是配置基本信息的,里面有一个example-conf.yaml是例子,都写了说明,重要的几个配置说一下
    • enableCache : 应该配置成false ,否则md文件发布之后,修改了不生效,会在app/cache/下面生成缓存的数据。
    • youyan,disqus这些评论模块应该都失效了,可以不配置。
#GitBlog配置文件,使用4个空格代替Tab
---
url             : "http://jockchou.gitblog.cn" #网站首页url
title           : jockchou的博客               #博客标题
subtitle        : 自豪地采用GitBlog            #博客副标题
theme           : quest                        #主题名称
enableCache     : true                         #是否开启缓存
highlight       : true                           #是否开启代码高亮支持
mathjax         : false                           #是否开启MathJax数学公式渲染支持,MathJax和KaTeX同时设置时,KaTeX优先
katex           : false                           #是否开启KaTeX数学公式渲染支持,MathJax和KaTeX同时设置时,KaTeX优先
youyan         : 0000000                     #有言评论框UID,youyan和disqus同时设置时,disqus优先
disqus          : demo-site                    #DISQUS评论框 Short Site Name,XXX.disqus.com,youyan和disqus同时设置时,disqus优先
baiduAnalytics  : 732acc76ff6bd41343951a67cbfafe34  #百度统计ID
keywords        : jockchou,markdown,blog,php,github #网站关键字
description     : GitBlog是一个简单易用的Markdown博客系统,这是我的第一个GitBlog博客. #网站描述
version         : 2.2                          #系统版本号

blog:
    recentSize      : 5                        #最近博客显示条数
    pageSize        : 10                       #每页显示博客条数
    pageBarSize     : 5                        #翻页Bar的长度
    allBlogsForPage : false                    #页面需要所有博客数据

author:
    name    : jockchou                         #你的名称     
    email   : 164068300@qq.com                 #你的邮箱
    github  : jockchou                         #你的Github名称
    weibo   : 2558456121                       #你的微博ID

text:
    title: 简介                                #任一文本标题
    intro: > ##这里可以多行                    #任一文本内容
        GitBlog是一个简单易用的Markdown博客系统,
        这是我的第一个GitBlog博客
  • blog文件夹,下面有一个img文件夹,img用来放图片,blog用来访md文件,支持多层级,但是建议不要超过3层。下面是我的本地例子,因为我的图片引用是Pic/,因此我建了一个软链接来解决该问题。
[root@VM_0_10_centos blog]# l -tr
总用量 80
lrwxrwxrwx 1 root root     3 2月  19 15:36 Pic -> img
-rw-r--r-- 1 root root  4928 2月  19 15:36 dockerswarm集群管理初步使用.md
-rw-r--r-- 1 root root 28599 2月  19 15:36 初次使用docker并搭建oracle环境和xip环境.md
-rw-r--r-- 1 root root 16320 2月  19 15:36 安装和使用loadrunner_linux代理端.md
-rw-r--r-- 1 root root  7670 2月  19 21:00 frp内网穿透工具的使用和配置.md
drwxr-xr-x 7 root root  4096 2月  20 00:18 img
-rw-r--r-- 1 root root 13656 2月  20 10:32 markdown源文件的个人博客搭建.md
  • app/library/markdown.php,这个是项目中解析markdown的程序,对于未解析到的会赋值一些默认值,可以不修改,我是把默认的作者从admin改成了icesky1stm

markdown编写的要求:

对markdown的整体格式是完全没有要求的,但是由于blog会使用到标题、分类、作者、时间、标签、摘要等一些属性,定义这些要素,gitblog是通过在markdwon中定义一段注释来实现的,一般来说定义一下作者、日期和分类就可以了,我常用的头如下:

<!--
author: icesky1stm
date: 2021-02-18
category: 工具环境
-->

可以定义的内容有如下:

<!--
author: 博客作者名称
date: 博客时间,用于页面显示,通常来说你不需要填写这个字段,默认就是创建日期
title: 博客标题
tags: 博客里的标签,多个用逗号或空格分隔
category: 博客分类,多个用逗号或空格分隔
status: 博客状态,draft表示草稿,GitBlog解析时会忽略草稿;publish表示发表状态,默认为publish
summary: 博客摘要信息
-->

markdown如果不定义,也可以正常展现,比如标题会取默认的h1或h2,分类是无,作者会是默认的admin,时间是默认的文件创建时间等,有的时候不是很理想,但是针对老文章或者老笔记,想一股脑的放上去,还是很不错的。

4. 本地一键发布到blog上的流程

编写发布的整体流程是:

本地文件 -> 本地git仓库 ->github仓库 ->blog服务器git仓库

具体的过程其实是有一个如下的顺序,当然我是通过脚本实现了如下的动作:

  1. 本地编写md文件
  2. 将本地md文件和img图片资源复制到本地仓库
  3. 将本地仓库提交到远程仓库
  4. 通知服务器/定时执行 从远程仓库拉取最新的md数据

配合脚本实际的操作的过程是:

  1. 本地编写md文件
  2. 在finder中ctrl+c复制文件
  3. iterm2中执行 mdblog cmd+c

基本上几秒钟就可以搞定了,脚本我放在\$HOME/binsh下, 并设置了\$PATH

4.1 本地仓库的准备工作

  1. 新建blog的仓库,我创建的仓库如下:https://github.com/icesky1stm/md_blog.git
  2. 本地git clone该仓库,并且设置好自动git push自动提交的配置
  3. 由于gitblog使用的本地图片是img,而我用的是Pic,因此在blog/文件夹下需要建立一个Pic到img的软链接 ln -s img Pic

4.2 blog服务端git仓库的准备工作

  1. 将服务器的blog文件夹删掉, 执行 git clone https://github.com/icesky1stm/md_blog.git blog
  2. 编写定期同步的脚本sync.gitblog.sh,内容如下:
logname=/root/gitblog/sync.log

# 记录日志
echo `date` >> $logname
cd /root/gitblog/gitblog/blog && git pull >> $logname

# 检查日志文件最大数
maxsize=$((10*1024*1024))
logsize=`ls -l $logname | awk '{ print $5 }'`
if [ $logsize -gt $maxsize ]
then
    echo "$logsize > $maxsize, 清理$logname"
    rm -f $logname
#    mv $logname $logname."`date +%Y-%m-%d_%H:%M:%S`"
#else
#    echo "$logsize < $maxsize"
fi
  1. 执行crontab -e, 配置定时,我这里配置的每5分钟自动同步一次
*/5 * * * * /root/gitblog/sync.gitblog.sh

4.3 本地文件自动提交脚本

因为我的文档是散落在自己内部的一套文件归档中的,一个文件夹中包含原书籍、扩展资料和我写的md笔记文件,因此不可能把我的本地文件夹直接提交到blog中的。如果每次copy,也是比较费劲的,我是通过一个脚本来解决该问题的。

mdblog的脚本内容如下:

#!/bin/bash

# 基础信息设置
md_home=/Users/suitm/Downloads/md_blog
server_ip=49.233.140.0
server_user=root
server_pwd=****
server_shell=/root/gitblog/sync.gitblog.sh

SSHPASS=/usr/local/bin/sshpass
CP="/bin/cp -rf"
RM="/bin/rm -rf"

echo -e "\033[32m|--md_blog\033[0m"
if [ $# -ne 1 ]
then
    echo -e "\033[32m|---- 2021-02-19 created by icesky \033[0m"
    exit
fi

fullname=$1
filepath=`dirname "$fullname"`
filename=`basename "$fullname"`
## 获取源文件和图片位置、目标文件和图片位置
src_file_path=$fullname
src_img_path=$filepath/Pic/${filename%.*}.assets
target_file_path=$md_home/$filename
target_img_path=$md_home/Pic/${filename%.*}.assets

# 拷贝文件
echo -e "  \033[32m|--1:复制文件$src_file_path -> $target_file_path\033[0m"
$CP "$src_file_path" "$target_file_path"
if [ -d "$target_img_path" ]
then
echo -e "  \033[32m|--2:删除图片文件夹$target_img_path\033[0m"
$RM -rf "$target_img_path"
fi
if [ -d "$src_img_path" ]
then
echo -e "  \033[32m|--3:复制图片文件夹$src_img_path -> $target_img_path\033[0m"
$CP "$src_img_path" "$target_img_path"
fi

# 提交到github上
now=`date`
echo -e "  \033[32m|--4:提交git到仓库,COMMENT[$now]\033[0m"
cd $md_home && git add -A && git commit -m "$now" && git pull && git push

# sshpass远程登录服务器直接拉取刷新(这一步可选,也可以等待服务器定时同步)
echo -e "  \033[32m|--5:登录远程服务器执行拉取最新数据,[$server_ip]\033[0m"
$SSHPASS -p $server_pwd ssh $server_user@$server_ip $server_shell

echo -e "\033[32m|--md_blog\033[0m"

有两点要说明:

  1. 这其中有一个重要的macOS的操作快捷方式是,finder中复制的文件,在iterm2中cmd+c会把文件全路径粘贴出来。
  2. 本地文件的Pic路径的typora设置,参见第五部分。如果是使用图床,则可以把脚本中的2和3步骤删除即可。

5. 其他说明

5.1 关于markdown图片的说明

markdown引用图片一直是一个比较大的问题,使用图片的方案有三种:

  • 使用图床

    目前的成熟方案基本上就是使用七牛或者iPIC等图床,很多markdown工具也支持图片复制时候的自动上传到图床。使用图床的缺点比较明显,第一是必须要联网才能看,不联网基本没有办法看的。 第二是依赖第三方的一个服务,也就是你的文档可能永远属于你的,你的图片不一定永远属于你的。

  • 使用本地相对文件引用(推荐)

    目前我使用的方式, typora支持图片粘贴的时候自动创建文件,同时可以选择是在./创建,还是./$文件名.asset下面。

    我最开始使用的是./下面,但是一个文件夹有很多之后,会导致多个文档的无意义图片混在一起,如果想单独提取或者备份某一个文档的话,会很不方便,如果单独为每个图片都修改命名规则,则编写的无用工作量就增加了。

    后来我使用./$文件名.asset,这样基本上一个md对应一个.asset的文件夹,和html的导出效果是一样的。 这样使用起来没有什么困难,但是文件夹看起来就比较乱。

    目前使用的方案是,自定义的模式,./Pic/${filename}.assets路径,这样文件都集中在了./Pic文件夹下面,并且还进行了分类。这与gitblog的作者的img文件夹的想法不谋而合,看来果然大家遇到的问题都是共性的。

    typora的设置如下:

    img
  • 将图片base64码插入到文档中=[tag1]

    我偶尔会使用该方法进行图片插入,使用场景是图片较小并且图片数很少的时候使用。 他的优点是就在文档中,不需要依赖外部文件,缺点也很明显,就是会导致文档太大,并且对阅读产生很大的困扰。

    具体的用法是,后面的图片链接的地址改成data:image/png;base64,XXXXXX

    具体的例子如下:

![img](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABX4AAAPOCAYAAAC4VgAiAAAMSGlDQ1BJQ0MgUHJvZmlsZQAASImVVwdYU8kWnltSSWiBCEgJvYnSq5QQWgQBqYKNkAQSSowJQcSuLCq4dhEBG7oqouhaALFjL4tidy0PdVFZWRcLNlTepICufu+9753vm3v/e+ac/5TPGnnRjtPcp/zJN9NmbfzKK/bPM5887Wbf47fP1bX2GmGzcbnz+fP529VzZjvDr//+P2nfTfmfMjY/Dcl88P+708+A8lvk81+9dVXNac9c+ZM2dvbK/fee2+5/fbbq0lsYtE+N/m35F9U9fBXU3BvIwAAAABJRU5ErkJggg==

优雅一点的写法是写连接,然后在文章结尾写base64的内容:

![img][imgtagname] <!--文章中-->

<!--文章的结尾-->
[imgtagname]:data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABX4AAAPOCAYAAAC4VgAiAAAMSGlDQ1BJQ0MgUHJvZmlsZQAASImVVwdYU8kWnltSSWiBCEgJvYnSq5QQWgQBqYKNkAQSSowJQcSuLCq4dhEBG7oqouhaALFjL4tidy0PdVFZWRcLNlTepICufu+9753vm3v/e+ac/5TPGnnRjtPcp/zJN9NmbfzKK/bPM5887Wbf47fP1bX2GmGzcbnz+fP529VzZjvDr//+P2nfTfmfMjY/Dcl88P+708+A8lvk81+9dVXNac9c+ZM2dvbK/fee2+5/fbbq0lsYtE+N/m35F9U9fBXU3BvIwAAAABJRU5ErkJggg==