先日、エックスサーバーのレンタルサーバーにPython(Flask)で開発したWebアプリをデプロイしたので、その方法をメモ。
XServer レンタルサーバーではWSGIは使えないので、CGIHandlerを使ってPythonを起動する方法です。
毎回Python起動 → Flask読み込み → アプリ初期化 というオーバーヘッドが発生するので「遅いけど動く」状態です。今回デプロイしたアプリ用途は、少人数で使用する管理用の小さなツール(API呼び出し)だったので十分実用的と判断しました。
今回のデプロイ環境
- サーバー:XServer レンタルサーバー
 - URL:https://example.com/myapp (ディレクトリ)
 - Python:3.13系
 - フレームワーク:Flask
 
デプロイには、XServer レンタルサーバーへSSH接続が必要となります。SSH接続については以下の記事を参考にしてください。

ディレクトリ構造の準備
アプリを配置するディレクトリを準備しておきます。
アプリURLを https://example.com/myapp としたいので、該当ドメインのドキュメントルートに myapp ディレクトリを作成します。
SSH接続して以下でも作成できます。
# ドメインのドキュメントルートにアプリ用ディレクトリを作成
$ mkdir -p ~/example.com/public_html/myapp今回デプロイするPython(Flask)でつくったWebアプリのディレクトリ構造(※一部)
/home/your-server-id/example.com/public_html/myapp/
├── .env                   # 環境変数
├── .htaccess              # Apache設定(※後述)
├── index.cgi              # CGIエントリーポイント(※後述)
├── app.py                 # Flaskアプリ本体
├── config.py              # 設定ファイル
├── その他Pythonファイル
├── requirements.txt       # 必要なパッケージリスト
├── templates/             # HTMLテンプレート
│   └── upload.html
└── temp/                  # 一時ファイル保存用アプリのファイルたちはFTPクライアントでアップロードします。
# 権限に注意!
chmod 600 .envSSH接続とMinicondaをインストール(初回のみ)
エックスサーバーのレンタルサーバーではroot権限がないため、SSH接続して、ユーザー環境にMinicondaをインストールします。(初回のみの作業です)
SSH接続後、ホームディレクトリで以下を実行します。
# ダウンロード・インストール
$ wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh
$ bash Miniconda3-latest-Linux-x86_64.sh
# Please, press ENTER to continue
# >>> [Enterキーを押します]
# Do you accept the license terms? [yes|no]
# >>> yes
# Miniconda3 will now be installed into this location:
# /home/hogehoge/miniconda3
#
#   - Press ENTER to confirm the location
#   - Press CTRL-C to abort the installation
#   - Or specify a different location below
#
# [/home/hogehoge/miniconda3] >>> yes(場所を変える場合は適宜対応を)
# You can undo this by running `conda init --reverse $SHELL`? [yes|no]
# [no] >>> yesインストールが始まります。途中、いくつか聞かれるので以下のとおり。
- ライセンス規約:yes
 - インストール場所:デフォルトのままEnter
 - 初期化:yes
 
インストールが終了したら、設定の再読み込みを行います。
# 設定の再読み込み
$ source ~/.bashrc
# 以下のように表示されていればOK
(base)[hogehoge@svXXXX ~]$  念のため、以下のコマンドで動作しているか確認してみます。バージョンが出力されれば問題ありません。
(base)[hogehoge@svXXXX ~]$ conda --version
conda 25.7.0
(base)[hogehoge@svXXXX ~]$ python --version
Python 3.13.5仮想環境を作成
配置したいWEBアプリのPythonのバージョンを確認し、仮想環境を作成します。
仮想環境の作成はホームディレクトリ(ルート)で行います。
(ここからは (base)[hogehoge@svXXXX ~]$ を省略します)
conda create -n my_ve_py python=3.13 -ymy_ve_py は仮想環境の名前です(任意)
仮想環境の作成時に以下のようなエラーが出る場合があります。Anacondaの利用規約に同意する必要があるというエラーメッセージです。メッセージ内にあるコマンドをそのまま実行すれば解決します。
CondaToSNonInteractiveError: Terms of Service have not been accepted for the following channels. Please accept or remove them before proceeding:
    - https://repo.anaconda.com/pkgs/main
    - https://repo.anaconda.com/pkgs/r
To accept these channels' Terms of Service, run the following commands:
    conda tos accept --override-channels --channel https://repo.anaconda.com/pkgs/main
    conda tos accept --override-channels --channel https://repo.anaconda.com/pkgs/r
