7 min read

本地虚拟机搭建 Ghost 博客系统

本地虚拟机搭建 Ghost 博客系统
Photo by Marvin Meyer / Unsplash

准备工作

安装虚拟机

我这里是 macos 的系统。用的是 OrbStack
它是一款 mac 独占的容器和虚拟机的运行环境,目前是可以免费使用的。

安装命令:

brew install orbstack

Orbstack 的图形界面做的非常直观易懂。大家稍微研究一下就能上手了。

我这里就直接用命令行来创建我们所需的虚拟机环境。

orb create ubuntu:jammy ubt2204

设置刚搭建好虚拟机为默认虚拟机,这样只要输入 orb 就可以直接登录了。

orb default ubt2204
orb

orb 的其它常用命令

# 列出所有的虚拟机
orb list

# 重启虚拟机
orb restart <vm-name>

# 停止虚拟机
orb stop <vm-name>
# 开启虚拟机
orb start <vm-name>

安装 docker 和 docker compose

运行下面的命令。
注意: 如果下载安装速度慢,先修改下面代码的注释,用国内的源下载安装。

# 获取最新版本的 Docker Compose
COMPOSE_VERSION=$(curl -s https://api.github.com/repos/docker/compose/releases/latest | grep 'tag_name' | cut -d '"' -f 4)

# 安装 Docker
sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates curl software-properties-common


# 直接去官方下载。如果速度太慢,则注释掉下面这两句,并取消国内源那两句代码的注释
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/$(echo $OS | awk '{print tolower($1)}') $(lsb_release -cs) stable" | sudo tee 

# 使用国内的源加快下载速度
# curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
# echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://mirrors.aliyun.com/docker-ce/linux/$(echo $OS | awk '{print tolower($1)}') $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null


/etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io
sudo systemctl start docker
sudo systemctl enable docker
sudo usermod -aG docker $USER

# 安装 Docker Compose
sudo curl -L "https://github.com/docker/compose/releases/download/${COMPOSE_VERSION}/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose

# 应用组更改
newgrp docker

# 验证安装
echo "Docker version:"
sudo docker --version
echo "Docker Compose version:"
docker-compose --version

正式开始部署

创建目录结构

首先在 VPS 上创建所需的目录。这些目录将用于存放 Ghost 数据、Nginx 配置和 MySQL 数据库文件。

mkdir -p ~/blog/ghost/content
mkdir -p ~/blog/nginx/conf.d
mkdir -p ~/blog/db/ghost_data_mysql
mkdir -p ~/certs
mkdir -p ~/blog/scripts
mkdir -p ~/.acme.sh

获取所需信息

获取下面的信息填入下面的变量栏中:

  • 获取域名(如果有域名的话),这里没有就填 localhost
  • GMAIL_ACCOUNT,你的 gmail 邮箱,和 Gmail 的 App 的密码,从该链接获取:Create and manage your app passwords

    可以将邮箱名和密码,结合下面复制的环境变量的模版,记录下来。

  • 随机生成两组密码,作为 Mysql 中的密码

生成随机密码的命令

# 获取随机数最为密码
# head -c 20 是生成20位的密码,可根据安全性自行改变
openssl rand -base64 24 | tr -dc 'A-Za-z0-9@#$%&*+=' | head -c 20; echo

需要获取的 环境变量 模版

# 域名设置
DOMAIN_NAME=""

# MySQL 数据库的 root 用户密码
MYSQL_ROOT_PASSWORD=""

# MySQL 数据库的普通用户密码
MYSQL_PASSWORD=""

# 邮箱服务器设置
GMAIL_ACCOUNT=""
GMAIL_APP_PASSWORD=""

直接利用下面的数据

创建存放环境变量的文件:

touch ~/blog/.env
vi ~/blog/.env

将下面的变量复制粘贴到文件中,并修改最后两项。

# 域名设置
DOMAIN_NAME="localhost"

# MySQL 数据库的 root 用户密码
MYSQL_ROOT_PASSWORD="Gf2FFID62aZNWH1zRbn0"

# MySQL 数据库的普通用户密码
MYSQL_PASSWORD="b5uCiGOD8kG8DXy5Ouqw"

# 邮箱服务器设置
GMAIL_ACCOUNT="[email protected]"
GMAIL_APP_PASSWORD="your_gmail_app_password"

准备配置文件和模版文件

Nginx的配置文件

创建 Nginx 配置文件 ~/blog/nginx/conf.d/default.conf,确保配置正确的反向代理设置。

touch ~/blog/nginx/conf.d/default.conf
vi ~/blog/nginx/conf.d/default.conf

本地环境使用的 nginx配置:

server {
    listen 8080;
    server_name localhost;

    location / {
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # 确保这里的地址和端口对应 Ghost 运行的实际地址和端口
        proxy_pass http://localhost:2368;  
    }
}

Ghost 的配置文件

这里是一个容易出现问题的地方

你需要使用邮件发送服务器才能邀请用户。ghost 自带的 mailgun 是需要收费的。
我们需要在配置文件中,将该服务改成 Gmail 邮件收发服务器。

创建 ghost 配置文件的模版文件

touch ~/blog/ghost/config.production.json.template
vi ~/blog/config.production.json.template

将下面的内容粘贴至 config.production.json.template 的配置文件内容:

{
    "url": "http://${DOMAIN_NAME}",
    "server": {
        "port": 2368,
        "host": "0.0.0.0"
    },
    "database": {
        "client": "mysql",
        "connection": {
            "host": "ghost-mysql",
            "port": 3306,
            "user": "ghost",
            "password": "${MYSQL_PASSWORD}",
            "database": "ghost"
        }
    },
    "mail": {
        "from": "'Custom Name' <${GMAIL_ACCOUNT}>", 
        "transport": "SMTP",
        "logger": true,
        "options": {
	        "service": "Gmail",
            "host": "smtp.gmail.com",
            "secureConnection": true,
            "auth": {
                "user": "${GMAIL_ACCOUNT}",
                "pass": "${GMAIL_APP_PASSWORD}"
            }
        }
    },
    "logging": {
        "transports": [
            "file",
            "stdout"
        ]
    },
    "process": "systemd",
    "paths": {
        "contentPath": "/var/lib/ghost/content"
    }
}

Docker Compose 的配置文件

创建 Docker Compose 文件:

touch ~/blog/docker-compose.yml
vi ~/blog/docker-compose.yml

将下面的内容复制粘贴进去:

services:
  ghost-mysql:
    image: mysql:5.7  # Recommended MySQL version for compatibility
    container_name: ghost-mysql
    volumes:
      - ~/blog/db/ghost_data_mysql:/var/lib/mysql:z
      # - ~/blog/db/mysql/config:/etc/mysql/conf.d/**
    expose:
      - "3306"
    environment:
      MYSQL_ROOT_PASSWORD: "${MYSQL_ROOT_PASSWORD}"
      MYSQL_DATABASE: ghost
      MYSQL_USER: ghost
      MYSQL_PASSWORD: "${MYSQL_PASSWORD}"
    restart: always 
    networks:
      - ghost-network

  ghost:
    container_name: ghost
    image: ghost:5.79.4  # Use the latest Ghost image
    ports:
      - "2368:2368"
    volumes:
      - ~/blog/ghost/content:/var/lib/ghost/content:z # 持久化内容
      - ~/blog/ghost/config.production.json:/var/lib/ghost/config.production.json:z # Overwrite default settings
    environment:
      NODE_ENV: production # set production or development
      url: http://localhost:2386  # 如果有域名则为: https://${DOMAIN_NAME}
    expose:
      - "3306"
    restart: always # 设置 Ghost 服务的重启策略为 always
    depends_on:
      - ghost-mysql
    networks:
      - ghost-network

  nginx:
    container_name: nginx
    image: nginx:latest
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ~/blog/nginx/conf.d/:/etc/nginx/conf.d/
    restart: always 
    depends_on:
      - ghost
    networks:
      - ghost-network

networks:
  ghost-network:
    name: ghost-network
    driver: bridge
    

将我们的变量的注入配置文件中

注入环境变量的脚本文件

该脚本用来将模版文件中通用的变量名,替换成我们的自己的环境变量。

touch ~/blog/init.sh
vi ~/blog/init.sh

将下面的内容复制粘贴到脚本中:

#!/bin/bash

# 加载环境变量
source .env

# 导出环境变量,envsubst 会用到这些
export DOMAIN_NAME
export MYSQL_PASSWORD
export GMAIL_ACCOUNT
export GMAIL_APP_PASSWORD

# 替换 config.production.json 文件中的变量
envsubst '${DOMAIN_NAME}, ${MYSQL_PASSWORD}, ${GMAIL_ACCOUNT}, ${GMAIL_APP_PASSWORD}' < ~/blog/config.production.json.template > ~/blog/ghost/config.production.json

赋予执行权限

chmod +x ~/blog/init.sh

注入和检查

安装 envsubst 的包

sudo apt install cron gettext -y

运行注入脚本

cd ~/blog
./init.sh

检查注入是否成功。即文件中的这些变量 ${MYSQL_PASSWORD}, ${GMAIL_ACCOUNT}, ${GMAIL_APP_PASSWORD} 有没有被正确的变量取代。

cat ~/blog/ghost/config.production.json

运行和排错

使用 docke compose 的命令

运行所有应用

~/blog 目录下,用 Docker Compose 拉起所有的容器。

cd ~/blog
docker-compose up -d

如果没有问题,这时候你可以访问:
http://localhost:8080
就可以访问到你的博客啦。

关闭应用和重新运行

发现问题时,可以移除所有容器。再重新运行(👆继续上面那一步)

cd ~/blog
docker-compose down

查看和追踪问题日志

可能大部分问题自己都解决不了,但下面几条命令还是必须得会的。
因为你在寻求帮助的时候,还是需要把错误提示和日志复制粘贴给别人看的。

# 查看容器运行情况
docker compose ps

# 查看容器运行日志
docker compose logs <docker-name>

# 查看容器的所有信息
docker inspect <docker-name>