2GB VPSで複数サイトを運営する方法:nginx・静的サイト・Dockerの構成例

メモリ2GBのUbuntu VPSで複数サイトを安全に運営するためのnginx構成、ディレクトリ設計、Docker分離、監視とバックアップを解説します。

2GB VPSで複数サイトを運営する方法:nginx・静的サイト・Dockerの構成例のイメージイラスト

この記事でわかること

CPU 2コア・メモリ2GB程度のUbuntu VPSを、1サイト専用ではなく複数の小規模サイトを育てる基盤として使う設計を解説します。

  • 静的サイトとDockerアプリを同居させる構成
  • ドメインごとのnginx設定とディレクトリ分離
  • 2GBでメモリ不足を起こさない優先順位
  • SSH、ファイアウォール、自動更新の初期設定
  • 追加、更新、ロールバック、バックアップの運用方法

前提: Ubuntu Server 24.04 LTS、nginx、公開鍵SSHを想定します。実際に必要な容量はアクセス数とアプリ構成によって変わります。

2GB VPSで複数サイトは運営できるか

静的サイトを中心にすれば十分可能です。静的HTML、CSS、画像はnginxがファイルとして配信するため、サイトごとにPHPやデータベースの常駐プロセスを持つ必要がありません。

一方、複数のWordPress、Javaアプリ、大きなデータベース、ローカルLLMなどを同時に動かすと、2GBはすぐに不足します。重要なのは、すべてをDocker化することではなく、負荷の性質に合わせて配置方法を選ぶことです。

サイト・機能2GB VPSでの方針
ブログ、LP、ポートフォリオ静的HTMLとしてnginxから直接配信
小さなフォームAPIlocalhostで小さなサービスを常駐
管理画面が必要な小規模アプリDockerで1つずつ追加しメモリ上限を設定
WordPress必要なサイトだけ。キャッシュとDB容量を監視
ローカルLLM2GB構成とは分離し、別GPU環境を利用

おすすめ構成

Internet

   ├─ example-a.com ─┐
   ├─ example-b.com ─┼─ nginx :80/:443
   └─ app.example.com┘       │
                             ├─ /srv/www/site-a/current(静的)
                             ├─ /srv/www/site-b/current(静的)
                             └─ 127.0.0.1:9001(Docker/API)

外部へ公開する入口をnginxに集約し、各アプリは127.0.0.1だけで待ち受けます。ファイアウォールで公開するのは、原則としてSSH、HTTP、HTTPSだけです。

nginx公式ドキュメントでも、静的ファイル配信とproxy_passによるリバースプロキシが基本用途として案内されています。

最初に行うUbuntuの保護設定

システムを更新する

sudo apt update
sudo apt upgrade

更新後に/run/reboot-requiredが存在する場合は、サイトを配置する前に再起動しておきます。

SSHを公開鍵認証に限定する

新しい管理ユーザーで公開鍵ログインとsudoが動くことを確認してから、パスワード認証とrootの直接ログインを無効化します。

PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin no

設定変更後は、現在のSSH接続を閉じる前に別ターミナルから再接続テストを行ってください。SSHの基礎はSSHの仕組みと公開鍵認証で解説しています。

UFWで必要なポートだけ許可する

sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enable
sudo ufw status

Ubuntu公式のセキュリティ案内では、更新、最小権限、UFWなどのファイアウォール、SSHによるリモートアクセスが基本項目として挙げられています。

セキュリティ更新を自動化する

sudo apt install unattended-upgrades

Ubuntuではunattended-upgradesがセキュリティ更新を自動適用します。公式ドキュメントによると標準では日次で動作します。ログは/var/log/unattended-upgradesで確認できます。

サイトごとのディレクトリ設計

サイト名とリリースを分けて配置します。

/srv/www/
├── site-a/
│   ├── current -> releases/20260712-1340
│   └── releases/
│       ├── 20260701-1200/
│       └── 20260712-1340/
└── site-b/
    ├── current -> releases/20260710-1800
    └── releases/
        └── 20260710-1800/

この方式には3つの利点があります。

  1. 新しいファイルを転送中でも公開中サイトが変化しない
  2. シンボリックリンクの切替だけで公開できる
  3. 問題があれば前のリリースへすぐ戻せる

Astroなどの静的サイトへ移行する流れは、WordPressからAstroへの移行手順を参照してください。

nginxでドメインを分ける

サイトごとにserverブロックを作り、server_namerootを分けます。

server {
    listen 80;
    listen [::]:80;
    server_name example-a.com www.example-a.com;

    root /srv/www/site-a/current;
    index index.html;

    location / {
        try_files $uri $uri/ =404;
    }
}

