这是我搭建和改造这个博客所需要的东西以及遇到的问题和解决方法

Docker

docker-compose.yml

version: '3.1'

services:

  ghost:
    image: ghost:latest
    restart: always
    ports:
      - 2368:2368
    environment:
      # see https://ghost.org/docs/config/#configuration-options
      database__client: mysql
      database__connection__host: db
      database__connection__user: root
      database__connection__password: password
      database__connection__database: ghost
      url: "http://43.143.34.190:2368"
      
      mail__transport: "SMTP"
      mail__options__host: "smtp.qq.com"
      mail__options__port: 465
      mail__options__secureConnection: true
      mail__options__auth__user: "your_qq_number@qq.com"
      mail__options__auth__pass: "manbohajimimanbo"
      mail__from: '"Tike Map" <your_qq_number@qq.com>' 
      security__deviceVerification__enabled: "false"
      
    volumes:
      - ghost:/var/lib/ghost/content

  db:
    image: mysql:8.0
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: password
    volumes:
      - db:/var/lib/mysql
      - /etc/localtime:/etc/localtime:ro  
      - /etc/timezone:/etc/timezone:ro

volumes:
  ghost:
  db:

Https-Nginx docker-compose.yml

version: "3.8"

services:
  nginx:
    image: nginx:alpine
    container_name: ghost-nginx
    restart: always
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./conf.d:/etc/nginx/conf.d:ro
      - ./certs:/etc/nginx/certs:ro
    networks:
      - ghostnet

networks:
  ghostnet:
    external: true
    name: docker_default

Code inject 以及 Design & branding

settings->Code injection

Site header

<!-- Prism.js 代码高亮主题 -->
<link
  rel="stylesheet"
  href="https://unpkg.com/prismjs@1.29.0/themes/prism-tomorrow.min.css"
/>

<!-- 行号插件样式 -->
<link
  rel="stylesheet"
  href="https://unpkg.com/prismjs@1.29.0/plugins/line-numbers/prism-line-numbers.css"
/>

<style>
  /* ===== 基础代码块样式 ===== */
  pre[class*="language-"],
  code[class*="language-"] {
    border-radius: 8px;
    font-size: 1.4rem;
  }

  /* 行号整体向右留空间 */
  pre.line-numbers {
    padding-left: 3.2em;
  }

  /* Ghost 原生 code card 外边距 */
  .kg-card.kg-code-card {
    margin: 1.2rem 0;
  }

  /* ===== 滚动条:默认隐藏,悬停显示 ===== */
  pre[class*="language-"] {
    overflow: auto;

    /* Firefox / 旧 Edge */
    scrollbar-width: none;
    -ms-overflow-style: none;
  }

  /* Chrome / Safari */
  pre[class*="language-"]::-webkit-scrollbar {
    height: 0;
    width: 0;
  }

  /* 悬停时显示滚动条 */
  pre[class*="language-"]:hover {
    scrollbar-width: thin;
  }

  pre[class*="language-"]:hover::-webkit-scrollbar {
    height: 10px;
    width: 10px;
  }

  pre[class*="language-"]:hover::-webkit-scrollbar-thumb {
    border-radius: 999px;
  }
</style>

Site footer

<!-- Prism 核心库 -->
<script src="https://unpkg.com/prismjs@1.29.0/components/prism-core.min.js"></script>

<script src="https://unpkg.com/prismjs@1.29.0/components/prism-markup.min.js"></script>
<script src="https://unpkg.com/prismjs@1.29.0/components/prism-css.min.js"></script>
<script src="https://unpkg.com/prismjs@1.29.0/components/prism-clike.min.js"></script>
<script src="https://unpkg.com/prismjs@1.29.0/components/prism-javascript.min.js"></script>
<script src="https://unpkg.com/prismjs@1.29.0/components/prism-json.min.js"></script>
<script src="https://unpkg.com/prismjs@1.29.0/components/prism-python.min.js"></script>
<script src="https://unpkg.com/prismjs@1.29.0/components/prism-bash.min.js"></script>

