Normal view

There are new articles available, click to refresh the page.
Before yesterdayTricks & Tech

又一次重建 Hexo Blog

By: Battle Le
22 October 2025 at 00:00

昨天想更新 blog,没想到就是下午迁移出了问题,然后又是花了一个晚上排查问题。后来才发现好简单……所说是无用的调试,还是记录一下,免得以后又遇到。

掉进坑(无用调试)

执行 git pull origin main 后出错

1
2
3
4
5
6
luckye@Lucky-Mac-mini lucky-blog % git pull origin main

ERROR: Repository not found.
[fatal: Could not read from remote repository.

Please make sure you have the correct access rights and the repository exists.

提示远程仓库不存在,问了 ChatGPT 说是SSH 密钥的问题,生成公钥和私钥重新添加后也不起作用。

ls -al 后有 .git 文件,确认下命令行有没有走代理流量

1
curl -I www.google.com

返回正常,再看看能不能连接到 GitHub

1
ssh -T -p 443 git@ssh.github.com

输入 yes 也是正常。看看 git branch 在哪个分支上,是 main。

在 GitHub-Code-Local-SSH 直接复制项目名,执行

1
git remote set-url origin git@github.com:xxx/xxx.github.io.git

输入后没反应是正确的,接着

1
2
3
git pull
返回
fatal: couldn't find remote ref main

再确认分支有没有错

1
2
3
git branch -a
返回
* main

接着查看当前 Git 仓库的本地配置文件内容的命令

1
2
3
4
5
6
7
8
9
10
11
12
cat .git/config
返回
[core]
repositoryformatversion = 0
filemode = true
bare = false
[remote "origin"]
url = git@github.com:username/repo.git
fetch = +refs/heads/*:refs/remotes/origin/*
[branch "main"]
remote = origin
merge = refs/heads/main

接着查看当前 HEAD(最新提交)的一些详细信息

1
2
3
4
5
6
7
git show --summary
返回
commit 5d0ca94755d1dbe39f5be0983 (HEAD -> main, origin/main, origin/HEAD)
Author: xxx <xxxgmail.com>
Date
Fri Oct 17 23:47:06 2025 +0800
"update"

这些看着都没问题那就只好重新 clone 一下了。重新 push 创建了新的 main 分支

1
git push -u origin main

我把 Default 设置为 main,把 master 删除。重新 clone 一下 main 分支。更改默认分支后进行 clone。

移动再克隆

第一步直接 mv

1
mv ~/本地文稿/lucky-blog ~/本地文稿/lucky-blog-bak

bak 就是 backup 的缩写

第二步 git clone

1
git clone git@github.com:xxx/xxx.github.io.git ~/xxx-blog

重新安装 Hexo

1
ls /opt/homebrew

奇了怪了,Homebrew 也不生效,其实并不是没了,而是当前 PATH 没指向 /opt/homebrew/bin。干脆就全部安装下吧。要开启 Qutumult X 开启 SS 服务器功能,不然没有代理无法下载。安装 Homebrew

1
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

要执行下面三条命令才能安装

1
2
3
4
5
echo >> /Users/lucky/.zprofile

echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> /Users/lucky/.zprofile

eval "$(/opt/homebrew/bin/brew shellenv)"

clone 之后文件夹重命名,重新安装 Hexo

1
2
3
brew install node
brew install git
npm install -g hexo-cli

水落石出

就在我以为重装能成功之后结果还是不行,越弄越烂,最后还是麻烦余光帮我排查,在私人仓库添加一个 collaborator,他上去一看就发现问题所在。

仓库和 Cloudflare 所关联的根本不是同一个半年前我已经迁移到 Cloudfare,新建了一个 repo,全然忘记老的仓库不再使用,所以牛头不对马嘴😅

Clone 正确仓库

那接下来就简单了,重新备份(昨晚已经备份过,跳过),然后再 clone。类似于重启大法,对正确的这个仓库没有进行过操作,都不用安装 Homebrew,Hexo,所以异常的快速简单。

使用 GitHub 图形界面

改动了啥一目了然

这一次,终于抛弃那些繁琐的命令,本来就搞不懂。下载 GitHub 图形界面,登陆 GitHub 账号,然后设置 git config 关联的邮箱,因为 git 标准里要求必须有邮箱(和登录的 GitHub 账号没有关系),可以选择匿名邮箱账号,为了不出幺蛾子用自己邮箱登陆,选中仓库(别再选错),一键 Clone,选择保存路径。

然后只有两步,Commit to main 然后 Push origin,搞定。想看本地渲染的还是

1
2
cd ~/blog 
hexo s

如果提示没有项目依赖就装一个,都不用全局安装

1
npm install

在老的 MacBook Pro 上也同样部署了,比以前方便太多,另一台下次更改前先 Push origin (⌘ + P) 一下就好。

大功告成!感谢余光,FriendsA 帮我排查了这么久时间🙏

疑难点

之前排查的过程中,老 repo 的线上分支 Default 是 master,但是也有 main,以为是项目的 mastermain 不同导致的错误。(这两个其实只是名字区别,只是最近主流都用 main 了)

  • branch 指的是 Hexo push 的远程分支

  • 如果 Git 仓库默认分支是 main,_config.yml 必须写 main,否则 Hexo 会往 master 推送(即使你的本地 default 是 main)

  • 只修改 _config.yml 并没有提交,这个修改是本地未保存的 Git 改动。Hexo 会用最新的文件夹去 push,但 Git 依旧会检测到本地未提交改动

  • 因此,如果想 Hexo push 到 main,最好先把 _config.yml 的修改提交或保存,避免被 Git 阻止。

在 _config.yml 中修改

deploy:
type: ‘git’
repo: git@github.com:luckylele666/luckylele666.github.io.git
branch: master

master 修改为 main

如果是在本地部署可以这样设置,但是我现在的构建方式不是这样了。

原理

传统 Hexo 部署

以前常用的流程:Hexo 本地 → hexo g(生成静态文件) → hexo d(推送到远程服务器/仓库)

  • _config.yml 的 deploy配置是关键,指定仓库和分支
  • Hexo 自己负责生成 public/ 并把它推送到 GitHub 或其他远程
  • 必须在本地先生成,再上传

不足:

  • 每次修改都要本地生成
  • 本地要安装完整 Hexo 环境(Node、主题、插件)才能生成

Cloudflare Pages 部署

我现在的模式是:GitHub 仓库(纯代码,私人仓库,更加隐私) → Cloudflare Pages(自动构建 & 发布)

特点:

  1. 自动化构建:Cloudflare 会在 push 到 main 分支时自动执行 Hexo generate,生成 public/ 并直接发布到站点
  2. 不依赖 Hexo deploy,不用再在本地运行 hexo d,也不需要在 _config.yml 里配置分支
  3. 纯 Git 流程:只需要用 git add → commit → push 管理版本,Cloudflare 会负责构建和部署(用了 GitHub 图形管理界面甚至都不用 Git 命令

为什么不用 hexo g,hexo d

因为 hexo d 其实做了两件事:

  1. 生成静态文件(hexo g)
  2. 把生成的 public/ 推送到指定远程分支(hexo d)

而 Cloudflare 已经代替了第 2 步:

  • Cloudflare 会在云端执行构建(等同于 hexo g)
  • 自动把生成结果发布到你的 Pages 网站

所以本地运行 hexo g hexo d 反而是多余的,甚至可能把 Git 历史搞乱(尤其是 _deploy_git/ 里嵌套 Git 仓库的情况)。


用下来个人感觉在代码方面,免费版之间,ChatGPT>Grok>Gemini,不要太过于相信 AI 的答案,现阶段感觉还是不如人脑。

💡注释

  • ~ 是 用户>xxx 的别名
  • cd 是 change directory(切换目录) 的缩写
  • ~ 表示 当前用户的主目录(home 目录)
  • /blog 是主目录下的一个子文件夹

Hosting Ghost Blog with Docker on NixOS

By: Orchestr
20 August 2023 at 22:44
Hosting Ghost Blog with Docker on NixOS

As previously mentioned, I have successfully deployed NixOS on my Oracle ARM machine. You can find the original post here:

How to Install NixOS on Oracle ARM machine
The steps I undertook to install NixOS on an Oracle ARM machine.
Hosting Ghost Blog with Docker on NixOSDigital ImmigrantsOrchestr
Hosting Ghost Blog with Docker on NixOS

In the past, my blog was hosted on Tencent Cloud using Typecho. Unfortunately, due to unforeseen circumstances, I lost ownership of that machine along with all my previous posts. Consequently, I took a hiatus from blogging, remaining in a state of silence for a few years. However, I now realize the importance of reviving my blog before lethargy engulfs me.

After conducting extensive research and considering various platforms such as Ghost, WordPress, Typecho ,Hugo and some other platforms, I finally settled on Ghost. Its remarkable speed, plethora of customized themes, aesthetically pleasing web user interface, and integrated membership system influenced my decision.

Check out all the cool stuff Ghost has to offer on their website below:

Ghost: The Creator Economy Platform
The world’s most popular modern publishing platform for creating a new media platform. Used by Apple, SkyNews, Buffer, Kickstarter, and thousands more.
Hosting Ghost Blog with Docker on NixOSGhost - The Professional Publishing Platform
Hosting Ghost Blog with Docker on NixOS

Due to the absence of Ghost in the NixOS packages, and the cumbersome nature of adapting it into a NixOS service, Docker has emerged as an excellent solution for hosting Ghost. Here, I have provided a comprehensive breakdown of the steps I followed to set up a blog using Ghost with Docker on NixOS. This can be modified to use on other platforms.

Step 0: Enable Docker on NixOS

Enabling Docker(Podman) on NixOS is a straightforward process, requiring modification of just one configuration file. I personally prefer using the vim editor, but feel free to use your preferred tool such as nano, emacs, or VS Code.

The initial step involves logging into the machine, particularly if it is being used as a server.

ssh ${username}@${server IP}

Then, we can start to modify the configuration file:

sudo vim /etc/nixos/configuration.ni

There are two ways of adding Docker to the NixOS system: for all users:

environment.systemPackages = with pkgs; [
  docker
];

And for one user only:

users.users.${username}.packages = with pkgs; [
  docker
];

You can choose either way based on your needs. The next step is to enable the Docker service.

virtualisation.docker.enable = true;
virtualisation.oci-containers.backend = "docker";

Note that we're using oci-containers to control Dockers. If you have chosen to install Podman, remember to modify it accordingly. Some may question why we're not using docker-compose; this is a simple answer – we embrace the capabilities of NixOS, and that suffices.

Last, remember to create a directory for docker to use. Here's my example:

mkdir ~/.docker

Step 1: Set up Docker Network

Using the Docker CLI command docker network will indeed create the network, but it may not be the optimal approach. Since we're operating within the context of NixOS, we can add it as a service. Add the following code snippet to your configuration.nix file, ensuring to customize the name according to your requirements. In my case, I'm utilizing npm as an example since I'm employing nginx-proxy-manager as my Nginx reverse proxy service.

systemd.services.init-docker-ghost-network-and-files = {
  description = "Create the network npm for nginx proxy manager using reverse proxy.";
  after = [ "network.target" ];
  wantedBy = [ "multi-user.target" ];

  serviceConfig.Type = "oneshot";
  script =
    let dockercli = "${config.virtualisation.docker.package}/bin/docker";
    in ''
      # Put a true at the end to prevent getting non-zero return code, which will
      # crash the whole service.
      check=$(${dockercli} network ls | grep "npm" || true)
      if [ -z "$check" ]; then
        ${dockercli} network create npm
      else
        echo "npm already exists in docker"
      fi
    '';
};

Step 2: Set up Mysql for Ghost

We will now proceed with crafting Docker configurations. The initial step involves creating an external directory for MySQL to store its data, ensuring that we can modify MySQL without accessing the Docker environment directly. At present, this MySQL database is exclusively intended for Ghost; however, you have the freedom to tailor it according to your specific requirements.

mkdir ~/.docker/ghost-blog/mysql -p

Please add the following snippet to your configuration file as well:

virtualisation.oci-containers.containers."ghost-db" = {
  image = "mysql:latest";
  volumes = [ "/home/hua/.docker/ghost-blog/msql:/var/lib/mysql" ];
  environment = {
    MYSQL_ROOT_PASSWORD = "your_mysql_root_password";
    MYSQL_USER = "ghost";
    MYSQL_PASSWORD = "ghostdbpass";
    MYSQL_DATABASE = "ghostdb";
  };
  extraOptions = [ "--network=npm" ];
};

Please note that Ghost no longer supports SQLite and MariaDB as its database options.

Step 3: Set up Ghost Docker

Finally, It's time for Ghost.

Basic Set up Configuarion

Following the previous instructions, we will proceed to create the content folder:

mkdir ~/.docker/ghost-blog/content

Now, let's move on to configuring Ghost:

virtualisation.oci-containers.containers."ghost-blog" = {
  image = "ghost:latest";
  volumes =
    [ "/home/hua/.docker/ghost-blog/content:/var/lib/ghost/content" ];
  dependsOn = [ "ghost-db" ];
  ports = [ 3001:3001 ];
  environment = {
    NODE_ENV = "develop";
    url = "http://${server IP}:3001";
    database__client = "mysql";
    database__connection__host = "ghost-db";
    database__connection__user = "ghost";
    database__connection__password = "ghostdbpass";
    database__connection__database = "ghostdb";
  };
  extraOptions = [ "--network=npm" ];
};

Within this section, we configure the port mapping, environment variables, and volume mapping. Please note that you should customize the MySQL configurations in accordance with your specific setup in the final step.

Mail Server Set Up

Taking Gmail as an example, please note that you can modify this configuration according to your specific needs.

virtualisation.oci-containers.containers."ghost-blog".environment = {
  mail__transport = "SMTP";
  mail__option_service = "Google";
  mail__options__auth__user = "username@gmail.com";
  mail__options__auth__pass = "your google app password";
  mail__options__host = "smtp.gmail.com";
  mail__options__port = "587";
  mail__options__secure = "false";
  mail__from = "username@gmail.com";
  tls__rejectUnauthorized = "true";
}

Please remember that the Google app password mentioned here is different from your actual Google account password. You can generate a Google app password by following the steps outlined in the Sign in with app passwords guide.

By configuring these settings, visitors will be able to sign up and leave comments on our website.

More Custom Options

Please refer to the instructions provided on the Ghost website at the following link:

Configuration - Adapt your publication to suit your needs
Find out how to configure your Ghost publication or override Ghost’s default behaviour with robust config options, including mail, storage, scheduling and more!
Hosting Ghost Blog with Docker on NixOSGhost - The Professional Publishing Platform
Hosting Ghost Blog with Docker on NixOS

Step 4: Set up Nginx Reverse Proxy

There are numerous articles available on the internet that explain how to set up Nginx as a system service or utilize nginx-proxy-manager as a Docker service. For the purpose of this example, I will demonstrate the Docker service approach. Remember to create the necessary folders as well.

virtualisation.oci-containers.containers."nginx-proxy-manager" = {
  image = "jc21/nginx-proxy-manager:latest";
  dependsOn = [ "ghost-blog" "chatgpt-next-web" ];
  volumes = [
    "/home/hua/.docker/nginx-proxy-manager/data:/data",
    "/home/hua/.docker/nginx-proxy-manager/letsencrypt:/etc/letsencrypt"
  ];
  ports = [ "80:80", "443:443", "81:81" ];
  extraOptions = [ "--network=npm" ];
};

Step 5: Rebuild System

sudo nixos-rebuild switch`

Step 6: Start to Use

After rebuilding the system, you can proceed to open the web pages for both Ghost and nginx-proxy-manager.

For information and usage details about Ghost, please visit:

Ghost: The Creator Economy Platform
The world’s most popular modern publishing platform for creating a new media platform. Used by Apple, SkyNews, Buffer, Kickstarter, and thousands more.
Hosting Ghost Blog with Docker on NixOSGhost - The Professional Publishing Platform
Hosting Ghost Blog with Docker on NixOS

To learn more about nginx-proxy-manager, please visit:

Nginx Proxy Manager
Docker container and built in Web Application for managing Nginx proxy hosts with a simple, powerful interface, providing free SSL support via Let’s Encrypt
Hosting Ghost Blog with Docker on NixOS
Hosting Ghost Blog with Docker on NixOS

Please note that once you have set up the nginx reverse proxy for Ghost, it's necessary to modify the Docker configuration for Ghost as follows:

virtualisation.oci-containers.containers."ghost-blog".environment = {
  NODE_ENV = "production";
  url = "https://your-website-address";
}

Please replace your-website-address with the actual address of your website. After making this modification, rebuild the system again.

In conclusion, if you have any further questions, please feel free to leave a comment without hesitation.

❌
❌