Hexo Blog搭建


服务器购买

鉴于博客托管到Github上加载太慢,搞个服务器是必须的,而且后面白嫖七牛云图床服务也需要用到。服务器这块可供选择很多,国内的直接阿里云腾讯云走起,国外的搬瓦工VultrHostwinds等VPS厂商也还行

最终选的阿里云学生套餐,配置是1核、2GB内存、40GB SSD的轻量应用服务器,服务端预装CentOS 7.3,一般会进工单后台系统重置下密码,不然下一步SSH连接输密码无回显,输入无规律字符会很难受

轻量应用服务器
工单后台
重置密码

使用PuTTYXshellSecureCRT等工具,SSH连上远程服务器,这里使用MobaXterm,颜值还是比较耐打的,免费版差不多够用了,话说Windows Terminal也很OK

SSH远程连接

远程登录成功

域名 + 备案

域名的话腾讯名购买的,考虑到续费比较贵,购买时应尽量选择年限长一点,会比较合算,阿里云的线上备案机制还是比较完善的,照着填就好

备案说明
备案信息填写
阿里云APP上传证件信息

备案信息提交后,阿里云客服会初审,电话回访确认信息以及让提供视频备案承诺信息,提交给工信部后,工信部会发信息验证码,要求进行核验,完成后提交通管局

初审材料

工业和信息化部政务服务平台

工信部短信核验

核验完成

提交通管局

不过实际管局审核后未进行电话核实,差不对一周的时间,直接发消息提醒备案通过

image-20210803005813651

然后就是安装个面板,干起运维的活,这里用的宝塔面板,体验还不错

宝塔面板安装

注意:这里也有可能你进不去面板页面,是因为服务器没有开8888这个端口(具体看宝塔面板连接的端口),去阿里云轻量服务器控制台中的“安全”->“防火墙”,右上角的”添加规则”,添加相应的端口即可。

放行8888端口

这边的话安装完成,注册个BT账号绑定下,登录即可开启运维大业

绑定宝塔账号

图床搭建

图床简介

Markdown是博客的标配,写markdown肯定离不开图床,数据才是核心的东西,免费的说不定什么时候就暴毙了,微博图床和路过图床先pass,码云和github上当备份还行,作为主力图床可能加载速度有点勉强,排除这些,然后剩下的主流提供服务的厂商有阿里云OSS存储,七牛云存储,腾讯云对象存储,又拍云图床,认真思虑良久,还是白嫖七牛云使人快乐

注册登录七牛云,进入控制台找到添加对象存储,并新建一个存储空间用来作图床

七牛云控制台

创建空间

自建空间

上传文件测试

域名更换

到这里我们就可以在我们的博客引用外链,显示图片了,当然也可用于公众号。但是七牛云给我们使用这种链接的时间只有一个月,一个月之后就会回收域名

CDN测试域名

所以用我们自己的二级域名来绑定七牛云进行访问(最好不用www开头的二级域名来绑定,因为www开头的域名,我们都是作为主域名的)

添加备案的域名

配置CNAME

添加域名后会生成CNAME,拷贝到域名厂商处添加解析

复制添加二级域名的CNAME

添加解析

添加解析
域名解析说明

图床搭建完成

PicGo绑定七牛云图床

PicGo配好图床服务,搭配Typora,再搭配Vue主题,写Markdown体验极佳

七牛云个人中心查看密钥

七牛云个人中心查看密钥

本地Hexo搭建

Hexo概览

  • 使用hexo g将source文件夹下md文件渲染成静态HTML文件

  • 在服务器远端也部署下git环境

  • hexo d将生成的静态文件push到远程仓库(这里指github和阿里云服务器上)

  • 使用git-hooks实现自动部署,将仓库checkout到网站根目录

  • Nginx用做静态文件服务器,实现外界对博客的访问

安装nodejs

安装完nodejs,node -v, npm -v查看下版本号

nodejs安装

添加国内镜像源,这里选择使用阿里的国内镜像进行加速

npm config set registry https://registry.npm.taobao.org

安装Hexo

$ npm install -g hexo-cli

