Skip to content
Published on

セルフホスト型デプロイ基盤の選び方 2026 — Coolify・Dokploy・CapRover・Kamal・Openshipを分ける五つの軸

シェア
Authors

はじめに — Openshipが話題になった日、また同じ問いが戻ってきた

GeekNewsにOpenshipが投稿されました。説明はどこか聞き覚えがありながらも野心的です — リポジトリを指定するだけでスタックを検知してコンテナをビルドし、ドメインとTLSを設定し、デプロイまで行う。設定ファイルもパイプラインもYAMLも不要だといいます。Apache 2.0ライセンスで、デスクトップアプリ・Webダッシュボード・CLI・REST APIをすべて提供します。

そしてコメント欄は、いつものように同じ問いに収束します。「Coolifyと何が違うのか」「素直にcomposeを使えばいいのでは」「これ、誰がメンテするのか」。

本稿はその問いに答えるための判断フレームです。機能一覧を並べる比較は役に立ちません。候補のほとんどは同じ機能を謳っていて — Gitプッシュデプロイ、自動TLS、データベース、バックアップ、ログ — 実際に3か月後の後悔を分けるのは、その一覧にはあまり載らない五つの点です。先に結論を言っておくと、本稿の結論は「セルフホスティングのほうがいい」でも「マネージドのほうがいい」でもありません。セルフホスティングは、お金の代わりに注意力を支払う取引であり、その交換レートはチームごとに異なる、ということです。

判断を分ける五つの軸

機能表の代わりに次の五つの問いで候補をふるいにかければ、たいてい二つ以下に絞り込めます。

第一に、コントロールプレーンはどこに住むか。常時起動しているダッシュボードサーバーなのか、それともコマンド実行中だけ存在するローカルCLIなのか。これが「デプロイシステムが落ちたら何が起きるか」を決めます。

第二に、ロールバックは何秒、何個のコマンドで済むか。深夜3時に切り戻す経路がUIボタン一つなのか、以前のイメージタグを探して手動で再デプロイすることなのか、あるいはそもそも手順が文書化すらされていないのか。

第三に、シークレットはどこにどんな形で保存されるか。プラットフォームのデータベースに入るなら、そのデータベースのバックアップとアクセス権限がそのままシークレットのセキュリティ境界になります。

第四に、ノードが一台から複数台に増えたとき何が変わるか。ほとんどのツールが「マルチサーバー対応」とうたいますが、実際には複数台にそれぞれ個別にデプロイすることと、クラスターとして扱うことの間には大きな差があります。

第五に、このツールを使うのに毎月何時間かかるか。これがマネージドPaaSの料金と実際に比較すべき項目です。

コントロールプレーンはどこに住むか

この軸において、候補ははっきりと二つの陣営に分かれます。

常駐コントロールプレーン陣営 — Coolify、Dokploy、CapRover、Openship(サーバーモード)。サーバー上に常にダッシュボードが起動しています。Coolifyの場合、コントロールプレーンがダッシュボード・内部PostgreSQL・Gitウェブフックの受信・デプロイのオーケストレーションを担い、ワーカーノードにはSSHで接続してコンテナを起動します。コントロールプレーン自体は2 vCPU/4GB程度で十分というのが一般的な推奨です。

# Coolifyのインストール — 実行前にスクリプトの中身を読む習慣を勧めます
curl -fsSL https://cdn.coollabs.io/coolify/install.sh -o /tmp/coolify-install.sh
less /tmp/coolify-install.sh
bash /tmp/coolify-install.sh

この陣営の利点は明快です。デプロイする人がバックエンドエンジニアである必要はありません。ログの確認、環境変数の修正、再デプロイがすべてブラウザ上で完結します。ワンクリックのアプリテンプレートで、Postgres・Redis・監視スタックを数分で立ち上げられます。

