2025年7月8日、「あとで読む」アプリの定番 Pocket がサービスを終了します。ウェブページの保存や未読管理、オフライン閲覧を可能にしたPocketは、多くのユーザーにとって欠かせないツールでした。しかし、サービス終了に伴い、代替アプリの選択が急務です。
この記事では、セルフホストを避けたい方には Raindrop、プライバシーと自由度を重視する方には karakeep をおすすめします。特に、karakeepはOIDC対応や公式モバイルアプリなど、独自の強みを持つ優れたツールです。以下では、karakeepの利点と、k3sを使った構築手順をわかりやすく解説します。
Pocketの代替アプリ:Raindropとkarakeepの概要
Raindrop:手軽で直感的なクラウド型ソリューション
Raindropは、セルフホストの手間を避けたい方に最適な「あとで読む」アプリです。主な特徴は以下の通り:
- 美しいUI:直感的な操作で、ストレスなく記事を整理。
- タグ管理:柔軟なカテゴリ分けで、大量の記事も簡単に管理。
- クロスプラットフォーム:Web、iOS、Androidでシームレスに利用可能。
- Pocketからの移行:インポート機能でスムーズに移行。
無料プランでも十分な機能があり、プレミアムプランでは高度な整理機能が追加されます。手軽さを求める方にぴったりです。
karakeep:セルフホストで完全制御
一方、karakeepはセルフホスト型のリーディングリストアプリです。自分のサーバーで運用することで、以下のようなメリットがあります:
- データプライバシー:クラウド依存せず、個人情報を完全に管理。
- カスタマイズ性:自分のニーズに合わせた柔軟な設定。
- 長期的な自由度:サービス終了のリスクなし。
他のセルフホスト型アプリ(WallabagやLinkwarden)と比較しても、karakeepは優れた機能で際立っています(詳細は次項)。初期設定の手間はありますが、プライバシーと自由度を重視する方に最適です。
デモサイトはこちら
karakeepの強み:WallabagやLinkwardenとの違い
karakeepは、以下の点で他のセルフホスト型アプリをリードしています:
- OIDC対応でセキュアな認証
Wallabagは基本的な認証方式に限定されますが、karakeepは**OpenID Connect(OIDC)**に対応。KeycloakやAuth0などとのシングルサインオン(SSO)統合が可能で、エンタープライズ用途にも適しています。 - 公式モバイルアプリでどこでもアクセス
Linkwardenはコラボレーション機能が強いものの、公式モバイルアプリがありません。一方、karakeepはiOSとAndroid向けの公式アプリを提供し、オフライン閲覧も快適です。 - アーカイブ機能でコンテンツを永続保存
karakeepとLinkwardenは、ウェブページをPDFやHTML形式でアーカイブ可能。Wallabagもアーカイブ機能を持ちますが、設定が煩雑で、保存形式の柔軟性やUIの直感性ではkarakeepが優れています。
その他の違い
- 高速検索
karakeepはMeilisearchを統合し、大量の記事でも高速に検索可能。WallabagやLinkwardenの検索は速度面で劣ります。 - モダンな設計
karakeepは軽量でモダンなUI/UXを採用。WallabagのUIはやや古く、Linkwardenはチーム利用に特化しています。 - カスタマイズ性
karakeepはプラグインやAPIが充実し、開発者にとって柔軟な拡張が可能です。
これらの特徴から、プライバシーと機能性を両立したい方にkarakeepは最適です。
まとめ:自分に合った「あとで読む」環境を
Pocketの終了は残念ですが、Raindropなら手軽に、karakeepならプライバシーと自由度を確保して「あとで読む」を続けられます。特にkarakeepは、OIDC対応、公式アプリ、アーカイブ機能で他をリード。k3sを使った構築で、完全制御の環境を手に入れましょう!
ぜひこの手順を試し、karakeepのコミュニティ (リンクを挿入)で情報交換してみてください。あなたの「あとで読む」ライフを、もっと自由に、もっと快適に!
以下は実際の構築手順
k3sでkarakeepを動かす
karakeepをセルフホストするには、軽量なKubernetesディストリビューションであるk3sがおすすめです。k3sはリソース消費が少なく、ホームサーバーやVPSでも簡単に運用できます。ここでは、k3sを使ったkarakeepのデプロイ手順を紹介します。
ディレクトリ構成
以下のディレクトリ構成で、karakeepと依存コンポーネント(Meilisearch、Chrome)を管理します:
./projects
├── base
│ ├── karakeep
│ │ ├── deployment-chrome.yaml # Chromeコンテナのデプロイ
│ │ ├── deployment-karakeep.yaml # karakeep本体のデプロイ
│ │ ├── deployment-meilisearch.yaml # Meilisearchのデプロイ
│ │ ├── kustomization.yaml # kustomize設定
│ │ └── namespace.yaml # 名前空間定義
└── overlays
├── dev
│ ├── 01_configMap # 開発環境の設定
│ └── karakeep
└── prod
├── 01_configMap # 本番環境の設定
├── 02_settings
│ └── karakeep
│ └── secret-karakeep.yaml # シークレット情報
└── karakeep
├── ingress-traefik.yaml # Traefikイングレス
├── kustomization.yaml # 本番用kustomize
├── local-hostpath-pvc.yaml # ストレージ設定
├── patch-deployment-chrome.yaml
├── patch-deployment-karakeep.yaml
├── patch-deployment-meilisearch.yaml
└── Readme.md
主要yamlファイルの役割
- deployment-karakeep.yaml:karakeep本体のデプロイ設定。
- deployment-meilisearch.yaml:高速検索のためのMeilisearch設定。
- deployment-chrome.yaml:ウェブページのアーカイブに必要なChromeコンテナ。
- ingress-traefik.yaml:Traefikを使った外部アクセス設定。
- secret-karakeep.yaml:NEXTAUTH_SECRETなどの機密情報を管理。
- local-hostpath-pvc.yaml:ローカルストレージの永続化設定。
基本リソースのデプロイ
baseディレクトリでkustomizeを適用し、karakeep、Meilisearch、Chromeをデプロイ:
kubectl apply -k ./projects/base/karakeep
本番環境の設定
overlays/prodでパッチを適用し、本番環境を構築:
kubectl apply -k ./projects/overlays/prod/karakeep
外部アクセスの設定
Traefikイングレスで外部からアクセス可能にします。
- deployment-karakeep.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: karakeep-app
spec:
selector:
matchLabels:
app: karakeep-app
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
type: RollingUpdate
template:
metadata:
labels:
app: karakeep-app
spec:
volumes:
- name: karakeep-main
emptyDir: {}
containers:
- name: karakeep-container
image: karakeep-image
imagePullPolicy: IfNotPresent
securityContext:
runAsNonRoot: false
runAsUser: 0
runAsGroup: 0
resources: {}
ports:
- containerPort: 3000
protocol: TCP
env:
- name: TZ
value: Asia/Tokyo
- name: MEILI_ADDR
value: "http://meilisearch-svc.karakeep.svc.cluster.local:7700"
- name: BROWSER_WEB_URL
value: "http://chrome-svc.karakeep.svc.cluster.local:9222"
- name: NEXTAUTH_URL
valueFrom:
secretKeyRef:
name: karakeep-secret
key: server_external_url
optional: true
- name: DATA_DIR
value: "/data"
- name: NEXTAUTH_SECRET
valueFrom:
secretKeyRef:
name: karakeep-secret
key: nextauth_secret
optional: true
- name: MEILI_MASTER_KEY
valueFrom:
secretKeyRef:
name: karakeep-secret
key: meili_master_key
optional: true
- name: NEXT_PUBLIC_SECRET
valueFrom:
secretKeyRef:
name: karakeep-secret
key: next_public_secret
optional: true
volumeMounts:
- name: karakeep-main
mountPath: /data
subPath: data
---
apiVersion: v1
kind: Service
metadata:
name: karakeep-svc
labels:
app: karakeep-app
spec:
selector:
app: karakeep-app
ports:
- protocol: TCP
name: "http"
port: 80
targetPort: 3000
type: ClusterIP
- deployment-chrome.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: chrome-app
spec:
selector:
matchLabels:
app: chrome-app
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
type: RollingUpdate
template:
metadata:
labels:
app: chrome-app
spec:
volumes:
- name: chrome-main
emptyDir: {}
containers:
- name: chrome-container
image: chrome-image
imagePullPolicy: IfNotPresent
securityContext:
runAsNonRoot: false
runAsUser: 0
runAsGroup: 0
resources: {}
ports:
- containerPort: 9222
protocol: TCP
command: ["chromium-browser"]
args:
- --headless
- --no-sandbox
- --disable-gpu
- --disable-dev-shm-usage
- --remote-debugging-address=0.0.0.0
- --remote-debugging-port=9222
- --hide-scrollbars
---
apiVersion: v1
kind: Service
metadata:
name: chrome-svc
labels:
app: chrome-app
spec:
selector:
app: chrome-app
ports:
- protocol: TCP
name: "http"
port: 9222
targetPort: 9222
type: ClusterIP
- deployment-meilisearch.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: meilisearch-app
spec:
selector:
matchLabels:
app: meilisearch-app
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
type: RollingUpdate
template:
metadata:
labels:
app: meilisearch-app
spec:
volumes:
- name: meilisearch-main
emptyDir: {}
containers:
- name: meilisearch-container
image: meilisearch-image
imagePullPolicy: IfNotPresent
securityContext:
runAsNonRoot: false
runAsUser: 0
runAsGroup: 0
resources: {}
ports:
- containerPort: 7700
protocol: TCP
env:
- name: TZ
value: Asia/Tokyo
- name: MEILI_ADDR
value: "http://meilisearch-svc.karakeep.svc.cluster.local:7700"
- name: BROWSER_WEB_URL
value: "http://chrome-svc.karakeep.svc.cluster.local:9222"
- name: NEXTAUTH_URL
value: "http://karakeep-svc.karakeep.svc.cluster.local:3000"
- name: MEILI_NO_ANALYTICS
value: "true"
- name: NEXTAUTH_SECRET
valueFrom:
secretKeyRef:
name: karakeep-secret
key: nextauth_secret
optional: true
- name: MEILI_MASTER_KEY
valueFrom:
secretKeyRef:
name: karakeep-secret
key: meili_master_key
optional: true
- name: NEXT_PUBLIC_SECRET
valueFrom:
secretKeyRef:
name: karakeep-secret
key: next_public_secret
optional: true
volumeMounts:
- name: meilisearch-main
mountPath: /meili_data
subPath: meilisearch
---
apiVersion: v1
kind: Service
metadata:
name: meilisearch-svc
labels:
app: meilisearch-app
spec:
selector:
app: meilisearch-app
ports:
- protocol: TCP
name: "http"
port: 7700
targetPort: 7700
type: ClusterIP
- ./projects/base/karakeep/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: karakeep
resources:
- ./namespace.yaml
- ./deployment-karakeep.yaml
- ./deployment-chrome.yaml
- ./deployment-meilisearch.yaml
images:
- name: karakeep-image
newName: ghcr.io/karakeep-app/karakeep
newTag: "latest"
- name: chrome-image
newName: gcr.io/zenika-hub/alpine-chrome
newTag: "latest"
- name: meilisearch-image
newName: getmeili/meilisearch
newTag: "latest"
- ingress-traefik.yaml
# ここにingress-traefik.yamlの内容を記載
- patch-deployment-karakeep.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: karakeep-app
namespace: karakeep
spec:
selector:
matchLabels:
app: karakeep-app
template:
metadata:
labels:
app: karakeep-app
spec:
containers:
- name: karakeep-container
env:
- name: DISABLE_SIGNUPS
value: "true"
- name: DISABLE_PASSWORD_AUTH
value: "true"
- name: OAUTH_ALLOW_DANGEROUS_EMAIL_ACCOUNT_LINKING
value: "true"
# - namae: OAUTH_PROVIDER_NAME
# valueFrom:
# secretKeyRef:
# name: karakeep-secret
# key: oauth_provider_name
# optional: true
- name: OAUTH_SCOPE
value: "openid email profile"
- name: OAUTH_WELLKNOWN_URL
valueFrom:
secretKeyRef:
name: karakeep-secret
key: oauth_oidc_issuer
optional: true
- name: OAUTH_CLIENT_SECRET
valueFrom:
secretKeyRef:
name: karakeep-secret
key: oauth_oidc_client_secret
optional: true
- name: OAUTH_CLIENT_ID
valueFrom:
secretKeyRef:
name: karakeep-secret
key: oauth_oidc_client_id
optional: true
- name: OPENAI_API_KEY
valueFrom:
secretKeyRef:
name: karakeep-secret
key: openai_api_key
optional: true
securityContext:
runAsNonRoot: false
runAsUser: 0
runAsGroup: 0
volumes:
- name: karakeep-main
emptyDir: null # emptyDirを削除
persistentVolumeClaim:
claimName: karakeep-pvc
securityContext:
fsGroup: 1000
- OAUTH_PROVIDER_NAME
は現状、指定するとエラーになると思います。そのため、コメントアウトにしています。
注意点
- Meilisearchの設定:01_configMapでAPIキーを適切に設定してください。
- Chromeコンテナ:アーカイブ機能に必須。リソース消費を抑えるため、スケーリングを調整。
- Traefik:イングレスコントローラを事前にインストール(Traefik公式参照)。
- シークレット管理:secret-karakeep.yamlにNEXTAUTH_SECRETやMEILI_MASTER_KEYを安全に設定。
詳細なyamlファイルは、リポジトリを参照してください。