はじめに — なぜ「1台構成」では限界が来るのか
個人開発やスタートアップの初期段階では、1台のVPSにWebサーバー・アプリケーション・データベースをすべて同居させるのが一般的です。しかしユーザー数が増えると、次のような問題が発生します。
- 1台が落ちたらサービス全停止(単一障害点)
- CPU・メモリが足りないのにスケールアップ(サーバー増強)には限界がある
- アプリのポートがインターネットに直接晒されるため、攻撃対象が広がる
この記事では、VPSとAPIを組み合わせたサービスを安全にスケールさせる基本設計を、初心者向けにわかりやすく解説します。
全体構成図 — 3層アーキテクチャの基本
スケーラブルなサーバー構成の基本は、役割ごとにサーバーを分離することです。
ユーザー
│
▼
┌─────────────────┐
│ ロードバランサー │ ← 外部に公開(80/443のみ)
│ (LB / Gateway) │
└───────┬─────────┘
│ プライベートネットワーク
┌─────┼─────┐
▼ ▼ ▼
┌───┐ ┌───┐ ┌───┐
│ W1│ │ W2│ │ W3│ ← Workerサーバー(外部非公開)
└─┬─┘ └─┬─┘ └─┬─┘
│ │ │
▼ ▼ ▼
┌─────────────────┐
│ データベース │ ← 外部非公開
└─────────────────┘
この構成は大きく3つの層に分かれます。
| 層 | 役割 | 外部公開 |
|---|---|---|
| ①エッジ層 | LB / API Gateway | する(80/443のみ) |
| ②アプリケーション層 | Workerサーバー(APIサーバー) | しない |
| ③データ層 | データベース | しない |
ポイントは、インターネットに直接公開するのはエッジ層だけという点です。WorkerサーバーやDBはプライベートネットワーク内に閉じ込め、外部から直接アクセスできないようにします。
ロードバランサー(LB)の役割
ロードバランサーは「交通整理係」です。ユーザーからのリクエストを受け取り、複数のWorkerサーバーに均等に振り分けます。
LBが担う4つの仕事
| 機能 | 内容 |
|---|---|
| 負荷分散 | リクエストを複数のWorkerに振り分け、1台に負荷が集中するのを防ぐ |
| ヘルスチェック | 各Workerに定期的にリクエストを送り、応答がないサーバーを自動で除外する |
| SSL終端 | HTTPS通信の暗号化・復号をLBで一括処理。Worker側はHTTPだけ扱えばよい |
| セキュリティの壁 | Workerのポートやアドレスを外部に見せない「盾」の役割 |
振り分けアルゴリズム
代表的なものを3つ紹介します。
| 方式 | 仕組み | 向いている場面 |
|---|---|---|
| ラウンドロビン | 順番に1台ずつ割り当て | Workerのスペックが均一な場合 |
| 最小接続数 | 接続数が最も少ないWorkerに割り当て | 処理時間にばらつきがある場合 |
| IPハッシュ | クライアントIPに基づいて同じWorkerに割り当て | セッション維持が必要な場合 |
迷ったらラウンドロビンから始めて問題ありません。多くのケースでは十分に機能します。
Nginxでの設定例
VPSでLBを構築する場合、Nginxが定番です。以下は最小限の設定例です。
# /etc/nginx/conf.d/lb.conf
upstream api_workers {
server 10.0.0.11:3000; # Worker1(プライベートIP)
server 10.0.0.12:3000; # Worker2
server 10.0.0.13:3000; # Worker3
}
server {
listen 443 ssl;
server_name api.example.com;
ssl_certificate /etc/letsencrypt/live/api.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/api.example.com/privkey.pem;
location / {
proxy_pass http://api_workers;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
10.0.0.x はプライベートIPです。外部からはアクセスできず、LBからのみ到達可能です。
API Gateway — LBだけでは足りない理由
LBはリクエストの「振り分け」が主な仕事ですが、実際のAPI運用ではもう少し賢い制御が必要です。ここで登場するのがAPI Gatewayです。
API Gatewayが担う仕事
| 機能 | 具体例 |
|---|---|
| 認証・認可 | JWTトークンやAPIキーの検証をGatewayで一括処理 |
| レート制限 | 1ユーザーあたり毎秒100リクエストまで、のような制限 |
| リクエストルーティング | /users/* → ユーザーサービス、/orders/* → 注文サービスへ振り分け |
| ログ・監視 | 全リクエストのアクセスログを集約 |
| CORS処理 | クロスオリジンの制御をGatewayで統一管理 |
つまりAPI Gatewayは「LBの機能 + アプリケーションレベルの制御」を担う上位概念です。
LBとAPI Gatewayの使い分け
| ロードバランサー | API Gateway | |
|---|---|---|
| 主な役割 | L4/L7の負荷分散 | L7のリクエスト制御・認証・ルーティング |
| 処理レイヤー | TCP/HTTP | HTTP/API |
| 代表ツール | Nginx, HAProxy | Kong, Traefik, APISIX, Nginx + Lua |
| 導入の手軽さ | シンプル | 設定項目が多い |
小規模ならNginx 1台でLBとGateway的な役割を兼任させるのが現実的です。レート制限やIP制限程度ならNginxの標準機能で十分対応できます。規模が大きくなってきたらKongやTraefikの導入を検討しましょう。
Workerサーバーを「隠す」セキュリティ設計
この構成で最も重要なセキュリティ上のポイントは、Workerサーバーのポートを外部に晒さないことです。
なぜ隠すのか
Workerサーバーが外部に公開されていると、以下のリスクがあります。
- ポートスキャンで稼働中のサービスが丸見えになる
- アプリケーションの脆弱性を直接攻撃される
- LBを迂回してアクセスされるため、レート制限や認証が無意味になる
プライベートネットワークの構築方法
主要なVPSプロバイダーはプライベートネットワーク機能を提供しています。
| VPS | 機能名 | 費用 |
|---|---|---|
| ConoHa VPS | ローカルネットワーク | 無料 |
| さくらのVPS | スイッチ | 無料 |
| Vultr | VPC 2.0 | 無料 |
| Linode (Akamai) | VLAN / VPC | 無料 |
プライベートネットワークを使うと、同じデータセンター内のVPS同士が10.x.x.xのようなプライベートIPで通信できます。この通信はインターネットを経由しないため、外部からは到達できません。
ファイアウォール設定(ufwの例)
Workerサーバーでは、外部からのアクセスを遮断し、プライベートネットワーク経由のアクセスのみ許可します。
# Workerサーバーのファイアウォール設定
# デフォルトで外部からの接続を拒否
sudo ufw default deny incoming
sudo ufw default allow outgoing
# SSH(管理用)のみ外部から許可
sudo ufw allow 8022/tcp
# アプリケーションポートはプライベートIPからのみ許可
sudo ufw allow from 10.0.0.0/24 to any port 3000
# 有効化
sudo ufw enable
この設定により、ポート3000(アプリケーション)へはプライベートネットワーク内のLBからしかアクセスできなくなります。
スケールアウトの実践 — Workerを増やす手順
ユーザーが増えてWorkerの負荷が上がったら、サーバーを追加(スケールアウト)します。この構成なら手順はシンプルです。
手順
- 新しいVPSを作成し、プライベートネットワークに参加させる
- アプリケーションをデプロイ(Docker化しておくと楽)
- ファイアウォールを設定(上記のufw設定と同じ)
- LBの設定に新しいWorkerのプライベートIPを追加
- Nginxをリロード(
sudo nginx -s reload)
# LBのupstreamにWorker4を追加するだけ
upstream api_workers {
server 10.0.0.11:3000;
server 10.0.0.12:3000;
server 10.0.0.13:3000;
server 10.0.0.14:3000; # ← 追加
}
ダウンタイムなしでWorkerを追加できるのが、この構成の大きなメリットです。
データベースのボトルネック対策
Workerをいくら増やしても、DBが1台のままではそこがボトルネックになります。段階的に対策しましょう。
| 段階 | 対策 | 効果 |
|---|---|---|
| ① | コネクションプーリング(PgBouncer等) | DB接続数の効率化 |
| ② | リードレプリカの追加 | 読み取りクエリの負荷分散 |
| ③ | Redisによるキャッシュ | 頻繁なクエリをメモリで高速処理 |
| ④ | シャーディング | データを分割して複数DBに分散(大規模向け) |
初心者のうちは①と③から始めるのがおすすめです。リードレプリカはマネージドDB(RDS等)を使えば比較的簡単に導入できます。
運用面のポイント — 監視とログ集約
サーバーが増えると「どのサーバーで何が起きているか」の把握が難しくなります。以下の仕組みを早めに入れておきましょう。
最低限入れておきたいもの
| カテゴリ | ツール例 | 目的 |
|---|---|---|
| 死活監視 | UptimeRobot(無料), Mackerel | サーバーやエンドポイントが落ちたら通知 |
| メトリクス監視 | Prometheus + Grafana | CPU・メモリ・リクエスト数の推移を可視化 |
| ログ集約 | Loki + Grafana, Fluentd | 全サーバーのログを1箇所で検索 |
| アラート | Grafana Alerting, PagerDuty | 閾値超えを検知してSlackやメールに通知 |
特にログ集約は重要です。Worker3台のログを個別にSSHで確認するのは非効率ですし、障害時に原因特定が遅れます。
まとめ — 段階的にスケールする設計指針
最後に、ユーザー数の増加に応じた段階的な設計指針をまとめます。
| 段階 | ユーザー規模(目安) | 構成 |
|---|---|---|
| Phase 1 | 〜数百人 | VPS 1台にすべて同居。まずはサービスを出すことが最優先 |
| Phase 2 | 数百〜数千人 | DBを分離。アプリとDBを別サーバーに |
| Phase 3 | 数千〜数万人 | LB + Worker複数台 + DB。本記事の構成 |
| Phase 4 | 数万人〜 | API Gateway導入、リードレプリカ、キャッシュ層追加 |
大事なのは最初から完璧な構成を目指さないことです。Phase 1でサービスを公開し、ユーザーが増えてきたら段階的にスケールさせる。その判断基準として、本記事の構成パターンを参考にしてください。
VPSの選び方については国内VPS 6社徹底比較も参考にしてください。


コメント