记录搭建Halo博客的过程

一直以来我都想搭建一个属于自己的博客,用来记录一些想法和折腾的过程。但因为严重的拖延症(٩(ŏ﹏ŏ、)۶),这个计划一拖再拖。最近终于下定决心行动起来。对比了市面上几款主流的博客系统后,我最终选择了 Halo 来搭建我的第一个博客页面。 这篇文章主要记录整个搭建过程,以及过程中遇到的问题和解决方法。

一直以来我都想搭建一个属于自己的博客,用来记录一些想法和折腾的过程。但因为严重的拖延症(٩(ŏ﹏ŏ、)۶),这个计划一拖再拖。最近终于下定决心行动起来。对比了市面上几款主流的博客系统后,我最终选择了 Halo 来搭建我的第一个博客页面。
这篇文章主要记录整个搭建过程,以及过程中遇到的问题和解决方法。我使用的是 Debian 11 系统,并通过 Docker Compose 进行部署。其他系统的步骤大体相似,可供参考。

使用 Docker Compose 部署

一键安装 Docker + Docker Compose(推荐)

如果你还没有 Docker,本命令会一起装好:

curl -fsSL https://get.docker.com | bash

安装完成后执行:

docker -v
docker compose version

如果都能输出版本号,就说明 Docker Compose v2 已内置安装完成。

📌 注意:现在 Docker Compose 已经内置到 docker compose 命令中,
不再使用旧版的 docker-compose(带连字符)。

安装Halo

在系统任意位置创建一个文件夹,此文档以 ~/halo 为例。

mkdir ~/halo && cd ~/halo

创建 docker-compose.yaml

touch docker-compose.yaml

这里使用Halo加PostgreSQL数据库,粘贴以下内容至 docker-compose.yaml ,注意修改相关变量

version: "3"

services:
  halo:
    image: registry.fit2cloud.com/halo/halo:2.21
    restart: on-failure:3
    depends_on:
      halodb:
        condition: service_healthy
    networks:
      halo_network:
    volumes:
      - ./halo2:/root/.halo2
    ports:
      - "8090:8090"
      # 若不开放IP加端口访问,可修改成  - "127.0.0.1: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:

此示例的 PostgreSQL 数据库容器默认没有设置端口映射,如果需要在容器外部访问数据库,可以自行在 halodb 服务中添加端口映射,PostgreSQL 的端口为 5432

运行参数详解:

参数名

描述

spring.r2dbc.url

数据库连接地址,详细可查阅下方的 数据库配置

spring.r2dbc.username

数据库用户名

spring.r2dbc.password

数据库密码

spring.sql.init.platform

数据库平台名称,支持 postgresqlmysqlmariadbh2

halo.external-url

外部访问链接,如果需要在公网访问,需要配置为实际访问地址

数据库配置:

链接方式

链接地址格式

spring.sql.init.platform

PostgreSQL(推荐)

r2dbc:pool:postgresql://{HOST}:{PORT}/{DATABASE}

postgresql

MySQL

r2dbc:pool:mysql://{HOST}:{PORT}/{DATABASE}

mysql

MariaDB

r2dbc:pool:mariadb://{HOST}:{PORT}/{DATABASE}

mariadb

H2 Database

r2dbc:h2:file:///${halo.work-dir}/db/halo-next?MODE=MySQL&DB_CLOSE_ON_EXIT=FALSE

h2

为了保持部署流程的简洁,此文档仅提供了必要的配置示例,完整的配置选项列表可查阅:配置说明

启动Halo

  1. 启动 Halo 服务

    docker compose up -d

    实时查看日志:

    docker compose logs -f
  2. 用浏览器访问 <IP:8090> 即可进入 Halo 管理页面,首次启动会进入初始化页面。

    提示

    如果需要配置域名访问,建议先配置好反向代理以及域名解析再进行初始化。如果通过 http://ip:端口号 的形式无法访问,请到服务器厂商后台将运行的端口号添加到安全组,如果服务器使用了 Linux 面板,请检查此 Linux 面板是否有还有安全组配置,需要同样将端口号添加到安全组。