For information on safely removing channels from your conda configuration,
please see the official documentation:
    https://www.anaconda.com/docs/tools/working-with-conda/channels# 利用規約に同意
conda tos accept --override-channels --channel https://repo.anaconda.com/pkgs/main
conda tos accept --override-channels --channel https://repo.anaconda.com/pkgs/r仮想環境をアクティベートし、必要なパッケージのインストールを行います。アプリに必要なパッケージをrequirements.txtにしておくと便利。
# 仮想環境をアクティベート
conda activate my_ve_py
# アプリディレクトリに移動
cd example.com/public_html/myapp
# 必要パッケージのインストール
pip install -r requirements.txt
# パッケージ確認
pip listエックスサーバー用設定ファイルの作成
WEBアプリ動作時(ユーザーがアクセスしたとき)以下のような流れになるように準備します。
ユーザーがhttps://example.com/myapp/ にアクセス
↓
Apache(エックスサーバー)が index.cgi を実行
↓
index.cgi が仮想環境のPythonを直接呼び出し
↓
Flaskアプリが動作.htaccess
# CGI実行を有効化
Options +ExecCGI
AddHandler cgi-script .cgi
# HTTPSリダイレクト
RewriteEngine On
RewriteCond %{HTTPS} !on
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
# 静的ファイル以外をindex.cgiに転送
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /myapp/index.cgi/$1 [QSA,L]
# .envファイルへのアクセス拒否
<Files ".env">
    Order allow,deny
    Deny from all
</Files>13行目のパスはアプリの配置場所に合わせて変更してください。
# 権限を制限
chmod 644 .htaccess仮想環境のPythonを呼び出すindex.cgi
#!/home/your-server-id/miniconda3/envs/my_ve_py/bin/python
# -*- coding: utf-8 -*-
import os
import sys
import traceback
import textwrap
# アプリディレクトリの絶対パスを指定
app_dir = '/home/your-server-id/example.com/public_html/myapp'
sys.path.insert(0, app_dir)
os.chdir(app_dir)
# 環境変数設定
os.environ['FLASK_ENV'] = 'production'
print("Content-Type: text/html; charset=utf-8\n")
try:
    # Flaskアプリをインポート
    from app import app
    # CGIハンドラーを使用
    from wsgiref.handlers import CGIHandler
    
    # アプリ実行
    CGIHandler().run(app)
    
except Exception as e:
    if os.environ.get("FLASK_ENV") == "development":
        # 開発時
        error_html = textwrap.dedent(f"""
            <html>
            <head><title>Error</title></head>
            <body>
                <h1>Error</h1>
                <p>{e}</p>
                <pre>{traceback.format_exc()}</pre>
            </body>
            </html>
        """)
        print(error_html)
    else:
        # 本番
        print("<html><body><h1>Internal Server Error</h1></body></html>")
        # 詳細はログに出す
        sys.stderr.write(traceback.format_exc())- your-server-id:契約サーバーID
 - 1行目のPythonパス:which python で確認したパスを記述
 - 8行目のapp_dir:アプリの実際の絶対パスを指定
 
index.cgi に実行権限を付与しておきます。
chmod +x index.cgiアプリ本体app.pyをCGI環境での実行に対応させる
ローカル開発用のコードをコメントアプト
# app.py の最後の部分
if __name__ == '__main__':
    # CGI環境では以下を実行しない
    pass
    # app.run(debug=True, host='0.0.0.0', port=5000)  # コメントアウトファイルパスの設定
import os
from dotenv import load_dotenv
# 絶対パスで設定
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
UPLOAD_FOLDER = os.path.join(BASE_DIR, 'temp')
# .envファイルの読み込み
load_dotenv(os.path.join(BASE_DIR, '.env'))
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDERこれで、ブラウザでアプリURLにアクセスすると、動作確認できます。
デプロイ後のメンテナンス
アプリの更新方法は、
- ローカルで修正・テスト
 - FTPで変更ファイルをアップロード
 - ブラウザで動作確認
 
SSH接続は不要で、ファイルを上書きするだけで反映されます。
パッケージの追加がある場合
SSH接続し、仮想環境にてパッケージを追加する必要があります。
# SSH接続
# 仮想環境アクティベート
conda activate my_ve_py
# パッケージ追加
pip install new-package
# または requirements.txt更新後
pip install -r requirements.txt