没有理想的人不伤心

基于 HALO 框架的博客折腾记录

2025/10/26
2
0

halo+ngrok 内网穿透部署个人博客,elog 进行语雀同步,阿里云 oss 作图床

halo 是一个快速建站框架

ngrok 负责内网穿透,即配置反向代理,让外网可以访问内网服务器(本机)

elog:easy blog,使笔记软件和个人博客进行同步,支持多款笔记软件和博客框架
image.png

获取 halo 并部署

GitHub 地址:https://github.com/halo-dev/halo

官方文档:

使用 Docker 部署 | Halo 文档

建议使用 docker 或 docker-compose 进行部署

下载安装 docker 的步骤省略了,安装完之后配置阿里云的容器镜像(我配置的不能用,不知道是啥问题)

获取镜像 docker pull halohub/halo

可以指定版本

创建容器 docker run -it -d --name halo -p 8090:8090 -v ~/.halo2:/root/.halo2 -e JVM_OPTS="-Xmx256m -Xms256m"registry.fit2cloud.com/halo/halo:2.20

注意挂载/.halo2 以及进行端口映射

运行之后在本地浏览器访问:http://ip:8090/console/setup

ip 换成自己服务器的 ip,若为本机,则 127.0.0.1

进入注册页面自定义账号密码

1732070724270-30f61f68-b1b8-4d23-a502-705792d33e47.png

初始化之后就能进入管理平台

1732070759402-ca87aa6b-e968-4739-b8be-75a26b7b4ec5.png

使用 ngrok 进行内网穿透

这里我选择使用的是国内的 sunny-ngrok:www.ngrok.cc

注册账号后,要开通隧道需要首先进行实名认证,收两块钱接口费

认证后,点击开通隧道,可以先选择免费的服务器尝试

1732070937012-ab8ac2b6-8d31-494f-ac87-62b0fde19d2d.png

1732071019136-8c4b1e63-73b0-4c5b-acef-28def5cf12b4.png

这里可以使用自己的域名,也可以使用他的域名,前置域名就是二级域名,

域名可以上阿里云、腾讯云进行注册

确认添加后,可以在隧道列表编辑配置并使用自己的域名

1732072555354-42d7c98b-7d61-448f-9f4a-1cf26d5bad26.png

接下来下载他们的客户端,我用的是 Ubuntu

https://www.ngrok.cc/_book/start/ngrok_linux.html

下载好后,隧道列表详情会显示你该运行的命令,连接上隧道就完成了配置

1732072652477-dc7616bc-e91b-4a04-8978-815d25550db2.png

现在就可以成功的从外网访问到内网啦!

这样的缺点是每次都需要手动的将笔记搬移到网站上,那么有没有能够同步工具呢

历经千辛万苦在 github 找到了 elog

https://github.com/LetTTGACO/elog

这个工具配置也许有点复杂,但没关系,有生态!

在其中我找到了语雀+halo+github action 的完美实践!

https://github.com/Flionay/yuque_halo

语雀自带图床,因此在语雀编写并不需要配置图床,但是语雀有防盗链,即不能从别的站点访问语雀图床中的图片

解决:使用阿里云 oss

笔记同步

https://github.com/Flionay/yuque_halo

  1. git clone https://github.com/Flionay/yuque_halo.git
  2. cd ./yuque_halo

在此目录下安装依赖,首先是要有 npm 环境,环境安装这里省略

npm install

  1. cp .elog.example.env .elog.env

并在.elog.env 中添加相应配置

#语雀(账号密码模式)
YUQUE_USERNAME=账号
YUQUE_PASSWORD=密码
# 语雀公共参数
YUQUE_LOGIN=空间名
YUQUE_REPO=知识库 id

# 阿里云 oss 图床对象存储
OSS_SECRET_ID=xxxx
OSS_SECRET_KEY=xxx
OSS_BUCKET=用户名
OSS_REGION=oss-cn-beijing

