Crowi
運用

セルフホスティング(カスタムランナープロジェクト)

自前のランナープロジェクトで 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 / ...
                              └────────┘   └────────┘

webapi は別コンテナで、いずれもコンテナ内ポート 3000 で待ち受けます。 /collab/* は WebSocket なので、プロキシ側で Upgrade ヘッダの引き渡し を 有効にしてください。

ランナープロジェクトを作る

プロジェクトディレクトリと package.json

任意の場所にディレクトリを作り、@crowi/api使いたいプラグイン を依存に 宣言します。下記は S3 ストレージ + Elasticsearch 検索 + PlantUML/KaTeX/emoji レンダラを使う例です。

package.json
{
  "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)から 設定します。

crowi.config.json
{
  "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_KEYWS_TOKEN_SECRET を必ず設定してください。

.env
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 を実行します。

Dockerfile
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 レプリカで同一値にします。詳細は リアルタイム共同編集 を参照してください。

次のステップ

On this page