环境

pve(master): 192.168.1.200

pve(vm-centos): 192.168.1.201
pve(vm-Ubuntu): 192.168.1.109
pve(vm-windows7): 192.168.1.61

一、 起因

pve-matser 上执行了 apt dist-upgrade

提示我: You are attempting to remove the meta-package 'proxmox-ve'!

图

想都没想按照提示执行了, 结果pve控制台就没了. qm等相关命令也没了.

二、 解决

思路: 根据日志提示和lsblk相关的输出, 判断只是删除了相关的pev包, 源数据还在, 安装相关的pve包回去即可

按照日志和apt log 提示, 找到了被删除的包

2.1 添加源

echo "deb [arch=amd64] http://download.proxmox.com/debian/pve buster pve-no-subscription" > /etc/apt/sources.list.d/pve-install-repo.list

2.2 添加 gpg key

wget http://download.proxmox.com/debian/proxmox-ve-release-6.x.gpg -O /etc/apt/trusted.gpg.d/proxmox-ve-release-6.x.gpg

chmod +r /etc/apt/trusted.gpg.d/proxmox-ve-release-6.x.gpg

2.3 安装 Proxmox VE 包

apt install proxmox-ve postfix open-iscsi

2.4 相关报错 pve-container : Depends: binutils but it is not installable

我是原生安装的pve, 不是从debian过来的, 所以缺少相关的包. 添加debian的源到source.list之后update即可

2.4 相关日志

/var/log/syslog

2.5 IO errors

一般是磁盘满了, 清理下磁盘

仅限 tcp 端口

一、 Windows/Winserver

:: @author  wanghuaizhuang
:: @date 2024-2-29
:: @version V1.0

:: get the high risk ports on windows/winserver
:: usage: right-click and run this script as administrator

@echo off
setlocal enabledelayedexpansion

:: set high risk ports
set "ports=21 22 23 25 53 69 110 111 135 139 143 161 389 445 873 1025 1099 1433 1521 2049 2181 2222 2375 2379 2888 3128 3306 3389 3690 3888 4000 4040 4440 4848 4899 5000 5005 5432 5601 5631 5632 5900 5984 6123 6379 7001 7051 7077 7180 7182 7848 8019 8020 8042 8048 8051 8069 8080 8081 8083 8086 8088 8161 8443 8649 8848 8880 8888 9000 9001 9042 9043 9083 9092 9100 9200 9300 9990 10000 11000 11111 11211 18080 19888 20880 25000 25010 27017 27018 28017 50030 50060 50070 50090 60000 60010 60030"

for %%p in (%ports%) do (
netstat -ano | findstr LISTEN | findstr /c:":%%p " >nul
if errorlevel 1 (
echo High Risk Port %%p is not listening. > nul
) else (
echo High Risk Port %%p is listening
set count=0
for /f "tokens=5" %%a in ('netstat -aon ^| findstr ":%%p " ^| findstr "LISTENING"') do (
if !count! equ 0 (
wmic process where processid="%%a" get processid, executablepath
set /a count+=1
)
)
echo "------------------------------------------------------------------"

)
)
pause



参数说明:

  • /c: 完全匹配
  • ":%%p " –> ":139 " (注意空格)避免较长端口号中间包含139
  • errorlevel 1 判断命令执行的返回
  • bat同级目录输出文件

二、 Linux

## get high risk ports on Linux

## @author wanghuaizhuang
## @date 2024-4-8
## @version V2.0

#! /bin/bash

# high-risk ports
valid_ports="21 22 23 25 53 69 110 111 135 139 143 161 389 445 873 1025 1099 1433 1521 2049 2181 2222 2375 2379 2888
3128 3306 3389 3690 3888 4000 4040 4440 4848 4899 5000 5005 5432 5601 5631 5632 5900 5984 6123 6379 7001 7051 7077 7180 7182 7848 8019 8020 8042 8048 8051 8069 8080 8081 8083 8086 8088 8161
8443 8649 8848 8880 8888 9000 9001 9042 9043 9083 9092 9100 9200 9300 9990 10000 11000 11111 11211 18080 19888 20880 25000 25010 27017 27018 28017 50030 50060 50070 50090 60000 60010 60030
"

# get listening ports
ports=$(ss -tuln | awk 'NR>1 {print $5}' | awk -F '[:]' '{print $NF}' | awk '!seen[$0]++')