更新容器组

  1. 备份数据,可以参考 备份与恢复 进行完整备份(可选,但推荐备份)。

  2. 更新 Halo 服务

    修改 docker-compose.yaml 中配置的镜像版本。

    services:
     halo:
       image: registry.fit2cloud.com/halo/halo:2.21
    docker compose up -d

使用Nginx配置域名访问并开启强制https

安装Nginx

更新系统软件源

sudo apt update && sudo apt upgrade -y

安装 Nginx

sudo apt install nginx -y

安装完成后可以检查版本:

nginx -v

启动并设置开机自启

sudo systemctl start nginx
sudo systemctl enable nginx

验证是否运行成功

运行以下命令查看状态:

sudo systemctl status nginx

或者在浏览器中访问服务器 IP:

http://你的服务器IP

如果能看到“Welcome to nginx!” 页面,说明安装成功。

配置域名

安装 Certbot(Let's Encrypt 客户端)

apt-get -o Acquire::Check-Valid-Until=false update

apt-get install -y certbot python3-certbot-nginx

检查 Nginx 配置是否正确

nginx -t

如果输出:

syntax is ok

test is successful

说明配置正确,可以申请证书

使用 Certbot 申请证书(自动修改 Nginx 配置)

certbot --nginx -d blog.example.com

-d blog.example.com:替换为你的真实域名

Certbot 会自动验证域名、生成证书,并修改 Nginx 配置开启 HTTPS

如果你只想 申请证书而不让 Certbot 自动改 Nginx 配置:

certbot certonly --nginx -d blog.example.com

设置自动续期

Let’s Encrypt 证书有效期 90 天,安装时 Certbot 会自动添加 systemd 定时任务:

systemctl list-timers | grep certbot

你也可以手动测试续期:

certbot renew --dry-run

注意事项:

域名必须解析到服务器公网 IP,否则验证会失败

如果你使用防火墙,确保 80/443 端口开放

修改证书路径

创建证书目录

mkdir -p /etc/ssl/blog.example.com

移动证书路径

cp /etc/letsencrypt/live/blog.example.com/fullchain.pem /etc/ssl/blog.example.com/
cp /etc/letsencrypt/live/blog.example.com/privkey.pem /etc/ssl/blog.example.com/

注意将上面的 'blog.example.com' 替换为自己的域名

配置Nginx

配置 Nginx 代理 Halo

nano /etc/nginx/sites-available/halo.conf

粘贴以下内容,注意修改相关变量

# Halo upstream

upstream halo {

server 127.0.0.1:8090; # 如果 Docker 映射了端口 8090

keepalive 64;

}

# HTTP — 强制跳转到 HTTPS

server {

listen 80;

listen [::]:80;

server_name blog.example.com;

# 修改为自己的域名

return 301 https://$host$request_uri;

}

# HTTPS — 代理 Halo

server {

listen 443 ssl http2;

listen [::]:443 ssl http2;

server_name blog.example.com;

# 修改为自己的域名

ssl_certificate /etc/ssl/blog.example.com/fullchain.pem;

ssl_certificate_key /etc/ssl/blog.example.com/privkey.pem;

# toblog.doit.moe — 修改为自己的域名

ssl_protocols TLSv1.2 TLSv1.3;

client_max_body_size 100M;

location / {

proxy_pass http://halo;

proxy_http_version 1.1;

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;

proxy_set_header Upgrade $http_upgrade;

proxy_set_header Connection "upgrade";

}

}

测试并重载 Nginx:

nginx -t
systemctl reload nginx

禁止IP:端口访问Halo(需配置好域名)

cd ~/halo

修改docker-compose.yaml 文件

找到 Halo 服务部分,像这样:

services:

halo:

image: halohub/halo:latest

container_name: halo

ports:

- "8090:8090"

改成:

services:

halo:

image: halohub/halo:latest

container_name: halo

ports:

- "127.0.0.1:8090:8090"

这样 Halo 只会绑定到 127.0.0.1,外网无法直接访问。

然后执行:

docker compose down
docker compose up -d

验证

curl http://127.0.0.1:8090 # ✅ 本地可访问
curl http://<服务器公网IP>:8090 # ❌ 应该拒绝连接

LICENSED UNDER CC BY-NC-SA 4.0