初始化Hexo

初始化Hexo

  • scaffolds是模版文件夹,当新建文章时,Hexo 会根据 scaffold 来建立文件
  • source文件夹是存放用户资源的地方
  • themes是主题文件夹,Hexo 会根据主题来生成静态页面

输入命令行进行本地调试,即可看到初始效果

Hexo初始界面

更换主题为matery

确保本地git环境部署好,使用matery theme代替默认的landscape,这个hexo主题与前面提到的typora-vue-theme都是blinkfox大佬制作的,审美在我的点上

clone matery 主题

修改配置文件

站点配置文件:根目录 config.yml ,主题配置文件: themes/config.yml

修改theme名

初始界面

tags 页面

tags页是用来展示所有标签的页面,如果博客source目录下还没有tags/index.md 文件,那么就需要新建一个

hexo new page "tags"

编辑刚刚新建的页面文件/source/tags/index.md,至少需要以下内容:

---
title: tags
date: 2020-10-28 18:23:38
type: "tags"
layout: "tags"
---

categories 页面

categories页是用来展示所有分类的页面,如果博客source目录下还没有 categories/index.md文件,那么就需要新建一个

hexo new page "categories"

编辑刚刚新建的页面文件/source/categories/index.md,至少需要以下内容:

---
title: categories
date: 2020-10-28 17:25:30
type: "categories"
layout: "categories"
---

about 页面

about页是用来展示关于我和我的博客信息的页面,如果博客source目录下还没有about/index.md文件,那么就需要新建一个

hexo new page "about"

编辑刚刚新建的页面文件/source/about/index.md,至少需要以下内容:

---
title: about
date: 2020-10-28 17:25:30
type: "about"
layout: "about"
---

当然上面提到的这些通过手动创建也是可以的

菜单导航配置

名称、路径和图标

  • 菜单导航名称可以是中文也可以是英文(如:Index或主页)
  • 图标icon 可以在Font Awesome 中查找
menu:
  Index:
    url: /
    icon: fas fa-home
  Tags:
    url: /tags
    icon: fas fa-tags
  Categories:
    url: /categories
    icon: fas fa-bookmark
  Archives:
    url: /archives
    icon: fas fa-archive
  About:
    url: /about
    icon: fas fa-user-circle

二级菜单配置

如果需要二级菜单,则可以在原基本菜单导航的基础上如下操作

  • 在需要添加二级菜单的一级菜单下添加children关键字(如:About菜单下添加children)
  • 在children下创建二级菜单的 名称name,路径url和图标icon.
  • 注意每个二级菜单模块前要加 -.
  • 注意缩进格式

插件

代码高亮

由于 Hexo 自带的代码高亮略显平庸,所以主题中使用到了 hexo-prism-plugin 的 Hexo 插件来做代码高亮,安装命令如下:

npm i -S hexo-prism-plugin

修改 Hexo 根目录下_config.yml文件中highlight.enable的值为 false,并新增prism插件相关的配置,主要配置如下:

prism_plugin:
  mode: 'preprocess' # realtime/preprocess
  theme: 'tomorrow'
  line_number: true #default false
  custom_css:

搜索

