为什么突然想建这个博客?

搭建这个博客的起因可以追溯到我的一个大学同学。

他也有一个博客(他的博客链接:灯塔之海)。

当时他向我宣传他的博客时,就怂恿我,让我也建一个。

但当时我并没有开始搭建,不过也是为之后这个网站的搭建埋下了种子。

后来,我在开发一个项目的时候,感觉在这个过程中收获了很多,就想着把这个过程记录下来。

本来是打算记在oneNote或Notion上的,在记录的时候突然想起这件事。

想到他会把他学习研究的过程整理成博客,方便复习和分享。

然后就有了这个博客。

搭建的过程

搭建博客的选择和方法有很多种,我的只是其中一种:部署动态博客 CMS 系统。

一、准备工作

购买:一台VPS和一个域名

软件:MobaXterm

(1)VPS的购买与选择

VPS我买的是下图中的这个服务,搭载的系统是Ubuntu 24.04 LTS。服务商网址:https://claw.cloud/

不是很推荐购买这个服务,当时买它是有两个因素的:

  1. 最开始购买VPS的初衷是用来科学上网的。所以只能买这类能提供特殊功能的VPS

  2. 看中了他的价格三美元一个月。我找不到更便宜的了,在特殊的VPS里面。

不推荐购买中这个服务是因为:

  1. 大陆地区的南部、通过ssh远程连接、经行远程操作时,延迟太高了。有时候打完一个单词要过五、六秒钟才能出现。

  2. 搭建的科学上网节点的延迟也是很高,经常在400(ms)上下,速度也只有0.2(MB/s)左右。

  3. 如果只用来搭建博客、应该有其他性价比更高的普通服务商

如果购买其他VPS,只需要满足 “1核/内存1G/存储20”即可。

(2)域名的购买与选择

我的域名是在下图中的网站购买的。服务商网址:https://regery.com/en

这个域名服务商是我那个朋友推荐的,我用下来的感觉也是非常不错的,但是不支持中文和需要电话号码。

购买避坑指南

  1. 在填写个人信息(Registrant Details)时,可以乱编,但只能使用英文字母。

  2. 很多小众域名首年便宜但续费较贵,记得关闭 auto renew(自动续费),防止第二年悄悄扣款。

  3. 注册商自带了基础的 WHOIS 隐私保护,只要确保 Show contact details in public records 保持关闭,就不用花冤枉钱去买额外的高级隐私包。

(3)下载远程终端管理软件

推荐使用MobaXterm。官网地址:MobaXterm free Xserver and tabbed SSH client for Windows

这个也是我那个朋友推荐的,他用了两年了,亲测好用。

BiliBili上可以找到下载和安装教程。

二、在服务器上部署

我的部署方法是:先安装docker容器,然后再在docker容器里面部署Halo。

如果跟着我的步骤部署时,遇到错误:

  1. 你可以在文章的引用部分找相关链接,我会提供官方docs的链接。

  2. 也可询问AI(推荐Deepseek和Gemini)

(1)*先扩展系统内存(可以跳过)

这一步的用处是:

  1. 当物理内存不足时,系统会将不常用的内存数据移到 Swap 文件。

  2. 避免因内存耗尽导致系统崩溃或进程被杀。

  3. 改善系统稳定性,为数据库的应用提供缓冲。

注意事项:

  1. Swap 文件在磁盘上,速度远慢于物理内存(尤其是使用机械硬盘时)

  2. 频繁使用 Swap 会缩短 SSD 寿命

  3. 一般建议 Swap 大小为物理内存的 1-2 倍

  4. 禁用方法:如需禁用,执行 sudo swapoff /swapfile 并删除 /etc/fstab 相关行