欠点も同じくらい明快です。独立して故障しうる部品がもう一つ増える、それがコントロールプレーンです。ダッシュボードが落ちても、すでに起動しているアプリは動き続けますが、その状態ではデプロイもロールバックもできません。そしてダッシュボードは攻撃対象にもなります — 2026年にCoolify関連のCVEが報告され、「ダッシュボードを公開インターネットから外し、VPNやIP許可リストの背後に置け」という勧告が繰り返し出されました。セルフホスト型デプロイツールのダッシュボードを0.0.0.0に開けっ放しにするのは、実質的にrootシェルを開けっ放しにするのと同じです。

無常駐陣営 — Kamal 2、そして素のcompose + SSH。コントロールプレーンが存在しません。開発者のノートPCやCIランナーでコマンドを実行している間だけ存在し、終わればサーバーにはコンテナとプロキシだけが残ります。

# config/deploy.yml — Kamal 2
service: app
image: acme/app

servers:
  web:
    - 10.0.0.11
    - 10.0.0.12

proxy:
  ssl: true
  host: app.example.com
  healthcheck:
    path: /up
    interval: 3

registry:
  server: ghcr.io
  username: acme-ci
  password:
    - KAMAL_REGISTRY_PASSWORD

env:
  clear:
    RAILS_ENV: production
  secret:
    - DATABASE_URL
    - SECRET_KEY_BASE

accessories:
  db:
    image: postgres:17
    host: 10.0.0.20
    env:
      secret:
        - POSTGRES_PASSWORD
    directories:
      - data:/var/lib/postgresql/data
kamal setup          # 初回のみ: Dockerのインストール、プロキシの起動、アクセサリの作成
kamal deploy         # ビルド → プッシュ → サーバーごとのローリング入れ替え
kamal app logs -f    # 全サーバーのログをストリーム表示
kamal rollback       # 直前の正常なバージョンに戻す
kamal proxy reboot   # プロキシだけを再起動

Kamal 2はTraefikを取り除き、独自のkamal-proxyを使います。ゼロダウンタイムデプロイのために作られたプロキシなので、新しいコンテナがヘルスチェックを通過するまで待ってからトラフィックを渡す動作がデフォルトです。Rails 8の標準デプロイツールでもあるため、Railsエコシステムでは事実上の標準になっていますが、Dockerイメージを作れさえすれば言語は問いません。

この陣営の利点は、そもそも故障するコントロールプレーンが存在しない、という一点に尽きます。欠点は深夜3時に見るUIがないこと — ログを見るにはSSHかCLIを使うしかなく、チームにターミナルが得意でない人がいれば、その人はデプロイのフローから外れてしまいます。

Openshipは興味深いことに両方のモードを提供しています。デスクトップアプリがローカルのコントロールプレーンとなってSSH経由でデプロイするモードと、サーバーに常駐させてGitプッシュデプロイを受け付けるモードが別々に用意されています。ただし本稿執筆時点の公開バージョンは0.1.x台で、リポジトリ自身も「コアはプロダクション対応、現在も活発に開発中」と表現しています。マルチノードクラスター、プライベートネットワーキング、ビジュアルCI/CDパイプラインは、まだロードマップ上の予定項目、とされています。新規プロジェクトで試してみる価値はありますが、すでに稼働中のサービスを移行する対象とするには時期尚早です。

ロールバックとゼロダウンタイムデプロイの実際

デプロイツールを選ぶとき、人々がもっとも確認をおろそかにし、もっとも頻繁に後悔する項目です。

ゼロダウンタイムデプロイは事実上どの候補も対応しています。方式も似ています — 新しいコンテナを起動し、ヘルスチェックを通過したら、プロキシがトラフィックを渡し、古いコンテナを落とす。Kamalではkamal-proxyが、CoolifyとDokployではTraefik系が、CapRoverではDocker Swarmのローリングアップデートが、OpenshipではOpenResty ベースのエッジが、それぞれその役割を担います。

違いはロールバックに出ます。確認すべきことは三つです。

  • 以前のイメージがサーバーに残っているか。残っていなければロールバックは「レジストリから取り直す」ことになり、レジストリにアクセスできなければロールバック自体が不可能になります。Kamalは以前のコンテナを残しておくため、kamal rollbackが即座に機能します。
  • ロールバックに必要な情報がUIやCLIですぐに見えるか。以前のデプロイのイメージタグを探すためにレジストリのコンソールを漁らなければならないなら、それはロールバック経路がないのと同じです。
  • マイグレーションはどうなるか。これはどのツールも解決してくれません。前方・後方互換のマイグレーションを使い、デプロイとスキーマ変更を切り離すことは、依然としてアプリケーション側の設計問題です。

