小型 VPS 向けセルフホスティングスタック:2 GB と 4 GB の RAM に収まるもの
小型 VPS で現実的に始めるセルフホスティングの基本スタック:Docker Compose、Caddy、Vaultwarden、Uptime Kuma、Forgejo。サービスごとの RAM 予算、バックアップ、セキュリティの基本まで。
結論:2 GB の VPS なら、Docker Compose 上で Caddy(HTTPS リバースプロキシ)、Vaultwarden(パスワード)、Uptime Kuma(監視)、Forgejo(git)というセルフホストの中核を、約 0.6〜1 GB の RAM で余裕をもって動かせます。Nextcloud を加えるなら 4 GB が欲しいところですが、Syncthing や File Browser のような軽量ツールを選べば 2 GB のままでも十分です。
このガイドでは、動作する Compose ファイル、サービスごとの RAM 予算、そして多くのセルフホスト環境が手遅れになるまで後回しにしがちな2つのこと、つまりオフサイトバックアップとネットワーク露出面の封鎖を紹介します。コマンドは、Docker の公式リポジトリから Docker Engine と Compose プラグインをインストールした Debian 12/13 または Ubuntu 24.04 を前提としています。
サービスごとの RAM 予算
数値は、対応している場合は SQLite を使い、1〜5人のユーザーでアイドル〜軽負荷時の典型的な常駐メモリです。アップグレード時、大きなリポジトリの git clone、Nextcloud のプレビュー生成などのピーク時はこれより高くなることがあるので、少なくとも 20% の余裕を残し、1〜2 GB のスワップファイルを追加しましょう。
| サービス | 役割 | 典型的な RAM | 備考 |
|---|---|---|---|
| OS + sshd + journald | ベースシステム | 150〜250 MB | Debian または Ubuntu の最小構成 |
| Docker Engine + containerd | コンテナランタイム | 80〜120 MB | コンテナを使うための固定コスト |
| Caddy | リバースプロキシ、自動 HTTPS | 20〜50 MB | 単一バイナリ、データベース不要 |
| Vaultwarden | Bitwarden 互換のパスワードサーバー | 20〜60 MB | Rust 製、SQLite |
| Uptime Kuma | 稼働状況と証明書の監視 | 100〜200 MB | Node.js 製。モニター数に応じて増加 |
| Forgejo | Git ホスティング、Issue、CI フック | 150〜300 MB | Go 製。小規模チームなら SQLite で十分 |
| Nextcloud + MariaDB + Redis | ファイル、カレンダー、連絡先 | 600 MB〜1.2 GB | PHP-FPM ワーカーが大半を占める |
| Syncthing | ファイル同期、Web スイートなし | 50〜150 MB | Nextcloud の軽量な代替 |
| File Browser | Web ファイルマネージャー | 20〜40 MB | HTTPS でファイルをアップロード・共有 |
| Radicale | CalDAV と CardDAV | 30〜50 MB | Nextcloud なしでカレンダーと連絡先 |
VPS のサイズを選ぶ
中核スタック(Caddy、Vaultwarden、Uptime Kuma、Forgejo)とベースシステムで約 0.6〜1 GB になり、2 vCPU / 2 GB のサーバーに Syncthing と Radicale を加える余裕を残して収まります。MariaDB と Redis を伴う Nextcloud を加えると合計は約 1.5〜2.2 GB に達するので、フルスイートとその他すべてを動かすなら 4 GB が現実的な最低ラインです。ディスクも重要です。Forgejo のリポジトリや同期ファイルは増えていきますが、サービス自体に必要なのは数 GB だけです。
NoctisNode では、Pulse プラン(2 vCPU、2 GB RAM、40 GB NVMe、28日あたり $10)が中核スタックに、Umbra(4 vCPU、4 GB、60 GB NVMe、28日あたり $15)が中核スタック + Nextcloud に適しています。どちらもフル root 権限と専用 IPv4 付きの KVM で、Monero などの暗号資産で支払えます。このガイドの内容はプロバイダーに依存しません。
Docker Compose ファイル
Web ポートを公開するのは Caddy だけで、アプリには内部の Compose ネットワーク経由でしか到達できません。Forgejo は SSH 経由の git 用にポート 2222 も公開するので、ホストの OpenSSH は独自のポートのままです。`.env` ファイルで `FORGEJO_TAG` を Forgejo の現在のメジャーバージョンに設定し、例のドメインを自分の DNS レコードに置き換えてください。
# /srv/stack/compose.yaml
services:
caddy:
image: caddy:2
restart: unless-stopped
ports:
- "80:80"
- "443:443"
- "443:443/udp"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- ./caddy/data:/data
- ./caddy/config:/config
vaultwarden:
image: vaultwarden/server:latest
restart: unless-stopped
environment:
DOMAIN: "https://vault.example.com"
SIGNUPS_ALLOWED: "true" # set to "false" after creating your account
volumes:
- ./vaultwarden:/data
uptime-kuma:
image: louislam/uptime-kuma:2
restart: unless-stopped
volumes:
- ./uptime-kuma:/app/data
forgejo:
image: codeberg.org/forgejo/forgejo:${FORGEJO_TAG}
restart: unless-stopped
environment:
USER_UID: "1000"
USER_GID: "1000"
FORGEJO__service__DISABLE_REGISTRATION: "true"
volumes:
- ./forgejo:/data
ports:
- "2222:22"
# /srv/stack/Caddyfile
# vault.example.com {
# reverse_proxy vaultwarden:80
# }
# status.example.com {
# reverse_proxy uptime-kuma:3001
# }
# git.example.com {
# reverse_proxy forgejo:3000
# }起動する
- 01.初回起動時に Caddy が証明書を取得できるよう、`vault`、`status`、`git` の A(と AAAA)レコードをサーバーの IP に向けます。
- 02.`/srv/stack` を作成して `compose.yaml`、`Caddyfile`、`.env` を置き、`docker compose up -d` を実行します。
- 03.Forgejo の URL を開いてインストーラーを完了します。公開登録は無効なので、インストーラーで最初に作成したアカウントが管理者になります。
- 04.Vaultwarden のアカウントを作成したら、`SIGNUPS_ALLOWED` を `"false"` に設定して再度 `docker compose up -d` を実行します。Argon2 でハッシュ化した `ADMIN_TOKEN` を設定しない限り、管理パネルは無効のままにしておきます。
- 05.Uptime Kuma の管理者ユーザーは起動直後に作成しましょう。作成するまでセットアップページは誰でも開けてしまいます。
- 06.各サービスと証明書の有効期限についてモニターを追加します。同じサーバー上のモニターは自身の障害を報告できないので、できれば別の場所から監視しましょう。
Note · HTTPS は Caddy が自動で処理します。ヘッダー、レート制限、より複雑なルーティングについてはCaddy リバースプロキシガイドを参照してください。
実際に復元できるバックアップ
保存する価値のあるものはすべて `/srv/stack` の下にあります。SQLite データベース、Forgejo のリポジトリ、Caddy の証明書、そして設定です。プロバイダーのスナップショットに頼らず、restic バックアップガイドのとおり、restic で暗号化したオフサイトのコピーを自分で保持しましょう。
サービスが書き込み中にコピーした SQLite ファイルは不整合になることがあります。小型サーバーで最も簡単かつ安全な方法は、バックアップにかかる1分間だけスタックを停止することです。MariaDB 付きの Nextcloud を追加した場合は、restic の実行前に `mariadb-dump` でデータベースをダンプしてください。少なくとも一度は作業用ディレクトリへの復元をテストしましょう。一度も復元したことのないバックアップは、ただの推測にすぎません。
#!/bin/sh
# /usr/local/sbin/stack-backup (run nightly from cron or a systemd timer)
# needs RESTIC_REPOSITORY and RESTIC_PASSWORD_FILE in the environment
cd /srv/stack || exit 1
docker compose stop
rc=0
restic backup /srv/stack --tag stack || rc=$?
docker compose start
[ "$rc" -eq 0 ] || exit "$rc"
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --pruneセキュリティの基本
- ▹SSH:鍵認証のみ、root のパスワードログインなし、必要に応じて非標準ポート。[SSH 強化ガイド](/guides/ssh-hardening)を参照。
- ▹ファイアウォールの注意点:Docker は独自の iptables/nftables チェーンを書き込むため、Docker で公開したポートは `ufw` のルールを迂回します。公開が必要なもの(80、443、2222)だけを公開し、データベースや管理用のポートは決して公開しないこと。
- ▹アップデート:ホストでは `unattended-upgrades` を有効にし、実際に守れるスケジュールで `docker compose pull && docker compose up -d` を実行しましょう。
- ▹登録:Vaultwarden と Forgejo では公開登録をオフにし、代わりにユーザーを招待しましょう。
- ▹ディスク暗号化:`/srv` を[暗号化されたルート](/guides/luks-encrypted-root)に置けば、ディスクイメージをコピーされても何も漏れません。リモートサーバーでは[SSH による LUKS のリモート解錠](/guides/luks-remote-unlock-ssh)を使い、[LUKS2 と LUKS1 の比較](/guides/luks2-vs-luks1)で説明している LUKS2 フォーマットを選びましょう。
- ▹シークレット:`.env` と Vaultwarden のデータディレクトリは root だけが読めるようにします(`chmod 600`/`700`)。
よくある質問
Qセルフホスティングにはどのくらいの RAM が必要ですか?
ACaddy、Vaultwarden、Uptime Kuma、Forgejo からなる中核スタックは、OS と Docker を含めて約 0.6〜1 GB で動くので、2 GB の VPS で十分です。MariaDB と Redis を伴う Nextcloud を加えると、実用上の最低ラインは 4 GB になります。
Q2 GB の VPS で Nextcloud を動かせますか?
A動きますが、他のサービスと並行すると余裕がほとんどなく、プレビュー生成や同期が集中すると遅くなります。2 GB なら、Syncthing と File Browser、Radicale の組み合わせで、わずかなメモリでファイル、カレンダー、連絡先をカバーできます。
QVaultwarden のセルフホストは安全ですか?
AVaultwarden はエンドツーエンドで暗号化された保管庫データしか保存しないため、サーバーが侵害されても平文のパスワードが直接漏れることはありません。登録はオフにし、管理パネルは無効にするかハッシュ化したトークンで保護し、定期的にアップデートし、データディレクトリをバックアップしてください。
Qセルフホストの Docker スタックに最適なリバースプロキシは?
A数行の設定で HTTPS 証明書を自動取得・更新できるので、小規模な構成には Caddy が最も簡単です。Nginx や Traefik も使えますが、より多くの設定が必要です。
Qufw は Docker コンテナを保護しますか?
Aデフォルトでは保護しません。Docker は独自のファイアウォールルールを挿入するため、Docker の `ports:` オプションで公開したポートは ufw を迂回します。公開すべきポートだけを公開してください。