1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【3ステップ】FastAPI本番VPSにLaravelアプリをサブパス配置【作業2日】

Last updated at Posted at 2025-11-24

普段から「ユーザーの課題解決×実務に活かす」意識で個人開発をしています。
今回もその一環として、既存システムを止めずに新機能追加という、業務頻出の構成パターンに取り組みました。


ゴールと背景

もともと、Xserver VPS 上で FastAPI 製の旅行管理アプリ を本番運用していました。

  • https://example.com/
    → FastAPI + Uvicorn で動く旅行管理アプリ

この環境を壊さずに、Laravel を触る練習も兼ねて、シンプルなポモドーロタイマーを同じドメインに追加したい、というのが今回のゴールです。

最終的にはこうなりました:

  • https://example.com/
    → これまで通り FastAPI(既存サービス)
  • https://example.com/pomodoro
    → Laravel 製ポモドーロタイマー(新規)

この記事では、

  • ローカルで Laravel プロジェクトを作るところから
  • VPS へのデプロイ
  • Nginx で FastAPI と Laravel を サブパス単位で振り分ける(リバースプロキシ)

までを、ハマったポイントも含めてメモしておきます。

※ 実際のドメイン名は匿名化のため、この記事では https://example.com として記載しています。


前提環境

  • VPS:Xserver VPS(中身は Ubuntu)

  • 既存サービス:FastAPI + Uvicorn

    • https://example.com/ で稼働中
  • Web サーバ:Nginx

  • 新規アプリ:Laravel 12.x / PHP 8.4

  • ドメイン:例)example.com

    • Let’s Encrypt + Certbot で TLS 設定済み

全体構成イメージ

URL と役割

  • /(ルートパス)

    • → FastAPI(旅行管理アプリ)
  • /pomodoro(サブパス)

    • → Laravel(ポモドーロタイマー)

これを Nginx の設定で振り分けています。

図にするとこんな感じ

  • Nginx がフロントでリクエストを受ける
  • / は Uvicorn で動いている FastAPI へ proxy_pass
  • /pomodoro は PHP-FPM 経由で Laravel に渡す

という「1台の VPS / 1つのドメインで、FastAPI と Laravel をサブパスで共存」という構成です。


Step1:ローカルで Laravel プロジェクト作成〜GitHub へ

まずはローカルで普通に Laravel プロジェクトを作りました。

プロジェクト作成(ローカル)

laravel new laravel-pomodoro
cd laravel-pomodoro

※ 手元では Laravel Installer または composer create-project を使用。

機能はあえて最小限

  • 25分カウント用のタイマー(休憩は手動で管理)
  • スタート/ストップ/リセットのみ
  • 画面は Blade のシンプルな1ページ

あくまで今回は「インフラ+デプロイの経験」が主目的なので、
アプリ機能はかなり絞りました(MVP)。

ルーティング

routes/web.php はこんな感じにしています。

<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\PomodoroController;

Route::get('/', [PomodoroController::class, 'index'])
    ->name('pomodoro.index');

Route::get('/pomodoro', [PomodoroController::class, 'index']);
Route::get('/pomodoro/', [PomodoroController::class, 'index']);
  • / にアクセス → ポモドーロ画面
  • /pomodoro / /pomodoro/ にアクセス → 同じくポモドーロ画面

簡単な Feature テスト

最低限、「トップページが表示されること」だけはテストを書くようにしました。

php artisan test --filter=PomodoroPageTest

テストの中身はざっくり:

  • GET / で 200 が返る
  • タイマー画面の文言が含まれている

くらいのシンプルなものです。

GitHub に公開

最後に GitHub にプッシュしておきます。

git init
git remote add origin https://github.com/ユーザー名/laravel-pomodoro.git
git add .
git commit -m "Initial Laravel pomodoro app"
git push -u origin main

Step2:VPS に Laravel 用の環境を用意する

次に、VPS 側で Laravel を動かす準備をしました。

PHP / PHP-FPM / Composer

Ubuntu 上で以下をインストール。

apt update
apt install -y php php-fpm php-mbstring php-xml php-sqlite3 php-zip php-curl
apt install -y composer

インストール後の確認:

php -v
php-fpm8.4 -v   # バージョンが出ればOK
composer -V

今回は php8.4-fpm が動いている状態です。

Laravel プロジェクトを配置

VPS 上の作業ディレクトリは /var/www にしました。

cd /var/www
git clone https://github.com/ユーザー名/laravel-pomodoro.git
cd laravel-pomodoro

Composer で依存関係インストール(本番向け)

export COMPOSER_ALLOW_SUPERUSER=1
composer install --no-dev --optimize-autoloader

.env とアプリキー

cp .env.example .env
php artisan key:generate

セッションをファイルに変更

デフォルトでは SESSION_DRIVER=database になっていて、
SQLite のファイルが無いとエラーになります。

今回はシンプルなタイマーで、DB にセッションを保存する必要はないため、
.envSESSION_DRIVERfile に変更しました。

SESSION_DRIVER=file

ここを忘れると、本番でこんなエラーになります:

Database file at path [...] does not exist.
Ensure this is an absolute path to the database. (Connection: sqlite)

パーミッション調整

Laravel がログやキャッシュを書き込めるように、最低限の権限を付けます。

chown -R www-data:www-data storage bootstrap/cache
chmod -R ug+rwx storage bootstrap/cache

ここまでで:

  • VPS 上に Laravel プロジェクト配置済み
  • 依存関係も入り
  • .env もセット
  • セッションも file ドライバに変更済み

という状態になりました。


Step3:Nginx で FastAPI と Laravel をサブパスで共存させる

ここが今回のメインであり、一番ハマったところです。

もともとの構成(Before)

もともとは、 example.com は FastAPI だけが動いている構成でした。

  • https://example.com/ → Nginx → Uvicorn(FastAPI)

Nginx の location / で FastAPI に proxy_pass している、よくある構成です。

今回やりたい構成(After)

  • / → 引き続き FastAPI に振り分け
  • /pomodoro → Laravel(PHP-FPM) に振り分け

つまり、同じ Nginx の server ブロックの中で、サブパスごとにバックエンドを変えるイメージです。

Nginx の設定例(サンプル)

/etc/nginx/sites-available/app のイメージはこんな感じです(簡略版):

server {
    listen 443 ssl;
    server_name example.com;

    # Laravel の public をドキュメントルートに
    root /var/www/laravel-pomodoro/public;

    # (証明書まわりは Certbot が入れてくれる想定)
    ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

    # ============================
    #  /pomodoro → Laravel
    # ============================

    # /pomodoro に来たら /pomodoro/ にそろえる
    location = /pomodoro {
        return 302 /pomodoro/;
    }

    # /pomodoro/ 以下は Laravel に任せる
    location /pomodoro/ {
        try_files $uri $uri/ /index.php?$query_string;
    }

    # .php は PHP-FPM に渡す(/index.php を含む)
    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php8.4-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }

    # ============================
    #  / → FastAPI(既存)
    # ============================
    location / {
        proxy_pass http://127.0.0.1:8000;  # Uvicorn(FastAPI)
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

# HTTP から HTTPS へのリダイレクト用(省略可)
server {
    listen 80;
    server_name example.com;
    return 301 https://$host$request_uri;
}

ポイントだけ整理すると:

  • root は Laravel の public ディレクトリに向ける
  • /pomodoro / /pomodoro/ は Laravel の index.php に流す
  • .phplocation はシンプルにして PHP-FPM に渡す
  • / は今まで通り FastAPI に proxy_pass

という形です。


ハマりポイントまとめ(nginx & Laravel 編)

1. index.php がダウンロードされる問題

最初は、 /pomodoro にアクセスすると、なぜか index.php がダウンロードされる現象にハマりました。

原因は:

  • .php を PHP-FPM に渡す location ~ \.php$ よりも、
  • 別の location のほうが優先されていたり、
  • aliasroot の使い方がややこしかったり

という、Nginx の location 優先順位周りでした。

最終的には:

  • root/var/www/laravel-pomodoro/public にして
  • .phplocation をシンプルに書き直す

ことで解決しました。

2. 404 でも「白い画面」と「黒い画面」がある

途中、404 が出ても、

  • 真っ白な 404(Nginx のデフォルトページ)
  • 黒背景の 404(Laravel のエラーページ)

の2種類がありました。

これに気づいてからは、

  • 白い 404 → Nginx までしか届いていない
  • 黒い 404 → Laravel まで届いていて、Laravel 側のルーティング or Controller の問題

と切り分けできるようになり、
「どこまで処理が進んでいるか」を判断するのがだいぶ楽になりました。

3. SQLite のセッションエラー

Laravel 側で「セッションドライバが database のまま」だったため、
本番環境で次のエラーが出ました:

Database file at path [/var/www/laravel-pomodoro/database/database.sqlite] does not exist.

今回はセッションを DB に保存する必要がなかったので、
.envSESSION_DRIVERfile に変えて解決しました。


ローカルでの動かし方(確認用)

最後に、ローカルで動かす場合のメモも残しておきます。

git clone https://github.com/ユーザー名/laravel-pomodoro.git
cd laravel-pomodoro

composer install

cp .env.example .env
php artisan key:generate

# セッションは file ドライバにしておく
# SESSION_DRIVER=file

php artisan serve
# → http://127.0.0.1:8000 でポモドーロ画面が表示されればOK

まとめ & 学び

今回の小さな個人開発で学べたことをまとめると:

  • Laravel プロジェクト作成〜 GitHub 公開〜 VPS デプロイまで、一通りの流れを体験できた
  • FastAPI と Laravel を、1台の VPS / 1つのドメインでサブパス共存させる構成を試せた
  • Nginx の location の優先順位や、root / alias の違い
  • 「Nginx の 404」と「Laravel の 404」の見分け方
  • セッションドライバやパーミッションなど、本番環境ならではのハマりポイント

個人的には、

既存サービスを止めずに、新しいアプリを同じドメイン配下にサクッと生やしてみる

という体験ができたのが一番の収穫でした。

  • まずはシンプルな機能でもいいから本番に載せてみる
  • そのうえで URL 設計やアーキテクチャを見直していく

という流れは、業務でもそのまま応用できるパターンだと思います。


今後の拡張(自分用メモ)

ここから先は、「必ずやる」ではなく、時間と気力があれば試したい候補として残しておきます。

1. 作業ログの保存(後からふり返れるようにする)

  • ポモドーロ開始・終了のタイミングで、

    • 開始時刻
    • 終了時刻
    • タスク名(任意)
  • などを、シンプルなテーブル(例:pomodoro_logs)に記録する

やることイメージ:

  • Laravel の Migration で pomodoro_logs テーブルを作る
  • Controller で「タイマー完了時」に1行 INSERT
  • 後で「今日何ポモやったか」「どのタスクにどれだけ時間を使ったか」を一覧表示

→ 自分の学習ログにもなるし、SQL や集計の練習題材にもできる。

2. 多言語対応(旅行管理アプリと世界観をそろえる)

  • 画面の文言を Blade 直書きではなく、言語ファイルに切り出す

    • resources/lang/ja/pomodoro.php
    • resources/lang/en/pomodoro.php
    • など
  • 画面のどこかに「言語切り替えボタン」を置く
    ?lang=ja / ?lang=en といったクエリや、セッションで管理する

やる場合のゴールイメージ:

  • 日本語・英語(余裕があれば中国語)で画面を切り替え可能
  • 旅行管理アプリの「多言語対応」とストーリー的につながる

3. URL 設計の見直し(アプリが増えたときの整理)

今は:

  • / → 旅行管理アプリ(FastAPI)
  • /pomodoro → Laravel ポモドーロ

というシンプル構成ですが、将来アプリが増えたら:

  • /apps/travel-manager
  • /apps/pomodoro

のように「共通のプレフィックス配下にツール群をまとめる」案もアリかなと考えています。

やる場合のイメージ:

  • 新URL:/apps/pomodoro に Nginx で振り分け
  • 旧URL:/pomodoro は 301 リダイレクトで /apps/pomodoro へ転送
  • README / Qiita には「将来のURL整理案」として追記

→ 実際に URL を変えるかどうかは未定だけど、
 「増えたときどう整理するか」を考えているというメモとして残しておきます。

4. UI のブラッシュアップ(レスポンシブ対応の検討)

  • 今は PC での利用前提のシンプルな1画面

  • 余裕があれば:

    • スマホ幅でボタンサイズを大きくする
    • タイマー表示を中央寄せ&大きめ表示
    • フォントサイズ・余白を見直し

最小でやるなら:

  • CSS で @media (max-width: 768px) の簡単な調整を入れるだけでも、
    モバイルでもストレスなく使える」に一歩近づく。

このあたりは、あくまで「候補リスト」であって、
やる/やらないは時間と優先度を見て決めるつもりです。

今回はまず、

  • 既存 FastAPI 本番環境を壊さないこと
  • サブパス /pomodoro で Laravel を共存させること
  • その過程とハマりポイントを言語化しておくこと

ここまで到達できたので、ひと区切りとしては十分かなと思っています。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?