<!-- 行号插件 -->
<script src="https://unpkg.com/prismjs@1.29.0/plugins/line-numbers/prism-line-numbers.min.js"></script>

<script>
  document.addEventListener("DOMContentLoaded", function () {
    const codeBlocks = document.querySelectorAll("pre > code");

    codeBlocks.forEach((code) => {
      const pre = code.parentElement;

      const langClass = Array.from(code.classList).find(c =>
        c.startsWith("language-")
      );
      if (langClass && !pre.classList.contains(langClass)) {
        pre.classList.add(langClass);
      }

      if (!pre.classList.contains("line-numbers")) {
        pre.classList.add("line-numbers");
      }
    });

    if (window.Prism && Prism.highlightAll) {
      Prism.highlightAll();
    }
  });
</script>

PS:这里的代码高亮是需要将代码块的language设置为js或者对应的语言才能够实现

Settings->Design & branding

Customize

注意一定要先Brand设置好颜色后再在Theme里面选择Accent color,然后再选Site background color

看板娘miku

通过https://github.com/Dreamer-Paul/Pio?tab=readme-ov-file 实现的,不过需要让Ai给你魔改一下,将相应的js、css主动嵌入到你的theme源码里面

在Setting->Theme->Change theme里面将当前的主题源码下载下来然后改

miku模型则是在https://mx.paul.ren/里面下载的

想要完整的theme源码就从网站里面通过蛛丝马迹把我的联系方式找出来,然后给我发个邮箱我把源码给你发过去

issue-设备验证

新版本默认开启设备认证,也就是当你的admin账号再次登录后(包括之前登过的设备),需要通过发邮箱验证码进行认证.通常来说只要你登录过一次,这个session会保留很久,不过当你偶然删除session后,再次登录就会触发这个东西,如果你没有配置你的SMTP服务那么就会一直卡死~~

照理来说这个问题在dockerfile里面设置一个变量即可,就是

security__deviceVerification__enabled: "false"

不过好像不行,所以说只能搞一个SMTP服务

开启SMTP服务-QQ

登录wx.mail.qq.com,右上角有一个设置,进去后点击左边的安全设置,下滑找到SMTP服务

可能第一次需要开启什么的,然后选择生成授权码即可

随即在docker-compose.yml里面的environment添加

      mail__transport: "SMTP"
      mail__options__host: "smtp.qq.com"
      mail__options__port: 465
      mail__options__secureConnection: true
      mail__options__auth__user: "your_qq_number@qq.com"
      mail__options__auth__pass: "manbohajimimanbo"

里面的mail__options__auth__pass是填生成的16位授权码,只会出现一次,注意留存

issue-EENVELOPE

这个错误是由于NodeMailer在检查邮件 envelope(发件人 / 收件人地址格式)抛出的错误

由于没有设置mail__fromGhost 会默认使用ghost@url域名来作为邮箱地址,不过此时我这里还是ip,所以说邮箱ghost@43.143.34.190不合法就会报错,这里需要我们设置一下

mail__from: '"博客名" <your_qq_number@qq.com>'

此时,这个问题才最终解决,当再次登录的时候

会收到类似如下的邮箱

域名备案

由于俺图便宜搞了个国内的服务器,在腾讯云上图便宜买了个域名tike00.chat,所以说需要ICP备案,怎么备案的跟着腾讯云的教程走就是了,注意事项可能就是填信息的时候,紧急联系人的电话不能跟自己的电话一样,然后通讯地址必须精确到多少号什么的(几楼几单元)

信息填完后会让你等,会有客服给你打电话确认信息,注意通话畅通吧,一上来先问你的身份证后六位还有邮箱确认身份,确认完一些信息后就让你等政府部门审批,先是短信确认让你访问一个网址输入什么手机验证码什么的,后面让你等审批,我这个是等了两周吧

