WordPressブログ用のレンタルサーバーとして人気の「カラフルボックス(ColorfulBox)」ですが、実はPythonのWebアプリケーション(FastAPI)も動かせます。
ただし、共用サーバー(cPanel + LiteSpeed)でFastAPIのようなASGIアプリを動かすのは一筋縄ではいきません。私自身、複数のAPIを運用する中で 404・500・503 と一通りの地雷を踏み抜いて、最終的に「壊れない構成」にたどり着きました。
この記事は、その 安定運用の決定版 です。以前書いた手順から方針を大きく見直し、実際に障害復旧を経て確定した「正解ルート」だけをまとめています。
この記事のポイントを先に一言でいうと、「Passengerにアプリを配信させず、cronでuvicornを起動して、.htaccessでプロキシする」 です。これに尽きます。
環境概要
| 項目 | 内容 |
|---|---|
| サーバー | カラフルボックス 共用サーバー(cPanel / LiteSpeed + Passenger / CloudLinux) |
| Python | 3.11 |
| フレームワーク | FastAPI |
| ASGIサーバー | uvicorn |
| プロセス起動 | cron(死活監視スクリプト) |
| 公開経路 | .htaccess のリバースプロキシ([P]) |
なぜカラフルボックスでFastAPIは難しいのか
cPanelには「Setup Python App」という機能があり、一見すると簡単にPythonアプリを動かせそうに見えます。しかしこの機能は Passenger というWSGI向けの仕組みを使っており、FastAPIのような ASGIアプリケーションには対応していません。
さらに厄介なのが、LiteSpeed環境では Passenger(LSAPI)がプロセスを頻繁に生成・kill するループに入りやすい ことです。「Passengerからuvicornを起動する」という一見スマートな方式は、この環境では不安定で、私の環境では最終的に動きませんでした。
そこで、発想を変えます。Passengerは使わず、次の構成にします。
ブラウザ
↓ fetch /api/myapp/xxx ← 先頭スラッシュの絶対パス
LiteSpeed
↓ public_html/api/myapp/.htaccess のプロキシ($1 を素通し)
uvicorn (127.0.0.1:PORT) ← cron が起動・死活監視
↓
FastAPIPassengerは「登録して仮想環境を作るためだけ」に使い、実際のリクエスト処理はcronで起動したuvicornが担当します。これが結論です。
設計の4原則(ここだけ覚えれば良い)
今回たどり着いた「壊れない構成」は、次の4つに集約されます。
1. uvicornはcronで起動する(Passengerに配信させない)
死活監視スクリプトをcronで5分ごとに回し、落ちていたら起動する。Passenger経由の起動はLSAPIのkillループで不安定なので使わない。
2. main.pyのルートは「/」直下で定義する
@app.get("/health") のように書く。/api/myapp/ という公開URLのプレフィックスは、後述の .htaccess の相対マッチで自然に剥がれるので、アプリ側で付けてはいけない。
3. .htaccessは $1 を素通しでプロキシする
RewriteRule ^(.*)$ http://127.0.0.1:PORT/$1 [P,L]。余計なパスを足さない。
4. 公開ディレクトリには .htaccess だけを置く
public_html/api/myapp/ に main.py や passenger_wsgi.py を置くと、LiteSpeedがPassengerアプリと誤検出して500エラーになる。実行ファイルはアプリ本体側にだけ置く。
ファイル配置
アプリ本体と公開ディレクトリを 明確に分離 します。
/home/[ユーザー名]/
├── api/
│ ├── start_uvicorn.sh # cronで各ポートのuvicornを起動・監視
│ └── myapp/ # ← アプリ本体はこちらだけ
│ ├── main.py # FastAPI(ルートは / 直下)
│ ├── passenger_wsgi.py # 保険(通常は使わない)
│ ├── requirements.txt
│ ├── logs/
│ └── data/
│
└── public_html/api/myapp/ # ← 公開側は .htaccess だけ
└── .htaccessStep 1: cPanelでPython環境を作る
cPanel →「Setup Python App」→ CREATE APPLICATION で仮想環境を作ります。この機能は「venvを作るため」だけに使い、配信はさせません。