# Halo 站点信息
HALO_ENDPOINT=Halo 站点地址
HALO_TOKEN=获取的 Halo 个人令牌
HALO_POLICY_NAME=获取的存储策略

语雀:

账号一般是手机号

公共参数查看:

  • 随意打开一篇文章,网址处分别是空间名(个人空间一般就是用户名)、知识库 id 以及文章 id。

1732370082294-58718f44-b178-442f-a860-289d8a2b876d.png

****

Halo:

站点地址就是你网站的地址(域名或 IP)

我这里使用的 ngrok 反向代理,并且在阿里云注册域名绑定了反向代理服务器,因此我的地址就是 blog.hndr01d.online

个人令牌:

首先在控制台左下角打开个人中心

1732370313977-1057eeb5-f613-44ca-8873-0f31a27e25d0.png

找到个人令牌选项卡,并新建一个令牌,名称随意,过期日期不用管,权限最低是文章和附件,图方便也可以全给。

1732370405747-6968adc4-eb5b-4ee5-8153-afe18eaf7de5.png

创建之后复制下来粘贴。

1732370469318-e455580e-fdc3-42ef-b2fc-841e464486c0.png

存储策略:

F12 打开开发者工具,并在控制台点击附件选项卡,刷新一下

网络找到 **policies,**打开响应,找到存储策略,一般默认为default-policy,除非你在 halo 中配置了存储策略

1732370645601-e22619dc-5cec-4c1b-9a5f-f85e03edcc84.png

阿里云 oss:

首先找到 oss 并开通

打开控制台,配置 oss

1732370895222-29af2486-a297-4870-bb03-9e4fb3032d51.png

创建 Bucket,这里设置的名字就是你需要填在配置里的 bucket 用户名,bucket 的其他配置随意

配置 RAM 的AccessKey

https://ram.console.aliyun.com/profile/access-keys

1732371045846-923acc92-472b-44ec-91c8-9d5d6df1326e.png

创建AccessKey,并记录一下生成的 id 和 key,粘贴到对应的位置

region:

https://help.aliyun.com/document_detail/140601.html

对照创建 bucket 时选择的服务器区域,并获得 region,注意加一个前缀 oss-

配置文件大功告成

在正式上传到 Halo 站点前,建议先运行本地同步命令,从语雀拉取文档到本地

npm run dev:local

拉取到本地测试没问题时,再运行同步到 Halo 命令

npm run dev:halo

OSS 的策略配置

考虑到 oss 流量“贵如油”

因此考虑怎么限制只允许自己网站的 IP 对 oss 资源进行访问

然而阿里云并没有这个选项

打开了阻止公共访问,自己的 ip 也访问不了了

那么只能退而求其次

打开公共的读权限

1732371487631-76032603-0588-48e8-b174-d97243dc53a4.png

这样谁都能读

接下来开启防盗链,杜绝其他 ip 的访问

1732371549295-546898c0-d803-473c-87b7-ab98e6ba1ef9.png

在白名单中加入自己的域名,并且不允许空 referer

要是允许了空 referer,在别的域名确实访问不了,但是浏览器直接输入 oss 资源地址能正常访问

这样就大功告成了!



用 sunny-ngrok 服务器太卡了,限制太多了

在腾讯云上租了一台云服务器,使用 frp 来配置内网穿透

FRP 在云服务器上配置内网穿透

考虑到 ngrok 免费版网速太慢而且不稳定,刚好手上有一台云服务器,那么就可以使用 frp 做内网穿透

FRP 文档:https://gofrp.org/zh-cn/docs

FRP 基于 go 语言开发,因此要先下载 go 环境

  1. 安装 go 环境

参考https://go.dev/doc/install#requirements

  1. 下载 FRP

请在https://github.com/fatedier/frp/releases下载最新版本的 FRP 或者根据自己的需求下载

wget https://github.com/fatedier/frp/releases/download/v0.61.0/frp_0.61.0_linux_amd64.tar.gz

解压tar -zxvf frp_0.61.0_linux_amd64.tar.gz

里面包含了客户端和服务器端

