セルフホスティング(カスタムランナープロジェクト)
自前のランナープロジェクトで api イメージを作り、web フロントエンドまで結線して本番デプロイする手順
このページは、公式の full / slim イメージでは要件を満たせない場合に、自前の ランナープロジェクトを作って本番デプロイする 運用者向けの手順です。具体的には 次のようなケースを想定しています。
- 公式イメージに同梱されない 独自プラグイン(社内 npm レジストリのものなど)を 読み込みたい
- ストレージ / 検索 / メール / レンダラのドライバを 任意の組み合わせ で固定したい
- イメージの依存を必要最小限に絞り、ビルドパイプラインを自社で管理したい
公式イメージ(モノレポ同梱の apps/crowi-runner / apps/crowi-runner-slim から
ビルドするもの)で足りる場合は、インストール の「公式 Docker
イメージのビルド」で十分です。ここではその一歩先、ランナープロジェクトを一から
作る 場合を扱います。
Crowi の本番構成は「api(Hono)+ web(Next.js)+ MongoDB(+ 任意で Redis /
Elasticsearch / S3)」です。@crowi/api は プラグインを同梱しない ため、
どのドライバを使うかはランナープロジェクトが所有します。この前提は
設定 の「プラグインの解決方法」で詳説しています。
全体像
単一ドメイン + リバースプロキシ構成(推奨)の場合、リクエストは次のように 振り分けます。
┌──────────────────────────────┐
ブラウザ ──HTTPS──▶ リバースプロキシ (nginx / Caddy 等)
│ / → web :3000 │
│ /api/* → api :3000 │
│ /collab/* → api :3000 (WS) │
└──────────────────────────────┘
│ │
┌────▼───┐ ┌────▼───┐
│ web │ │ api │──▶ MongoDB / Redis / ...
└────────┘ └────────┘web と api は別コンテナで、いずれもコンテナ内ポート 3000 で待ち受けます。
/collab/* は WebSocket なので、プロキシ側で Upgrade ヘッダの引き渡し を
有効にしてください。
ランナープロジェクトを作る
プロジェクトディレクトリと package.json
任意の場所にディレクトリを作り、@crowi/api と 使いたいプラグイン を依存に
宣言します。下記は S3 ストレージ + Elasticsearch 検索 + PlantUML/KaTeX/emoji
レンダラを使う例です。
{
"name": "my-crowi-runner",
"private": true,
"type": "module",
"scripts": {
"start": "crowi-api"
},
"dependencies": {
"@crowi/api": "2.0.0-alpha.0",
"@crowi/plugin-storage-aws-s3": "2.0.0-alpha.0",
"@crowi/plugin-search-elasticsearch": "2.0.0-alpha.0",
"@crowi/plugin-renderer-plantuml": "2.0.0-alpha.0",
"@crowi/plugin-renderer-katex": "2.0.0-alpha.0",
"@crowi/plugin-renderer-emoji": "2.0.0-alpha.0"
}
}バージョンは 実際に使う Crowi のリリースに揃えてください。@crowi/api と
@crowi/plugin-* は同一バージョンで足並みを揃えるのが安全です(リリースは
linked group として同時にバージョンが上がります)。
暗黙のデフォルトプラグイン(@crowi/plugin-storage-local /
@crowi/plugin-search-mongo / @crowi/plugin-mail-smtp)は宣言しなくても
読み込まれます。ローカルストレージ + MongoDB 検索 + SMTP のままでよければ、
@crowi/api だけを依存にすれば動きます(= slim 相当を自前で組む形)。
crowi.config.json
読み込むプラグインと有効ドライバを宣言します。プラグインごとの設定値(バケット名
や認証情報など)は ここには書かず、起動後に管理画面(/admin/plugins)から
設定します。
{
"plugins": [
"@crowi/plugin-storage-aws-s3",
"@crowi/plugin-search-elasticsearch",
"@crowi/plugin-renderer-plantuml",
"@crowi/plugin-renderer-katex",
"@crowi/plugin-renderer-emoji"
],
"storage": { "driver": "s3" },
"search": { "driver": "elasticsearch" }
}フィールドの意味とドライバ名の対応は 設定 を参照してください。
.env
api が起動時に読む環境変数を用意します。最低限 MONGO_URI、本番では
CROWI_ENCRYPTION_KEY と WS_TOKEN_SECRET を必ず設定してください。
MONGO_URI=mongodb://mongodb:27017/crowi
REDIS_URL=redis://redis:6379 # 複数レプリカ運用では必須
CROWI_ENCRYPTION_KEY=... # openssl rand -base64 32
WS_TOKEN_SECRET=... # 全 api レプリカで同一値にする各変数の意味は 設定 の「環境変数」を参照してください。
WS_TOKEN_SECRET を未設定にするとプロセスごとにランダム生成されます。
単一インスタンスの検証用途なら許容されますが、複数レプリカでは全レプリカで
同一値 にしないと、リアルタイム共同編集の WebSocket 認証が片側で失敗します。
ローカルで起動確認
依存をインストールし、プロジェクトディレクトリを cwd にして 起動します
(process.cwd() が projectDir になる必要があります)。
pnpm install # または npm install
pnpm start # = crowi-api。api がコンテナ内ポート 3000 で待ち受けるapi は起動時にこのプロジェクトの node_modules/ からプラグインを解決します。
プラグインの追加・削除に api の再ビルドは不要 です。
api の Docker イメージを作る
ランナープロジェクトをそのままイメージ化します。公式イメージと同じく、
WORKDIR をランナープロジェクトのルート(= projectDir)にし、
node_modules/@crowi/api/dist/app.js を実行します。
FROM node:24-bookworm-slim
WORKDIR /app
# ランナープロジェクトのマニフェストを先に入れて依存だけ先に解決(キャッシュ効率)
COPY package.json pnpm-lock.yaml* package-lock.json* ./
RUN corepack enable && pnpm install --prod || npm install --omit=dev
# 設定とソースを配置
COPY crowi.config.json ./
# .env はイメージに焼き込まず、コンテナ env / env_file で渡すことを推奨
ENV NODE_ENV=production
ENV PORT=3000
EXPOSE 3000
CMD ["node", "node_modules/@crowi/api/dist/app.js"]社内レジストリのプラグインを使う場合は、pnpm install の前に .npmrc を
COPY してレジストリ / 認証を設定してください。crowi.config.json を
コンテナ外からマウントすれば、再ビルドなしでドライバ選択を差し替えられます
(公式 compose もこの方式です)。
機密値(CROWI_ENCRYPTION_KEY / WS_TOKEN_SECRET など)は イメージに
焼き込まず、デプロイ時のコンテナ環境変数か env_file で渡します。
web フロントエンドを結線する
web は packages/web/Dockerfile からビルドします。ビルド済みの
crowi/crowi-web イメージは 描画専任 の Next サーバで、絶対 API URL を一切
焼き込みません。ブラウザは自分のオリジンの相対パス /api/v2・/files を叩き、
WebSocket URL は window.location から導出します。よって 1 つのイメージが任意の
api 先で動きますが、それらのパスを api へ振る 前段リバースプロキシが必要 です。
web サーバを直接公開して /api の proxy を任せ ない でください。output: 'standalone' では Next の rewrites() proxy 宛先が ビルド時に焼かれ
(CROWI_API_URL を実行時に読まない)、直接公開した web サーバは build 時の既定先に
proxy してしまい api に届きません。前段にリバースプロキシを置いてください。
推奨構成は web と api の前段に 同一オリジン + リバースプロキシ を置く形です。
プロキシの振り分け(/api・/files、およびリアルタイムの /collab・/presence・
/notifications の WebSocket アップグレード)の Caddy / nginx 最小例と、
クロスオリジン・Vercel / PaaS の各バリエーションは
デプロイ構成 にまとめてあります。本番投入前に必ず読んでください。
起動順とヘルスチェック
ミドルウェアを先に起動
MongoDB(必要に応じて Redis / Elasticsearch)を起動し、到達可能にします。
マイグレーションを適用
v1 からのアップグレードや preflight マイグレーションがある場合は、api 起動前に 適用します。詳細は v1 からのアップグレード を参照してください。
api → web の順で起動
api を起動して /api/v2/app/info が 200 を返すことを確認してから、web を起動します。
複数レプリカで運用する場合は、REDIS_URL(セッション / 共同編集の pub/sub)が
必須 で、WS_TOKEN_SECRET を全 api レプリカで同一値にします。詳細は
リアルタイム共同編集 を参照してください。