| 項目 | 設定値 |
|---|---|
| Python version | 3.11 |
| Application root | api/myapp |
| Application URL | example.com ▾ api/myapp |
| Application startup file | passenger_wsgi.py |
| Application Entry point | application |
作成すると /home/[ユーザー名]/virtualenv/api/myapp/3.11/ に仮想環境ができます。
⚠️ 作成後、このアプリは cPanel 上でRestart・編集しないこと。 操作すると
.htaccessにPassenger設定が再生成され、せっかくのプロキシ構成を上書きして障害が再発します。
Step 2: アプリ本体をアップロード
main.py は ルートを「/」直下 に定義します(/api/ プレフィックスは付けない)。
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
async def root():
return {"status": "ok"}
@app.get("/health")
async def health():
return {"status": "ok"}
# 例:POSTエンドポイント
@app.post("/convert")
async def convert():
...公開URL https://example.com/api/myapp/health は、.htaccess の相対マッチで health だけがuvicornに渡るので、アプリ側は /health で受けるのが正解です。
Step 3: 依存パッケージをインストール
cPanelの「詳細」→「ターミナル」を開き、以下を実行します:
source /home/[ユーザー名]/virtualenv/api/myapp/3.11/bin/activate
cd /home/[ユーザー名]/api/myapp
pip install -r requirements.txt
Step 4: 公開側の .htaccess(プロキシ)
/home/[ユーザー名]/public_html/api/myapp/.htaccess を次の内容にします。WordPressの .htaccess(/gp/.htaccess など)は絶対に触りません(後述の地雷参照)。
# LiteSpeed → uvicorn (port PORT) へのリバースプロキシ
RewriteEngine On
# 実ファイルはそのまま配信
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^ - [L]
# それ以外は uvicorn に素通しでプロキシ
RewriteRule ^(.*)$ http://127.0.0.1:PORT/$1 [P,L]
# プロキシ関連ヘッダー
<IfModule mod_headers.c>
RequestHeader set X-Forwarded-Proto "https"
Header always set Access-Control-Allow-Origin "*"
Header always set Access-Control-Allow-Methods "GET, POST, OPTIONS"
Header always set Access-Control-Allow-Headers "Content-Type"
</IfModule>PORT は他アプリと被らない番号(例:8001、8002…)にします。
ポイントは
http://127.0.0.1:PORT/$1の$1素通し。この.htaccessは/api/myapp/配下にあるため、RewriteRuleのパターンはこのディレクトリからの相対パスにマッチします。/api/myapp/healthなら$1 = healthとなり、http://127.0.0.1:PORT/healthに転送されます。だからmain.py側は/healthで受けるわけです。
Step 5: uvicornをcronで起動する
手動起動(nohup)は サーバー再起動で消える うえ、うっかり多重起動すると後述の503を招きます。死活監視スクリプト+cron で自動化します。
/home/[ユーザー名]/api/start_uvicorn.sh:
#!/bin/bash
# uvicornが動いていなければ起動する(複数アプリ対応・多重起動ガード付き)
# === アプリ1 (port 8001) ===
if ! pgrep -f "uvicorn main:app.*port 8001" > /dev/null; then
cd /home/[ユーザー名]/api/app1
/home/[ユーザー名]/virtualenv/api/app1/3.11/bin/uvicorn main:app
--host 127.0.0.1 --port 8001 --workers 1
>> /home/[ユーザー名]/api/app1/uvicorn.log 2>&1 &
fi
# === アプリ2 (port 8002) ===
if ! pgrep -f "uvicorn main:app.*port 8002" > /dev/null; then
cd /home/[ユーザー名]/api/app2
/home/[ユーザー名]/virtualenv/api/app2/3.11/bin/uvicorn main:app
--host 127.0.0.1 --port 8002 --workers 1
>> /home/[ユーザー名]/api/app2/uvicorn.log 2>&1 &
fipgrep で「既に動いていれば何もしない」ので、cronで何度叩いても多重起動しません。
--workers 1は必須です。 カラフルボックスはプロセス数上限が厳しく、--workers 2以上にするとアカウント全体が503になります(後述)。
手動で一度起動して確認:
bash /home/[ユーザー名]/api/start_uvicorn.sh
sleep 2
ps aux | grep -E "8001|8002" | grep -v grepcronに登録(貼り付け事故を避けるため crontab - 方式を推奨):
crontab - << 'EOF'
MAILTO=""
SHELL="/bin/bash"
*/5 * * * * /home/[ユーザー名]/api/start_uvicorn.sh
EOF
crontab -l動作確認
# ① バックエンド直(uvicornが応答するか)
curl -i http://127.0.0.1:8002/health
# ② 公開経路ごし(← 本番)
curl -i --max-time 10 https://example.com/api/myapp/health②で content-type: application/json のJSON が返れば開通です。server: の表示がLiteSpeedでも、中身がuvicornのJSONならプロキシは正しく貫通しています。
踏んだ地雷と解決策
ここが本題です。私が実際に踏んだものを全部載せます。
地雷1: PassengerはASGIに対応していない
cPanelの「Setup Python App」はWSGI向けのPassengerを使うため、ASGIのFastAPIはそのままでは動きません。cron起動+プロキシで回避します。
地雷2: Passenger経由の起動はkillループで不安定
「passenger_wsgiからuvicornを起動する」方式を試したところ、LiteSpeedのLSAPIがプロセスを生成しては signal: 15 でkillする、を延々繰り返しました。ログにこう出ます。
Child process with pid: xxxxx was killed by signal: 15
packetLen < 0結論:Passengerには配信させず、cronでuvicornを起動する。 これで安定します。
地雷3: 公開側にpasseger_wsgi.py / main.pyを置くと500
public_html/api/myapp/ に実行ファイル(特に passenger_wsgi.py)を置くと、LiteSpeedがPassengerアプリと誤検出し、500 Internal Server Error(Request Timeout) になります。公開側は .htaccess だけにしてください。
地雷4: パスの不一致で404
フロントが /api/myapp/convert を叩くのに、main.py のルートが /api/convert だったり、.htaccess が余計に /api/ を足していたりすると、uvicornが {"detail":"Not Found"} を返します。「main.pyはルート直下」「.htaccessは $1 素通し」 で揃えれば一致します。
地雷5: --workers 2 でアカウント全体が503
--workers 2 で起動したところ、カラフルボックスのプロセス数上限(CloudLinuxのNPROC)に達し、サイト全体が 503 Service Unavailable になりました。共用サーバーでは --workers 1 固定 が鉄則です。
地雷6: 多重起動で503、しかもコマンドすら打てなくなる
手動 nohup の重ね起動やPassengerの暴走でプロセスが溢れると、ps や pkill すら次のエラーで動かなくなります。
bash: fork: リソースが一時的に利用できませんfork自体ができない状態です。この時は fork不要のbash組み込み kill で脱出します。
kill -9 -1 # 自分の全プロセスにSIGKILL(SSHごと切れる=正常)SSHに入り直すとforkできる状態に戻り、サイトも復活します(WordPress等のPHPはuvicorn不要なので、プロセスさえ減れば戻ります)。
地雷7: /gp/(WordPress)の .htaccess に書くと消える・壊す
APIプロキシを WordPressの .htaccess に書くのは厳禁です。理由は2つ。
- WordPress本体・LiteSpeed Cache・セキュリティプラグインが
.htaccessを 自動再生成する際に消される - LiteSpeed環境で
[P]を素で書くと、キャッシュ・書き換えと競合して サイト全体が503 になることがある
プロキシは必ず アプリ専用の公開ディレクトリ側の .htaccess に書きます。
地雷8: ffmpegが見つからない警告
起動時に次の警告が出ることがあります。
RuntimeWarning: Couldn't find ffmpeg or avconv - defaulting to ffmpegこれは音声・動画変換を使う場合のみ影響し、通常のドキュメント変換には無害 です。気になる場合のみ ffmpeg を導入します。
複数アプリを併存させる
ポートを分ければ、1つの共用サーバーで複数のFastAPIアプリを同居できます。
- アプリ1 →
127.0.0.1:8001→/api/app1/ - アプリ2 →
127.0.0.1:8002→/api/app2/
start_uvicorn.sh に各ポートのブロックを並べ、公開側にそれぞれ .htaccess を置くだけ。新しいAPIを足すときは、この型をそのままコピー すれば、同じ轍を踏まずに量産できます。
まとめ
カラフルボックスのような共用サーバーでFastAPIを安定運用するコツは、Passengerと戦わないこと に尽きます。
- Passengerには配信させない → cronでuvicorn起動
main.pyはルート直下、.htaccessは$1素通し- 公開側は
.htaccessだけ、WordPressの.htaccessは触らない --workers 1固定- 503で詰んだら
kill -9 -1で脱出
月額数百円のレンタルサーバーでPython APIを複数運用できるのは、個人開発者にとって大きな武器です。この構成なら、再起動後も自動復帰する「壊れない運用」ができます。
この構成の実例として、Microsoft MarkItDown を使ったファイル変換ツールを作りました。そちらは別記事で紹介しています。
関連記事
MarkItDownで、pptx/docx/pdfを → Markdownに変換するWebツールを作った
WordPressサイトにレンタルサーバー『カラフルボックス』をおすすめする理由【2026年】

