返回文章列表

Halo博客+兰空图床搭建保姆级指南

分类
SilentBlade
SilentBlade
2026-07-30 10 分钟阅读 73 阅读

1. 简介

1.1 核心软件与依赖

  • Docker & Docker-Compose:容器化底层运行环境
  • Minio:自建对象存储服务,提供底层存储支持
  • MySQL:关系型数据库
  • Redis:高性能缓存中间件
  • Nginx Proxy Manager(以下简称 NPM):开源的 Nginx 反向代理可视化管理工具
  • Portainer:Docker 容器可视化管理面板
  • 兰空图床 (Lsky Pro):自建图片管理系统(若使用阿里云 OSS、七牛云 Kodo 等第三方 S3 存储可省略)
  • Cloudflare:DNS 解析与安全服务商
  • Halo:现代化开源博客系统

为什么选择自建图床,而非阿里云 OSS 或七牛云 Kodo 等第三方服务?

  1. 完全控制权:自主掌握数据存储、访问权限与安全策略,规避第三方服务商的政策变动或服务限制。
  2. 隐私与安全:核心及敏感图片资产本地化存储,防止第三方平台越权访问或泄露。
  3. 高度自定义:可按需定制图片压缩、动态水印、格式转换等个性化功能,灵活对接业务。
  4. 成本可控:在存储与流量规模可控的情况下,自建方案相比第三方的按量计费模式更具性价比。
  5. 免平台依赖:不绑定特定云厂商,降低因服务商故障或停服导致的中断风险。

1.2 端口规划

提示:本教程以主域名 itweek.top 为例,二级域名访问格式统一为:https://[子域名].itweek.top

软件 端口 二级域名前缀 / 子域名
Minio 9090 - API 端口
9091 - 控制台端口
m - 映射 API 端口
minio - 映射控制台端口
MySQL 3306
Redis 6379
NginxProxyManager 80 - HTTP 端口
443 - HTTPS 端口
81 - NPM 管理界面端口
npm
兰空图床 8089 - HTTP 端口
8088 - HTTPS 端口
lsky
Portainer 9000 - 容器管理端口 pt
Halo 8090 - 博客管理端口 blog

1.3 目录结构规范

我们将 /home/soft/docker 作为根目录,用于统一存放所有服务的部署配置文件。

目录结构

推荐使用 VS Code 的 Remote - SSH 插件连接至云服务器,便于高效地编辑配置文件与维护目录结构。

在开始部署前,建议按照上图所示的目录结构提前创建好相关的文件夹与配置文件。


2. 服务器与域名配置

服务器配置:建议配置不低于 2 核 2G 内存。安全组/防火墙需放行 80814433306 等常用端口。本文假定服务器公网 IP 为 118.60.60.118

域名解析:借助 DNS 泛解析NPM (Nginx Proxy Manager),我们能高效管理大量子域名,无需频繁手动配置 DNS 与反向代理规则,同时可实现 SSL 证书的自动化申请与管理。本文假定主域名为 itweek.top

下面以 Namesilo 域名注册与 Cloudflare DNS 解析为例,介绍如何配置泛解析,并为后续通过 NPM 申请 SSL 证书做好准备。

详细的操作指南请参考:Namesilo+Cloudflare申请域名及DNS解析指南

配置完成后,请务必保存好 Cloudflare 提供的 API 令牌 (API Token),后续配置 NPM 时需要用到。


3. 服务容器化部署配置

3.1 Minio

  • docker-compose.yml
yaml
version: '3'
services:
  minio:
    restart: unless-stopped
    image: minio/minio
    container_name: minio
    volumes:
      - ./config:/config
      - ./data:/data
    # 指定控制台的端口
    command: server /data  --console-address ":9001"
    environment:
      - 'MINIO_ROOT_USER=minio'
      - 'MINIO_ROOT_PASSWORD=minio'
    ports:
      # api端口
      - 9090:9000
      # 控制台端口,如果上述command不配置,默认为9090
      - 9091:9001

提示:请根据实际需求修改 MINIO_ROOT_PASSWORD(建议设置为强密码)。

3.2 Mysql

  • docker-compose.yml
yaml
version: '3'
services:
  mysql:
    restart: always
    image: mysql:5.7.35
    container_name: mysql
    volumes:
      - ./datadir:/var/lib/mysql:rw
      - ./my.cnf:/etc/mysql/my.cnf
    environment:
      - "MYSQL_ROOT_PASSWORD=root"
      - "TZ=Asia/Shanghai"
    ports:
      # 使用宿主机的3306端口映射到容器的3306端口
      - 3306:3306

注意:建议修改 MYSQL_ROOT_PASSWORD 默认密码。若在群晖(Synology DSM)环境下部署,挂载卷 ./datadir:/var/lib/mysql:rw 必须显式指定 rw(读写)权限,否则后续可能会遇到无法删除或写入数据库的问题。

  • my.cnf
ini
[mysqld]
user=mysql
default-storage-engine=INNODB
character-set-server=utf8
character-set-client-handshake=FALSE
init_connect='SET NAMES utf8'
max_connections=1000
[client]
default-character-set=utf8mb4
[mysql]
default-character-set=utf8mb4

3.3 Redis

  • docker-compose.yml
yaml
version: '3.3'
services:
  redis:
    image: redis:latest
    container_name: redis
    restart: always
    ports:
      - '6379:6379'
    volumes:
      - ./data:/data
      - ./redis.conf:/usr/local/etc/redis/redis.conf
      - ./logs:/logs
    #配置文件启动
    command: redis-server /usr/local/etc/redis/redis.conf
  • redis.conf
ini
# 开启保护
protected-mode no

# 绑定监听IP地址
bind 0.0.0.0

# 自定义密码
requirepass root

# 启动端口
port 6379

# redis 默认就开启 rdb 全量备份,以下是默认的备份触发机制
# 900s内至少一次写操作则执行bgsave进行RDB持久化
save 900 1
save 300 10
save 60 10000

# 是否压缩 rdb 备份文件,默认是压缩
# 如果 redis 承载的数据量非常大的话,建议不要压缩
# 因为压缩过程中需要耗费大量 cpu 和内存资源,磁盘相对而言比较廉价
rdbcompression yes

# rdb 备份的文件名
dbfilename dump.rdb

# Redis 备份文件存储目录,注意:该路径是 docker 容器内的路径
dir /data

# 是否开启 aof 增量备份功能,默认是否
appendonly yes
# AOF文件的名称,这里使用默认值
appendfilename appendonly.aof
# aof 增量备份的策略,这里是每秒钟一次,将累积的写命令持久化到硬盘中
appendfsync everysec

提示:请修改 requirepass 对应的默认密码。

3.4 NPM

  • docker-compose.yml
yaml
version: '3.8'
services:
  app:
    image: 'jc21/nginx-proxy-manager:latest'
    restart: unless-stopped
    ports:
      # These ports are in format <host-port>:<container-port>
      - '80:80' # Public HTTP Port
      - '443:443' # Public HTTPS Port
      - '81:81' # Admin Web Port
      # Add any other Stream port you want to expose
      # - '21:21' # FTP
    environment:
      # Mysql/Maria connection parameters:
      DB_MYSQL_HOST: "172.17.0.1"
      DB_MYSQL_PORT: 3306
      DB_MYSQL_USER: "root"
      DB_MYSQL_PASSWORD: "root"
      DB_MYSQL_NAME: "npm"
      # Uncomment this if IPv6 is not enabled on your host
      # DISABLE_IPV6: 'true'
    volumes:
      - ./data:/data
      - ./letsencrypt:/etc/letsencrypt

提示:请修改 DB_MYSQL_PASSWORDDB_MYSQL_NAME。在启动容器前,需在 MySQL 中手动创建 npm 数据库,容器启动时会自动初始化相关的表结构。

sql
create database npm default character set utf8mb4 collate utf8mb4_unicode_ci;

3.5 Portainer

提示:本服务为可选安装。主要用于可视化管理 Docker 容器、监控运行状态以及查看容器实时日志。

  • docker-compose.yml
yaml
version: "3"
services:
  portainer:
    image: portainer/portainer-ce:latest
    container_name: portainer
    restart: always
    ports:
      - "9000:9000"
    volumes:
      - ./data:/data
      - /var/run/docker.sock:/var/run/docker.sock

3.6 Lsky Pro

  • docker-compose.yml
yaml
version: '3'
services:
  lsky:
    image: halcyonazure/lsky-pro-docker:latest
    restart: unless-stopped
    hostname: lsky
    container_name: lsky
    environment:
      - WEB_PORT=8089
      - HTTPS_PORT=8088
    volumes:
      - ./web:/var/www/html/
      - /volume2/PUBLIC_PIC/uploads:/var/www/html/uploads
    ports:
      - "8089:8089"
      - "8088:8088"

提示:此处无需在 docker-compose.yml 中配置 MySQL 环境变量。首次访问图床时,可通过 Web 引导界面配置数据库连接信息。请提前在 MySQL 中创建好 lsky_pro 数据库。

sql
create database lsky_pro default character set utf8mb4 collate utf8mb4_unicode_ci;

4. Nginx Proxy Manager (NPM) 配置

4.1 初始化

访问后台管理页面 http://118.60.60.118:81,使用以下默认凭据进行登录:

ini
Email:    admin@example.com
Password: changeme

首次登录后,请按照系统提示立即修改默认邮箱与密码。

4.2 配置 SSL 证书

前提条件:确保已在 Cloudflare 中完成泛域名解析(指向当前服务器 IP),并已获取 Cloudflare API 令牌。

在 NPM 控制台依次点击 SSL Certificates -> Add SSL Certificate,选择 Let's Encrypt

配置SSL证书

按以下规范填写证书配置信息:

  • Domain Names : *.itweek.top

  • Email Address for Lets Encrypt : 填入域名提供商绑定的邮箱地址

  • DNS Provider : 选择 Cloudflare

  • Credentials File Content 按如下格式填写:

    properties
    # Cloudflare API token
    dns_cloudflare_email = mulyzhou@gmail.com
    dns_cloudflare_api_key = 1ef26**************da3deeef3ec
    
    • 确保 dns_cloudflare_emailEmail Address for Let's Encrypt 保持一致。
    • dns_cloudflare_api_key 替换为此前在 Cloudflare 申请的 API 令牌。

SSL信息

点击 Save,系统将自动向 Let's Encrypt 申请泛域名证书。申请成功后,证书列表会显示如下记录:

证书信息

4.3 配置反向代理 (Proxy Host)

依次点击 Dashboard -> Proxy Hosts -> Add Proxy Host

下面以 NPM 自身(二级域名:npm.itweek.top,容器内端口:81)为例进行配置:

添加二级域名

Details(基础配置) 页面填写示例如下:

添加二级域名完整信息

技术细节:此处填写的 172.17.0.1 是 Docker 默认桥接网络(bridge network)的网关 IP。通过该 IP,NPM 容器可以直接访问宿主机上暴露的其他服务端口。

SSL信息

SSL 配置页中,SSL Certificate 选择刚刚申请的 *.itweek.top,并勾选 Force SSL(强制 HTTPS)和 HTTP/2 Support。保存后,即可通过安全链接 https://npm.itweek.top 访问 NPM 管理后台。


5. Minio 对象存储配置

提示:本教程使用的是新版 Minio 控制台,界面布局与旧版本略有不同,请以实际操作界面为准。

5.1 配置反向代理域名

参照前文 NPM 配置流程,分别为 Minio 映射两个二级域名:

  1. 控制台域名https://minio.itweek.top(指向宿主机 9091 端口)
  2. API 访问域名https://m.itweek.top(指向宿主机 9090 端口)

配置完成后,即可通过统一的 https://m.itweek.top/存储桶名称/图片路径 路径直接公开访问图片。

Minio域名配置

5.2 配置区域与存储桶 (Bucket)

