Google keepのような見た目でAI連携も出来る「Blinko」

相変わらずセルフホストするメモアプリを探して。今回は「Blinko」です。 Google keepのような見た目ですっきり整理されていて使いやすいですね。日本語訳が変な事を除けば。訳がおかしいため少し使い方に悩んでしまいますが。
普通に書いたノートは「ブリンコ」に保存されますが、「備考(注)」に変換すれば、右上の電球でカード表示にして、スワイプしながらメモを眺められます。AIと連携することもできます。

Blinkoを Docker Composeでセットアップ

Docker Composeが用意されているので簡単です。手動でやるなら、以下を貼り付けて実行するだけです。

#!/bin/bash
# ============================================================
#  Blinko Notes — Docker Compose セットアップスクリプト
#  インストール先: /opt/docker/blinkonotes
# ============================================================
set -e

INSTALL_DIR="/opt/docker/blinkonotes"

echo "=========================================="
echo "  Blinko Notes セットアップ開始"
echo "=========================================="

# --- ディレクトリ作成 ---
echo "[1/4] ディレクトリを作成中..."
sudo mkdir -p "${INSTALL_DIR}/data"
sudo mkdir -p "${INSTALL_DIR}/db"

# --- シークレットキー自動生成 ---
echo "[2/4] シークレットキーを生成中..."
NEXTAUTH_SECRET=$(openssl rand -base64 32)
POSTGRES_PASSWORD=$(openssl rand -base64 24 | tr -d '=+/' | cut -c1-24)

echo "  NEXTAUTH_SECRET : 生成済み"
echo "  POSTGRES_PASSWORD: 生成済み"

# --- .env ファイル生成 ---
echo "[3/4] .env ファイルを作成中..."
sudo tee "${INSTALL_DIR}/.env" > /dev/null <<EOF
# Blinko Notes — 自動生成された環境変数ファイル
# 生成日時: $(date '+%Y-%m-%d %H:%M:%S')

NEXTAUTH_SECRET=${NEXTAUTH_SECRET}
POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
EOF
sudo chmod 600 "${INSTALL_DIR}/.env"

# --- docker-compose.yml 生成 ---
echo "[4/4] docker-compose.yml を作成中..."
sudo tee "${INSTALL_DIR}/docker-compose.yml" > /dev/null <<'COMPOSE_EOF'
networks:
  blinko-network:
    driver: bridge

services:
  blinko-website:
    image: blinkospace/blinko:latest
    container_name: blinko-website
    environment:
      NODE_ENV: production
      # SSO を使う場合は以下2行のコメントを外してドメインを設定
      # NEXTAUTH_URL: http://localhost:1111
      # NEXT_PUBLIC_BASE_URL: http://localhost:1111
      NEXTAUTH_SECRET: ${NEXTAUTH_SECRET}
      DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD}@postgres:5432/postgres
    depends_on:
      postgres:
        condition: service_healthy
    volumes:
      - ./data:/app/.blinko
    restart: always
    logging:
      options:
        max-size: "10m"
        max-file: "3"
    ports:
      - 1111:1111
    healthcheck:
      test: ["CMD", "wget", "--spider", "-q", "http://blinko-website:1111/"]
      interval: 30s
      timeout: 10s
      retries: 5
      start_period: 30s
    networks:
      - blinko-network

  postgres:
    image: postgres:14
    container_name: blinko-postgres
    restart: always
    ports:
      - 5435:5432
    environment:
      POSTGRES_DB: postgres
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      TZ: Asia/Tokyo
    volumes:
      - ./db:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD", "pg_isready", "-U", "postgres", "-d", "postgres"]
      interval: 5s
      timeout: 10s
      retries: 5
    networks:
      - blinko-network
COMPOSE_EOF

# --- 起動 ---
echo ""
echo "=========================================="
echo "  コンテナを起動中..."
echo "=========================================="
cd "${INSTALL_DIR}"
sudo docker compose --env-file .env up -d

echo ""
echo "=========================================="
echo "  セットアップ完了!"
echo "=========================================="
echo ""
echo "  アクセス URL : http://$(hostname -I | awk '{print $1}'):1111"
echo "  初回ログイン  : http://<IPアドレス>:1111/signup でアカウント作成"
echo ""
echo "  インストール先 : ${INSTALL_DIR}"
echo "  設定ファイル   : ${INSTALL_DIR}/.env  (シークレットキー保管)"
echo ""
echo "  よく使うコマンド:"
echo "    ログ確認   : cd ${INSTALL_DIR} && sudo docker compose logs -f"
echo "    停止       : cd ${INSTALL_DIR} && sudo docker compose down"
echo "    更新       : cd ${INSTALL_DIR} && sudo docker compose pull && sudo docker compose up -d"
echo "=========================================="