将下面的代码(非#号开头)一行一行的复制到终端中执行:

# 1. 创建一个 2GB 的非空文件(这需要一点时间,请耐心等待),如需修改可以发给AI LLM帮你修改
sudo dd if=/dev/zero of=/swapfile bs=1M count=2048

# 2. 赋予安全权限

sudo chmod 600 /swapfile

# 3. 将该文件设置为 Swap 空间

sudo mkswap /swapfile

# 4. 启用 Swap

sudo swapon /swapfile

# 5. 让 Swap 在服务器重启后依然有效

echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab

执行完上述命令后,可以用以下命令验证:

# 查看 Swap 是否启用
free -h

# 查看 Swap 详细信息
swapon --show

# 查看内存使用情况
cat /proc/meminfo | grep Swap

也可以使用指令htop 查看交换分区是否在工作:

(2)安装docker

将下面的代码(非#号开头)一行一行的复制到终端中执行:

# 快捷安装 Docker
curl -fsSL https://get.docker.com | bash -s docker

# 启动并设置开机自启
systemctl start docker
systemctl enable docker

#确保系统有 Docker Compose
sudo apt install docker-compose-plugin -y

#最后可以通过验证安装结果
sudo docker run hello-world 

相关链接:

(3)准备配置文件

在服务器上建一个专门存放博客文件的文件夹(如:halo-blog),方便以后备份或者迁移:

mkdir -p /root/halo-blog && cd /root/halo-blog

使用 nano 命令行编辑器创建一个 docker-compose.yml 文件:

nano docker-compose.yml

将以下内容复制并粘贴进去,然后对备注部分进行修改(建议修改完后,删除#号和所有中文)和保存:

services:
  halo:
    image: registry.fit2cloud.com/halo/halo-pro:2.24
    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:postgresql://halodb/halo
      - --spring.r2dbc.username=halo
      # PostgreSQL 的密码,请保证与下方 POSTGRES_PASSWORD 的变量值一致。
      - --spring.r2dbc.password=openpostgresql
      - --spring.sql.init.platform=postgresql
      # 外部访问地址,请根据实际需要修改
      - --halo.external-url=http://localhost:8090/
  halodb:
    image: postgres:15.4
    restart: on-failure:3
    networks:
      halo_network:
    volumes:
      - ./db:/var/lib/postgresql/data
    healthcheck:
      test: [ "CMD", "pg_isready" ]
      interval: 10s
      timeout: 5s
      retries: 5
    environment:
      - POSTGRES_PASSWORD=openpostgresql
      - POSTGRES_USER=halo
      - POSTGRES_DB=halo
      - PGUSER=halo

networks:
  halo_network:

保存:按 Ctrl + O 然后按回车

退出编辑器:按 Ctrl + X

Halo的官方参考文档:https://docs.halo.run/getting-started/install/docker-compose

开源地址:https://github.com/halo-dev/halo

官网:https://www.halo.run

社区:https://bbs.halo.run

(4)一件部署Halo

  1. 在有docker-compose.yaml文件的录下执行命令docker compose up -d,让容器在后台运行。

  2. 打开浏览器,访问 http://你的服务器公网IP:8090,进入Halo 引导界面。

  3. 根据引导完成初始化后,访问 http://你的服务器公网IP:8090/console 即可登录进入它的后台。

(5)*常用的基础docker compose指令(可以跳过)

# 启动服务(-d 后台运行)
docker compose up
docker compose up -d

# 停止服务
docker compose down

# 停止并删除容器、网络(保留数据卷)
docker compose down

# 停止并删除所有(包括数据卷)
docker compose down -v

# 重启服务
docker compose restart

# 查看运行状态
docker compose ps

# 查看日志
docker compose logs
docker compose logs -f              # 实时跟踪
docker compose logs --tail=100      # 查看最后100行
docker compose logs halo            # 查看指定服务

三、给博客冠上域名

(1)将域名托管至 Cloudflare

如果没有出意外,在过程二完成后,其实就已经上线了。

别人可以访问http://你的服务器公网IP:8090 看到你的博客。

但是为了保护服务器真实 IP、加速访问和获得免费的 SSL 证书,我决定把域名接入 Cloudflare(CF)。

  1. 添加站点:登录 Cloudflare 官网,点击 “连接域名”,输入买好的域名,套餐直接选择 Free(免费版)

  2. 修改 Name Servers:Cloudflare 会生成两行专属的 DNS 服务器地址(形如xxxx.ns.cloudflare.com)。

  3. 域名解析交接:回到域名注册商后台,将默认的 Regery NS 修改为 External NS(外部 NS),并把 Cloudflare 的这两行地址填进去。

  4. 等待生效:当 Cloudflare 后台显示绿色的 “您的域现在受 Cloudflare 保护” 时,说明交接顺利完成!

Cloudflare官方文档:https://developers.cloudflare.com/directory/

(2)配置 Cloudflare DNS 解析

我的博客后端服务原本运行在服务器的 8090 端口上(通过 http://XXXX.XXXX.XXXX.XXXXX:8090/ 访问)。但我希望用户输入标准的 https://blog.yuliannus2569.rest 就能直接访问。

  1. 进入 Cloudflare 的 “DNS” -> “记录” 页面。

  2. 点击 “添加记录”

    • 类型A

    • 名称blog (这样就自动生成了二级域名 blog.yuliannus2569.rest

    • IPv4 地址:填写服务器的真实 IP XXXX.XXXX.XXXX.XXXXX

    • 代理状态保持开启(橙色小云朵)(这一步是实现免费 HTTPS 的核心)

  3. 点击保存。(当时没截图)

(3)服务器安装 Nginx 并配置反向代理

因为 Cloudflare 的橙色云朵代理的是标准端口(80/443),而我的服务在 8090,所以需要在服务器上用 Nginx 做一层内部“引流”。

  1. 安装 Nginx,将下面的代码(非#号开头)一行一行的复制到终端中执行:

# 更新并安装 Nginx
sudo apt update && sudo apt install nginx -y

# 启动并设置开机自启
sudo systemctl start nginx && sudo systemctl enable nginx
  1. 配置反向代理,创建并编辑一个独立的配置文件:sudo nano /etc/nginx/conf.d/blog.conf

  2. 在文件中写入以下反代配置,把来自 blog 域名的流量切到本地的 8090 端口:

server {
    listen 80;
    server_name blog.yuliannus2569.rest;

    location / {
        proxy_pass http://127.0.0.1:8090;
        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;
    }
}
  1. 保存退出后,测试并重载 Nginx,将下面的代码(非#号开头)一行一行的复制到终端中执行:

# 检查语法
sudo nginx -t
 
# 重新加载配置
sudo nginx -s reload 
  1. 最后一步,回到 Cloudflare 后台,点击左侧的 “(SSL/TLS)/概述”,将加密模式设置为 “灵活 (Flexible)”

这样一来,完美的流量闭环就达成了: 浏览器 (HTTPS 访问) ──> Cloudflare 代理 (自动提供解密) ──> 服务器 Nginx (80端口) ──> 本地博客服务 (8090端口)

现在,直接在浏览器里输入 https://blog.yuliannus2569.rest,就能看到安全锁了

应该就没别的点了,在折腾的过程中踩了非常多的坑。

写的详细点,既方便我自己复刻,也希望能帮到别人。

在搭建的这个博客的过程中,我的那个朋友帮了我很多。

在此之前,我对服务器、网络代理、端口、操作系统等等,这方面的知识几乎一窍不通。

但我还是做到了,也学到了许多东西,所以我觉得别人也可以从这篇文章get something。

当然,我的成功也离不开我的朋友、Gemini和Deepseek的帮助。

搭建完成之后不久,我就写下了这篇文章。

因为已经搭建完了才写的过程,所以没有多少图片可提供参考的,有点小遗憾。

而且,这个项目也没有完美的实现,还是有一些可以改进的地方的,比如cloudflare与服务器之间的连接的安全等,这个就以后再搞吧,挖个坑先。

以后的打算

既然博客已经打好,这个博客以后就是我的常驻的赛博卧室和工具箱了。

这个博客可以当成我的“错题本”。

比如:在平时学习计算机技术、折腾各种代码(比如 Python、数据分析、UML 建模)或者做实验报告的时候,总会遇到各种奇奇怪怪的报错和坑(比如前阵子刚经历过把 Windows 驱动误删后痛苦重装的悲剧……)。 以后只要解决了一个技术难题,或者成功本地部署了什么好玩的大模型(比如用 Docker 和 Ollama 跑 local LLM),我都会把这些过程整理成文章发到这里。一方面是作为自己的备忘录,另一方面也希望能帮到其他人。

也可能会在博客上面分享一些好玩的有意思或者新奇的东西。