2つ目のサイトはserver_namerootを変更した別ファイルとして作成します。設定を反映する前に必ず構文を確認します。

sudo nginx -t
sudo systemctl reload nginx

reloadなら、正常な既存接続を維持したまま新しい設定へ切り替えられます。

Dockerアプリはlocalhostへ閉じる

小さなAPIや管理画面をDockerで動かす場合、次のようにホスト側の待受アドレスを指定します。

services:
  app:
    image: example/app:stable
    restart: unless-stopped
    ports:
      - "127.0.0.1:9001:3000"
    mem_limit: 256m

nginxからのみアクセスさせます。

server {
    listen 443 ssl;
    server_name app.example.com;

    location / {
        proxy_pass http://127.0.0.1:9001;
        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;
    }
}

DockerはUFWとは別にネットワークルールを扱うため、0.0.0.0:9001のような意図しない公開を避けることが重要です。コンテナの管理ポートやデータベースポートを外部へ直接公開しないでください。

2GBでのリソース配分

次の値は上限ではなく、構築時の目安です。実測しながら調整してください。

用途運用上の考え方
nginxと複数静的サイト共通プロセスで配信し、サイトごとの常駐メモリを増やさない
監視・メール・侵入防止必要最小限のサービスだけ常駐
小さなAPIコンテナ最初は128〜256MB程度の上限から検証
小規模DBキャッシュ設定を抑え、バックアップ容量も監視
スワップ緊急時の猶予として使い、常時使用するなら構成を見直す

実際の2GB構成では、nginx、侵入防止、メール送信、小さなフォームAPIを合わせても使用メモリが約400MBに収まる例があります。ただし、アクセス量、OS、各サービスの設定で値は変わります。

TLS証明書をサイトごとに管理する

DNSがVPSを向いた後、Certbotなどでサイトごとの証明書を発行します。

sudo certbot --nginx -d example-a.com -d www.example-a.com

発行後は自動更新タイマーと更新テストを確認します。

systemctl status certbot.timer
sudo certbot renew --dry-run

HTTPをHTTPSへ転送し、HSTSはHTTPSが確実に動作してから追加します。

新しいサイトを追加する手順

  1. ドメインまたはサブドメインを決める
  2. /srv/www/<site>/releasesを作る
  3. 静的ビルドまたはDockerアプリを配置する
  4. localhostまたはIP直打ちで動作確認する
  5. nginx設定を追加してnginx -tを実行する
  6. DNSを設定する
  7. TLS証明書を発行する
  8. 監視とバックアップ対象へ追加する

この順序なら、DNSを設定する前にほとんどの不具合を見つけられます。

日常監視で見る項目

# メモリとスワップ
free -h

# ディスク使用量
df -h

# 負荷とプロセス
uptime
systemctl --failed

# nginx設定とログ
sudo nginx -t
sudo journalctl -u nginx --since today

# Dockerを使う場合
docker stats --no-stream
docker compose ps

ディスク容量だけでなく、ログの増加、Dockerイメージ、古いリリース、バックアップの世代数も確認します。

バックアップ方針

静的サイトの生成元はVPS外にも保存します。Gitリポジトリ、ローカルPC、別ストレージのうち、少なくとも2か所に置きます。

  • サイトのソースコードとMarkdown
  • nginx設定
  • systemdサービス設定
  • お問い合わせ先などの秘密設定
  • Docker Composeと永続ボリューム
  • データベースの定期ダンプ

サーバーのスナップショットだけに依存すると、復元テストや別環境への移行が難しくなります。再構築手順を文書化し、ファイル単位のバックアップも持ってください。

2GBから上位プランへ移る判断基準

  • スワップ使用が常態化している
  • OOM Killerでプロセスが終了する
  • データベースキャッシュを必要以上に削っている
  • バックアップやビルド中に応答が悪化する
  • 動的アプリやWordPressを複数追加したい
  • 障害分離のためサイトを別サーバーへ分けたい

メモリを増やすだけでなく、静的サイトと動的アプリを別インスタンスに分ける方法もあります。収益が出始めたサイトから独立させると、障害範囲と運用コストを管理しやすくなります。

まとめ

2GB VPSで複数サイトを運営する鍵は、静的サイトをnginxから直接配信し、動的機能だけをlocalhostの小さなサービスやDockerへ分離することです。

公開入口をnginxへ集約し、サイトごとのディレクトリ、リリース、ドメイン、ログを分ければ、小さく始めた複数サイトを同じ基盤で育てられます。アクセスや収益が伸びたサイトだけを後から独立させる構成にも移行しやすくなります。

参考資料