登录 https://minio.itweek.top,输入在 docker-compose.yml 中配置的管理员账号和密码。

创建地区

建议在系统设置中将 Region(地区)设置为 us-east-1

创建存储桶

创建存储桶

新建名为 image 的存储桶(Bucket),创建成功后进入该存储桶设置,将其 Access Policy(访问策略)修改为 Public

设置存储桶的权限

测试上传一张图片(如 WX20240426-164920@2x.png),配置无误后,即可通过公网链接 https://m.itweek.top/image/WX20240426-164920@2x.png 直接访问预览该图片。

测试上传图片

该图片在服务器上的物理存储路径如下。日常运维中,只需对该数据目录进行备份即可保障数据安全。若对高可用有需求,可进一步研究 Minio 容器化集群部署,本文暂不展开。

图片服务器的位置

5.3 创建 Access Key 与 Secret Key

创建密钥

创建密钥

生成并记录下 Access KeySecret Key,这两个密钥将在后续对接兰空图床时使用。


6. 兰空图床 (Lsky Pro) 深度配置

6.1 兰空图床简介

Lsky Pro 是一款高效、美观的开源图床程序,核心特性包括:

  1. 开源免费:基于 GitHub 开源,社区活跃。
  2. 多仓储驱动:原生支持本地、阿里云 OSS、腾讯云 COS、七牛云等多种第三方存储介质。
  3. 跨平台部署:轻量化设计,易于通过 Docker 进行跨平台容器化部署。
  4. 美观易用:采用现代化的 UI 设计,支持拖拽上传与图片管理。
  5. API 赋能:提供完备 API 接口,便于集成至各大博客、编辑器及第三方客户端。
  6. 多用户与流控:支持多用户角色、独立的容量限制与权限控制。
  7. 图片处理:内置剪裁、压缩、动态水印等基础图像处理引擎。

6.2 配置 NPM 反向代理与 HTTPS

在 NPM 中配置兰空图床的专属域名 https://lsky.itweek.top

image-20240716100319849

重要配置:为避免反向代理导致静态资源加载异常,需在 NPM 对应 Host 的 Custom locations 选项卡中添加自定义 Header 规则:proxy_set_header X-Forwarded-Host $http_host;

配置自定义header

同样在 SSL 标签页中选定对应的证书,勾选 Force SSLHTTP/2 Support,然后点击 Save 保存。

SSL配置

关于为何需要在此处添加自定义 Header 的技术细节,可参考官方仓库 Issue 讨论。该配置在初始化完成后,还需要配合下文对源码进行微调。

6.3 数据库与管理员初始化

使用浏览器访问 https://lsky.itweek.top,进入图床安装向导页面。

初始化

输入预先创建好的 MySQL 数据库名 lsky_pro。数据库连接地址填写 Docker 网关 IP 172.17.0.1,并输入 MySQL 的账号密码。配置好管理员邮箱和密码后,点击立即安装

配置数据库和管理员账号

6.4 关键源码修改(解决反向代理与 Minio 适配问题)

由于兰空图床部署在 Nginx 反向代理后方,且我们需要对接自建的 Minio 存储,需要对挂载在宿主机 lsky/web 目录下的源码进行以下几处调整:

  1. 配置 App URL:编辑 /config/app.php
    php
    'url' => env('APP_URL', 'https://lsky.itweek.top'),
    'asset_url' => env('ASSET_URL', 'https://lsky.itweek.top'),
    
  2. 强制 HTTPS 协议:编辑 /app/Providers/AppServiceProvider.php,在第 32 行下方追加一行代码:
    php
    \Illuminate\Support\Facades\URL::forceScheme('https');
    
  3. 适配 Minio 路径风格:编辑 /app/Services/ImageService.php,在第 356 行 'bucket_endpoint' => (bool)$configs->get(MinioOption::BucketEndpoint), 下方新增一行代码:
    php
    'use_path_style_endpoint' => true,
    
  4. 配置 Redis 缓存:修改根目录下的 .env 文件,启用高性能的 Redis 驱动:
    properties
    CACHE_DRIVER=redis
    REDIS_HOST=172.17.0.1
    REDIS_PASSWORD=null
    REDIS_PORT=6379
    

