はじめに
IT資格試験の学習サイト HiDecker を個人開発しています。
PythonのFlaskで作ったWebアプリを本番公開するにあたり、月額0円で運用できる Oracle Cloud Infrastructure(OCI)のAlways Free枠 を選びました。
この記事では、OCIでのVM作成からNginx・gunicorn・SSL・独自ドメイン設定まで、実際にハマったポイントも含めて全手順を解説します。
構成概要
インターネット
↓ HTTPS (443)
Nginx(リバースプロキシ・SSL終端)
↓ HTTP (127.0.0.1:8000)
gunicorn(WSGIサーバ)
↓
Flask アプリ
↓
SQLite(DB)
使用技術
- クラウド: Oracle Cloud Infrastructure(Always Free)
- OS: Ubuntu 24.04
- Webサーバ: Nginx
- WSGIサーバ: gunicorn
- フレームワーク: Python 3.12 + Flask
- DB: SQLite
- SSL: Let's Encrypt(certbot)
- プロセス管理: systemd
- ドメイン: ムームードメイン
1. OCI Always Free枠でVMを作成する
Always Freeで使えるリソース
OCIのAlways Freeは他社の無料枠と比べてかなり太っ腹です:
- Compute: AMD VM(1 OCPU・1GB RAM)×2 または ARM VM(Ampere A1・4 OCPU・24GB RAM)×1
- Block Storage: 200GB
- アウトバウンド通信: 月10TB
Flaskアプリ程度であれば ARM VM(Ampere A1)の1インスタンス で十分です。
VM作成手順
- OCIコンソールにログイン
- 「コンピュート」→「インスタンス」→「インスタンスの作成」
- イメージ:Canonical Ubuntu 24.04
- シェイプ:VM.Standard.A1.Flex(Always Free対象)
- OCPU:1、メモリ:6GB(無料枠内)
- SSHキーをアップロード(または生成)
- 「作成」をクリック
セキュリティリストでポートを開放
デフォルトでは80・443番ポートが閉じているので開放します。
OCIコンソール:「ネットワーキング」→「仮想クラウド・ネットワーク」→「セキュリティ・リスト」→「イングレス・ルールの追加」
| ポート | プロトコル | 用途 |
|---|---|---|
| 22 | TCP | SSH |
| 80 | TCP | HTTP |
| 443 | TCP | HTTPS |
Ubuntuのufwも設定する
OCIのセキュリティリストだけでなく、OS側のファイアウォールも設定が必要です。
sudo ufw allow 22
sudo ufw allow 80
sudo ufw allow 443
sudo ufw enable
2. サーバの初期設定
パッケージを更新する
sudo apt update && sudo apt upgrade -y
pyenvでPython 3.12をインストール
システムのPythonとは別にpyenvで管理します。
# pyenvの依存パッケージ
sudo apt install -y make build-essential libssl-dev zlib1g-dev \
libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm \
libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev \
libffi-dev liblzma-dev git
# pyenvをインストール
curl https://pyenv.run | bash
# ~/.bashrcに追記
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bashrc
echo 'command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(pyenv init -)"' >> ~/.bashrc
source ~/.bashrc
# Python 3.12をインストール
pyenv install 3.12.0
pyenv global 3.12.0
python --version # Python 3.12.0
3. Flaskアプリのセットアップ
アプリをデプロイするディレクトリを作成
mkdir -p ~/productions/myapp
cd ~/productions/myapp
GitHubからクローン
git clone https://github.com/yourname/yourapp.git .
仮想環境を作成して依存パッケージをインストール
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
.envファイルを作成
cat > .env << EOF
SECRET_KEY=your_secret_key_here
DATABASE_URL=sqlite:///instance/app.db
EOF
DBを初期化
flask db upgrade
# または
python -c "from app import create_app, db; app = create_app(); app.app_context().push(); db.create_all()"
4. gunicornでFlaskアプリを起動する
gunicornをインストール
requirements.txt に追加しておきます。
gunicorn
pip install gunicorn
動作確認
.venv/bin/gunicorn --bind 127.0.0.1:8000 "app:create_app()"
別ターミナルで:
curl -I http://127.0.0.1:8000
# HTTP/1.1 200 OK が返ってくればOK
5. systemdでサービス化する
毎回手動で起動するのは大変なので、systemdに登録してサーバ再起動後も自動起動するようにします。
サービスファイルを作成
sudo nano /etc/systemd/system/myapp.service
[Unit]
Description=MyApp Flask Application
After=network.target
[Service]
User=ubuntu
WorkingDirectory=/home/ubuntu/productions/myapp
Environment="PATH=/home/ubuntu/productions/myapp/.venv/bin"
EnvironmentFile=/home/ubuntu/productions/myapp/.env
ExecStart=/home/ubuntu/productions/myapp/.venv/bin/gunicorn \
--workers 2 \
--bind 127.0.0.1:8000 \
--timeout 60 \
"app:create_app()"
Restart=always
[Install]
WantedBy=multi-user.target
サービスを有効化・起動
sudo systemctl daemon-reload
sudo systemctl enable myapp
sudo systemctl start myapp
sudo systemctl status myapp
6. Nginxをインストール・設定する
インストール
sudo apt install -y nginx
Nginxの設定ファイルを作成
sudo nano /etc/nginx/sites-available/myapp
server {
listen 80;
server_name yourdomain.com www.yourdomain.com;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/
sudo nginx -t # 設定ファイルの構文チェック
sudo systemctl reload nginx
7. Let's EncryptでSSL化する
certbotをインストール
sudo apt install -y certbot python3-certbot-nginx
SSL証明書を取得
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com
メールアドレスを入力し、利用規約に同意すると自動でSSL証明書が取得・設定されます。
自動更新を確認
sudo systemctl status certbot.timer
sudo certbot renew --dry-run # 更新テスト
8. 独自ドメインの設定(ムームードメインの場合)
ムームードメインのDNS設定でAレコードを追加します。
| ホスト名 | 種別 | 内容 |
|---|---|---|
| (空欄) | A | OCIのパブリックIP |
| www | A | OCIのパブリックIP |
DNS反映には最大1〜2時間かかります。
9. デプロイのフロー
開発環境でコードを変更した後、本番に反映する手順です。
# 開発環境
git add .
git commit -m "feat: 新機能追加"
git push
# 本番環境
cd ~/productions/myapp
git pull
sudo systemctl restart myapp
ハマったポイントまとめ
① gunicornのワーカーがハングしてタイムアウトする
症状: 504 Gateway Time-out が発生する。
原因: 他の重いプロセスがリソースを消費してgunicornワーカーが応答できなくなる。または開発用の python run.py を起動したまま放置していた。
対策:
- systemdの
--timeoutを60秒以上に設定する - 作業後は必ず
python run.pyをCtrl+Cで終了する -
sudo lsof -i :8000でポートの使用状況を確認する
② ポートが解放されない
症状: [Errno 98] Address already in use
原因: 手動起動したgunicornプロセスが残っている。
対策:
sudo lsof -i :8000 # 使用中のプロセスを確認
sudo kill -9 <PID> # プロセスを強制終了
③ OCIのセキュリティリストだけではポートが開かない
症状: OCIコンソールでポートを開けても外部からアクセスできない。
原因: Ubuntu側のufw(ファイアウォール)でもブロックされている。
対策: OCIのセキュリティリストとUbuntuのufwの両方で設定が必要。
④ certbotのSSL取得に失敗する
症状: Connection refused エラー
原因: ドメインのDNSがまだ反映されていない状態でcertbotを実行した。
対策: DNS反映後(dig yourdomain.com でIPが確認できてから)certbotを実行する。
まとめ
OCI Always Free枠を使えば 月額0円 でFlaskアプリを本番運用できます。
今回紹介した構成(Nginx + gunicorn + systemd + Let's Encrypt)は安定性が高く、個人開発の本番環境として十分です。
実際にこの構成で動いているサイト → HiDecker - IT資格試験問題集
ITパスポート・基本情報技術者・応用情報技術者・情報セキュリティマネジメントの問題を無料で学習できます。よければ使ってみてください!