DockerでCoolifyを構築:自宅ラボでHerokuやVercelを代替するセルフホストPaaS環境を作る

HomeLab tutorial - IT technology blog
HomeLab tutorial - IT technology blog

午前2時13分、Vercelからの請求アラートでスマートフォンが震えました。不具合によるWebhookのリトライループが14万秒ものサーバーレス実行時間を消費し、予期せぬ180ドルのプランアップグレードが発生していたのです。冷めたコーヒーを片手に画面を見つめながら、私はもう潮時だと悟りました。自宅に遊休マシンが転がっているのに、実験的な個人開発プロジェクトやステージング環境のために商用SaaSの高額な料金を支払うなどナンセンスです。その日の朝、私はすべてのアプリ環境をホームラックの古いDell OptiPlexへ移行しました。

理不尽な利用制限や毎月の予期せぬ請求にうんざりしているなら、Coolifyこそがその解決策になります。Coolifyは、あらゆるLinuxマシンをモダンなPaaS(Platform-as-a-Service)へと変貌させるオープンソースのセルフホスト型デプロイエンジンです。いわば「プライベート版Heroku」であり、Gitプッシュによる自動デプロイ、Let’s EncryptによるSSL証明書の自動取得、クリック操作でのデータベース構築、プルリクエストごとのプレビュー環境など、すべてを手元のハードウェア上で実現できます。

クイックスタート(5分)

Coolifyの立ち上げは、コーヒーを淹れるよりも短い時間で完了します。ハードウェアとしては、Intel i5-8500、16 GBのRAM、256 GBのNVMe SSDを搭載した古いミニPCが1台あれば、数十個の軽量サービスを余裕で稼働させられます。Coolifyの前提条件は、Ubuntu 22.04/24.04 LTSまたはDebian 12のクリーンインストール環境、最低2 vCPUコア、2 GBのメモリ、そしてroot権限です。

まず、パッケージキャッシュを更新し、必要なネットワークユーティリティをインストールします:

sudo apt update && sudo apt install -y curl ufw

インストーラーを実行する前に、ファイアウォールのポートを開放しておきます。Coolifyには、ポート22(SSH)、ポート80(HTTP検証およびリダイレクト用)、ポート443(HTTPSトラフィック)、およびメインのWebダッシュボード用であるポート8000が必要です:

sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow 8000/tcp
sudo ufw enable

続いて公式のブートストラップスクリプトを取得して実行します。このスクリプトはCPUアーキテクチャ(x86_64またはARM64)を自動判別し、未導入であればDocker EngineおよびComposeプラグインをインストールした上で、Coolifyのコアコンテナ群を起動します:

curl -fsSL https://cdn.coolify.io/install.sh | bash

スクリプトの処理は約2分で完了します。ターミナルにASCIIアートのバナーが表示されたら、ブラウザを開いてサーバーのローカルIPアドレスにアクセスしてください:

http://192.168.1.150:8000

初期画面で管理者アカウントを作成すれば、あなた専用のプライベートクラウドエンジンが稼働開始し、最初のリポジトリを受け入れる準備が整います。

仕組みを深掘り:Coolifyはどのようにトラフィックを制御しているのか

PortainerやYachtは、素のDockerコンテナを操作するためのグラフィカルなダッシュボードに過ぎません。しかしCoolifyの動作原理は根本から異なります。Coolifyは自動化されたCI/CDパイプライン兼トラフィックディレクターとして機能し、内部のTraefikプロキシをDockerのイベントソケット(/var/run/docker.sock)に直接接続しています。

デプロイがトリガーされるたびに、Coolifyは次のような洗練されたビルドサイクルを実行します:

  • ビルド構成の自動検出: リポジトリのルートディレクトリを走査します。Dockerfileやdocker-compose.ymlが存在する場合はそれを直接使用します。見つからない場合はNixpacksを呼び出してpackage.json、go.mod、Cargo.tomlなどの定義ファイルを解析し、アプリケーションを軽量なマルチステージのプロダクション用イメージへと自動パッケージングします。
  • リバースプロキシへの登録: 独立したDockerブリッジネットワーク(coolify-infraなど)上でコンテナが立ち上がると、Traefikがそのコンテナに付与されたDockerラベルを読み取ります。Nginxの設定ファイルを手動で書いたりデーモンをリロードしたりすることなく、ドメイン宛てのトラフィックのプロキシ処理が即座に開始されます。
  • SSLハンドシェイク: 完全修飾ドメイン名(FQDN)がサーバーのパブリックIPを向いていれば、TraefikがACMEチャレンジを実行し、約15秒以内に無料のLet’s Encrypt TLS証明書を自動取得・適用します。
  • ステートの保持: 環境変数、ビルドログ、チームの権限情報などは内部のPostgreSQLコンテナ内に保存され、すべてのデータはホストマシンの/data/coolifyディレクトリへ永続化されます。

