1
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Oracle Cloud無料枠(Always Free)にFlaskアプリを本番デプロイした全手順

1
Posted at

はじめに

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作成手順

  1. OCIコンソールにログイン
  2. 「コンピュート」→「インスタンス」→「インスタンスの作成」
  3. イメージ:Canonical Ubuntu 24.04
  4. シェイプ:VM.Standard.A1.Flex(Always Free対象)
    • OCPU:1、メモリ:6GB(無料枠内)
  5. SSHキーをアップロード(または生成)
  6. 「作成」をクリック

セキュリティリストでポートを開放

デフォルトでは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パスポート・基本情報技術者・応用情報技術者・情報セキュリティマネジメントの問題を無料で学習できます。よければ使ってみてください!


参考

1
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?