以前にも軽く紹介しましたら、改めて入れてみました。ブックマーク管理の「Karakeep」です。Linkwardenと同じようなサービスですが、若干方向性が違い、LinkwardenはPDFや画像などあらゆる方法でWebページを保存しようとするのに対し、Karakeepは検索機能が軽快で、気になったページはとりあえずどんどん追加しておく、といったような使い方になりそうかと。いずれもAIと連携して自動タグ付けなどが行えます。

目次
LXDコンテナにインストールするスクリプト
LXDコンテナにインストールするなら、下記スクリプトをコピペすればOKです。tailscale serveによりHTTPS化され、安全に利用出来ます。
#!/bin/bash
set -euo pipefail
# =============================================================
# Karakeep セットアップスクリプト (tailscale serve版)
#
# 構成 (LXDコンテナ内で実行):
# - Karakeep : https://<hostname>.<tailnet>.ts.net:3313 (tailscale serve 3313)
#
# ディレクトリ構成:
# /opt/docker/karakeep/
# docker-compose.yml
# .env
#
# 前提条件:
# - LXDコンテナ内でrootまたはsudoで実行
# - Docker がインストール済みであること
# - tailscale up 済みであること
# - Tailscale管理コンソールでHTTPS Certificatesを有効化済み
# https://login.tailscale.com/admin/dns
# =============================================================
KARAKEEP_DIR="/opt/docker/karakeep"
PORT=13000
TAILSCALE_PORT=3313
# ── カラー出力 ────────────────────────────────────
GREEN='\033[0;32m'
RED='\033[0;31m'
NC='\033[0m'
echo ""
echo "════════════════════════════════════════"
echo " Karakeep セットアップ (tailscale serve版)"
echo "════════════════════════════════════════"
echo ""
# ── Tailscale確認 ─────────────────────────────────
if ! command -v tailscale &>/dev/null; then
echo -e "${RED}ERROR: tailscaleがインストールされていません${NC}"
exit 1
fi
if ! tailscale status &>/dev/null 2>&1; then
echo -e "${RED}ERROR: tailscaleが接続されていません。tailscale up を実行してください${NC}"
exit 1
fi
# ── tailnetドメイン取得 ───────────────────────────
echo "==> [1/4] Tailscaleドメインを取得..."
sudo tailscale set --operator=$USER 2>/dev/null || true
TAILSCALE_DOMAIN=$(tailscale status --json | python3 -c "
import json, sys
d = json.load(sys.stdin)
print(d.get('Self', {}).get('DNSName', '').rstrip('.'))
" 2>/dev/null)
if [ -z "$TAILSCALE_DOMAIN" ]; then
echo -e "${RED}ERROR: Tailscaleドメインを取得できませんでした${NC}"
echo "Tailscale管理コンソールでMagicDNSが有効になっているか確認してください"
exit 1
fi
echo -e " ${GREEN}ドメイン: ${TAILSCALE_DOMAIN}${NC}"
echo -e " ${GREEN}Karakeep : https://${TAILSCALE_DOMAIN}:${TAILSCALE_PORT}${NC}"
# ── ディレクトリ作成 ──────────────────────────────
echo ""
echo "==> [2/4] ディレクトリ・設定ファイルを準備..."
mkdir -p "${KARAKEEP_DIR}"
echo -e " ${GREEN}✓ ${KARAKEEP_DIR}/${NC}"
# ── シークレット生成 ──────────────────────────────
NEXTAUTH_SECRET=$(openssl rand -base64 36)
MEILI_MASTER_KEY=$(openssl rand -base64 36)
# ── .env 生成 ─────────────────────────────────────
cat > "${KARAKEEP_DIR}/.env" <<EOF
KARAKEEP_VERSION=release
NEXTAUTH_SECRET=${NEXTAUTH_SECRET}
MEILI_MASTER_KEY=${MEILI_MASTER_KEY}
NEXTAUTH_URL=https://${TAILSCALE_DOMAIN}:${TAILSCALE_PORT}
EOF
chmod 600 "${KARAKEEP_DIR}/.env"
echo -e " ${GREEN}✓ ${KARAKEEP_DIR}/.env${NC}"
# ── docker-compose.yml 生成 ───────────────────────
cat > "${KARAKEEP_DIR}/docker-compose.yml" <<EOF
services:
karakeep:
image: ghcr.io/karakeep-app/karakeep:\${KARAKEEP_VERSION:-release}
container_name: karakeep
restart: unless-stopped
depends_on:
- karakeep-chrome
- karakeep-meilisearch
volumes:
- karakeep-data:/data
ports:
- "127.0.0.1:${PORT}:3000"
env_file:
- .env
environment:
MEILI_ADDR: http://karakeep-meilisearch:7700
BROWSER_WEB_URL: http://karakeep-chrome:9222
DATA_DIR: /data
karakeep-chrome:
image: gcr.io/zenika-hub/alpine-chrome:124
container_name: karakeep-chrome
restart: unless-stopped
command:
- --no-sandbox
- --disable-gpu
- --disable-dev-shm-usage
- --remote-debugging-address=0.0.0.0
- --remote-debugging-port=9222
- --hide-scrollbars
karakeep-meilisearch:
image: getmeili/meilisearch:v1.13.3
container_name: karakeep-meilisearch
restart: unless-stopped
volumes:
- karakeep-meilisearch-data:/meili_data
environment:
MEILI_NO_ANALYTICS: "true"
MEILI_MASTER_KEY: \${MEILI_MASTER_KEY}
volumes:
karakeep-data:
karakeep-meilisearch-data:
EOF
echo -e " ${GREEN}✓ ${KARAKEEP_DIR}/docker-compose.yml${NC}"
# ── Docker起動 ────────────────────────────────────
echo ""
echo "==> [3/4] コンテナを起動..."
cd "${KARAKEEP_DIR}"
docker compose pull
docker compose up -d
echo ""
echo -e " ${GREEN}✓ コンテナ起動完了${NC}"
# ── tailscale serve 設定 ──────────────────────────
echo ""
echo "==> [4/4] tailscale serve を設定..."
tailscale serve --https=${TAILSCALE_PORT} off 2>/dev/null || true
tailscale serve --bg --https=${TAILSCALE_PORT} "http://localhost:${PORT}" || {
echo -e "${RED}ERROR: tailscale serve の設定に失敗しました${NC}"
exit 1
}
echo -e " ${GREEN}✓ tailscale serve 設定完了${NC}"
echo ""
tailscale serve status
# ── 完了メッセージ ────────────────────────────────
echo ""
echo "════════════════════════════════════════"
echo -e " ${GREEN}✅ 起動完了!${NC}"
echo "════════════════════════════════════════"
echo ""
echo " 🌐 URL : https://${TAILSCALE_DOMAIN}:${TAILSCALE_PORT}"
echo ""
echo " 📁 ディレクトリ構成:"
echo " 設定 : ${KARAKEEP_DIR}/docker-compose.yml"
echo " env : ${KARAKEEP_DIR}/.env"
echo ""
echo "════════════════════════════════════════"
echo " ⚠️ 初回アクセス時の注意"
echo "════════════════════════════════════════"
echo ""
echo " karakeep の起動完了まで1〜2分かかる場合があります。"
echo " アカウント作成後、.env に DISABLE_SIGNUPS=true を追記し"
echo " docker compose up -d karakeep で再起動することを推奨します。"
echo ""
echo "════════════════════════════════════════"
echo " 🔧 管理コマンド"
echo "════════════════════════════════════════"
echo ""
echo " ログ確認 : cd ${KARAKEEP_DIR} && docker compose logs -f karakeep"
echo " 停止 : cd ${KARAKEEP_DIR} && docker compose down"
echo " 更新 : cd ${KARAKEEP_DIR} && docker compose pull && docker compose up -d"
echo ""
echo "════════════════════════════════════════"
echo ""
起動したら日本語化、インポートやバックアップ機能も搭載
インストールが完了し起動したら、まずメールアドレスやパスワードを入力して管理者ユーザーを登録します。続いてログインしたら、まず日本語化しましょう。

標準でバックアップ機能も搭載しており、バックアップを設定した場合は標準では下記以下に保存され、ブラウザ上からZIPファイルで保存出来ます。
/var/lib/docker/volumes/karakeep_karakeep-data/_data/assets
環境移行にも備えたフルバックアップと復元
標準機能でバックアップしたzipファイルの中身はブックマークのメタデータのみのjsonで、バナー画像や添付ファイルは含まれていません。完全なバックアップや復元を行うために、下記のスクリプトを作成しました。
スクリプトの使い方
# バックアップ(コンテナ起動中のまま実行OK) sudo bash karakeep-backup.sh # → /opt/lxd-data/karakeep/karakeep_20260527_123456.tar.gz に保存 # 復元(バックアップファイルを指定) sudo bash karakeep-restore.sh /opt/lxd-data/karakeep/karakeep_20260527_123456.tar.gz # 復元(最新バックアップを自動選択) sudo bash karakeep-restore.sh
バックアップの中身
| 内容 | 説明 |
|---|---|
karakeep-data/db.db | ブックマーク・タグ・リスト・ユーザー情報すべて |
karakeep-data/assets/ | バナー画像・スクリーンショット・添付ファイル |
meilisearch-data/ | 全文検索インデックス |
config/.env | シークレットキー含む設定 |
config/docker-compose.yml | compose設定 |
定期自動バックアップにする場合
# cronに登録(毎日午前3時に実行) echo "0 3 * * * root bash /opt/docker/karakeep/karakeep-backup.sh" | sudo tee /etc/cron.d/karakeep-backup
7日以上古いバックアップは自動削除されます(KEEP_DAYS で変更可能)。
バックアップスクリプト
nano /opt/docker/karakeep/karakeep-backup.sh
cd /opt/docker/karakeep
bash karakeep-backup.sh
#!/bin/bash
set -euo pipefail
# =============================================================
# Karakeep バックアップスクリプト
# 保存先: /opt/lxd-data/karakeep/karakeep_YYYYMMDD_HHMMSS.tar.gz
# =============================================================
BACKUP_DIR="/opt/lxd-data/karakeep"
COMPOSE_DIR="/opt/docker/karakeep"
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
BACKUP_FILE="${BACKUP_DIR}/karakeep_${TIMESTAMP}.tar.gz"
KEEP_DAYS=7
GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[1;33m'
NC='\033[0m'
echo ""
echo "════════════════════════════════════════"
echo " Karakeep バックアップ開始"
echo " $(date '+%Y-%m-%d %H:%M:%S')"
echo "════════════════════════════════════════"
echo ""
if ! docker inspect karakeep >/dev/null 2>&1; then
echo -e "${RED}ERROR: karakeepコンテナが存在しません${NC}"
exit 1
fi
mkdir -p "${BACKUP_DIR}"
echo -e " ${GREEN}✓ バックアップ先: ${BACKUP_DIR}${NC}"
# ── WALチェックポイント ───────────────────────
echo ""
echo "==> [1/4] データベースをチェックポイント..."
docker exec karakeep sqlite3 /data/db.db "PRAGMA wal_checkpoint(TRUNCATE);" 2>/dev/null || \
echo -e " ${YELLOW}⚠ WALチェックポイントをスキップ${NC}"
echo -e " ${GREEN}✓ 完了${NC}"
# ── ボリュームをコピー ────────────────────────
echo ""
echo "==> [2/4] ボリュームデータを取得..."
TMPDIR=$(mktemp -d)
trap 'rm -rf "${TMPDIR}"' EXIT
echo " karakeep_karakeep-data ボリュームをコピー中..."
docker run --rm \
-v karakeep_karakeep-data:/source:ro \
-v "${TMPDIR}:/backup" \
alpine \
sh -c "cp -a /source/. /backup/karakeep-data/"
echo -e " ${GREEN}✓ karakeep-data${NC}"
echo " karakeep_karakeep-meilisearch-data ボリュームをコピー中..."
docker run --rm \
-v karakeep_karakeep-meilisearch-data:/source:ro \
-v "${TMPDIR}:/backup" \
alpine \
sh -c "cp -a /source/. /backup/meilisearch-data/"
echo -e " ${GREEN}✓ meilisearch-data${NC}"
echo " 設定ファイルをコピー中..."
mkdir -p "${TMPDIR}/config"
cp "${COMPOSE_DIR}/docker-compose.yml" "${TMPDIR}/config/" 2>/dev/null || true
cp "${COMPOSE_DIR}/.env" "${TMPDIR}/config/" 2>/dev/null || true
docker inspect karakeep --format '{{.Config.Image}}' > "${TMPDIR}/config/image_version.txt" 2>/dev/null || true
date '+%Y-%m-%d %H:%M:%S' > "${TMPDIR}/config/backup_date.txt"
echo -e " ${GREEN}✓ 設定ファイル${NC}"
# ── 圧縮 ──────────────────────────────────────
echo ""
echo "==> [3/4] 圧縮中..."
tar -czf "${BACKUP_FILE}" -C "${TMPDIR}" .
BACKUP_SIZE=$(du -sh "${BACKUP_FILE}" | cut -f1)
echo -e " ${GREEN}✓ ${BACKUP_FILE} (${BACKUP_SIZE})${NC}"
# ── 古いバックアップ削除 ──────────────────────
echo ""
echo "==> [4/4] 古いバックアップを整理 (${KEEP_DAYS}日以上前を削除)..."
find "${BACKUP_DIR}" -name "karakeep_*.tar.gz" -mtime +${KEEP_DAYS} -delete
REMAINING=$(find "${BACKUP_DIR}" -name "karakeep_*.tar.gz" | wc -l)
echo -e " ${GREEN}✓ 保持中のバックアップ: ${REMAINING}件${NC}"
echo ""
echo "════════════════════════════════════════"
echo -e " ${GREEN}✅ バックアップ完了!${NC}"
echo "════════════════════════════════════════"
echo ""
echo " 📦 ファイル : ${BACKUP_FILE}"
echo " 📏 サイズ : ${BACKUP_SIZE}"
echo ""
echo " 復元する場合は karakeep-restore.sh を使用してください"
echo "════════════════════════════════════════"
echo ""
復元
下記でスクリプトを保存したら、バックアップファイルを/opt/lxd-data/karakeepに保存します。
mkdir -p /opt/lxd-data/karakeep
cd /opt/lxd-data/karakeep
nano karakeep-restore.sh
#!/bin/bash
set -euo pipefail
# =============================================================
# Karakeep 復元スクリプト
#
# 使い方:
# bash karakeep-restore.sh <バックアップファイル> # 指定
# bash karakeep-restore.sh # 最新を自動選択
# =============================================================
BACKUP_DIR="/opt/lxd-data/karakeep"
COMPOSE_DIR="/opt/docker/karakeep"
GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[1;33m'
NC='\033[0m'
echo ""
echo "════════════════════════════════════════"
echo " Karakeep 復元スクリプト"
echo "════════════════════════════════════════"
echo ""
# ── バックアップファイルの決定 ────────────────
if [ -n "${1:-}" ]; then
BACKUP_FILE="$1"
else
BACKUP_FILE=$(find "${BACKUP_DIR}" -name "karakeep_*.tar.gz" | sort | tail -n 1)
if [ -z "${BACKUP_FILE}" ]; then
echo -e "${RED}ERROR: ${BACKUP_DIR} にバックアップファイルが見つかりません${NC}"
exit 1
fi
echo -e " ${YELLOW}最新バックアップを自動選択: ${BACKUP_FILE}${NC}"
fi
[ -f "${BACKUP_FILE}" ] || { echo -e "${RED}ERROR: ファイルが見つかりません: ${BACKUP_FILE}${NC}"; exit 1; }
BACKUP_DATE=$(basename "${BACKUP_FILE}" | sed 's/karakeep_\([0-9_]*\)\.tar\.gz/\1/')
echo " バックアップ日時 : ${BACKUP_DATE}"
echo " ファイル : ${BACKUP_FILE}"
echo " サイズ : $(du -sh "${BACKUP_FILE}" | cut -f1)"
echo ""
# ── 確認 ──────────────────────────────────────
echo -e " ${YELLOW}⚠️ 警告: 現在のデータはすべて上書きされます!${NC}"
echo ""
read -rp " 本当に復元しますか? (yes/no): " CONFIRM
[ "${CONFIRM}" = "yes" ] || { echo " キャンセルしました。"; exit 0; }
# ── 前提チェック ──────────────────────────────
echo ""
echo "==> [1/5] 前提確認..."
if ! docker volume inspect karakeep_karakeep-data >/dev/null 2>&1; then
echo -e "${RED}ERROR: karakeep_karakeep-dataボリュームが存在しません${NC}"
echo " 先にインストールスクリプトでkarakeepをセットアップしてください。"
exit 1
fi
echo -e " ${GREEN}✓ ボリューム確認OK${NC}"
# ── コンテナ停止 ──────────────────────────────
echo ""
echo "==> [2/5] コンテナを停止..."
cd "${COMPOSE_DIR}"
docker compose down
echo -e " ${GREEN}✓ 停止完了${NC}"
# ── 展開 ──────────────────────────────────────
echo ""
echo "==> [3/5] バックアップを展開中..."
TMPDIR=$(mktemp -d)
# 異常終了時はコンテナを再起動してTMPDIRを削除
trap 'echo -e "${YELLOW}中断されました。コンテナを再起動します...${NC}"; rm -rf "${TMPDIR}"; cd "${COMPOSE_DIR}" && docker compose up -d' EXIT
tar -xzf "${BACKUP_FILE}" -C "${TMPDIR}"
echo -e " ${GREEN}✓ 展開完了${NC}"
# ── ボリュームに書き戻し ──────────────────────
echo ""
echo "==> [4/5] ボリュームを復元中..."
if [ -d "${TMPDIR}/karakeep-data" ]; then
echo " karakeep-data を復元中..."
docker run --rm \
-v karakeep_karakeep-data:/dest \
-v "${TMPDIR}/karakeep-data:/source:ro" \
alpine \
sh -c "rm -rf /dest/* /dest/.[!.]* 2>/dev/null; cp -a /source/. /dest/"
echo -e " ${GREEN}✓ karakeep-data${NC}"
else
echo -e " ${YELLOW}⚠ karakeep-data が見つかりません(スキップ)${NC}"
fi
if [ -d "${TMPDIR}/meilisearch-data" ]; then
echo " meilisearch-data を復元中..."
docker run --rm \
-v karakeep_karakeep-meilisearch-data:/dest \
-v "${TMPDIR}/meilisearch-data:/source:ro" \
alpine \
sh -c "rm -rf /dest/* /dest/.[!.]* 2>/dev/null; cp -a /source/. /dest/"
echo -e " ${GREEN}✓ meilisearch-data${NC}"
else
echo -e " ${YELLOW}⚠ meilisearch-data が見つかりません(スキップ)${NC}"
fi
# ── コンテナ再起動 ────────────────────────────
echo ""
echo "==> [5/5] コンテナを再起動..."
trap - EXIT # 正常終了なのでEXITトラップ解除
rm -rf "${TMPDIR}"
cd "${COMPOSE_DIR}"
docker compose up -d
echo -e " ${GREEN}✓ 再起動完了${NC}"
echo ""
echo "════════════════════════════════════════"
echo -e " ${GREEN}✅ 復元完了!${NC}"
echo "════════════════════════════════════════"
echo ""
echo " karakeepの起動完了まで1〜2分かかる場合があります。"
echo " ブラウザでアクセスして動作を確認してください。"
echo ""
echo " ログ確認: cd ${COMPOSE_DIR} && docker compose logs -f karakeep"
echo "════════════════════════════════════════"
echo ""
bash karakeep-restore.sh