貌似ICP备案后还有公安联网备案,这个还没搞......(有点麻烦~

Nginx反代+Https

当时为了搞https 在腾讯云上面申请了一个证书,具体申请流程参考腾讯云给的教程(其实是我忘了,也不好复现)

这里主要说一下这个ssl证书申请下来后该怎么用,通常里面会有四个后缀的文件,分别是pem、csr、key、crt,其中csr是申请的时候用的,使用的时候用不到,pem跟crt的内容是一样的,其实是 你的站点证书+中间 CA 证书合成的证书链,key就是私钥

此时需要一个nginx的docker-compose.yml 已经放在最上面了,然后这个yml目录下放置一个conf.d文件夹和certs文件夹,conf.d里面放ghost.conf作为nginx的配置文件,certs里面放私钥和证书crt或者pem都行

ghost.conf

# 80:全部跳转到 https
server {
    listen 80;
    server_name tike00.chat www.tike00.chat;

    return 301 https://$host$request_uri;
}

# 443:SSL + 反代到 Ghost
server {
    listen 443 ssl http2;
    server_name tike00.chat www.tike00.chat;

    # 证书文件(挂载在 /etc/nginx/certs 下)
    ssl_certificate     /etc/nginx/certs/fullchain.pem;
    ssl_certificate_key /etc/nginx/certs/tike00.chat.key;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;
    client_max_body_size 50m;

    location / {
        # 注意这里的名字:docker-ghost-1,对应你当前ghost容器名(docker ps -a 看)
        proxy_pass http://docker-ghost-1:2368;

        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;
    }
}

里面关于

client_max_body_size 50m;

是这个nginx默认只能上传很小的文件,给他改大一点

搭建流程

主站-ghost

C+V 最上面的docker-compose.yml

需要根据需求改一下里面的一些值

port: 端口映射
database__connection__password: MySQL数据库连接密码
url: 自己的站的url,有域名就改成域名,有ssl证书就用https的
mail__options__auth__user: 自己的QQ邮箱
mail__options__auth__pass: 自己的SMTP授权码
mail__from: 自己随便设置的站名以及QQ邮箱
MYSQL_ROOT_PASSWORD: 创建数据库时的数据库密码,需要与上面的那个一致

执行

docker-compose up -d

由于这个数据实际上是挂载在宿主机里面的,所以说当你的docker爆炸的时候完全不用担心数据丢失。你的docker-compose.yml更新后需要重新配置到docker里面时,可以在你那个yml的目录下执行一下命令进行重启即可

docker-compose down
docker-compose up -d

反代-nginx

如果你恰好跟我的情况相同,有域名需要nginx来进行端口转发,同时还要弄https,那就按照上面的yml 并配置好两个目录conf.d和certs

注意把端口80和443两个server_name都改成自己的域名

执行

docker-compose up -d

最后想说的话

无论你觉得这个是好还是不好,反正我自己很喜欢,并且一直在努力按照自己想要的方向进行改造优化,现在AI这么发达,至少ChatGPT对于Ghost按照自己想要的一些东西进行优化还是没问题的,并不需要你有什么很厉害的开发能力.

我最先用Ghost主要就是觉得docker搭建起来方便,风格还算比较喜欢.后面感觉自己想要在这个博客上实现一些东西,然后就去认真做了,无论是AI还是求助别人,不能完全说是我自己的能力搞的,但是我做出来了,我很喜欢就行了.

如果你很喜欢,我也不建议你一比一完全复刻,大家都一样反而显得庸俗了,得找一下真正自己喜欢的风格或者方式对吧,这是自由的呀,算是对自己性格的一个张扬吧.

如果你不喜欢,比如说有些地方可以改进的,可以找一下我的联系方式 发发邮箱提提意见什么的,我觉得可以的话就会采纳然后感谢你,当然不可能全部都采纳,毕竟人与人之间可能喜好不尽相同.