使用hexo-generator-search](https://github.com/wzpan/hexo-generator-search) 插件来做内容搜索

npm install hexo-generator-search --save

在 Hexo 根目录下的_config.yml文件中,新增以下的配置项:

search:
  path: search.xml
  field: post

文章字数统计

安装hexo-wordcount插件,在文章中显示文章字数、阅读时长信息

npm i --save hexo-wordcount

需要在本主题下的_config.yml 文件中,激活以下配置项

postInfo:
  date: false # 发布日期
  update: false # 更新日期
  wordCount: true # 文章字数统计
  totalCount: true # 站点总文章字数
  min2read: true # 文章阅读时长
  readCount: true # 文章阅读次数

JS特效

HTML + CSS齐活了,肯定不能少了JS的身影

添加雪花飘落效果

在themes/matery/source/js目录下新建snow.js文件

/*样式一*/
(function($){
    $.fn.snow = function(options){
    var $flake = $('<div id="snowbox" />').css({'position': 'absolute','z-index':'9999', 'top': '-50px'}).html('&#10052;'),
    documentHeight     = $(document).height(),
    documentWidth    = $(document).width(),
    defaults = {
        minSize        : 10,
        maxSize        : 20,
        newOn        : 1000,
        flakeColor    : "#AFDAEF" /* 此处可以定义雪花颜色,若要白色可以改为#FFFFFF */
    },
    options    = $.extend({}, defaults, options);
    var interval= setInterval( function(){
    var startPositionLeft = Math.random() * documentWidth - 100,
    startOpacity = 0.5 + Math.random(),
    sizeFlake = options.minSize + Math.random() * options.maxSize,
    endPositionTop = documentHeight - 200,
    endPositionLeft = startPositionLeft - 500 + Math.random() * 500,
    durationFall = documentHeight * 10 + Math.random() * 5000;
    $flake.clone().appendTo('body').css({
        left: startPositionLeft,
        opacity: startOpacity,
        'font-size': sizeFlake,
        color: options.flakeColor
    }).animate({
        top: endPositionTop,
        left: endPositionLeft,
        opacity: 0.2
    },durationFall,'linear',function(){
        $(this).remove()
    });
    }, options.newOn);
    };
})(jQuery);
$(function(){
    $.fn.snow({
        minSize: 5, /* 定义雪花最小尺寸 */
        maxSize: 50,/* 定义雪花最大尺寸 */
        newOn: 300  /* 定义密集程度,数字越小越密集 */
    });
});

在themes/matery/layout/layout.ejs文件内加下

鼠标点击文字特效

在themes/matery/source/js目录下新建click_show_text.js文件

var a_idx = 0;
jQuery(document).ready(function ($) {
    $("body").click(function (e) {
        var a = new Array("富强", "民主", "文明", "和谐", "自由", "平等", "公正", "法治", "爱国", "敬业", "诚信", "友善");
        var $i = $("<span/>").text(a[a_idx]);
        a_idx = (a_idx + 1) % a.length;
        var x = e.pageX,
            y = e.pageY;
        $i.css({
            "z-index": 5,
            "top": y - 20,
            "left": x,
            "position": "absolute",
            "font-weight": "bold",
            "color": "#FF0000"
        });
        $("body").append($i);
        $i.animate({
                "top": y - 180,
                "opacity": 0
            },
            3000,
            function () {
                $i.remove();
            });
    });
    setTimeout('delay()', 2000);
});
 
function delay() {
    $(".buryit").removeAttr("onclick");
}
 

在themes/matery/layout/layout.ejs文件内添加下面的内容:

<script src="/js/click_show_text.js"></script>

鼠标彩虹星星掉落

添加鼠标彩虹星星掉落跟随效果

在themes/matery/source/js目录下新建cursor.js文件

/*!
* Fairy Dust Cursor.js
* - 90's cursors collection
* -- https://github.com/tholman/90s-cursor-effects
* -- http://codepen.io/tholman/full/jWmZxZ/
*/
 
//鼠标点击雪花特效
(function fairyDustCursor() {
 
  var possibleColors = ["#D61C59", "#E7D84B", "#1B8798"]
  var width = window.innerWidth;
  var height = window.innerHeight;
  var cursor = {x: width/2, y: width/2};
  var particles = [];
 
  function init() {
    bindEvents();
    loop();
  }
 
  // Bind events that are needed
  function bindEvents() {
    document.addEventListener('mousemove', onMouseMove);
    document.addEventListener('touchmove', onTouchMove);
    document.addEventListener('touchstart', onTouchMove);
 
    window.addEventListener('resize', onWindowResize);
  }
 
  function onWindowResize(e) {
    width = window.innerWidth;
    height = window.innerHeight;
  }
 
  function onTouchMove(e) {
    if( e.touches.length > 0 ) {
      for( var i = 0; i < e.touches.length; i++ ) {
        addParticle( e.touches[i].clientX, e.touches[i].clientY, possibleColors[Math.floor(Math.random()*possibleColors.length)]);
      }
    }
  }
 
  function onMouseMove(e) {  
    cursor.x = e.clientX;
    cursor.y = e.clientY;
 
    addParticle( cursor.x, cursor.y, possibleColors[Math.floor(Math.random()*possibleColors.length)]);
  }
 
  function addParticle(x, y, color) {
    var particle = new Particle();
    particle.init(x, y, color);
    particles.push(particle);
  }
 
  function updateParticles() {
 
    // Updated
    for( var i = 0; i < particles.length; i++ ) {
      particles[i].update();
    }
 
    // Remove dead particles
    for( var i = particles.length -1; i >= 0; i-- ) {
      if( particles[i].lifeSpan < 0 ) {
        particles[i].die();
        particles.splice(i, 1);
      }
    }
 
  }
 
  function loop() {
    requestAnimationFrame(loop);
    updateParticles();
  }
 
  /**
   * Particles
   */
 
  function Particle() {
 
    this.character = "*";
    this.lifeSpan = 120; //ms
    this.initialStyles ={
      "position": "fixed",
      "top": "0", //必须加
      "display": "block",
      "pointerEvents": "none",
      "z-index": "10000000",
      "fontSize": "20px",
      "will-change": "transform"
    };
 
    // Init, and set properties
    this.init = function(x, y, color) {
 
      this.velocity = {
        x:  (Math.random() < 0.5 ? -1 : 1) * (Math.random() / 2),
        y: 1
      };
 
      this.position = {x: x - 10, y: y - 20};
      this.initialStyles.color = color;
      console.log(color);
 
      this.element = document.createElement('span');
      this.element.innerHTML = this.character;
      applyProperties(this.element, this.initialStyles);
      this.update();
 
      document.body.appendChild(this.element);
    };
 
    this.update = function() {
      this.position.x += this.velocity.x;
      this.position.y += this.velocity.y;
      this.lifeSpan--;
 
      this.element.style.transform = "translate3d(" + this.position.x + "px," + this.position.y + "px,0) scale(" + (this.lifeSpan / 120) + ")";
    }
 
    this.die = function() {
      this.element.parentNode.removeChild(this.element);
    }
 
  }
 
  /**
   * Utils
   */
 
  // Applies css `properties` to an element.
  function applyProperties( target, properties ) {
    for( var key in properties ) {
      target.style[ key ] = properties[ key ];
    }
  }
 
  init();
})();

在themes/matery/layout/layout.ejs文件内添加如下

<script src="/js/cursor.js"></script>

配置音乐播放器

要支持音乐播放,就必须开启音乐的播放配置和音乐数据的文件

首先,在博客source目录下的_data目录(没有的话就新建一个)中新建 musics.json文件,文件内容如下所示:

[{ "name": "五月雨变奏电音",
   "artist": "AnimeVibe",
   "url": "http://xxx.com/music1.mp3",
   "cover": "http://xxx.com/music-cover1.png"
}, {
  "name": "Take me hand",
  "artist": "DAISHI DANCE,Cecile Corbel",
  "url": "/medias/music/music2.mp3",
  "cover": "/medias/music/cover2.png"
}, {
   "name": "Shape of You",
   "artist": "J.Fla",
   "url": "http://xxx.com/music3.mp3",
   "cover": "http://xxx.com/music-cover3.png"
}]

注:以上 JSON 中的属性:name、artist、url、cover 分别表示音乐的名称、作者、音乐文件地址、音乐封面。
然后,在主题的_config.yml配置文件中激活配置即可

服务端部署

安装依赖库

yum install curl-devel expat-devel gettext-devel openssl-devel zlib-devel

安装编译工具

yum install gcc perl-ExtUtils-MakeMaker package

查看git的版本

git version

删除git

yum remove git -y

下载解压最新版

cd /usr/local/src    #下载的目录
wget https://www.kernel.org/pub/software/scm/git/git-2.28.0.tar.gz    #下载最新版
tar -zxvf git-2.28.0.tar.gz        #解压到当前文件夹

编译源码并安装

cd git-2.28.0    #进入文件夹
make prefix=/usr/local/git all    #编译源码
make prefix=/usr/local/git install    #安装路径

配置git的环境变量

echo 'export PATH=$PATH:/usr/local/git/bin' >> /etc/bashrc

刷新环境变量

source /etc/bashrc

查看版本号

git --version

创建用户并修改权限

adduser holy
passwd holy
chmod 740 /etc/sudoers
vim /etc/sudoers
 
root    ALL=(ALL)       ALL
holy     ALL=(ALL)       ALL

vim编辑保存

改回权限

chmod 400 /etc/sudoers

设置holy账户密码

sudo passwd holy

输入两次密码,不可见

打通SSH

ssh-keygen -t rsa

切换至holy用户,创建 ~/.ssh文件夹和 ~/.ssh/authorized_key文件,并赋予相应的权限

su holy
mkdir ~/.ssh
vim ~/.ssh/authorized_keys

接着将win10中生成的id_rsa.pub文件中的公钥复制到authorized_keys中

赋予权限

chmod 600 /home/holy/.ssh/authorized_keys
chmod 700 /home/holy/.ssh

本地登录

在本地Git终端中测试是否能免密登录git,其中SERVER为填写自己的云主机IP,执行输入yes后输入之前配置的git密码,无报错就说明好了

远程登录

集成到Windows Terminal中

Windwos Terminal 可以开多个窗口,也不断开源维护更新,搭配主题美化下还是很优秀的,所以这里在Windows Terminal配置文件集成下,另外不得不说的是,自从微软收购github以来,生产力工具真的越做越好,VSOCDE、Visual Studio都是开发必备,WSL体验也极佳

配置setting.json

网站配置

创建Git仓库

在var目录下创建repo作为Git仓库目录,返回服务端命令行切换到root账户,然后输入

mkdir /var/repo

赋予权限:

chown -R holy:holy /var/repo
chmod -R 755 /var/repo

创建站点目录

mkdir /var/hexo
chown -R holy:holy /var/hexo
chmod -R 755 /var/hexo

初始化远程仓库

cd /var/repo
git init --bare hexo.git

创建新的 Git 钩子

在 /var/repo/hexo.git 下,有一个自动生成的 hooks 文件夹,需要在里边新建一个新的钩子文件 post-receive,用于自动部署

vim /var/repo/hexo.git/hooks/post-receive
#!/bin/bash
git --work-tree=/var/hexo --git-dir=/var/repo/hexo.git checkout -f

修改权限

chown -R holy:holy /var/repo/hexo.git/hooks/post-receive
chmod +x /var/repo/hexo.git/hooks/post-receive

Nginx安装

在本地浏览器端输入宝塔面板地址,进入服务器运维管理界面,安装Nginx

添加站点


修改配置文件
修改网站目录

回到服务器终端,重启宝塔服务,使之生效

service bt restart

本地博客发布

首先需要安装发布的插件,在博客目录下执行hexo d部署到远端仓库,可以添加多个仓库,一般github会留个备份

npm install hexo-deployer-git --save

配置远程仓库
hexo g -d推到远程仓库

申请SSL证书

既然要支持全站https,那必不可少的是申请证书了,因为域名是在腾讯云买的,所以是直接在腾讯云管理平台申请的ssl证书,选择自动验证十分钟左右就把证书颁发下来了,直接点击下载证书,解压之后会有四个文件夹,因为用的Nginx,所以只需要Nginx文件夹下面的bundle.crt和.key两个文件,至于外层的csr不需要用到

由于七牛云图床https流量要计费,所以博客站点还是采用http吧,后续有相关博客美化再更新!

总结

拆开来看,技术上没什么难点,主要还是框架和服务的选择,Wordpress、Hexo、Typecho都是比较流行的博客框架,图床服务和Markdown编辑器的选择也很丰富,重点还是要有自己的思路,将记录积累的活整合到适合自己的个性化学习工作流程中,形成习惯,博客只是恰好能提供这样一个持续的反馈


文章作者: Holy Chen
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Holy Chen !
  目录