三つ目が核心です。コンテナのロールバックが30秒で終わっても、スキーマを戻せなければ実際の復旧時間は30秒ではありません。これはツール選定より先に来る決断です。

もう一つ。実際に練習したことのないロールバック機能は、存在しないのと同じです。ステージングでわざと悪いデプロイをして戻す訓練を、四半期に一度はやるべきです。バックアップの復旧も同じです — バックアップが動いているという事実と、実際に復元できるという事実は別物です。

シークレット — もっとも足をすくわれやすい場所

ここで候補ごとの性格の違いがもっとも大きく表れます。

ダッシュボード型ツールは、たいていシークレットを自前のデータベースに保存します。UIから入力し、デプロイ時に環境変数として注入します。手軽ですが、結果としてそのデータベースがシークレットの保管場所になります。確認すべきは三つ — 保存時に暗号化されるか、その暗号化キーはどこにあるか(同じサーバー上にあるなら実質的な保護は限定的です)、ダッシュボードのバックアップにシークレットがそのまま含まれるか。

Kamalは逆方向です。シークレットを自分では保管せず、デプロイ時にローカルで読み込んでコンテナに注入します。.kamal/secretsファイルがその通り道で、このファイル自体はコミットせず、外部のボールトから値を埋めるのが推奨のやり方です。

# .kamal/secrets — 値ではなく「取得方法」を書く
KAMAL_REGISTRY_PASSWORD=$(op read "op://infra/ghcr/token")
DATABASE_URL=$(op read "op://infra/app/database-url")
SECRET_KEY_BASE=$(op read "op://infra/app/secret-key-base")
# CIでは同じ場所をCIシークレットで埋める
# .kamal/secrets.production
KAMAL_REGISTRY_PASSWORD=$KAMAL_REGISTRY_PASSWORD
DATABASE_URL=$DATABASE_URL

この方式の利点は、シークレットの単一の出所がデプロイツールの外に残る、という点です。デプロイ基盤を丸ごと入れ替えても、シークレット管理の仕組みはそのまま残ります。欠点は設定がもう一段階増えることと、ボールトが落ちるとデプロイが止まってしまうことです。

どちらを選ぶにせよ、守るべき最低ラインは同じです。シークレットをイメージに焼き込まないこと、ビルドログに出力させないこと、ローテーション手順を文書に残すこと、そしてデプロイツールのバックアップにシークレットが平文で入っていないか一度は自分の目で確認することです。

候補の比較

ツールコントロールプレーンロールバックシークレットの保存場所マルチノード状態 / ライセンス
Coolify常駐ダッシュボード + SSHワーカーUIで以前のデプロイを選択プラットフォームDBコントロールプレーン1台 + SSHワーカーN台成熟、コミュニティ大 / Apache 2.0
Dokploy常駐ダッシュボード(軽量)UIで以前のデプロイを選択プラットフォームDBDocker Swarmベース活発、Coolifyより軽量 / Apache 2.0
CapRover常駐ダッシュボード以前のイメージタグで再デプロイプラットフォーム設定Docker Swarmネイティブ老舗、安定 / Apache 2.0
Kamal 2なし(CLI実行時のみ)kamal rollbackで即座外部ボールトからデプロイ時に注入サーバーリストに列挙、ローリングデプロイ成熟、Rails 8標準 / MIT
Openshipデスクトップ・サーバー・クラウドから選択ドキュメント上は対応プラットフォーム管理予定項目0.1.x、初期 / Apache 2.0
compose + ランナーなし(CIが実行)自前で実装が必要CIシークレットまたはボールトサーバーごとに個別構成ツールなし、すべて自作

表を一行にまとめるとこうなります。チームにターミナルが苦手な人がいるならダッシュボード型、全員がバックエンドエンジニアならKamalかcompose。この基準一つで、実際の満足度の大半が説明できます。

