很多人想搭建自己的技术博客,但一开始往往会被服务器、域名、数据库、反向代理、HTTPS 证书这些概念劝退。
其实,如果只是搭建一个稳定、可维护、适合长期写技术文章的个人博客,并不需要一上来就折腾复杂架构。本文会带你从零开始,使用一台云服务器、一个域名,以及 Docker Compose 部署一套完整的个人博客系统。
本文最终采用的技术架构是:
Halo + PostgreSQL + Nginx Proxy Manager + HTTPS
最终效果是:
www.your-domain.com
http://www.your-domain.com
可以正常访问博客首页,并且可以通过:
https://www.your-domain.com/console
进入 Halo 后台管理页面。
本文适合没有建站经验的新手阅读。只要你准备好一台云服务器和一个域名,按照文章步骤完成服务器配置、域名解析、Docker 部署和 HTTPS 配置,就可以搭建出属于自己的个人技术博客。
一、整体架构
本次部署采用 Docker Compose 管理博客相关服务,整体结构如下:
云服务器
├── Nginx Proxy Manager
│ ├── 80 HTTP
│ ├── 443 HTTPS
│ └── 81 管理后台
│
├── Halo
│ └── 8090 内部端口
│
└── PostgreSQL
└── 5432 内部端口
访问链路如下:
用户浏览器
↓
https://www.your-domain.com
↓
Nginx Proxy Manager
↓
Halo:8090
↓
PostgreSQL
这里没有直接把 Halo 的 8090 端口暴露到公网,而是通过 Nginx Proxy Manager 做反向代理。
这样做有几个好处:
统一管理
80和443端口;统一申请和续期 SSL 证书;
Halo 服务不直接暴露到公网;
PostgreSQL 数据库不暴露公网端口;
后续迁移、备份和排错更加清晰。
尤其需要注意的是:PostgreSQL 只在 Docker 内部网络中提供服务,外部用户无法直接访问数据库。这比把 5432 端口暴露到公网更安全。
二、部署流程总览
搭建个人博客大致分为三个阶段。
2.1 前期准备
购买云服务器;
购买域名;
配置域名解析;
将域名指向服务器;
配置服务器防火墙端口。
2.2 服务器部署
安装 Docker;
创建 Docker 网络;
部署 Nginx Proxy Manager;
部署 PostgreSQL 数据库;
部署 Halo 并连接 PostgreSQL;
启动 Halo 和 PostgreSQL;
验证数据库与 Halo 服务是否正常;
在 Nginx Proxy Manager 中配置反向代理;
访问 Halo 初始化页面。
三、前期准备
3.1 购买云服务器
云服务器可以理解为博客的“主机”。博客程序、数据库、反向代理服务都会运行在这台服务器上。
阿里云、腾讯云、百度云等平台都可以购买云服务器。如果购买的是国内服务器,并且希望绑定自己的域名,通常需要进行备案。备案流程相对麻烦,审核周期也比较长。
如果只是想快速把个人博客跑起来,建议新手优先选择海外服务器。海外服务器通常不需要备案,购买服务器并完成域名解析后,就可以直接访问。
我这里使用的是腾讯云海外轻量应用服务器,年付价格大约 99 元,适合作为个人博客入门配置。
服务器配置建议如下:
这里建议系统镜像选择 Ubuntu。Ubuntu 的资料比较多,Docker、Nginx、Halo 等相关问题也更容易搜索到解决方案。

如果你不知道近期有哪些便宜服务器套餐,也可以关注一些专门分享云服务器优惠信息的 B 站 UP 主,他们会定期整理腾讯云、阿里云、百度云等平台的活动。

3.2 购买域名
如果说服务器是博客的“房子”,那么域名就是这套房子的“门牌号”。
用户最终访问博客时,通常不会直接输入服务器 IP,而是输入类似下面这样的域名:
www.example.top
example.top
腾讯云、阿里云、百度云等平台都可以购买域名。如果只是个人博客入门,.top、.site、.xyz 这类后缀价格较低,也可以使用。
我这里使用的是百度云购买的 .top 域名,首年价格大约 15 元,比较适合作为个人博客入门域名。
购买域名时建议注意:
域名尽量简短,方便记忆;
尽量避免复杂拼音或数字组合;
如果只是个人博客,便宜后缀也够用;
如果想长期经营个人品牌,可以优先考虑
.com。