在外网服务器(云服务器)中配置 FRP 服务器
在内网主机配置 FRP 客户端

  1. 服务器端配置:frps.tmol

ini 配置文件格式已被标记为抛弃

在 frps.toml 文件中添加以下内容,以指定 HTTP 请求的监听端口为 8080:

bindPort = 7000
vhostHTTPPort = 8080

如果需要配置 HTTPS 代理,还需要设置 vhostHTTPSPort

  1. 客户端配置:frpc.toml
serverAddr = "x.x.x.x"
serverPort = 7000

[[proxies]]
name = "web"
type = "http"
localPort = 80
customDomains = ["www.yourdomain.com"]

[[proxies]]
name = "web2"
type = "http"
localPort = 8080
customDomains = ["www.yourdomain2.com"]

serveraddr 为外网服务器 ip 地址

serverport 为服务器端的监听端口

若只有一个服务,那么设置一个 proxies 就可以

localhost 为提供服务的端口,halo 框架默认通过 8090 提供服务

customDomain 是你的域名,通过该域名来访问,不要忘了配置域名解析,将域名的 A 记录指向外网服务器 ip

  1. 启动 frp 服务器和客户端

./frps -c frps.toml

./frpc -c frpc.toml

上述配置完成,直接访问域名以及暴露的端口

测试正常,可以正常访问本地 halo 博客服务

使用 systemd 管理 frp 服务开机自启动:

  1. 在客户端和服务端分别将 frpc 和 frps 移动到系统路径
sudo mv frps /usr/local/bin/
sudo mv frpc /usr/local/bin/
  1. 确保 frps.tomb(服务端配置)或 frpc.tomb(客户端配置)文件已放置在 /etc/frp/ 目录下:
sudo mkdir -p /etc/frp
sudo mv frps.toml /etc/frp/
sudo mv frpc.toml /etc/frp/
  1. 创建 systemd 服务文件
sudo vim /etc/systemd/system/frps.service
sudo vim /etc/systemd/system/frpc.service
-  服务端 ` frps.service ` 文件内容:  
[Unit]
Description=FRP Server Service
After=network.target

[Service]
Type=simple
ExecStart=/usr/local/bin/frps -c /etc/frp/frps.toml
Restart=on-failure

[Install]
WantedBy=multi-user.target
-  客户端 ` frpc.service ` 文件内容:  
[Unit]
Description=FRP Client Service
After=network.target

[Service]
Type=simple
ExecStart=/usr/local/bin/frpc -c /etc/frp/frpc.toml
Restart=on-failure

[Install]
WantedBy=multi-user.target
  1. 重新加载 systemd配置

sudo systemctl daemon-reload

  1. 服务端客户端分别启动 frp 服务
sudo systemctl start frps
sudo systemctl start frpc
  1. 检查服务状态
sudo systemctl status frps
sudo systemctl status frpc
  1. 设置开机自启动
sudo systemctl enable frps
sudo systemctl enable frpc
  1. systemd 自动管理日志,使用以下命令查看运行日志:
journalctl -u frps
journalctl -u frpc

nginx 配置代理

在后期业务需求中,难免有时需要配置多服务、多域名的内网穿透,那么此时配置 frp 将变得极为麻烦

且虽然 frp 提供了 http2https 插件来配置 https,但是需要手动设置证书。尤其是当需要动态管理证书或多个域名时,手动更新证书会很麻烦。

而通过 Nginx 的反向代理,可以简化 FRP 的配置,让 FRP 只需暴露一个入口即可,具体的流量分发逻辑交给 Nginx。

Nginx 可以非常方便地启用 HTTPS,并与工具(如 Certbot)集成,实现自动申请和更新 SSL 证书。通过将 HTTPS 配置交给 Nginx,可以简化 FRP 的配置。

https 的配置

我们使用 let’s encrypt 提供的免费证书进行配置

  1. 安装官方推荐的工具以及 nginx 有关插件

sudo apt update && sudo apt upgrade

sudo apt install certbot python3-certbot-nginx

  1. 确保 nginx 正常