# iterate through ports
for port in $ports; do
# check whether the port is a high-risk port
if echo "$valid_ports" | grep -q "\<$port\>"; then
# print on terminal and save to file
echo -e 高危端口: "\e[31m$port\e[0m"

pid=$(lsof -i:$port | awk 'NR>1 {print $2}' | head -n 1)
path=$(ps $pid | awk 'NR==2 {print $5}')

echo -e 进程ID: "\e[31m$pid\e[0m"
echo -e 二进制文件: "\e[31m$path\e[0m"
echo -e "----------------\n"
echo "$port" >> output.txt
fi
done

guanzhi/GmSSL

是由北京大学自主开发的国产商用密码开源库,实现了对国密算法、标准和安全通信协议的全面功能覆盖,支持包括移动端在内的主流操作系统和处理器,支持密码钥匙、密码卡等典型国产密码硬件,提供功能丰富的命令行工具及多种编译语言编程接口。

GMSSL 国密实验室

是一个提供国密SSL相关软件/工具/服务的网站,网站简称国密SSL实验室 版本所有 2020 国密SSL实验室 保留全部权利 云钥网络提供技术支持 京ICP备17056405号-2

guanzhi/GmSSL

单独实现了 SM2, SM3, SM4 并不兼容 OpenSSL, 也不属于OpenSSL的扩展

一、 openssl国密版

  • 下载
    https://www.gmssl.cn/gmssl/index.jsp

  • 解压
    tar xzfm gmssl_openssl_1.1_b2024_x64_1.tar.gz -C /usr/local

二、 nginx国密版

  • 下载
    https://nginx.org/download/

  • 解压
    tar -xzvf nginx-1.24.0.tar.gz

  • 修改nginx中关于openssl的配置
    vim auto/lib/openssl/conf
    $OPENSSL/.openssl/—> $OPENSSL/

  • 编译安装

    ./configure \
    --prefix=/usr/local/nginx-1.24.0 \
    --without-http_gzip_module \
    --with-http_ssl_module \
    --with-http_stub_status_module \
    --with-http_v2_module \
    --with-stream \
    --with-file-aio \
    --with-openssl="/usr/local/gmssl"

    make && make install

三、 国密证书自签

(下面命令实际测试无效, 和gmssl版本有关, 已作废)

3.1 安装 gmssl 工具(二进制)

  • 下载
    https://github.com/guanzhi/GmSSL

  • 解压
    tar -xzvf GmSSL-3.1.1-Linux.tar.gz

  • 链接库 (源码编译安装的可以省略这一步)
    echo /usr/local/gmssl-3.1.1/lib > /etc/ld.so.conf.d/gmssl.conf
    ldconfig

  • 验证安装
    /usr/local/gmssl-3.1.1/bin/gmssl version

3.2 创建 CA

  • CA 私钥
    gmssl sm2keygen -pass 123456 -out ca.key

  • CA_CERT
    gmssl certgen -C CN -ST ZheJiang -L HangZhou -O PKU -OU CS -CN ROOTCA -days 365 -key ca.key -pass 123456 -out cacert.pem -key_usage keyCertSign -key_usage cRLSign

  • CA_CERT_parse

gmssl certparse -in cacert.pem

  • sign_key
    gmssl sm2keygen -pass 123456 -out sign.key

  • sign_req

gmssl reqgen -C CN -ST ZheJiang -L HangZhou -O PKU -OU CS -CN localhost -key sign.key -pass 123456 -out sign.req

  • sign_cert
    gmssl reqsign -in sign.req -days 365 -key_usage digitalSignature -cacert cacert.pem -key ca.key -pass 123456 -out sign.cert

三、测试

3.1 证书生成

免费证书生成

使用支持国密算法的浏览器, 这里用360浏览器测试

傻逼360, 360就是个傻逼

图

一、 安装 Alertmanager

1.1 基于二进制安装

  • 下载
    https://github.com/prometheus/alertmanager/releases

  • 解压
    tar -xzvf alertmanager-0.26.0.linux-amd64.tar.gz

  • 运行
    ./alertmanager --config.file="alertmanager.yml"

1.2 基于 docker 安装

docker run --name alertmanager -d -p 127.0.0.1:9093:9093 quay.io/prometheus/alertmanager