3.3 配置域名解析
购买域名之后,域名本身还不能直接访问你的服务器。你需要将域名解析到服务器的公网 IP。
简单理解就是:
用户访问 www.example.top
↓
DNS 解析到服务器公网 IP
↓
请求到达云服务器
↓
Nginx Proxy Manager 转发到 Halo
↓
返回博客页面
建议至少添加两条 A 记录:
这两条解析的作用分别是:
www.example.top → 服务器公网 IP
example.top → 服务器公网 IP
这样用户无论输入带 www 的域名,还是不带 www 的域名,都可以访问到你的博客。
3.4 在百度云配置域名解析
如果你的域名是在百度云购买的,可以在百度智能云控制台中配置解析。
3.4.1 进入域名服务
在百度智能云控制台中搜索并进入 域名服务。

3.4.2 找到域名管理
进入域名服务后,在左侧选择 域名管理,然后在右侧找到你购买的域名,点击 解析。

3.4.3 添加 www 解析记录
点击 添加解析,填写第一条记录:
这条记录的作用是:让用户访问 www.example.top 时,可以进入你的服务器。

3.4.4 添加 @ 解析记录
继续添加第二条记录:
这条记录的作用是:让用户访问 example.top 时,也可以进入你的服务器。

最终建议至少添加两条解析:
www.example.top → 服务器公网 IP
example.top → 服务器公网 IP
3.5 腾讯云服务器侧配置域名
如果你使用的是腾讯云轻量应用服务器,也可以在腾讯云控制台中把域名添加到对应服务器实例中,方便后续统一管理。
3.5.1 进入轻量应用服务器控制台
登录腾讯云控制台,点击左上角菜单,搜索或选择 轻量应用服务器。

3.5.2 添加域名解析
进入服务器实例后,选择:
域名解析 → 添加域名解析
在弹窗中输入你刚刚购买的域名,例如:
example.top
系统通常会自动生成两条主机记录:
www.example.top
example.top
确认无误后点击确定。

需要注意:真正决定域名能不能访问服务器的是 DNS 解析是否生效。如果你的域名不是在腾讯云购买的,仍然要以域名购买平台的解析配置为准。
3.6 配置服务器防火墙端口
博客部署过程中至少需要开放以下端口:
其中:
80和443是网站访问必须使用的端口;81是 Nginx Proxy Manager 的管理后台端口;22是远程连接服务器的 SSH 端口。

四、服务器部署阶段
4.1 安装 Docker
本文使用 Docker Compose 管理 Halo、PostgreSQL 和 Nginx Proxy Manager。
先检查 Docker 是否已经安装:
docker -v
docker compose version
如果没有安装,可以执行:
curl -fsSL https://get.docker.com | sudo bash
sudo systemctl enable docker
sudo systemctl start docker
为了后续使用 Docker 命令更方便,可以将当前用户加入 Docker 用户组:
sudo usermod -aG docker $USER
这个命令不会立刻对当前 SSH 会话生效。你可以重新登录服务器,或者后续命令先使用 sudo docker。
如果执行:
docker ps
出现类似下面的错误:
permission denied while trying to connect to the docker API
可以先使用:
sudo docker ps
4.2 创建 Docker 网络
Nginx Proxy Manager 和 Halo 需要在同一个 Docker 网络中通信,因此先创建一个公共网络:
sudo docker network create npm
如果提示网络已经存在,可以忽略。
这个 npm 网络后面会同时挂载到:
Nginx Proxy Manager 容器
Halo 容器
这样 Nginx Proxy Manager 才能通过容器名 halo 访问 Halo 服务。
4.3 部署 Nginx Proxy Manager
Nginx Proxy Manager 用来管理反向代理和 HTTPS 证书。
先创建目录:
mkdir -p ~/npm
cd ~/npm
vim docker-compose.yml
写入以下内容:
services:
npm:
image: 'jc21/nginx-proxy-manager:latest'
container_name: npm
restart: unless-stopped
ports:
- '80:80'
- '443:443'
- '81:81'
volumes:
- ./data:/data
- ./letsencrypt:/etc/letsencrypt
networks:
- npm
networks:
npm:
external: true
启动 Nginx Proxy Manager:
sudo docker compose up -d
检查容器状态:
sudo docker ps
如果正常,会看到类似:
jc21/nginx-proxy-manager:latest Up 0.0.0.0:80-81->80-81/tcp, 0.0.0.0:443->443/tcp npm
检查端口:
sudo ss -lntp | grep -E ':80|:443|:81'
如果看到 docker-proxy 占用了 80、443、81,说明 Nginx Proxy Manager 已经正常接管端口。
浏览器访问:
http://服务器公网IP:81
第一次进入会要求创建管理员账号:
Full Name:自定义
Email address:自己的邮箱
New Password:自定义强密码