查看 nginx 运行状态sudo systemctl status nginx

检查配置文件语法是否正确sudo nginx -t

  1. 申请 SSL 证书

使用 Certbot 自动配置 HTTPS:

sudo certbot --nginx

会提醒你设置邮箱,并且政策都 yes,最后输入你的域名,不能使用通配符,多个域名使用空格隔开

1732435960667-99814d41-3274-4a72-9e91-43fceed4ef52.png

Certbot 生成的证书文件存储在 /etc/letsencrypt/live/your-domain.com/ 目录下,包括以下文件:

  • fullchain.pem:完整的证书链文件。
  • privkey.pem:私钥文件。

该证书有效期是三个月

Certbot 会自动通过 cronsystemd 管理续期任务。可以手动验证续期是否正常:

sudo systemctl list-timers | grep certbot

nginx 配置

nginx 监听 443 端口并转发到本地的 frp 8080 端口

并将 80 端口的 http 流量重定向到 443 端口

然后由 frp 进行内网穿透

在配置 SSL 之后,关于 https 的配置自动生成了

/etc/nginx/sites-available/default

server {
  listen 80 default_server;
  listen [::]:80 default_server;
  root /var/www/html;

  index index.html index.htm index.nginx-debian.html;

  server_name _;

  location / {
    # First attempt to serve request as file,then
    # as directory,then fall back to displaying a 404.
    try_files $uri $uri/ =404;
  }
}
server {
  root /var/www/html;
  index index.html index.htm index.nginx-debian.html;
  server_name blog.hndr01d.online; # managed by Certbot


  location / {
    proxy_pass http://127.0.0.1:8080;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    #try_files $uri $uri/ =404;
  }
  listen [::]:443 ssl ipv6only=on; # managed by Certbot
  listen 443 ssl; # managed by Certbot
  ssl_certificate /etc/letsencrypt/live/blog.hndr01d.online/fullchain.pem; # managed by Certbot
  ssl_certificate_key /etc/letsencrypt/live/blog.hndr01d.online/privkey.pem; # managed by Certbot
  include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
  ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

}
server {
  if($host = blog.hndr01d.online) {
    return 301 https://$host$request_uri;
  } # managed by Certbot
  listen 80;
  listen [::]:80;
  server_name blog.hndr01d.online;
  return 404; # managed by Certbot
}

关键配置:

#打开 443 端口并转发到 8080 端口
server {
    listen 443 ssl;
    server_name your-domain.com;

    ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:8080;  # 转发到 FRP 监听的 8080 端口
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

#重定向到 443 端口
server {
    listen 80;
    server_name your-domain.com www.your-domain.com;

    location / {
        return 301 https://$host$request_uri;
    }
}

使用 docker compose 启用 mysql 并修改外部访问地址为 https

在完成上述 https 配置后,网站能正常访问了,然而,资源加载不出

1732444643368-6d962e16-6eac-4f65-a775-3cd16fd3b954.png

参考官方文档中的内容

1732440612232-099bf845-f69f-4dfc-8cb4-5a56d7db58f6.png

确实是我外部访问地址没有改为 https,然而,找遍了所有的,没有找到能设置的地方啊,文档中说的 applicationl.yaml 并不存在

参考了 google 搜到的内容,应该是要使用 docker compose 并更改配置来启动容器

修改 external-url 参数之后重建容器即可,只要挂载了工作目录,重建容器不会丢失任何东西。

创建docker-compose.yaml

需要注意的是,所有与 Halo 相关的配置都使用 Docker 容器启动参数代替,所以无需创建 application.yaml 文件。

根据文档选择使用的数据库的对应 dockers compose:https://docs.halo.run/getting-started/install/docker-compose/?current=halo-mysql

这里选择 halo+mysql

version: "3"

services:
  halo:
    image:registry.fit2cloud.com/halo/halo:2.20
    restart:on-failure:3
    depends_on:
      halodb:
        condition:service_healthy
    networks:
      halo_network:
    volumes:
      - ./halo2:/root/.halo2
    ports:
      - "8090:8090"
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8090/actuator/health/readiness"]
      interval:30s
      timeout:5s
      retries:5
      start_period:30s
    environment:
      # JVM 参数,默认为 -Xmx256m -Xms256m,可以根据实际情况做调整,置空表示不添加 JVM 参数
      - JVM_OPTS=-Xmx256m -Xms256m
    command:
      - --spring.r2dbc.url=r2dbc:pool:mysql://halodb:3306/halo
      - --spring.r2dbc.username=root
      # MySQL 的密码,请保证与下方 MYSQL_ROOT_PASSWORD 的变量值一致。
      - --spring.r2dbc.password=#########
      - --spring.sql.init.platform=mysql
      # 外部访问地址,请根据实际需要修改
      - --halo.external-url=http://localhost:8090/

  halodb:
    image:mysql:8.1.0
    restart:on-failure:3
    networks:
      halo_network:
    command: 
      - --default-authentication-plugin=caching_sha2_password
      - --character-set-server=utf8mb4
      - --collation-server=utf8mb4_general_ci
      - --explicit_defaults_for_timestamp=true
    volumes:
      - ./mysql:/var/lib/mysql
      - ./mysqlBackup:/data/mysqlBackup
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1", "--silent"]
      interval:3s
      retries:5
      start_period:30s
    environment:
      # 请修改此密码,并对应修改上方 Halo 服务的 SPRING_R2DBC_PASSWORD 变量值
      - MYSQL_ROOT_PASSWORD=########
      - MYSQL_DATABASE=halo

networks:
  halo_network:

注意其中的 - --halo.external-url=http://localhost:8090/ 请自行更改,以免访问不到,数据库密码请自行修改

启动 halo 和 mysql 服务:

docker-compose up -d

docker ps发现容器已经启动

1732445581085-313f4400-913e-4505-af79-58240364ff88.png

查看服务状态:

docker-compose logs -f

浏览器登陆查看/console ,由于换了数据库,数据迁移麻烦,又需要重新初始化!


更改配置后,只需要再docker-compose up -d就可以更新容器


最后发现,重新配置后,仍然不能加载某些资源

分析:

配置 nginx 前,使用 http 可以正常访问云服务器 frp 监听的 8080 端口

配置 nginx 后,使用 https 能访问到,但访问资源加载不出

由于在 nginx 中使用了重定向,将访问 80 端口的 http 请求,转换为 443 的 https,所以用 http 来访问也不行

那么再访问最开始的云服务器 8080 端口,结果是正常访问!

刚开始没想到是 nginx 配置问题,直到使用 docker-compose 配置外部访问地址仍然失效,才反应过来,既然 8080 端口可以正常访问,那么肯定是流量在经过 nginx 时发生了意外

所以仔细检查了 nginx 的配置文件,果不其然发现错误配置

因为这一条语句: try_files $uri $uri/ =404;

github action 集成

终于可以最后配置 github action 了。

迁移到云服务器

在本地部署用内网穿透的方式存在很多物理上的问题,首先是实验室经常断电,导致电脑的关机,还有就是实验室的网络问题以及电脑自动更新重启后,docker 没有自启动。诸多问题,还是考虑把博客迁移到云服务器上直接访问吧

而迁移最重要的无非就是数据了。

  1. 数据卷的传输

将挂载的数据卷 tar 压缩打包并通过 scp 上传至云服务器,并解压缩

具体命令在此不再展示

  1. 镜像的传输

由于 docker pull从官方镜像源拉取镜像不可用,因此考虑直接将本地镜像打包传输

docker save -o halo_image.tar halohub/halo
docker save -o mysql_image.tar mysql

并用 scp传输到云服务器上,然后载入镜像

docker load -i halo_image.tar
docker load -i mysql_image.tar

docker images查看是否导入成功

  1. docker-compose 的容器编排和部署

请参考 7. 使用 docker-compose.yaml

docker-compose up -d启动

docker ps查看容器是否启动

  1. 配置 nginx

只需要把 nginx 的 443 端口的流量反向代理到 8090 端口就大功告成啦

halo 版本更新

官方文档参考:https://docs.halo.run/getting-started/install/docker#升级版本
由于快一年没有维护过博客了,很多插件都因为 halo 的版本太低而无法下载使用,因此需要将其更新到最新版本的镜像

目前最新的版本是 2.21,因此打算更新到 2.21 版本
image.png
在更新版本前最后先备份,halo控制台中提供了备份功能, 参考文档: https://docs.halo.run/user-guide/backup

# 0. 配置镜像源,国外可不配置
sudo mkdir -p /etc/docker

sudo tee /etc/docker/daemon.json <<-'EOF'  
{  
"registry-mirrors": [  
"[https://do.nark.eu.org](https://do.nark.eu.org/)",  
"[https://dc.j8.work](https://dc.j8.work/)",  
"[https://docker.m.daocloud.io](https://docker.m.daocloud.io/)",  
"[https://dockerproxy.com](https://dockerproxy.com/)",  
"[https://docker.mirrors.ustc.edu.cn](https://docker.mirrors.ustc.edu.cn/)",  
"[https://docker.nju.edu.cn](https://docker.nju.edu.cn/)"  
]  
}  
EOF

sudo systemctl daemon-reload  
sudo systemctl restart docker

# 1. 拉取镜像
docker pull halohub/halo:2.21

# 2. 停止运行中的容器,需要指定具体容器名
docker stop halo
docker rm halo

# 3. 修改版本号后,按照最初安装方式重新启动即可
# 这里使用 docker compose 进行部署,在使用命令前需要更新 docker-compose.yaml 文件中的镜像名,文件内容如下
docker-compose up -d

docker-compose.yaml 文件内容:

version: "3"

services:
  halo:
    image:halo/halo:2.21
    restart:on-failure:3
    depends_on:
      halodb:
        condition:service_healthy
    networks:
      halo_network:
    volumes:
      - ./halo2:/root/.halo2
    ports:
      - "8090:8090"
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8090/actuator/health/readiness"]
      interval:30s
      timeout:5s
      retries:5
      start_period:30s
    environment:
      # JVM 参数,默认为 -Xmx256m -Xms256m,可以根据实际情况做调整,置空表示不添加 JVM 参数
      - JVM_OPTS=-Xmx256m -Xms256m
    command:
      - --spring.r2dbc.url=r2dbc:pool:mysql://halodb:3306/halo
      - --spring.r2dbc.username=root
      # MySQL 的密码,请保证与下方 MYSQL_ROOT_PASSWORD 的变量值一致。
      - --spring.r2dbc.password=######
      - --spring.sql.init.platform=mysql
      # 外部访问地址,请根据实际需要修改
      - --halo.external-url=http://localhost:8090/

  halodb:
    image:mysql:8.1.0
    restart:on-failure:3
    networks:
      halo_network:
    command: 
      - --default-authentication-plugin=caching_sha2_password
      - --character-set-server=utf8mb4
      - --collation-server=utf8mb4_general_ci
      - --explicit_defaults_for_timestamp=true
    volumes:
      - ./mysql:/var/lib/mysql
      - ./mysqlBackup:/data/mysqlBackup
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1", "--silent"]
      interval:3s
      retries:5
      start_period:30s
    environment:
      # 请修改此密码,并对应修改上方 Halo 服务的 SPRING_R2DBC_PASSWORD 变量值
      - MYSQL_ROOT_PASSWORD=######## 
      - MYSQL_DATABASE=halo

networks:
  halo_network:

从 obsidian 发布文章至 halo

最近发现了一个超级好用的笔记软件 —— obsidian,也是果断粉了
因此想要在 obsidian上做笔记,然后同步更新到我的博客上,于是找到了一个 obsidian 的插件 —— halo
直接在插件市场下载该插件,然后添加配置:
插件使用说明: https://github.com/halo-sigs/obsidian-halo/blob/main/README.zh-CN.md
image.png