スクリプトが自動でやること

ステップ内容
ディレクトリ作成/opt/docker/blinkonotes/data(アプリデータ)と db(PostgreSQL)を作成
シークレット生成openssl randNEXTAUTH_SECRETPOSTGRES_PASSWORD を自動生成し .env に保存
compose作成.env を参照する docker-compose.yml を生成(TZ=Asia/Tokyo設定済み)
起動docker compose up -d で即時起動

セットアップ後

  • URL: http://<サーバーのIP>:1111/signup で最初のアカウントを作成
  • デフォルト認証情報はなし(自分でサインアップして管理者アカウントを作る設計)

起動したら最初にユーザー登録(会員登録)してログインします。

カード表示にしたらこんな感じになります。

ユーザー名のアイコンをクリックして設定画面を表示します。英語表示にしたほうが使いやすいですね。

よく使うコマンド

cd /opt/docker/blinkonotes

# ログ確認
sudo docker compose logs -f

# 停止
sudo docker compose down

# アップデート
sudo docker compose pull && sudo docker compose up -d

シークレットキーの保管場所: /opt/docker/blinkonotes/.envchmod 600 で保護済み)

バックアップと復元

スクリプトを /opt/docker/blinkonotes/ に作成し、実行する流れです。

cd /opt/docker/blinkonotes/
sudo nano blinko-backup.sh
#!/bin/bash
# ============================================================
#  Blinko Notes — バックアップ & 復元スクリプト
#  使い方:
#    バックアップ: sudo bash blinko-backup.sh backup
#    復元        : sudo bash blinko-backup.sh restore <バックアップファイル.tar.gz>
#    自動登録    : sudo bash blinko-backup.sh setup-cron
# ============================================================
set -e

INSTALL_DIR="/opt/docker/blinkonotes"
BACKUP_DIR="/opt/docker/blinkonotes/backups"
DATE=$(date '+%Y%m%d_%H%M%S')
BACKUP_FILE="${BACKUP_DIR}/blinko_backup_${DATE}.tar.gz"
POSTGRES_CONTAINER="blinko-postgres"

# ============================================================
#  バックアップ処理
# ============================================================
do_backup() {
  echo "=========================================="
  echo "  Blinko Notes バックアップ開始"
  echo "  日時: ${DATE}"
  echo "=========================================="

  mkdir -p "${BACKUP_DIR}"

  # --- [1] PostgreSQL ダンプ ---
  echo "[1/3] PostgreSQL をダンプ中..."
  docker exec "${POSTGRES_CONTAINER}" \
    pg_dump -U postgres -d postgres --no-password \
    > "${BACKUP_DIR}/postgres_${DATE}.sql"
  echo "      => ${BACKUP_DIR}/postgres_${DATE}.sql"

  # --- [2] アプリデータ ---
  echo "[2/3] アプリデータをコピー中..."
  cp -a "${INSTALL_DIR}/data" "${BACKUP_DIR}/data_${DATE}"

  # --- [3] .env ---
  echo "[3/3] .env をコピー中..."
  cp "${INSTALL_DIR}/.env" "${BACKUP_DIR}/env_${DATE}"

  # --- tar.gz にまとめる ---
  echo ""
  echo "  アーカイブ作成中..."
  tar -czf "${BACKUP_FILE}" \
    -C "${BACKUP_DIR}" \
    "postgres_${DATE}.sql" \
    "data_${DATE}" \
    "env_${DATE}"

  rm -rf \
    "${BACKUP_DIR}/postgres_${DATE}.sql" \
    "${BACKUP_DIR}/data_${DATE}" \
    "${BACKUP_DIR}/env_${DATE}"

  BACKUP_SIZE=$(du -sh "${BACKUP_FILE}" | cut -f1)

  echo ""
  echo "=========================================="
  echo "  バックアップ完了!"
  echo "  ファイル : ${BACKUP_FILE}"
  echo "  サイズ   : ${BACKUP_SIZE}"
  echo "=========================================="

  # 直近7世代を保持、古いものを削除
  ls -t "${BACKUP_DIR}"/blinko_backup_*.tar.gz 2>/dev/null | tail -n +8 | xargs -r rm --
  echo "  保存数   : $(ls "${BACKUP_DIR}"/blinko_backup_*.tar.gz 2>/dev/null | wc -l) 件"
  echo "=========================================="
}

