WordPressブログ用のレンタルサーバーとして人気の「カラフルボックス(ColorfulBox)」ですが、実はPythonのWebアプリケーション(FastAPI)も動かせます。

ただし、共用サーバー(cPanel + LiteSpeed)でFastAPIのようなASGIアプリを動かすのは一筋縄ではいきません。私自身、複数のAPIを運用する中で 404・500・503 と一通りの地雷を踏み抜いて、最終的に「壊れない構成」にたどり着きました。

この記事は、その 安定運用の決定版 です。以前書いた手順から方針を大きく見直し、実際に障害復旧を経て確定した「正解ルート」だけをまとめています。

この記事のポイントを先に一言でいうと、「Passengerにアプリを配信させず、cronでuvicornを起動して、.htaccessでプロキシする」 です。これに尽きます。


    環境概要

    項目内容
    サーバーカラフルボックス 共用サーバー(cPanel / LiteSpeed + Passenger / CloudLinux)
    Python3.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 が起動・死活監視
      ↓
    FastAPI

    Passengerは「登録して仮想環境を作るためだけ」に使い、実際のリクエスト処理は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.pypassenger_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 だけ
        └── .htaccess

    Step 1: cPanelでPython環境を作る

    cPanel →「Setup Python App」→ CREATE APPLICATION で仮想環境を作ります。この機能は「venvを作るため」だけに使い、配信はさせません。

    項目設定値
    Python version3.11
    Application rootapi/myapp
    Application URLexample.comapi/myapp
    Application startup filepassenger_wsgi.py
    Application Entry pointapplication

    作成すると /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 &
    fi

    pgrep で「既に動いていれば何もしない」ので、cronで何度叩いても多重起動しません。

    --workers 1 は必須です。 カラフルボックスはプロセス数上限が厳しく、--workers 2 以上にするとアカウント全体が503になります(後述)。

    手動で一度起動して確認:

    bash /home/[ユーザー名]/api/start_uvicorn.sh
    sleep 2
    ps aux | grep -E "8001|8002" | grep -v grep

    cronに登録(貼り付け事故を避けるため 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の暴走でプロセスが溢れると、pspkill すら次のエラーで動かなくなります。

    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ツールを作った Microsoft製ライブラリ「MarkItDown」を使い、PowerPoint・Word・Excel・PDFなどをドラッグ&ドロップだけでMarkdownに変換できるWebツールを作りました。ChatGPTやClaudeにドキュメントを渡す前処理に最適。対...  続きを読む WordPressサイトにレンタルサーバー『カラフルボックス』をおすすめする理由【2026年】 セキュリティ・コスパ・アップロード上限・Python対応まで、カラフルボックスをWordPressサイトにおすすめする5つの理由を解説。エックスサーバー・ConoHa WING・さくら・ロリポップとの比較つき。  続きを読む

    参考リンク