はじめに
個人開発していたアプリ(FastAPI + Nginx)を、VPS上で実際に公開するまでの作業記録です。
ローカルで動いていたものを「インターネット上で誰でもアクセスできる状態」にするまでには、思ったより多くのステップがありました。今後同じような作業をする時の備忘録として、また同じ課題に直面している方の参考になればと思います。
構成
Internet
↓ (HTTPS)
Nginx (443)
↓ (リバースプロキシ)
FastAPI (uvicorn:8000)
↓
SQLite (your-database-file.db)
技術選定
VPS(Xserver VPS)
最初はAWSやGCPも考えましたが、学習目的ならシンプルなVPSの方が全体像を掴みやすいと判断しました。
- サーバー管理の基礎(SSH、systemd、ファイアウォール等)を学べる
- 料金体系が分かりやすい
- Ubuntu環境で自由に構築できる
AWS Lambdaなどのサーバーレスも便利ですが、まずは「サーバーを立てて運用する」という基本を押さえたかった形です。
FastAPI
Pythonで書けるWebフレームワークの中で選びました。
-
自動ドキュメント生成(
/docsでSwagger UI)が便利 - 型ヒントベースで開発体験が良い
- 非同期処理に対応していて、今後のパフォーマンス改善の余地がある
- Django より軽量で、個人開発の規模に合っている
今後データ分析や機械学習との連携も視野に入れているので、Python エコシステムとの相性も重視しました。
SQLite
DB選定で悩みましたが、今回は小規模・学習用途と割り切ってSQLiteにしました。
選んだ理由:
- サーバーレスDBなので、MySQLやPostgreSQLのような別プロセス不要
- ファイル1つで完結するので管理が楽
- マイグレーションやバックアップの練習がしやすい
- 個人利用やデモ用途には十分
限界も理解している:
- 同時書き込みに弱い(複数ユーザーが同時編集すると競合しやすい)
- 大量データや高トラフィックには向かない
将来的にユーザーが増えたり、本格運用するならPostgreSQLへの移行を検討する予定です。ただ現時点では「まず動くものを公開する」ことを優先しました。
Nginx
FastAPIを直接インターネットに公開するのではなく、Nginxを前段に置きました。
- SSL終端(HTTPS化)をNginxで担当
- 静的ファイル配信はNginxの方が効率的
- 今後複数アプリを同じサーバーで動かす際の拡張性
FastAPIだけでも動きますが、実務ではリバースプロキシを挟むのが一般的なので、構成を合わせました。
systemd
開発中はuvicornコマンドで手動起動していましたが、本番環境ではサーバー再起動時に自動で立ち上がる必要があります。
systemdを使うことで:
- VPS再起動後も自動起動
- プロセスが落ちた時の自動再起動
- ログ管理が
journalctlで統一できる
この辺りは実務でも必須の知識だと思うので、しっかり設定しました。
実装手順
1. VPS初期設定
# パッケージ更新
sudo apt update && sudo apt upgrade -y
# 必要なツールをインストール
sudo apt install -y git nginx python3-venv python3-pip certbot python3-certbot-nginx sqlite3
SSH鍵認証の確認も済ませました。パスワード認証より安全ですし、毎回パスワード入力しなくて済むので作業効率も上がります。
2. リポジトリのクローン
# 適切なディレクトリに移動 (例: /var/www)
cd /var/www
git clone https://github.com/your-username/your-app.git
cd your-app
普段から開発はGit管理しているので、この作業はスムーズでした。開発環境と本番環境で同じコードを使えるのは大きなメリットです。
3. Python環境構築
# 仮想環境作成
python3 -m venv venv
# 有効化
source venv/bin/activate
# 依存パッケージインストール
pip install -r requirements.txt
requirements.txtで管理しておくと、環境構築が一発で済みます。開発環境と本番環境でバージョンを揃えられるのも安心です。
4. SQLiteデータベース確認
# DBファイルが存在するか確認
ls -lh your-database-file.db
# テーブル確認
sqlite3 your-database-file.db
.tables
.schema your_table_name
.exit
SQLiteはファイル1つで完結するので、この確認だけで済みます。MySQLのようにサーバープロセスを起動する必要がないのは楽です。
5. 開発サーバーで動作確認
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
まずはVPS内部で動くか確認。ただし外部からは8000番ポートに直接アクセスできません(ファイアウォール設定)。そのため次のステップでNginxを設定します。
6. Nginxリバースプロキシ設定
sudo nano /etc/nginx/sites-available/your-app
server {
listen 80;
server_name your-domain.example.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/your-app /etc/nginx/sites-enabled/
# 設定テスト
sudo nginx -t
# 反映
sudo systemctl restart nginx
この時点でhttp://your-domain.example.comでアクセスできるようになりました。
7. SSL化(Let's Encrypt)
HTTPのままだとブラウザで警告が出るので、HTTPS化します。
sudo certbot --nginx -d your-domain.example.com
Certbotが自動でNginx設定を書き換えてくれます。HTTPからHTTPSへのリダイレクトも設定してくれるので、ほぼ自動で完了しました。
# 自動更新テスト
sudo certbot renew --dry-run
Let's Encryptの証明書は90日で期限切れになりますが、Certbotが自動更新するので運用の手間はありません。
8. systemdで自動起動設定
開発用のuvicornコマンドをそのまま使うのではなく、systemdで管理します。
sudo nano /etc/systemd/system/your-app.service
[Unit]
Description=Your App FastAPI Application
After=network.target
[Service]
User=root
WorkingDirectory=/var/www/your-app
Environment="PATH=/var/www/your-app/venv/bin"
ExecStart=/var/www/your-app/venv/bin/uvicorn app.main:app --host 0.0.0.0 --port 8000
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
(注) User や WorkingDirectory, Environment, ExecStart のパスは、ご自身の環境に合わせて適切に変更してください。
# 設定反映
sudo systemctl daemon-reload
# 自動起動有効化
sudo systemctl enable your-app
# 起動
sudo systemctl start your-app
# ステータス確認
sudo systemctl status your-app
これでVPSが再起動してもアプリが自動で立ち上がるようになりました。
運用での気づき
アプリ更新フロー
現状、コード更新時は手動で反映しています。
cd /var/www/your-app
git pull origin main
sudo systemctl restart your-app
この辺りは今後CI/CDで自動化したいところです。GitHub Actionsでテスト→デプロイまで自動化できれば、より実務的な構成になりそうです。
ログ確認
問題が起きた時のために、ログの見方は把握しておきました。
# アプリケーションログ
sudo journalctl -u your-app -f
# Nginxのアクセスログ
sudo tail -f /var/log/nginx/access.log
# Nginxのエラーログ
sudo tail -f /var/log/nginx/error.log
実際に動かしていると、たまに予期しないエラーが出ることもあるので、ログを追える環境は重要です。
SQLiteのバックアップ
ファイル1つで完結するSQLiteは、バックアップも簡単です。
# 日次バックアップ(cronで自動化予定)
cp your-database-file.db backups/your-database-file_$(date +%Y%m%d).db
将来的にはPostgreSQLに移行するかもしれませんが、今はこのシンプルさが気に入っています。
今後の改善予定
1. CI/CD導入
GitHub Actionsでテスト→デプロイを自動化したいです。
- PRマージ時に自動テスト実行
- mainブランチへのマージで自動デプロイ
- ロールバック機能も検討
2. DB移行の検討
ユーザーが増えたり、同時アクセスが増えた場合はPostgreSQLへの移行を検討します。
- SQLAlchemyを使っているので、DB切り替えはそこまで大変ではないはず
- マイグレーションツール(Alembic)も導入済み
3. 監視・アラート
- アプリがダウンした時の通知
- ディスク容量の監視
- アクセスログの分析
UptimeRobotなどの無料ツールから始めて、必要に応じてDatadogなども試したいです。
4. パフォーマンス改善
- FastAPIの非同期処理をもっと活用
- Nginxでの静的ファイルキャッシュ
- DB接続プールの最適化
今はまだユーザーが少ないですが、負荷が増えた時のために準備しておきたいです。
まとめ
FastAPIアプリをVPS上でHTTPS公開するまでの一連の流れを経験できました。
- Git管理によるコード配置
- 仮想環境での依存管理
- Nginxによるリバースプロキシ
- SSL証明書の取得と自動更新
- systemdによる自動起動設定
- SQLiteでの軽量DB運用
個人開発でも実務を意識した構成にすることで、実際の業務でも活かせる知見が得られたと思います。
特にSQLiteの選択は賛否あるかもしれませんが、「小さく始めて必要に応じてスケールする」という考え方は、スタートアップ的な開発でも重要だと感じています。
次はCI/CD周りや監視体制の構築に挑戦していきたいです。