# ============================================================
#  復元処理
# ============================================================
do_restore() {
  RESTORE_FILE="$1"

  if [ -z "${RESTORE_FILE}" ]; then
    echo "エラー: 復元するバックアップファイルを指定してください。"
    echo "使い方: sudo bash blinko-backup.sh restore <ファイル.tar.gz>"
    exit 1
  fi

  if [ ! -f "${RESTORE_FILE}" ]; then
    echo "エラー: ファイルが見つかりません: ${RESTORE_FILE}"
    exit 1
  fi

  echo "=========================================="
  echo "  Blinko Notes 復元開始"
  echo "  ファイル: ${RESTORE_FILE}"
  echo "=========================================="
  echo ""
  echo "  ⚠️  警告: 現在のデータはすべて上書きされます。"
  echo "  続行しますか? (yes / no)"
  read -r CONFIRM
  if [ "${CONFIRM}" != "yes" ]; then
    echo "  中止しました。"
    exit 0
  fi

  # --- [1] 解凍 ---
  echo ""
  echo "[1/7] アーカイブを解凍中..."
  WORK_DIR=$(mktemp -d)
  tar -xzf "${RESTORE_FILE}" -C "${WORK_DIR}"
  echo "      => ${WORK_DIR}"

  SQL_FILE=$(ls "${WORK_DIR}"/postgres_*.sql 2>/dev/null | head -1)
  DATA_DIR=$(ls -d "${WORK_DIR}"/data_* 2>/dev/null | head -1)
  ENV_FILE=$(ls "${WORK_DIR}"/env_* 2>/dev/null | head -1)

  # --- [2] 全コンテナ停止 ---
  echo "[2/7] コンテナを停止中..."
  cd "${INSTALL_DIR}"
  docker compose down

  # --- [3] .env を復元 ---
  echo "[3/7] .env を復元中..."
  if [ -n "${ENV_FILE}" ]; then
    cp "${ENV_FILE}" "${INSTALL_DIR}/.env"
    chmod 600 "${INSTALL_DIR}/.env"
    echo "      => .env 復元済み"
  else
    echo "      ⚠️  .env が見つかりません。既存の .env を使用します。"
  fi

  # --- [4] アプリデータを復元 ---
  echo "[4/7] アプリデータを復元中..."
  if [ -n "${DATA_DIR}" ]; then
    rm -rf "${INSTALL_DIR}/data"
    cp -a "${DATA_DIR}" "${INSTALL_DIR}/data"
    chown -R 1000:1000 "${INSTALL_DIR}/data"
    chmod -R 755 "${INSTALL_DIR}/data"
    echo "      => data/ 復元済み (権限設定済み)"
  else
    echo "      ⚠️  data ディレクトリが見つかりません。スキップします。"
  fi

  # --- [5] DBデータを削除して再初期化 ---
  echo "[5/7] DB を再初期化中..."
  # .env のパスワードと db/ ディレクトリの整合性を保つため
  # db/ を一旦削除し、DBコンテナ起動時に .env のパスワードで再作成させる
  rm -rf "${INSTALL_DIR}/db"
  echo "      => db/ 削除済み (.env のパスワードで再初期化します)"

  # DBコンテナだけ先に起動
  docker compose --env-file "${INSTALL_DIR}/.env" up -d postgres

  echo "      PostgreSQL の起動を待機中..."
  until docker exec "${POSTGRES_CONTAINER}" pg_isready -U postgres -q 2>/dev/null; do
    sleep 2
  done
  echo "      => PostgreSQL 起動完了"

  # --- [6] PostgreSQL にリストア ---
  echo "[6/7] PostgreSQL にリストア中..."

  # public と pgboss スキーマを両方クリア
  echo "      スキーマをクリア中..."
  docker exec "${POSTGRES_CONTAINER}" \
    psql -U postgres -d postgres -c "
      DROP SCHEMA IF EXISTS public CASCADE;
      DROP SCHEMA IF EXISTS pgboss CASCADE;
      CREATE SCHEMA public;
    " > /dev/null

  echo "      SQL をリストア中..."
  # pgboss の重複エラーは無視 (|| true) — blinko 起動時に自動補完される
  docker exec -i "${POSTGRES_CONTAINER}" \
    psql -U postgres -d postgres < "${SQL_FILE}" > /dev/null 2>&1 || true

  # リストア確認
  NOTE_COUNT=$(docker exec "${POSTGRES_CONTAINER}" \
    psql -U postgres -d postgres -t -c "SELECT COUNT(*) FROM notes;" 2>/dev/null | tr -d ' ')
  echo "      => notes テーブル: ${NOTE_COUNT} 件"

  # セッションをクリア (古いトークンによるログイン不能を防ぐ)
  docker exec "${POSTGRES_CONTAINER}" \
    psql -U postgres -d postgres -c "DELETE FROM session;" > /dev/null 2>&1 || true
  echo "      => セッションクリア済み"

  # --- [7] 全コンテナ起動 ---
  echo "[7/7] 全コンテナを起動中..."
  docker compose --env-file "${INSTALL_DIR}/.env" up -d

  echo "      コンテナの起動を待機中..."
  sleep 5

  # blinko-website が起動していなければ再試行
  if ! docker compose ps | grep -q "blinko-website.*Up"; then
    echo "      blinko-website が起動していません。再試行中..."
    sleep 5
    docker compose --env-file "${INSTALL_DIR}/.env" up -d
    sleep 3
  fi

  # 一時ディレクトリを削除
  rm -rf "${WORK_DIR}"

  echo ""
  echo "=========================================="
  echo "  復元完了!"
  echo "  ノート数 : ${NOTE_COUNT} 件"
  echo "  URL      : http://$(hostname -I | awk '{print $1}'):1111"
  echo ""
  echo "  ⚠️  セッションをクリアしました。"
  echo "     シークレットウィンドウで開き、再ログインしてください。"
  echo "=========================================="
}