二、 配置 Alertmanager

2.1 配置 Alertmanager 告警方式

  • 编辑配置文件: alertmanager.yml

  • smtp_smarthost 字段需要注明端口

    global: 
    resolve_timeout: 5m
    smtp_smarthost: 'smtp.qq.com:25'
    smtp_from: 'yourqq@qq.com'
    smtp_auth_username: 'yourqq@qq.com' #
    smtp_auth_password: 'yourpasswd/authenticCode'
    route:
    group_by: ['alertname']
    group_wait: 30s
    group_interval: 5m
    repeat_interval: 1h
    receiver: 'email'
    receivers:
    - name: 'email'
    email_configs:
    - to: 'receviers@live.com'
    inhibit_rules:
    - source_match:
    severity: 'critical'
    target_match:
    severity: 'warning'
    equal: ['alertname', 'dev', 'instance']

2.2 配置 Prometheus

  • 编辑配置文件 prometheus.yml

    alerting:
    alertmanagers:
    - static_configs:
    - targets: ["192.168.1.201:9093"]

    rule_files:
    - "/usr/local/prometheus/rules/*"
  • /usr/local/prometheus/rules/* 用于存放告警规则

2.3 告警示例

vim /usr/local/prometheus/rules/first.rules.yml

groups:
- name: cpuAlertGroup
rules:
- alert: hostCPUUsageTooHigh
expr: (1 - sum(increase(node_cpu_seconds_total{mode="idle"}[1m])) by (instance) / sum(increase(node_cpu_seconds_total[1m])) by (instance) ) * 100 > 50
for: 30s
labels:
biz_type: cpu_usage
annotations:
summary: "Instance {{ $labels.instance }} CPU usgae high"
description: "{{ $labels.instance }} CPU usage above 50% (current : {{ $value }})"

三、 测试

  • 测试脚本
#!/usr/bin/python
# -*- coding: UTF-8 -*-

### 用法: python cpu_mem.py 4 1024
### 解释:
### 占满 4个核心
### 占用1024MB内存

import sys
import time
from multiprocessing import Process

def exec_func(bt):

while True:
for i in range(0, 9600000):
pass
time.sleep(bt)

if __name__ == "__main__":

if len(sys.argv) != 3:
print('Need one argument! ')
sys.exit()
cpu_logical_count = int(sys.argv[1])
cpu_sleep_time = 0.01
memory_used_mb = int(sys.argv[2])

try:
s = ' ' * (memory_used_mb * 1024 * 1024)
except MemoryError:
print("剩余内存不足,内存有溢出......")

try:
p = Process(target=exec_func, args=("bt",))
ps_list = []
for i in range(0, cpu_logical_count):
ps_list.append(Process(target=exec_func, args=(cpu_sleep_time,)))
for p in ps_list:
p.start()
for p in ps_list:
p.join()
except KeyboardInterrupt:
print("资源浪费结束!")

图
图

一、 基于nginx-module-vts监控

1.1 下载

https://github.com/vozlt/nginx-module-vts

1.2 重新编译nginx

./configure \
--prefix=/usr/local/nginx-1.25.0 \
--add-module=./nginx-module-vts-0.2.2 \
--with-http_ssl_module \
--with-http_realip_module \
--with-http_stub_status_module \
--with-http_gzip_static_module

1.3 nginx 配置

http {
#---隐藏其他配置
vhost_traffic_status_zone;
vhost_traffic_status_filter_by_host on;
server {
#---隐藏其他的路由
location /status {
vhost_traffic_status_display;
vhost_traffic_status_display_format html;
}
}
}

1.4 Prometheus 配置

- job_name: "nginx_vts_status"
metrics_path: '/status/format/prometheus'
scrape_interval: 10s
static_configs:
- targets: ["192.168.1.201:88"]

1.5 配置 grafana

导入模板: https://grafana.com/grafana/dashboards/14824-nginx-vts-stats/

二、 基于nginx-prometheus-exporter监控

2.1 配置nginx

  • 确保当前运行的nginx支持http_stub_status
    ./nginx -V 2>&1 | grep -o with-http_stub_status_module

  • nginx 开启http_stub_status
    vim /path2yournginx/nginx.conf

      server {
    listen 80;
    location /nginx_status {
    stub_status on;
    access_log off;
    allow 127.0.0.1;
    deny all;
    }
    }

2.2 配置nginx-prometheus-exporter

  • 下载
    https://github.com/nginxinc/nginx-prometheus-exporter

  • 解压
    tar -xzvf node_exporter-1.7.0.linux-amd64.tar.gz -C /usr/local/

  • 运行
    ./nginx-prometheus-exporter -nginx.scrape-uri http://127.0.0.1/nginx_status

2.3 配置 Prometheus

- job_name: "nginx_status"
metrics_path: '/metrics'
scrape_interval: 10s
static_configs:
- targets: ["192.168.1.201:9113"]

2.4 导入模板

https://grafana.com/grafana/dashboards/11199-nginx/

一、 安装

该脚本的安装符合FHS规范, 如需自定义目录请手动使用go编译
bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ install

二、 配置

  • Windows GUI客户端, 右键导出客户端配置

三、 代理配置

vim /etc/profile

export http_proxy='socks5://127.0.0.1:10808'
export https_proxy='socks5://127.0.0.1:10808'

一、 二进制安装

二、 基于容器构建

2.1 容器构建

vim Dockerfile

FROM centos:centos7.9.2009

ARG NODE_EXPORTER_HOME=/usr/local/node-exporter

# Add file
COPY ./node_exporter-1.7.0.linux-amd64.tar.gz /opt

# tar file and rename to "prometheus"
RUN mkdir -p ${NODE_EXPORTER_HOME}
RUN tar -xzvf /opt/node_exporter-1.7.0.linux-amd64.tar.gz -C /usr/local/node-exporter --strip-components=1

RUN groupadd -r node_exporter && \
useradd -g node_exporter -s /bin/bash -c "node_exporter user" node_exporter && \
chown -R node_exporter:node_exporter /usr/local/node-exporter

# port
EXPOSE 9100

WORKDIR ${NODE_EXPORTER_HOME}

USER node_exporter

ENTRYPOINT [ "./node_exporter" ]

2.2 容器编排

vim docker-compose.yml

version: "3"
services:
node_exporter:
image: node_exporter:latest
user: "node_exporter"
ports:
- "9100:9100"
container_name: node_exporter
restart: always
volumes:
- /proc:/host/proc:ro
- /sys:/host/sys:ro
- /:/rootfs:ro
command:
- '--path.procfs=/host/proc'
- '--path.rootfs=/rootfs'
- '--path.sysfs=/host/sys'
- '--collector.filesystem.ignored-mount-points=^/(sys|proc|dev|host|etc)($$|/)'
networks:
default:
driver: bridge

一、 部署 Docker

1.1 安装 Docker

yum install yum-utils
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

yum install docker-ce \
docker-ce-cli \
containerd.io \
docker-buildx-plugin \
docker-compose-plugin

1.2 设置 docker 自启

systemctl enable docker.socket --now
systemctl enable docker --now

二、 配置容器MySQL

2.1 获取 MySQL 容器

官方容器
docker pull mysql/mysql-server:5.7.41

2.2 创建相关目录

  • MySQL数据目录: mkdir -p /home/mysql-5.7.41/data
  • MySQL配置目录: mkdir -p /home/mysql-5.7.41/conf

2.3 容器编排文件

#vim docker-compose.yml
version: '3'
services:
mysql:
image: mysql/mysql-server:5.7.41
restart: always
container_name: mysql-5.7.41
environment:
MYSQL_ROOT_PASSWORD: $youpasswd
TZ: Asia/Shanghai
ports:
- 3307:3307
volumes:
- /home/mysql-5.7.41/data:/var/lib/mysql
- /home/mysql-5.7.41/conf/my.cnf:/etc/mysql/my.cnf

2.4 MySQL 配置文件

#vim /home/mysql-5.7.41/conf/my.cnf
[mysqld]
port=3307
user=mysql
default-storage-engine=INNODB
character-set-server=utf8
character-set-client-handshake=FALSE
collation-server=utf8mb4_general_ci
init_connect='SET NAMES utf8'
max_connections=1000
[client]
default-character-set=utf8mb4
[mysql]
default-character-set=utf8mb4

三、 启动容器 MySQL

  • 启动
    docker-compose up -d
  • 日志
    docker logs -f mysql-5.7.41

零、 Environment

CentOS7.9 x86_64 kvm
GLIBC 2.17 升级至 2.28

一、 准备工作

1.1 升级 GCC 12.3

  • 下载:
    wget --no-check-certificate https://mirrors.nju.edu.cn/gnu/gcc/gcc-12.3.0/gcc-12.3.0.tar.gz

  • 解压:
    tar -xzvf gcc-12.3.0.tar.gz

  • 安装依赖:
    yum install bzip2 gcc gcc-c++

  • 下载环境:
    /gcc-12.3.0/contrib/download_prerequisites

  • 编译安装:
    cd gcc-12.3.0
    mkdir build
    cd build
    ../configure -enable-checking=release -enable-language=c,c++ -disable-multilib
    make install

  • 参数解释:

    enable-languages     #表示你要让你的gcc支持那些语言
    disable-multilib #不生成编译为其他平台可执行代码的交叉编译器
    disable-checking #生成的编译器在编译过程中不做额外检查
    enable-checking=xxx #检查xx
  • 删除旧版 gcc:
    yum remove gcc g++

  • 链接新版 gcc (产出文件默认遵循FHS规范)
    ln -s /usr/local/bin/gcc /usr/bin/gcc

  • 验证新版 gcc

1.2 升级make

  • 下载:
    wget --no-check-certificate https://mirrors.nju.edu.cn/gnu/make/make-4.3.tar.gz

  • 解压:
    tar zxvf make-4.3.tar.gz

  • 编译安装(产出文件默认遵循FHS规范)
    cd make-4.3
    ./configure
    make -j4
    make install

  • 移除原来的make
    mv /usr/bin/make{,.back}

  • 链接新版本的make
    ln -s /usr/local/bin/make /usr/bin/make

  • 验证新版make

1.3 升级 GLIBC 2.8

  • 下载:
    wget --no-check-certificate https://mirrors.nju.edu.cn/gnu/glibc/glibc-2.28.tar.gz

  • 解压:
    tar -xzvf glibc-2.28.tar.gz

  • 编译安装
    cd glibc-2.28
    mkdir build && cd build

    ../configure --prefix=/usr --disable-profile --enable-add-ons --with-headers=/usr/include --with-binutils=/usr/bin --disable-sanity-checks --disable-werror

    make install

不要修改 --prefix=/usr

参数解释:

--prefix=/usr/local/GLIBC-2.8:
指定安装目录的前缀。在这里,指定了/usr/local/GLIBC-2.8,这意味着编译后的文件将被安装到该目录下。

--disable-profile:
禁用性能分析支持,通常是禁用生成程序的性能分析信息。

--enable-add-ons:
启用支持附加模块的功能。这通常用于启用一些额外的功能或插件。

--with-headers=/usr/include:
指定头文件的位置,这里设置为/usr/include,告诉配置脚本在这个目录中寻找头文件。

--with-binutils=/usr/bin:
指定binutils工具的位置,这里设置为/usr/bin。Binutils包含了一组用于处理二进制文件的工具,如汇编器、链接器等。

--disable-sanity-checks:
禁用一些编译时的检查,这可能会加快编译过程,但也可能导致生成的库不够稳定或不符合某些标准。

--disable-werror:
禁用将警告视为错误的选项。通常情况下,编译过程中遇到的警告会被视为错误,导致编译中断。此选项用于忽略这些警告,即使它们本来应该导致编译失败。

二、 相关报错

2.1 安装glibc-2.28时报LD_LIBRARY_PATH相关错误

错误详情:

l * LD_LIBRARY_PATH shouldn’t contain the current directory when
* building glibc. Please change theenvironment variable
* and run configure again.

解决:
echo $LD_LIBRARY_PATH
将输出的结果临时注释, 编译安装完成之后再取消注释

2.2 更新glibc-2.28后执行yum报错Error accessing file for config file:///etc/yum.conf

错误详情:

解决: 重新安装yum

  • 下载:
    wget http://yum.baseurl.org/download/3.4/yum-3.4.3.tar.gz

  • 解压:
    tar -zxvf yum-3.4.3.tar.gz

  • 安装:
    cd yum-3.4.3
    touch /etc/yum.conf

一、 分类文章数量

文件路径: themes\next\layout\_partials\header\menu-item.njk

<!--分类文章数量-->
{%- set menuBadge = '' %}
{%- if theme.menu_settings.badges %}
{%- set badges = {
archives : site.posts.length,
categories : site.categories.length,
tags : site.tags.length,
Linux : site.categories.findOne({name: 'Linux'}).length,
NetWork : site.categories.findOne({name: 'NetWork'}).length,
Database : site.categories.findOne({name: 'Database'}).length,
'CI/CD' : site.categories.findOne({name: 'CI/CD'}).length,
Monitor : site.categories.findOne({name: 'Monitor'}).length,
K8S : site.categories.findOne({name: 'K8S'}).length,
Docker : site.categories.findOne({name: 'Docker'}).length,
OpenWrt : site.categories.findOne({name: 'OpenWrt'}).length
}
%}
{%- for menu, count in badges %}
{%- if node.name == menu %}
{%- set menuBadge = '<span class="badge">' + count + '</span>' %}
{%- endif %}
{%- endfor %}
{%- endif %}

二、 单行代码颜色

文件路径: \themes\next\source\css\_common\scaffolding\highlight\index.styl

// Placeholder: $code-inline $code-block
$code-inline {
//background: var(--highlight-background);
//color: var(--highlight-foreground);
color: #c7254e;
background: #f9f2f4;
}

$code-block {
//@extend $code-inline;
background: var(--highlight-background);
color: var(--highlight-foreground);
line-height: $line-height-code-block;
margin: 0 auto 20px;
}

三、 关于搜索功能

hexo配置文件: /_config

search:
# path: ./node_modules/hexo-generator-searchdb/templates/search.xml
path: search.json
field: post
content: true
format: html
limit: 1000

四、 背景图片

主题配置文件: /themes/next/_config.yml

custom_file_path:
#head: source/_data/head.njk
#header: source/_data/header.njk
#sidebar: source/_data/sidebar.njk
#postMeta: source/_data/post-meta.njk
#postBodyEnd: source/_data/post-body-end.njk
#footer: source/_data/footer.njk
#bodyEnd: source/_data/body-end.njk
#variable: source/_data/variables.styl
#mixin: source/_data/mixins.styl
style: source/_data/styles.styl

创建文件: /blog/source/_data/styles.styl

body {
background:url(/images/background.jpg);
background-repeat: no-repeat;
background-attachment:fixed;
background-position:100% 100%;
}

五、 页面圆角

主题配置文件: /themes/next/_config.yml

custom_file_path:
#head: source/_data/head.njk
#header: source/_data/header.njk
#sidebar: source/_data/sidebar.njk
#postMeta: source/_data/post-meta.njk
#postBodyEnd: source/_data/post-body-end.njk
#footer: source/_data/footer.njk
#bodyEnd: source/_data/body-end.njk
variable: source/_data/variables.styl
#mixin: source/_data/mixins.styl
style: source/_data/styles.styl

创建文件: /blog/source/_data/variables.styl

// 圆角设置
$border-radius-inner = 20px 20px 20px 20px;
$border-radius = 20px;

六、 字数统计和阅读时长

npm install hexo-symbols-count-time --save

hexo配置文件: /blog/_config.yml

symbols_count_time:
#文章内是否显示
symbols: true
time: true
# 网页底部是否显示
total_symbols: true
total_time: true

主题配置文件: /theme/next/_config.yml

symbols_count_time:
separated_meta: true # 是否换行显示 字数统计 及 阅读时长
item_text_post: true # 文章 字数统计 阅读时长 使用图标 还是 文本表示
item_text_total: true # 博客底部统计 字数统计 阅读时长 使用图标 还是 文本表示
awl: 4
wpm: 275

七、 推荐文章

npm install hexo-recommended-posts --save

hexo配置文件: /blog/_config.yml

recommended_posts:
#server: https://api.truelaurel.com #后端推荐服务器地址
timeoutInMillis: 10000 #服务时长,超过此时长,则使用离线推荐模式
internalLinks: 3 #内部文章数量
externalLinks: 1 #外部文章数量
fixedNumber: false
autoDisplay: true #自动在文章底部显示推荐文章
excludePattern: []
titleHtml: <h1>推荐文章<span style="font-size:0.45em; color:gray">(由<a href="https://github.com/huiwang/hexo-recommended-posts">hexo文章推荐插件</a>驱动)</span></h1> #自定义标题

推荐文章(由hexo文章推荐插件驱动)