Can't deploy latest versions on fly.io

I encountered the same issue with tini, yet it appears that it does not affect the normal initialization/operation of SB.

When I first migrated from version 2.0.0 to 2.1.6, the system failed to function properly.

My approach was to begin with the ‘blank’ official image of version 2.1.6 (or 2.1.7).

If it could launch and deploy successfully, I then incrementally restored my previous environment and added custom initialization scripts on top of this minimal, working official base.

I am able to share the initialization setup for my read-only SB instance (from Windows OS):

  1. fly.toml
app = 'enlarge-the-percentage'
primary_region = 'lax'
swap_size_mb = 256

[deploy]
  strategy = 'immediate'

[[mounts]]
  source = 'silverbullet_space'
  destination = '/space'

[[services]]
  protocol = 'tcp'
  internal_port = 3000
  auto_stop_machines = 'stop'
  auto_start_machines = true
  min_machines_running = 0

  [[services.ports]]
    port = 80
    handlers = ['http']

  [[services.ports]]
    port = 443
    handlers = ['tls', 'http']

[[vm]]
  memory = '256mb'
  cpu_kind = 'shared'
  cpus = 1

[[statics]]
  guest_path = '/space/STYLE'
  url_prefix = '/STYLE'
  1. Dockerfile
FROM ghcr.io/silverbulletmd/silverbullet:v2

RUN apk add --no-cache dos2unix

WORKDIR /

COPY init.sh /init.sh
RUN dos2unix /init.sh && chmod +x /init.sh

ENTRYPOINT ["/sbin/tini", "-g", "--"]
CMD ["/init.sh"]
  1. init.sh
#!/bin/bash
set -euo pipefail

cd /space

# -------------------------------
# 2️ 初始化或验证 Git 仓库
# -------------------------------
EXPECTED_USER_NAME="Xcz"
EXPECTED_USER_EMAIL="[email protected]"
EXPECTED_CREDENTIAL_HELPER="store"
EXPECTED_PULL_REBASE="false"
EXPECTED_PUSH_AUTOREMOTE="true"
EXPECTED_CORE_EDITOR="nano"
EXPECTED_ORIGIN_URL="https://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@github.com/ChenZhu-Xie/xczphysics_SilverBullet.git"

if [ ! -d ".git" ]; then
  echo "[INFO] 初始化 Git 仓库"
  git init -b main
fi

# Helper: 设置或修正配置
set_config_if_needed() {
  local key=$1
  local expected=$2
  local current
  current=$(git config --local --get "$key" || echo "")
  if [ "$current" != "$expected" ]; then
    echo "[WARN] 修正 Git 配置 $key: 当前='$current' -> 期望='$expected'"
    git config "$key" "$expected"
  else
    echo "[INFO] Git 配置 $key 正确"
  fi
}

# 检查并修复配置
set_config_if_needed "user.name" "$EXPECTED_USER_NAME"
set_config_if_needed "user.email" "$EXPECTED_USER_EMAIL"
set_config_if_needed "credential.helper" "$EXPECTED_CREDENTIAL_HELPER"
set_config_if_needed "pull.rebase" "$EXPECTED_PULL_REBASE"
set_config_if_needed "push.autoSetupRemote" "$EXPECTED_PUSH_AUTOREMOTE"
set_config_if_needed "core.editor" "$EXPECTED_CORE_EDITOR"

# 检查远程 origin
CURRENT_ORIGIN=$(git remote get-url origin 2>/dev/null || echo "")
if [ -z "$CURRENT_ORIGIN" ]; then
  echo "[WARN] 未检测到远程 origin,正在添加"
  git remote add origin "$EXPECTED_ORIGIN_URL"
elif [ "$CURRENT_ORIGIN" != "$EXPECTED_ORIGIN_URL" ]; then
  echo "[WARN] 远程 origin URL 不正确,正在修复: 当前='$CURRENT_ORIGIN'"
  git remote set-url origin "$EXPECTED_ORIGIN_URL"
else
  echo "[INFO] 远程 origin URL 正确"
fi

# -------------------------------
# 3️ 创建默认文件(如果不存在)
# -------------------------------
if [ ! -f ".gitignore" ]; then # 创建 .gitignore(仅当不存在时)
  echo "[INFO] 创建 .gitignore"
  echo ".silverbullet.db*" > .gitignore
  echo "*.bat" >> .gitignore
  echo "*.sublime-workspace" >> .gitignore
  echo "CONTAINER_BOOT.md" >> .gitignore
fi

# -------------------------------
# 5️ 强制同步远程 main 分支
# ------------------------------- # 不论 SB 是否只读,这里在 持久化卷挂载后、SB 启动前进行的 写入操作都会强制实施,且预计成功
run_with_retry() { # 封装一个带重试的函数
  local cmd="$*"
  local attempt=1
  local max_attempts=5   # 最大 5 次
  local delay=5          # 每次间隔 5 秒

  until eval "$cmd"; do
    if [ $attempt -ge $max_attempts ]; then
      echo "[ERROR] 命令失败:$cmd"
      return 1
    fi
    echo "[WARN] 命令失败:$cmd"
    echo "[INFO] $delay 秒后重试... (第 $((attempt+1))/$max_attempts 次)"
    sleep $delay
    attempt=$((attempt+1))
  done
}

# -------------------------------
# 5️ 强制同步远程 main 分支
# -------------------------------
echo "[INFO] 检查本地是否配置了远程 origin..."
if ! git remote get-url origin &>/dev/null; then
  echo "[ERROR] 没有配置远程 origin,请检查 init.sh 中的 git remote add"
  exit 1
fi
echo "[INFO] 当前远程 URL: $(git remote get-url origin)"

echo "[INFO] 检查远程仓库可访问性..."
if ! run_with_retry "git ls-remote --exit-code origin &>/dev/null"; then
  echo "[ERROR] 无法访问远程仓库(可能是网络或权限问题)"
  exit 1
fi

echo "[INFO] 检查远程是否为空..."
if [ -z "$(git ls-remote --heads origin)" ]; then
  echo "[INFO] 远程仓库为空,初始化推送"
  git add .
  git commit -m "initial commit" || true
  if ! run_with_retry "git push -u origin main:main"; then
    echo "[ERROR] 初始 push 失败(可能是只读权限)"
    exit 1
  fi
else
  echo "[INFO] 远程仓库非空,强制同步 main 分支"
  run_with_retry "git fetch origin main"
  run_with_retry "git reset --hard origin/main"
fi

echo "[INFO] Git 同步成功 ✅"

# 交给原有的入口脚本继续启动
exec /docker-entrypoint.sh "$@"

As an alternative, the previously mentioned init.sh, once its last line is removed, may be used as CONTAINER_BOOT.md and executed directly by the official docker-entrypoint.sh.

However, I personally find it better to keep the boot file outside of SB_space?

In addition, logically speaking, init.sh and docker-entrypoint.sh should be run in sequence? as init.sh modifies some Git settings AND performs Git operations within SB_space. — Therefore, init.sh ought to be executed prior to docker-entrypoint.sh, not in parallel or subsequently?

In addition to the official init script docker-entrypoint.sh, the official Dockerfile
is also worth studying. I hope it will be of help.

2 Likes