ConoHa VPS×Ubuntu 24.04で挑むWEBサーバー構築記【Laravel+Next.jsモノレポ(5サイト)同居デプロイ&Certbot一括SSL化編】

みなさん、こんにちは!WEB工房しずおかの開発チームです。
[前回の記事(ConoHa VPS×Ubuntu 24.04で挑むWEBサーバー構築記【LNMP+Node.js/pnpm環境構築編】)]では、1台のVPS上で「Laravel + ReactオリジナルCMS」と「Next.js 5サイトのモノレポ構成」を動かすためのミドルウェア(Nginx, PHP 8.3, MySQL 8.0, Node.js 20, pnpm)のセットアップを行いました。
連載第3弾(完結編)となる今回は、いよいよ**「アプリケーションの配置・ビルド」「PM2によるプロセス管理」「Nginxのリバースプロキシ設定」「Certbotによる全ドメインの一括SSL(HTTPS)化」**を一気に進めていきます!
実際に遭遇したTypeScriptの型エラーやPM2のモノレポ特有のハマりどころとその解決策まで、リアルなノウハウを凝縮してお届けします。
1. 全体構成とマルチドメイン設計
今回は、単一のConoHa VPS(IP: 160.251.166.124)上に以下の全6ドメイン(+ www サブドメイン)を紐付け、バックエンドとフロントエンドを連携させます。
| ドメイン / FQDN | 役割 / 内部構成 | 内部ポート / ソケット |
| :--- | :--- | :--- |
| fujisan.kusanagi.city | バックエンド(Laravel 11 + PHP-FPM) | unix:/var/run/php/php8.3-fpm.sock |
| kusanagi.city / www.kusanagi.city | フロントエンド①(Next.js / Turborepo - apps/city) | http://127.0.0.1:3001 |
| kusanagi.systems | フロントエンド②(Next.js / Turborepo - apps/systems) | http://127.0.0.1:3002 |
| kusanagi.design | フロントエンド③(Next.js / Turborepo - apps/design) | http://127.0.0.1:3003 |
| kusanagi.life | フロントエンド④(Next.js / Turborepo - apps/life) | http://127.0.0.1:3004 |
| kusanagi.institute | フロントエンド⑤(Next.js / Turborepo - apps/institute) | http://127.0.0.1:3005 |
2. アプリケーションの配置とビルドエラーの克服
① 共有パッケージ(packages/core)の参照設定
Turborepoによるモノレポ構成では、共通コンポーネントやAPIクライアントを packages/core に集約しています。apps/city 等の各アプリから参照する際、呼び出しパスが自身のアプリ配下(@/...)を向いていると Module not found となるため、共有パッケージからのインポート形式に修正します。
// ❌ 誤り(自身の apps/city 内を探してしまう)
import api from '@/lib/api';
import LexicalContent from '@/components/LexicalContent';
// ⭕️ 正しい記述(モノレポ内の共有パッケージから読み込む)
import { api, LexicalContent } from '@kusanagi/core';
また、各アプリの package.json に "@kusanagi/core": "workspace:*" が指定されていることを確認します。
② ビルド時に発生したTypeScript型エラーの修正
pnpm build(または turbo build)を実行した際、プロダクションビルドの型チェックで発生した2つの大きなエラーの対処法です。
1. Next.js App Router における Metadata の canonical 型エラー
Next.js(App Router)の Metadata 型において、canonical は直下のプロパティではなく alternates の中にネストして定義する仕様になっています。
- エラーログ:
Type error: Object literal may only specify known properties, and 'canonical' does not exist in type 'Metadata'.
// ⭕️ 修正後(apps/city/src/app/articles/[id]/page.tsx)
export async function generateMetadata(): Promise<Metadata> {
return {
title: '...',
description: '...',
alternates: {
canonical: pageUrl, // alternatesの中に配置
},
openGraph: { ... }
};
}
2. Framer Motion のアニメーション型推論エラー
イージング関数などの文字列が単なる string 型と扱われ、Framer Motion側の厳格な Easing 型と衝突してビルドが停止する問題です。
- エラーログ:
Type 'string' is not assignable to type 'Easing | Easing[] | undefined'.
// ⭕️ 修正後(HeroSection.tsx)
import { motion, Variants } from 'framer-motion';
// 明示的に : Variants 型をつけることで厳格な型推論を通す
const itemVariants: Variants = {
hidden: { opacity: 0, y: 20 },
visible: {
opacity: 1,
y: 0,
transition: { duration: 0.8, ease: "easeOut" }
}
};
3. PM2によるNext.jsモノレポのプロセス管理
複数サイトを常時起動・自動再起させるため、プロセス管理ツール PM2 を使用します。
① ERR_PNPM_OTHER_PM_EXPECTED トラブルの回避
pnpm 経由でコマンドを動かそうとした際、ルートの package.json に "packageManager": "npm@..." の記述が残っていると ERR_PNPM_OTHER_PM_EXPECTED でプロセスが即座にクラッシュします。
設定ファイルから packageManager の行を削除するか、pnpm のバージョンを指定し直すことで解決します。
② PM2 起動コマンドの「決定版」
PM2から pnpm --filter ... などのラッパーを経由して起動しようとすると、引数の伝播(-- -p 3001)がうまくいかず Invalid project directory や Command "filter" not found となって失敗します。
【解決策】
各アプリのルートディレクトリ(--cwd)を明示し、node_modules 内の Next.js 実行バイナリを直接叩く方式が最も確実で動作が安定します。
# PM2をグローバルインストール(npm経由が確実)
$ sudo npm install -g pm2
# 各サイトを個別のポートで登録・起動
$ pm2 start /var/www/kusanagi-monorepo/node_modules/next/dist/bin/next --name "kusanagi-city" --cwd /var/www/kusanagi-monorepo/apps/city -- start -p 3001
$ pm2 start /var/www/kusanagi-monorepo/node_modules/next/dist/bin/next --name "kusanagi-systems" --cwd /var/www/kusanagi-monorepo/apps/systems -- start -p 3002
$ pm2 start /var/www/kusanagi-monorepo/node_modules/next/dist/bin/next --name "kusanagi-design" --cwd /var/www/kusanagi-monorepo/apps/design -- start -p 3003
$ pm2 start /var/www/kusanagi-monorepo/node_modules/next/dist/bin/next --name "kusanagi-life" --cwd /var/www/kusanagi-monorepo/apps/life -- start -p 3004
$ pm2 start /var/www/kusanagi-monorepo/node_modules/next/dist/bin/next --name "kusanagi-institute" --cwd /var/www/kusanagi-monorepo/apps/institute -- start -p 3005
# プロセス一覧の確認(全サイト STATUS: online を確認)
$ pm2 status
# サーバー再起動時にも全自動で復元されるよう保存
$ pm2 startup
$ pm2 save
4. Nginx設定&ファイアウォール(UFW)の解放
① アクセス時の「タイムアウト(応答なし)」を解消する
初期状態ではConoHa VPS上の UFW(ファイアウォール)により 80 / 443 番ポートが閉じられており、ブラウザアクセスが無限読み込みになります。
# HTTP (80) および HTTPS (443) の通信を許可
$ sudo ufw allow 80/tcp
$ sudo ufw allow 443/tcp
$ sudo ufw reload
② Nginx設定ファイル(www サブドメインの併記)
/etc/nginx/sites-available/kusanagi.city を作成し、www.kusanagi.city も同一の Next.js アプリへリバースプロキシされるように記述します。
server {
listen 80;
server_name kusanagi.city www.kusanagi.city;
location / {
proxy_pass [http://127.0.0.1:3001](http://127.0.0.1:3001);
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
設定ファイルをシンボリックリンク化し、構文チェックを行って反映します。
$ sudo ln -sf /etc/nginx/sites-available/kusanagi.city /etc/nginx/sites-enabled/
$ sudo nginx -t
$ sudo systemctl reload nginx
5. Certbot(Let's Encrypt)による全ドメイン一括 SSL化
全6ドメイン(および www.kusanagi.city を含む全7FQDN)を一括で HTTPS 化します。
# snap経由で最新のCertbotを導入
$ sudo apt remove certbot -y
$ sudo snap install --classic certbot
$ sudo ln -sf /snap/bin/certbot /usr/bin/certbot
# 全7FQDNを一括指定して証明書発行&Nginx設定の自動更新
$ sudo certbot --nginx \
-d fujisan.kusanagi.city \
-d kusanagi.city \
-d www.kusanagi.city \
-d kusanagi.systems \
-d kusanagi.design \
-d kusanagi.life \
-d kusanagi.institute
実行中の対話画面でメールアドレスの登録や利用規約(Y)に同意すれば、Certbot が Nginx の設定ファイルへ HTTPS(443ポート)設定と http:// ➔ https:// への自動リダイレクト設定をすべて書き加えてくれます。
# 自動更新機能のシミュレーションテスト
$ sudo certbot renew --dry-run
Congratulations, all simulated renewals succeeded と表示されれば、今後のSSL更新も全自動で行われます!
まとめ
全3回の連載を通じて、ConoHa VPS(Ubuntu 24.04)上への 「Laravelバックエンド + Next.jsモノレポ5サイト」 のマルチドメイン同居環境が無事に完成しました!
- インフラ・セキュリティ: 独自SSHポート(8823)運用とUFWによるアクセス制御
- ミドルウェア: LNMP(Nginx, PHP 8.3-FPM, MySQL 8.0)+ Node.js 20/pnpm の構築
- フロントエンド運用: Turborepo のプロダクションビルド&PM2 によるマルチポート並行稼働
- Webサーバー・SSL: Nginx リバースプロキシ&Certbot による全ドメイン一括 SSL化
WEB工房しずおかでは、単一サイトの構築にとどまらず、Laravel×Next.jsのような高度でモダンな構成、モノレポ構成のインフラ設計・パフォーマンス最適化を幅広く承っております。大規模な構成変更やVPS構築でお困りの際は、ぜひお気軽にお問い合わせください!