素のcompose構成も真剣に検討する価値のある選択肢です。サーバーにdocker composeとsystemdユニットを置き、GitHub Actionsのセルフホステッドランナーやウェブフック受信機がgit pull && docker compose up -dを実行する構成です。サービスが一つか二つで、デプロイが週1回程度なら、この構成がもっとも少ない概念でもっとも長持ちします。ただしゼロダウンタイムデプロイとロールバックは自分で作る必要があり、そこを作り込まなければデプロイのたびに数秒間途切れます。その数秒を許容できるかどうかが判断基準です。

払うのはお金ではなく注意力

セルフホスティングの議論でもっともよくある歪みは、コスト比較を料金だけで行うことです。月200ドルのマネージドPaaSと月40ドルのVPSを比べれば、結論は見え見えです。ところがその200ドルには、これまで自分たちがやらずに済んでいた仕事が含まれています。

セルフホスティングに移ると、次のことが自分たちの仕事になります。

  • OSのセキュリティパッチと再起動スケジュール
  • Dockerエンジンとデプロイ基盤自体のアップグレード(そしてアップグレードが壊れたときの復旧)
  • ディスク使用量の管理 — 古いイメージやビルドキャッシュがディスクを埋め尽くし、デプロイが止まることは本当によくあります
  • バックアップのスケジュールと復旧訓練
  • ダッシュボードのアクセス制御、VPNや許可リストの維持
  • 証明書更新失敗時の対応(自動化されていても失敗は起きます)
  • そしてこれらすべてに対するオンコール

時間に換算するとチームによって差はありますが、サービス数個規模で平常時なら月2〜4時間、何かが壊れた月には丸一日かかるというのがよくある範囲です。エンジニアの時間単価をいくらに置くかによって、この計算は簡単に逆転します。

したがって、正直な結論はこうなります。

  • セルフホスティングが有利な場合: インフラを扱えるメンバーがすでにチームにいて、どのみちサーバーが必要で(バックグラウンドワーカー、常駐プロセス、GPU)、データの所在地に関する要件があり、トラフィックに対してマネージドの料金が肥大化している場合。
  • マネージドが有利な場合: チームが小さく製品開発に集中すべきで、トラフィックが予測不能で、オンコールに立てる人がおらず、デプロイが頻繁で、規制上の要件がない場合。
  • 最悪の場合: セルフホスティングに移行したのに、誰も保守を引き受けない場合。これはマネージドより高くつきます — 半年後、誰もアップグレードできないプラットフォームの上でプロダクションが動くことになります。

コンテナランタイムの移行そのものに関する実務的な論点は、DockerからPodmanへの回を参考にしてください。

おわりに — 保守を担う人の名前を先に書いておく

Openshipのような新しいツールが次々と登場する理由は、この問題がまだうまく解決されていないからです。マネージドPaaSの利便性と自分のサーバーに対する統制権を同時に手にしたいという要求は正当であり、Coolify・Dokploy・Kamalはそれぞれ異なる角度からその要求に答えています。

  • 候補を五つの軸でふるいにかけましょう — コントロールプレーンの所在、ロールバック経路、シークレットの置き場所、マルチノード対応、月間の運用時間。機能表はその後です。
  • ダッシュボード型を選ぶなら、ダッシュボードを公開インターネットから外しましょう。VPNかIP許可リストの背後に置くのを基本にしてください。
  • Kamalやcomposeを選ぶなら、ロールバックとログ確認の手順を文書に残しましょう。UIがない分、手順そのものが組織の知識になります。
  • Openshipはまだ0.1.x台です。まずは新規のサイドプロジェクトで試してみて、マルチノードが必要なワークロードはロードマップが実際に実現してから検討するのが妥当です。
  • 導入文書の一行目に、このプラットフォームのアップグレードに責任を持つ人の名前を書いてください。その名前が空欄なら、ツール比較そのものに意味がありません。

セルフホスティングはコストをなくしません。請求書からカレンダーへ移すだけです。

参考資料