# ============================================================
#  cron 登録 (毎日 深夜2時)
# ============================================================
do_setup_cron() {
  SCRIPT_PATH="$(realpath "$0")"
  CRON_JOB="0 2 * * * /bin/bash ${SCRIPT_PATH} backup >> /var/log/blinko-backup.log 2>&1"
  (crontab -l 2>/dev/null | grep -v "blinko-backup.sh"; echo "${CRON_JOB}") | crontab -
  echo "=========================================="
  echo "  cron 登録完了"
  echo "  スケジュール: 毎日 深夜 2:00"
  echo "  ログ: /var/log/blinko-backup.log"
  echo "=========================================="
  crontab -l | grep blinko
}

# ============================================================
#  エントリポイント
# ============================================================
case "$1" in
  backup)
    do_backup
    ;;
  restore)
    do_restore "$2"
    ;;
  setup-cron)
    do_setup_cron
    ;;
  *)
    echo "使い方:"
    echo "  sudo bash blinko-backup.sh backup              # バックアップ実行"
    echo "  sudo bash blinko-backup.sh restore <ファイル>  # 復元実行"
    echo "  sudo bash blinko-backup.sh setup-cron          # 自動バックアップ登録(毎日2時)"
    exit 1
    ;;
esac

スクリプトに実行権限付与

# スクリプトに実行権限付与
sudo chmod +x /opt/docker/blinkonotes/blinko-backup.sh

バックアップ

sudo bash /opt/docker/blinkonotes/blinko-backup.sh backup

/opt/docker/blinkonotes/backups/blinko_backup_YYYYMMDD_HHMMSS.tar.gz に保存されます。直近7世代を自動保持し、古いものは自動削除。
念の為、定期的にエクスポートも実施しておくとよいでしょう。

復元

sudo bash /opt/docker/blinkonotes/blinko-backup.sh restore \
  /opt/docker/blinkonotes/backups/blinko_backup_20260320_020000.tar.gz

yes と入力して確定すると、自動で以下を実行します。

ステップ内容
コンテナ停止docker compose down
.env 復元シークレットキーを含む設定ファイルを復元
data/ 復元添付ファイル・設定等のアプリデータを復元
DB 復元PostgreSQL を pg_dump から完全リストア
コンテナ起動docker compose up -d

新規の環境で復元したい場合は、まずBlinkoをインストールしたら、すぐにバックアップスクリプトもインストールし、バックアップファイルを指定して復元すればOKです。もしバージョンが大きく変わって復元出来ない場合は、エクスポートしたファイルから復元するようにしましょう。

自動バックアップ登録(毎日 深夜2時)

sudo bash /opt/docker/blinkonotes/blinko-backup.sh setup-cron

ログは /var/log/blinko-backup.log に記録されます。

バックアップの中身

ファイル内容
postgres_*.sqlDBの全データ(ノート・タグ等)
data_*/添付ファイル・アップロード画像等
env_*.env(シークレットキー)

別サーバーへの移行も同じ手順で可能です。 セットアップスクリプトで新サーバーを初期化 → バックアップファイルを転送 → restore を実行するだけです。