レンタルサーバーでPythonのWebフレームワーク「Flask」を使ったアプリケーションを作りたいことはありませんか?通常、Flaskアプリケーションはサーバー上で常時起動するものですが、ロリポップなどの一般的なレンタルサーバーではCGI環境でのみPythonを実行することが可能です。
この記事では、CGI環境でFlaskアプリケーションを動かす方法と、通常のFlask開発環境との違いを解説します。データベースとの連携方法も含め、シンプルなユーザー管理アプリケーションを例に実装してみましょう。
CGI環境とは?
CGI(Common Gateway Interface)は、Webサーバーが外部プログラムと通信するための標準的な方法です。レンタルサーバーではPHPのように常時起動するアプリケーションサーバーを立てられないことが多いため、リクエストごとにPythonスクリプトを起動するCGI方式を使用します。
通常のFlask環境とCGI環境の違い
通常のFlask環境(常時起動する場合)
- アプリケーションサーバー(Gunicorn, uWSGI など)が常時起動
- URLルーティングはFlaskが直接処理
- 開発時は
flask run
コマンドで起動 - リクエストごとにプロセスの起動・終了が発生しない
CGI環境(レンタルサーバーなど)
- リクエストごとにPythonプロセスが起動・終了
- URLルーティングは
.htaccess
で設定 wsgiref.handlers.CGIHandler
を使用- パスのプレフィックスを考慮したリダイレクト設定が必要(ただし、
.htaccess
の設定次第では通常のリダイレクトも可能)
注意事項
ロリポップではCGI利用に関する注意事項があります。ルールを守って利用しましょう。
CGIを利用する前に、ローカル環境で十分にテストしてください。万が一、CGIが暴走してサーバーをダウンさせたり、負荷をかけるようなことがあった場合、以降CGIを利用できなくなります。
高負荷なCGIやPHPを使用したゲーム、Webリングなど、他のサーバーから呼ばれるスクリプトやサーバに過度な負荷をかけるものは禁止されています。詳細は利用規約や禁止事項をご確認ください。詳細はこちら: ロリポップ – CGI利用の注意事項
仮想環境の準備
レンタルサーバーでは、システム全体にパッケージをインストールできないため、Pythonの仮想環境を作成してパッケージをインストールします。
SSH接続が可能なサーバーであれば、以下のようにセットアップします。
# ホームディレクトリに移動
cd ~/web
# 仮想環境を作成
python3 -m venv myenv
# 仮想環境を有効化
source myenv/bin/activate
# 必要なパッケージをインストール
pip install flask mysql-connector-python
# 仮想環境を終了
deactivate
SSH接続ができない場合は、ローカルで仮想環境を作成し、必要なファイルをFTPでアップロードするといった方法もあります。
実装サンプル
今回はロリポップサーバー上でFlaskとMySQLを使った簡単なユーザー管理アプリケーションを作成しました。
ファイル構成
/
├── .htaccess
├── index.cgi
└── templates/
└── index.html
1. .htaccess の設定
まず、すべてのリクエストを index.cgi
に転送するための .htaccess
ファイルを作成します。これにより、「/add」のようなURLを index.cgi
で処理できるようになります。
RewriteEngine On # mod_rewrite を有効化
RewriteCond %{REQUEST_FILENAME} !-f # 実際のファイルが存在しない場合のみ適用
RewriteCond %{REQUEST_FILENAME} !-d # 実際のディレクトリが存在しない場合のみ適用
RewriteRule ^(.*)$ /index.cgi/$1 [QSA,L] # すべてのリクエストを /index.cgi/ に転送(クエリ文字列維持)
2. index.cgi の実装
次に、Flaskアプリケーションの本体となる index.cgi
を作成します。シバン行(最初の行)は、作成した仮想環境内のPythonインタプリタを指定します。
#!/path/to/your/myenv/bin/python3
# -*- coding: utf-8 -*-
import sys
import os
import mysql.connector
from flask import Flask, render_template, request, redirect
from werkzeug.middleware.dispatcher import DispatcherMiddleware
app = Flask(__name__)
# MySQL接続設定
db_config = {
'host': 'mysql.example.com',
'user': 'db_user',
'password': 'db_password',
'database': 'db_name',
}
def get_db_connection():
"""データベース接続を取得"""
return mysql.connector.connect(**db_config)
@app.route('/')
def home():
"""データベースからデータを取得して表示"""
with get_db_connection() as conn:
with conn.cursor(dictionary=True) as cursor:
cursor.execute("SELECT * FROM example_table")
rows = cursor.fetchall()
return render_template('index.html', rows=rows)
@app.route('/add', methods=['POST'])
def add():
"""新しいレコードを追加"""
name = request.form.get('name')
age = request.form.get('age')
if name and age:
with get_db_connection() as conn:
with conn.cursor() as cursor:
cursor.execute("INSERT INTO example_table (name, age) VALUES (%s, %s)", (name, age))
conn.commit()
return redirect('/')
@app.route('/delete', methods=['POST'])
def delete():
"""指定IDのレコードを削除"""
id = request.form.get('id')
if id:
with get_db_connection() as conn:
with conn.cursor() as cursor:
cursor.execute("DELETE FROM example_table WHERE id = %s", (id,))
conn.commit()
return redirect('/')
if __name__ == '__main__':
# CGI環境用の設定(通常のFlaskとは異なる)
from wsgiref.handlers import CGIHandler
application = DispatcherMiddleware(app, {}) # WSGIミドルウェアでアプリをラップ
CGIHandler().run(application) # CGI環境でアプリを実行
3. テンプレートの作成
最後に、フロントエンドとなるHTMLテンプレートを作成します。(templates/index.html)
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ユーザー管理</title>
</head>
<body>
<h1>ユーザー管理システム</h1>
<!-- データ追加フォーム -->
<h2>新しいユーザーを追加</h2>
<form action="/add" method="post">
<div>
<label for="name">名前:</label>
<input type="text" id="name" name="name" required>
</div>
<div>
<label for="age">年齢:</label>
<input type="number" id="age" name="age" required>
</div>
<div>
<button type="submit">追加</button>
</div>
</form>
<h2>ユーザー一覧</h2>
<table border="1">
<thead>
<tr>
<th>ID</th>
<th>名前</th>
<th>年齢</th>
<th>削除</th>
</tr>
</thead>
<tbody>
{% for row in rows %}
<tr>
<td>{{ row.id }}</td>
<td>{{ row.name }}</td>
<td>{{ row.age }}</td>
<td>
<form action="/delete" method="post">
<input type="hidden" name="id" value="{{ row.id }}">
<button type="submit">削除</button>
</form>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</body>
</html>
CGI環境特有のポイント解説
1. シバン行
#!/path/to/your/myenv/bin/python3
この行はCGIスクリプトの先頭に必須です。自分の仮想環境内のPythonインタプリタのパスを指定します。正確なパスはサーバーのディレクトリ構造によって異なりますので、実際の環境に合わせて変更してください。通常のFlaskアプリではこの記述は不要です。
シバン行のパスを確認するには、SSHで接続して以下のコマンドを実行します:
which python3 # システムのPythonのパスを確認
# または
echo $PWD/myenv/bin/python3 # 仮想環境のPythonのパスを確認
2. CGIHandler
if __name__ == '__main__':
from wsgiref.handlers import CGIHandler
application = DispatcherMiddleware(app, {})
CGIHandler().run(application)
通常のFlaskアプリでは、app.run()
で直接起動しますが、CGI環境では wsgiref.handlers.CGIHandler
を使ってWSGIアプリケーションを実行します。また、DispatcherMiddleware
でアプリをラップすることで、URLのパス処理を適切に行います。
3. .htaccessによるURLルーティング
RewriteEngine On # mod_rewrite を有効化
RewriteCond %{REQUEST_FILENAME} !-f # 実際のファイルが存在しない場合のみ適用
RewriteCond %{REQUEST_FILENAME} !-d # 実際のディレクトリが存在しない場合のみ適用
RewriteRule ^(.*)$ /index.cgi/$1 [QSA,L] # すべてのリクエストを /index.cgi/ に転送(クエリ文字列維持)
CGI環境では、リダイレクト先にCGIスクリプト名を含める必要があります
上記のような.htaccess
の設定が適切に行われていれば、通常のFlaskアプリケーションと同じく単純なredirect('/')
でも正常に動作します。これは、.htaccess
のリライトルールが/
へのリクエストを/index.cgi/
に内部的に変換してくれるためです。
4. 実行権限
CGI環境では、スクリプトに実行権限を付与する必要があります。FTPクライアントなどでアップロードした後に、ファイルのパーミッションを 700
に設定しましょう。
* ロリポップは 700
が推奨となっています。
chmod 700 index.cgi
通常のFlaskアプリケーションとの比較コード
参考までに、同じ機能を通常のFlask環境で実装すると以下のようになります。
from flask import Flask, render_template, request, redirect
import mysql.connector
app = Flask(__name__)
# MySQL接続設定
db_config = {
'host': 'mysql.example.com',
'user': 'db_user',
'password': 'db_password',
'database': 'db_name',
}
def get_db_connection():
return mysql.connector.connect(**db_config)
@app.route('/')
def home():
with get_db_connection() as conn:
with conn.cursor(dictionary=True) as cursor:
cursor.execute("SELECT * FROM example_table")
rows = cursor.fetchall()
return render_template('index.html', rows=rows)
@app.route('/add', methods=['POST'])
def add():
name = request.form.get('name')
age = request.form.get('age')
if name and age:
with get_db_connection() as conn:
with conn.cursor() as cursor:
cursor.execute("INSERT INTO example_table (name, age) VALUES (%s, %s)", (name, age))
conn.commit()
return redirect('/')
@app.route('/delete', methods=['POST'])
def delete():
id = request.form.get('id')
if id:
with get_db_connection() as conn:
with conn.cursor() as cursor:
cursor.execute("DELETE FROM example_table WHERE id = %s", (id,))
conn.commit()
return redirect('/')
if __name__ == '__main__':
app.run(debug=True) # 通常環境では app.run() で起動
ご覧の通り、CGI環境と通常環境の違いは主に以下の点です:
- シバン行の有無
- CGIHandlerの使用
.htaccess
によるURLルーティング
そして、適切な.htaccess
設定があれば、リダイレクトの記述も同じにできます。
パフォーマンスの違い
CGI環境では、リクエストごとにPythonプロセスの起動・DB接続の確立・終了が発生するため、通常のFlask環境に比べてパフォーマンスが劣ります。特に以下の点に注意が必要です:
- リクエスト処理が遅くなる傾向がある
- 同時アクセスが多いと負荷が高くなる
- セッション管理にファイルやデータベースの利用が必要
まとめ
CGI環境でもFlaskを使ってWebアプリケーションを作ることは可能ですが、通常の環境とは異なる設定や考慮点があります。本記事で紹介したポイントを押さえれば、レンタルサーバーでもPythonの恩恵を受けたアプリケーション開発が可能です。
ただし、本格的なアプリケーションを開発する場合は、PythonScriptなどのFastCGI対応の環境やVPS、PaaSなどの常時起動可能な環境を検討することをおすすめします。
参考:テーブル構造
今回使用したMySQLのテーブル構造は以下の通りです:
CREATE TABLE example_table (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
age INT NOT NULL
);
この記事が、レンタルサーバーでFlaskアプリケーションを開発する際の参考になれば幸いです。
コメント