注意:这个账号是 Nginx Proxy Manager 的管理员账号,用来管理反向代理和 SSL 证书,不是 Halo 博客后台账号。
4.4 部署 PostgreSQL 数据库
Halo 需要数据库来持久化保存站点配置、用户信息、文章内容和主题配置。
本文不使用宝塔面板安装 PostgreSQL,也不在宿主机上手动安装数据库,而是通过 Docker Compose 启动一个独立的 PostgreSQL 容器。
这样做有几个好处:
数据库环境独立,不污染宿主机;
部署和迁移更方便;
数据目录清晰,便于备份;
Halo 和 PostgreSQL 可以通过 Docker 内部网络通信;
PostgreSQL 不需要暴露公网端口,安全性更高。
在后面的 docker-compose.yml 中,PostgreSQL 服务由下面这一段定义:
halodb:
image: postgres:15.4
container_name: halodb
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=你的数据库强密码
- POSTGRES_USER=halo
- POSTGRES_DB=halo
- PGUSER=halo
其中几个关键配置如下:
第一次执行:
sudo docker compose up -d
PostgreSQL 容器会自动完成以下初始化工作:
拉取
postgres:15.4镜像;创建
halodb容器;初始化数据库数据目录;
创建
halo用户;创建
halo数据库;设置数据库密码;
将数据库数据持久化保存到
~/halo/db。
因此,这里不需要进入宝塔面板创建数据库,也不需要手动执行 SQL 创建数据库。
4.5 部署 Halo 并连接 PostgreSQL
创建 Halo 目录:
mkdir -p ~/halo
cd ~/halo
vim docker-compose.yml
写入完整配置。
需要修改两个地方:
数据库强密码;
--halo.external-url=https://www.your-domain.com/。
完整配置如下:
services:
halo:
image: registry.fit2cloud.com/halo/halo:2.24
container_name: halo
restart: on-failure:3
depends_on:
halodb:
condition: service_healthy
networks:
- halo_network
- npm
volumes:
- ./halo2:/root/.halo2
expose:
- "8090"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8090/actuator/health/readiness"]
interval: 30s
timeout: 5s
retries: 5
start_period: 30s
environment:
- JVM_OPTS=-Xmx256m -Xms256m
command:
- --spring.r2dbc.url=r2dbc:pool:postgresql://halodb/halo
- --spring.r2dbc.username=halo
- --spring.r2dbc.password=你的数据库强密码
- --spring.sql.init.platform=postgresql
- --halo.external-url=https://www.your-domain.com/
halodb:
image: postgres:15.4
container_name: halodb
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=你的数据库强密码
- POSTGRES_USER=halo
- POSTGRES_DB=halo
- PGUSER=halo
networks:
halo_network:
npm:
external: true
其中,Halo 连接 PostgreSQL 的关键配置是:
command:
- --spring.r2dbc.url=r2dbc:pool:postgresql://halodb/halo
- --spring.r2dbc.username=halo
- --spring.r2dbc.password=你的数据库强密码
- --spring.sql.init.platform=postgresql
含义如下:
这里有一个非常关键的点:
spring.r2dbc.password 和 POSTGRES_PASSWORD 必须完全一致。
否则 Halo 会因为数据库认证失败而无法启动。
4.6 启动 Halo 和 PostgreSQL
在 ~/halo 目录下执行:
sudo docker compose up -d
这个命令会同时启动两个容器:
查看容器状态:
sudo docker ps
正常情况下应该看到:
halo Up healthy 8090/tcp
halodb Up healthy 5432/tcp
npm Up 80/81/443
其中:
halodb healthy
说明 PostgreSQL 数据库已经启动成功。
halo healthy
说明 Halo 已经成功连接数据库,并且应用本身启动正常。
4.7 验证 PostgreSQL 是否初始化成功
可以通过下面命令进入 PostgreSQL 容器:
sudo docker exec -it halodb psql -U halo -d halo
进入后,如果看到类似:
halo=#
说明已经成功连接到 halo 数据库。
可以执行:
\l
查看数据库列表。
也可以执行:
\dt
查看当前数据库中的表。
如果 Halo 已经启动过,数据库中会出现 Halo 自动创建的数据表。
退出 PostgreSQL:
\q
如果能成功进入 psql,说明以下内容都已经正常:
PostgreSQL 容器启动成功;
halo用户创建成功;halo数据库创建成功;数据库密码配置正确;
数据库数据目录已经持久化到
~/halo/db。
需要注意的是,PostgreSQL 的 5432 端口没有映射到公网。
在本架构中,Halo 和 PostgreSQL 通过 Docker 内部网络 halo_network 通信,外部用户无法直接访问数据库。这比将数据库端口暴露到公网更安全。
4.8 检查 Halo 是否启动成功
通过健康检查接口确认:
sudo docker exec -it halo curl -s http://localhost:8090/actuator/health/readiness
正常返回:
{"status":"UP"}
这说明 Halo 本身已经正常运行。
如果返回异常,可以查看 Halo 日志:
sudo docker logs -f halo
如果是数据库连接失败,重点检查:
POSTGRES_PASSWORD和spring.r2dbc.password是否一致;halodb容器是否 healthy;Halo 和 PostgreSQL 是否在同一个
halo_network网络中;spring.r2dbc.url中的主机名是否写成了halodb。
4.9 在 Nginx Proxy Manager 中添加反向代理
现在 Halo 已经在 Docker 内部运行,但外部用户还不能直接通过域名访问。
接下来需要在 Nginx Proxy Manager 中添加反向代理,将域名请求转发到 Halo 容器。
浏览器访问:
http://服务器公网IP:81
进入 Nginx Proxy Manager 后,选择:
Hosts → Proxy Hosts → Add Proxy Host
填写代理信息。
Details 配置
这里最关键的是:
Forward Hostname / IP = halo
Forward Port = 8090
因为 Nginx Proxy Manager 和 Halo 在同一个 Docker 网络 npm 中,所以 Nginx Proxy Manager 可以直接通过容器名 halo 访问 Halo 服务。
如果你还想让不带 www 的域名也能访问,也可以在 Domain Names 中同时填写:
your-domain.com
www.your-domain.com
4.10 访问 Halo 初始化页面
配置完成后,浏览器访问:
https://www.your-domain.com
正常情况下会进入 Halo 初始化页面。
后台地址为:
https://www.your-domain.com/console
第一次进入 Halo,需要创建 Halo 管理员账号。
注意区分:
这两个账号不是同一个。
五、总结
以上是一套适合个人的技术博客部署方案:
Halo + PostgreSQL + Nginx Proxy Manager + HTTPS
最终访问链路如下:
用户访问域名
↓
Nginx Proxy Manager 处理 HTTPS
↓
转发到 Halo 容器 8090
↓
Halo 读写 PostgreSQL
这套架构的核心思想是:每个组件只负责自己最擅长的事情。
Docker Compose 负责服务编排
Nginx Proxy Manager 负责反向代理和 HTTPS
Halo 负责博客内容管理
PostgreSQL 负责数据持久化
本文中的 PostgreSQL 是作为 Docker Compose 中的一个独立服务运行。
Halo 容器启动时,通过 Docker 内部服务名 halodb 访问 PostgreSQL,因此数据库不需要暴露公网端口。
这种部署方式结构清晰、迁移方便、排错简单,也更适合作为个人技术博客的长期维护方案。