一直以来我都想搭建一个属于自己的博客,用来记录一些想法和折腾的过程。但因为严重的拖延症(٩(ŏ﹏ŏ、)۶),这个计划一拖再拖。最近终于下定决心行动起来。对比了市面上几款主流的博客系统后,我最终选择了 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。
运行参数详解:
数据库配置:
为了保持部署流程的简洁,此文档仅提供了必要的配置示例,完整的配置选项列表可查阅:配置说明
启动Halo
启动 Halo 服务
docker compose up -d实时查看日志:
docker compose logs -f用浏览器访问 <IP:8090> 即可进入 Halo 管理页面,首次启动会进入初始化页面。

提示
如果需要配置域名访问,建议先配置好反向代理以及域名解析再进行初始化。如果通过
http://ip:端口号的形式无法访问,请到服务器厂商后台将运行的端口号添加到安全组,如果服务器使用了 Linux 面板,请检查此 Linux 面板是否有还有安全组配置,需要同样将端口号添加到安全组。
更新容器组
备份数据,可以参考 备份与恢复 进行完整备份(可选,但推荐备份)。
更新 Halo 服务
修改
docker-compose.yaml中配置的镜像版本。services: halo: image: registry.fit2cloud.com/halo/halo:2.21docker 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 # ❌ 应该拒绝连接