6.5 图床全局安全与权限配置

建议在兰空图床管理后台的 系统设置 -> 控制 中,进行如下安全合规配置:

  • 关闭注册功能(防止恶意注册)
  • 关闭公共画廊
  • 禁止游客上传图片
  • 调整用户默认容量:在 用户管理 -> 编辑用户 中,将最大总容量修改为 10485760(即 10GB 空间,计算公式:$1024 \times 1024 \times 10$)。

6.6 配置 Minio 存储策略

在管理后台中点击 存储策略 -> 新增存储策略

新增存储策略

  • 名称Minio
  • 存储策略:选择 Minio
  • AccessKey:Minio 的 Access Key
  • SecretKey:Minio 的 Secret Key
  • 连接地址http://172.17.0.1:9090(此处填写容器内网 Minio API 地址,实现高效的内部传输)
  • 区域us-east-1
  • 存储桶名称image

点击确认创建。若在前端无法成功将默认存储策略切换为 Minio(部分版本已知 Bug),可通过直接修改数据库来强制生效。

lsky_pro 数据库中,查询 strategies 表获取 Minio 策略的 id,以及 groups 表中 系统默认组id。随后在关联表 group_strategy 中插入对应关系。假设默认组 ID 为 1,Minio 存储策略 ID 为 2,执行以下 SQL 语句:

sql
INSERT INTO `lsky_pro`.`group_strategy` (`group_id`, `strategy_id`) VALUES (1, 2);

7. Halo 博客图床集成

  • 在 Halo 应用市场中搜索并下载 图床插件
  • 在插件管理页面启用该图床插件。
  • 点击插件详情,进入 基本设置

图床插件设置

其中,API 地址 填写兰空图床的对外访问路径 https://lsky.itweek.top/api/v1。那么,核心的 API Token 该如何获取?

登录兰空图床后台,在 接口 页面查看 Token 申请说明:

兰空图床API

兰空图床授权API

在终端或接口测试工具中执行以下 curl 请求以获取授权 Token:

sh
curl --location --request POST 'https://lsky.itweek.top/api/v1/tokens' \
--header 'User-Agent: Apifox/1.0.0 (https://apifox.com)' \
--header 'Content-Type: application/json' \
--header 'Accept: */*' \
--header 'Host: image.itweek.top' \
--header 'Connection: keep-alive' \
--data-raw '{
    "email":"mulyzhou@gmail.com",
    "password":"*******"
}'

提示:请将请求中的 https://lsky.itweek.topemailpassword 替换为您真实的图床域名及管理员登录凭据。

执行成功后,接口返回的 JSON 数据中,token 字段即为我们所需的授权令牌。

json
{
    "status": true,
    "message": "success",
    "data": {
        "token": "2|cCSkzG**********cgWoxhHXJ"
    }
}

将该 Token 复制并填入 Halo 的图床插件配置中。配置完成后,便可在 Halo 博客后台的 工具 -> 图床管理 中,无缝同步和管理兰空图床上的图片资源。

至此,基于 Halo 博客与自建兰空图床(Minio 驱动)的高效、私有化创作环境已全部搭建完毕。


8. 总结

本文详细梳理了自建现代化博客系统的全套流程,从底层的 Docker 容器化环境搭建,到多域名反向代理(NPM)与 SSL 安全证书的自动化配置,再到自建高可用对象存储(Minio)和美观易用的兰空图床(Lsky Pro)双剑合璧。通过这一整套私有化部署方案,您不仅能拥有对博客数据和图片资产的 100% 绝对控制权,还能彻底摆脱第三方云厂商的价格绑定和政策限制。希望本篇指南能为您的独立创作之路打下坚实的基础。

评论 1

使用 GitHub 身份参与讨论

可以先写评论,登录后草稿会自动恢复。

访
Ju Wang
Ju Wang

看来确实很不错