セルフホスト

Nesh は MIT ライセンスで、Node.js が動く環境と Postgres が用意できれば自前でホストできます。リファレンス構成は Vercel + Supabase ですが、どちらも必須ではありません。

前提条件

  • Node.js 20 以降 (Vercel のビルドイメージそのままで動きます)。
  • Postgres 15 以降 — Supabase、Neon、RDS、自前運用、いずれも可。
  • Next.js のビルド成果物が動くホストならどこでも (Vercel、Cloudflare、Fly.io、VM、Docker など)。
  • 本番オリジンは HTTPS 必須 — ブラウザは平文 HTTP では Service Worker を登録しません。

1. クローンとインストール

リポジトリをクローンして依存関係をインストール:

git clone https://github.com/piro0919/nesh.git
cd nesh
pnpm install

2. Postgres を用意してマイグレーションを適用

スキーマはすべて supabase/migrations/ にあります。Supabase を使う場合は、リポジトリ同梱の CLI でローカルスタックを起動:

pnpm db:start

リモートプロジェクトにも同じマイグレーションを適用してください。Supabase 以外の Postgres を使う場合は supabase/migrations/ 配下の SQL ファイルを名前順に流し込みます。

全テーブルで Row-Level Security 有効。ダッシュボードからの DB アクセスは Supabase 認証されたユーザーとして、cron や REST 送信などの内部ルートだけが service role キーで RLS をバイパスします。

3. 環境変数

にコピーして以下を埋めます: .env.example.env.local.

NEXT_PUBLIC_SUPABASE_URLSupabase が公開する Postgres URL (または任意の PostgREST エンドポイント)。
NEXT_PUBLIC_SUPABASE_ANON_KEYAnonymous (公開) キー — ブラウザに渡しても安全。
SUPABASE_SERVICE_ROLE_KEYService-role キー — サーバー専用、RLS をバイパスします。DB パスワードと同等に扱ってください。
NEXT_PUBLIC_SITE_URLNesh デプロイの公開オリジン。SDK ユーザーに見せる apiBase と公開イベント追跡 URL の生成に使われます。
CRON_SECRETcron が自身を認証するための共有秘密。十分にランダムな文字列で OK。
VAPID_KEY_ENCRYPTION_KEYプロジェクト毎の VAPID 秘密鍵を保存時に暗号化する 32 バイトの AES-256-GCM 鍵。下記コマンドで生成。この鍵を失うと既存プロジェクトの VAPID アイデンティティへアクセスできなくなります。
ADMIN_USER_IDS任意。/admin ダッシュボードへアクセスできる Supabase ユーザー UUID をカンマ区切りで指定。
# Generate VAPID_KEY_ENCRYPTION_KEY
node -e "console.log(require('node:crypto').randomBytes(32).toString('base64'))"

# Generate CRON_SECRET
node -e "console.log(require('node:crypto').randomBytes(24).toString('base64url'))"

4. デプロイ

Vercel: リポジトリを連携し、ステップ 3 の環境変数を設定して deploy。同梱の vercel.ts が cron スケジュールを自動で配線します。

自前ホスト: 以下でビルド・起動:

pnpm build
pnpm start  # default :3000

Vercel 以外では /api/cron/dispatch を自分でスケジュールする必要があります — ステップ 5 を参照。

5. cron ワーカーをスケジュール

cron ワーカーは予約通知の dispatch、Webhook 配信の再試行、レート制限テーブルの掃除を行います。約 1 分ごとに動かしてください。認証は CRON_SECRET を Bearer トークンとして渡します。

Vercel の場合: 同梱の vercel.ts がこのスケジュールを宣言しているので、そのままで動作。

Vercel 以外: GitHub Actions、fly.io machines、crontab + curl、Kubernetes CronJob など、お好みのスケジューラで。crontab の例:

* * * * * curl -fsS -H "Authorization: Bearer $CRON_SECRET" \
  https://your-nesh.example.com/api/cron/dispatch

6. 最初のユーザーと管理者

UI からサインアップしてアカウントを作成。Supabase Studio (もしくは SQL) でユーザー UUID を取得し、ADMIN_USER_IDS に追加すると /admin ダッシュボードが解放されます。

運用上の注意

  • プロジェクト作成後は VAPID_KEY_ENCRYPTION_KEY を変更しないでください。DB と一緒にバックアップを取りましょう。ローテーションには projects.vapid_private_key の再暗号化が必要です。
  • 通知のファンアウトは送信ルートのプロセス内で順次実行される実装です (デフォルト上限の 5,000 購読者/プロジェクト程度を想定)。それ以上に伸ばす場合はキューに切り出すことを検討してください。
  • イベント追跡 (shown / clicked) は仕様上、認証なしの公開エンドポイントです (ビーコンは資格情報を送りません)。IP 単位でレート制限済み。
  • サーバーエラーは error_logs に永続化され /admin に出ます。デプロイのデバッグに便利。