このパイプライン構造を把握すれば、コンテナホスティングの全容がクリアになります。コミットがどのようにルーティング済みのネットワークコンテナへと変換されるかを理解できれば、特定のプロプライエタリなクラウドプラットフォームの制約に依存する必要はなくなります。

実践的な応用

ダッシュボードを立ち上げるのは第一段階に過ぎません。Coolifyの真価は、Gitと連携した全自動デプロイとプライベートデータベースの構築にあります。

Git Webhookを連携したプッシュデプロイの設定

Vercelのような直感的な開発フローを再現するために、GitHubまたはGitLabアカウントを連携します。Sources > Add Source > GitHub Appへ進み、OAuthのインストールウィザードに従ってください。Webhookの権限を設定し、対象のリポジトリとデプロイブランチ(mainやproductionなど)を選択します。

次に、機密情報をソースコードから分離するため、Environment Variablesタブで本番用の環境変数を定義します:

NODE_ENV=production
DATABASE_URL=postgresql://app_user:sUp3rS3cr3t@postgres-db:5432/production_app
PORT=3000

以降はmainブランチへプッシュするたびに、新しいコンテナイメージのビルド、ヘルスチェックの実行、プロキシ接続先の切り替え、古いインスタンスの停止が完全なゼロダウンタイムで実行されます。

1クリックでプライベートデータベースを構築

複雑なDocker Composeファイルを手作業で記述してデータベース環境を構築する手間はもう不要です。CoolifyならPostgreSQL 16、Redis 7、MySQL 8、MongoDBなどを1クリックで立ち上げられます。すべてのデータベースはデフォルトで隔離されたプライベートDockerネットワーク内に配置されます。リモートデバッグのために外部ポートフォワーディングを明示的に有効化しない限り、生のDBポートがパブリックインターネットに露出することはありません。

Cloudflare TunnelによるCGNATの回避

大半の一般的な家庭用インターネット回線は、CGNAT(キャリアグレードNAT)や変動する動的IP環境下にあります。また、自宅のルーターでポート80や443をインターネットへ直接開放することはセキュリティ上の大きな懸念点です。より安全でスマートな解決策は、Coolifyと軽量なCloudflare Tunnelコンテナを組み合わせることです。ワイルドカードDNSレコードをTraefik内部のインポートへ直接ルーティングさせます:

# cloudflaredのconfig.ymlの設定例
ingress:
  - hostname: "*.lab.example.com"
    service: http://localhost:80
  - service: http_status:404

Coolify側でapi.lab.example.comのようなアプリケーションドメインを設定すると、WebトラフィックはCloudflareのエッジネットワークを経由し、アウトバウンドのみのトンネルを通ってコンテナへ直接ルーティングされます。自宅のグローバルIPを隠蔽でき、ルーターのポートフォワーディングを設定する必要も一切ありません。

実践的な運用・メンテナンスのポイント

セルフホストを行うということは、あなた自身がSRE(サイト信頼性エンジニア)になることを意味します。PaaS環境を安定稼働させ続けるための運用プラクティスをいくつか紹介します:

1. ディスク容量枯渇を防ぐ週次Docker Pruneのスケジュール化

継続的なビルドを繰り返していると、タグなしイメージやビルドキャッシュの残骸、孤立したボリュームが急速に蓄積していきます。ホストのルートパーティションが容量100%に達すると、CoolifyのPostgreSQL内部データベースがロックしたり、WAL(ログ先行書き込み)が破損したりするリスクがあります。rootのcronジョブを設定し、キャッシュの定期クリーンアップを自動化しましょう:

# /etc/crontabに追加: 毎週日曜日の午前3時に不要なビルドアーティファクトを一括削除
0 3 * * 0 root docker system prune -af --volumes

2. /data/coolifyの自動バックアップ

すべてのサーバー定義、暗号化された環境変数、プロジェクトスキーマは/data/coolify配下に集約されています。RcloneやResticを使用して、このディレクトリのスナップショットを毎晩ネットワーク共有(NAS)や外部のS3互換バケットへバックアップしてください:

sudo rclone sync /data/coolify/ b2-storage:my-coolify-backups/ --fast-list

3. コンテナへの厳格なメモリ上限の設定

Node.jsの単一のメモリリークや暴走したワーカースレッドが原因でホストの全メモリが食いつぶされると、LinuxのOOM(Out-Of-Memory)キラーが発動します。もしOOMキラーがCoolifyのオーケストレーションエンジンやTraefikプロキシを停止させてしまうと、環境全体のサービスがダウンしてしまいます。各アプリケーションのResources設定から、512MBや1024MBなどのハードリミットを必ず設定しておきましょう。異常を起こしたコンテナ単体がクラッシュ&再起動するだけで済むよう隔離し、サーバー全体への巻き添えを防ぎます。

Coolifyは、ローレベルなDocker Composeファイルの運用負担と、高額なマネージドクラウドの間にある「最も美味しいスイートスポット」を突いたツールです。デプロイ環境の主導権を自分の手に取り戻すことで、完全に自分自身のルールで制御できる高信頼なデリバリーパイプラインが手に入ります。

Share: