【React × Python FastAPI】レンタルサーバー「ColorfulBox」でWebアプリをデプロイする方法

ColorfulBox（カラフルボックス）は、有名なXserver（エックスサーバー）と同様にWordPressを使ったブログ開設によく利用されるレンタルサーバーです。また、**Webアプリのデプロイと公開も可能**です。
共用レンタルサーバーであるためシステムのroot権限がなく、制約が多い部分はあるものの、対応言語やMySQLのセットアップはコントロールパネル（cPanel）上から簡単に行えます。

インフラ周りに慣れていない方でも、フロントエンドやバックエンドの開発が中心であればWebアプリを公開する手段としてColorfulBoxは有力な選択肢になるでしょう。そこで、ここではColorfulBoxを使ったWebアプリ（React × Python FastAPI）のデプロイ・公開方法を紹介します。

## ColorfulBoxの利用環境
### 対応言語
* PHP
* Perl
* Python
* Ruby

### データベース
* MySQL
* SQLite

### Webサーバー
*  LiteSpeed Web Server（Apacheと高い互換性を持つため設定方法が近い）

:::note warn
ColorfulBoxをWebアプリ公開用プラットフォームとして利用する際のデメリットは、技術選択の自由度が限られる点です。具体的には、バックエンドの言語にJavaやGoを使用したり、データベースとしてPostgreSQLを利用したりすることはできません。また、Dockerも利用できないため、より自由度の高いインフラ構築や技術力の向上を目指す場合は、AWSやVPSなどのプラットフォームを検討する方が賢明でしょう。
:::

## React × Python FastAPIのデプロイ方法
### 前提
* 独自ドメインを取得済でドキュメントルートが設定されていること
　
**【参考】ColorfulBox公式_独自ドメインの設定方法**
https://help.colorfulbox.jp/article/original-domain-conf/
　
**ドキュメントルート設定例**
`/home/ユーザー名/public_html/ドメイン名/`
　
* Tera TermでSSH接続できること
※cPanelの`詳細 > Terminal`から作業することもできます
　
* WinSCPでファイルアクセスできること
※cPanelの`ファイル > ファイルマネージャー`から作業することもできます

### 手順１：React Appをデプロイ

#### 1.1. React Appのビルドファイルをドキュメントルートに配置

配置例
<img width="700" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626788/6a0daf91-390d-8cb1-663f-710493695706.png">

これだけでひとまずは自身のドメインにアクセスしたらReact Appが表示されるはずです。

:::note info
React App で使用する環境変数はビルド時に取り込みされるため、デプロイ時に意識する必要はありません。
:::

#### 1.2. .htaccessの配置
`.htaccess`はReact AppをPython FastAPIと連携させる上で必須の設定ファイルとなります。
上記と同様、ドキュメントルートに配置します。

```.htaccess

<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteBase /

  # 静的ファイル (CSS/JS/画像など) が存在する場合は、Apacheがそのまま配信する
  RewriteCond %{REQUEST_FILENAME} -f [OR]
  RewriteCond %{REQUEST_FILENAME} -d
  RewriteRule ^ - [L]

  # それ以外のリクエストは uvicorn が立ち上がっている 127.0.0.1:8000 にプロキシ
  RewriteRule ^api/(.*)$ http://127.0.0.1:8000/api/$1 [P,L]
</IfModule>

```

<img width="700" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626788/990316c8-c5af-7cb1-cb91-f6a5f7610a9e.png">
上記の内容が重要でかつWebアプリによって内容が変わるので説明します。

**[1] URLのリライト対象を定義**
上記の例だと、`https://example.com/api/getItem/`のようなリクエストがあった場合にリライトの対象となります。

**[2] リライト先を定義**
上記の例だと、`https://example.com/api/getItem/`のようなリクエストがあった場合に`http://127.0.0.1:8000/api/getItem/`へリライトされます。

:::note info
Fast APIのSwagger UIを閲覧できるようにしたい場合は下記のようにルールを定義することで可能になります。

    RewriteRule ^fastapi/(.*)$ http://127.0.0.1:8000/$1 [P,L]

このように記述することで`https://example.com/fastapi/docs`へのリクエストが`http://127.0.0.1:8000/docs`へリライトされます。
ただ、Swagger UIは一般に公開すべき情報ではないと思うので推奨はしません。

:::



### 手順２：Python FastAPIをデプロイ

#### 2.1. cPanelにてPython環境のセットアップをする

[1]
<img width="800" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626788/babafd5e-bdda-bd0a-0b9c-7a6563f6fb74.png">

[2]
<img width="800" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626788/91a1303a-ac6b-5887-2580-32e6e8353e90.png">

[3]
<img width="800" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626788/ec00d203-dcbf-a068-21af-dac1b5e9909b.png">

| 項目名 | 入力値 |
|:-:|:-|
| Python version  | 任意のバージョンを指定<br>初期提案のバージョンが古いため注意 |
| Application root | 任意のパスを指定<br>（例：python/public/backend/） |
| Application URL | 不要のため、利用中のドメイン/サブドメインの<br>ドキュメントルートと被らなければどこでも良い |
| Application startup file | 「passenger_wsgi.py」を指定 |
| Application Entry point | 「application」を指定 |

入力ができたら右上の「CREATE」ボタンを押下する。

:::note warn
`Application URL`で指定したルートに`.htaccess`が自動作成されるため注意。
例：`example.com` ▾ `fastapi` を指定した場合
`/home/ユーザー名/public_html/example.com/fastapi/.htaccess`

:::

#### 2.2. Python FastAPIのソースコードをApplication rootに配置

Python環境のセットアップ時にて指定した`Application root`にPython FastAPIを動作させる上で必要なファイルを配置します。この際、必要なライブラリを事前にエクスポートしたファイルも配置しておくと後続の手順が楽になります。

    pip freeze > requirements.txt

配置例
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626788/b8ecaecf-2c3c-b02a-98d0-27e27ffc37cb.png)

#### 2.3. Pythonの環境変数を定義

Python環境のセットアップが完了すると、`Environment variables`のエリアが表示されるようになります。利用する環境変数があればこちらに追加します。
<img width="800" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626788/c88073d8-5e88-4e7c-9967-26e34bc2877d.png">


#### 2.4. Python FastAPIの動作に必要なライブラリをインストールする
ColorfulBoxではPython環境のセットアップをすることでPython仮想環境が作成されるため、アクティブ化コマンドが発行されます。アクティブ化してからインストールする必要があるため、下記コマンドをコピーしてターミナルで実行します。

<img width="800" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626788/59c4c970-7f31-5a2e-02be-06a9e696e1b4.png">

    # 例
    source /home/ユーザー名/virtualenv/python/public/backend/3.11/bin/activate && cd /home/ユーザー名/python/public/backend

    pip install --upgrade pip

    pip install -r requirements.txt



#### 2.5. passenger_wsgi.pyの編集

Python環境の作成によって`passenger_wsgi.py`が自動作成されるため、内容を編集します。
<img width="800" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626788/19a3a6c5-4c41-c627-9c08-9aa442156721.png">

```passenger_wsgi.py

import os
import subprocess

# --- uvicorn をバックグラウンドで起動 ---
# 「二重起動」を防ぐため、環境変数で一度起動したら再度起動しないようにする
if not os.environ.get("UVICORN_RUNNING"):
    os.environ["UVICORN_RUNNING"] = "1"
    subprocess.Popen([
        "/home/ユーザー名/virtualenv/python/public/backend/3.11/bin/uvicorn",  # <-- 仮想環境内の uvicorn 実行パスを指定
        "app.main:app",         # <-- FastAPIアプリ "app/main.py" の中にある "app" オブジェクトを実行
        "--host", "127.0.0.1",  # ローカルでバインド
        "--port", "8000",       # uvicorn がリッスンするポート
    ])

# --- Passenger 用のダミー WSGI アプリ ---
def application(environ, start_response):
    """
    Apache (Passenger) がリクエストを受けたときに呼ばれる。
    実際のリクエスト処理は uvicorn へプロキシ転送するので、
    ここではダミーのレスポンスを返すのみ。
    """
    status = "200 OK"
    headers = [("Content-Type", "text/plain")]
    body = b"Uvicorn is running in the background. Requests are proxied."
    start_response(status, headers)
    return [body]

```
    "/home/ユーザー名/virtualenv/python/public/backend/3.11/bin/uvicorn",  # <-- 仮想環境内
    
上記はセットアップしたPythonのバージョンごとに変わるため注意。

    "app.main:app",         # <-- FastAPIアプリ "app/main.py" の中にある "app" オブジェクトを実行

上記はWebアプリごとに内容が変わるため注意。
`Application root`を基準パスとして、FastAPIを実行する関数の相対パスおよびオブジェクトを指定してください。

これでPython側の設定も完了となります。

### 期待通りに動作しない場合
上記の手順が問題なく完了すればReact AppとPython FastAPIを連携したシステムの運用が可能になります。
ただ、動作しない場合の原因追究は慣れないと難しいため、調査方法と疑うべきポイントも紹介しておきます。

#### stderr.logからPython側のエラーを確認

Python環境をセットアップした際、指定した`Application root`に`stderr.log`が自動作成されているため、Python FastAPIで発生したエラーはこちらから確認することができます。

#### uvicornをタスクキルして手動で起動

```
# 起動中のuvicornのプロセスIDを取得
ps aux | grep uvicorn

# 出力例
user_id 468803  0.2  0.0 1174796 115168 pts/0  Sl   15:22   0:12 /home/user_id/virtualenv/python/public/backend/3.11/bin/python3.11_bin /home/user_id/virtualenv/python/public/backend/3.11/bin/uvicorn app.main:app --host 127.0.0.1 --port 8000

# 出力例をもとにタスクキル
kill 468803

# Python仮想環境をアクティブ化
source /home/ユーザー名/virtualenv/python/public/backend/3.11/bin/activate && cd /home/ユーザー名/python/public/backend

# passenger_wsgi.pyを手動で実行
python passenger_wsgi.py

```

上記手順を行うことで、uvicornの起動にエラーがある場合に詳細なエラー情報を拾うことができます。

#### ブラウザのデベロッパーツールから確認
フロントエンド開発者であればご存じとは思いますが、React App側でrequestやAxiosで送ったリクエストがエラーであった場合のコンソール出力を実装しておくことで、ログからどのようなリクエストが送信されたかを確認することができます。
<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626788/f24d5613-f2e8-46bf-a2dd-74a22dff97ef.png">

:::note warn
環境構築時以外に詳細なログは出力されないようにしておくことを推奨します。
:::

#### ドキュメントルートの.htaccessがPythonセットアップ時に上書きされていないか確認
先述しましたが、Python環境のセットアップ時に指定する`Application URL`の値によって`.htaccess`が特定のパスに自動作成されます。

**例：`example.com` ▾ `fastapi` を指定した場合**
`/home/ユーザー名/public_html/example.com/fastapi/.htaccess`

このパスが取得した独自ドメインのドキュメントルートと合致していると既存の`.htaccess`を上書きしてしまいます。


## 手順３：MySQLのセットアップ（任意）
ColorfulBoxでセットアップするMySQLは外部環境からアクセスすることができないため、cPanelからテーブル作成やSQLの実行を行う必要があります（2025/2時点）
<img width="800" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626788/5574f5dc-2272-452e-b6d2-74b483d56ce6.png">

cPanelのデータベースツール（phpMyAdmin）は割と直感的に利用できますが、ここではデータベースの作成からレコードのインポートまでの手順を紹介します。


#### 3.1. データベースの作成
[1]
<img width="800" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626788/997ab4aa-cc23-4501-b2ee-530d57e736ea.png">
[2]
<img width="800" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626788/378e3016-196c-4753-aa74-59f8cee251f3.png">
データベース名は`ユーザー名_入力値`となります。

また、SQLAlchemyで接続する際のデータベースURLは
`mysql+mysqlconnector://{ユーザー名}:{cPanelのログインパスワード}@{localhost:3306}/{データベース名}`
となります。

#### 3.2. テーブルの作成
[1]
<img width="800" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626788/6603940a-e930-48e3-a91e-b4a3eca08f9a.png">

[2]
下記は筆者がテーブルを作成した例です。
<img width="800" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626788/965454aa-6052-4e52-acb4-031fe342ea05.png">

#### 3.3. レコードの登録
レコードを登録する場合はテーブルの作成と同様にSQLを実行しても良いですが、CSVファイル等からインポートすることも可能です。ここでは参考までにCSVインポートの手順を紹介します。

<img width="800" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626788/0a6f09a2-efd7-48d6-96bb-dabcb91b4300.png">

➀ インポート対象のテーブルを選択
➁ インポートタブを選択
➂ CSVファイルを選択
➃ 「CSV」を選択
➄ ボタン押下

:::note warn
CSVファイルは１行目からレコードとして認識するため、ヘッダレスで用意する必要があります。
:::

## おわりに
ColorfulBoxでWebアプリのデプロイと公開をする方法は調べても見つからず、ChatGPTに色々質問しながらなんとかこの方法にたどり着いた経緯があったので紹介してみました。レンタルサーバーはWordPress以外の情報が少なく、筆者はあまりインフラの知識も無いので苦労しました..同じように苦戦している方のお力になれたら幸いです。

今回紹介する手順は以上となりますが、メールサービスのセットアップとWebアプリとの連携手順も準備ができたら紹介したいと思います。