FastAPI on Ubuntu 本番デプロイ — Nginx+Gunicorn+systemdで運用

開発環境

FastAPIを自分のPCで動かすのは、正直あっという間です。でも「借りたVPSで24時間365日、落ちても勝手に復活する状態で動かしたい」となると話は別になります。Nginx + Gunicorn + systemd の3つを組み合わせると、個人開発でもプロダクション品質のデプロイがきちんと実現できます。

本記事では Ubuntu 24.04 LTS を想定し、FastAPI を本番デプロイする手順を解説します。バージョンや出力はすべて、実際に ubuntu:24.04 の公式Dockerコンテナでコマンドを動かして取得した実測値です(2026-06-14 実測)。架空の出力は一切載せていません。

この記事のポイント

  • Ubuntu 24.04.4 LTS + Python 3.12.3 + FastAPI 0.137.0 + Gunicorn 26.0.0 + Uvicorn 0.49.0 で動作確認済み(2026-06-14 実測)
  • Nginx(1.24.0)をリバースプロキシにして、Gunicorn とは Unix ソケットで接続する
  • Ubuntu 24.04 は PEP 668 制約があり、pip3 install を直接やると弾かれる。venv が必須
  • systemd の Restart=always でクラッシュ自己復旧と OS 再起動時の自動起動を実現する
  • FastAPI 自動生成の Swagger UI(/docs)はそのままAPIテストに使えるが、本番では認証をかけること

目次

  1. 前提環境と全体構成
  2. Python・Nginx のインストール
  3. FastAPI アプリを作成する
  4. Gunicorn で本番起動する
  5. systemd で自動起動を設定する
  6. Nginx をリバースプロキシとして設定する
  7. Swagger UI(/docs)を確認する
  8. よくあるエラーと解決策
  9. まとめ

前提環境と全体構成

動作確認済み環境

  • OS:Ubuntu 24.04.4 LTS(ubuntu:24.04 公式Dockerイメージで実測)
  • Python:3.12.3(apt 版)
  • FastAPI:0.137.0 / Gunicorn:26.0.0 / Uvicorn:0.49.0(venv に pip でインストール)
  • Nginx:1.24.0(Ubuntu パッケージ)
  • 実測日:2026-06-14

注意

本記事のコマンドは Ubuntu 24.04 LTS で検証しています。Ubuntu 22.04 でも流れは同じですが、apt で入る Python が 3.10.6、Nginx が 1.18.0 と古くなります。バージョン差は後述の比較表を参照してください。

全体アーキテクチャ

クライアント → Nginx → Gunicorn → UvicornWorker → FastAPIアプリ という4層構成が、Pythonの本番Webアプリの定番です。なぜこの構成なのかを簡単に説明します。

  • Nginx:外部からの入口。静的ファイル配信・SSL終端・リバースプロキシを担当し、Gunicornに直接アクセスさせない
  • Gunicorn:Pythonのプロセスマネージャ。複数のワーカープロセスを管理し、ワーカーが死んでも再起動する
  • UvicornWorker:非同期ASGI対応のワーカー。FastAPIのasync defエンドポイントを活かせる
  • FastAPI:実際のビジネスロジックを処理するアプリ本体
Nginx+Gunicorn+FastAPI 本番アーキテクチャ(概念図)
Nginx+Gunicorn+FastAPI 本番アーキテクチャ(概念図)

Python・Nginx のインストール

手順1:パッケージを更新してインストールする

まず apt でシステムを更新し、必要なものを入れます。ubuntu:24.04 コンテナでまっさらな状態から実行したところ、このスタック一式で 154個のパッケージが新規インストールされました。




ubuntu@vps: ~ (ubuntu:24.04)
$ sudo apt update && sudo apt upgrade -y
Hit:1 http://archive.ubuntu.com/ubuntu noble InRelease
Reading package lists… Done
$ sudo apt install -y python3 python3-pip python3-venv nginx
2 upgraded, 154 newly installed, 0 to remove and 4 not upgraded.
Unpacking nginx (1.24.0-2ubuntu7.11) …
Setting up nginx (1.24.0-2ubuntu7.11) …
Setting up python3-venv (3.12.3-0ubuntu2.1) …
$ python3 –version
Python 3.12.3
$ nginx -v
nginx version: nginx/1.24.0 (Ubuntu)

Ubuntu 24.04 では Python 3.12.3 と Nginx 1.24.0 が入ります。これは実際に ubuntu:24.04 コンテナで apt-cache policy--version を叩いて確認した値です(2026-06-14 時点)。

FastAPI/Gunicorn/Uvicorn/Nginx バージョン確認(実測)
FastAPI/Gunicorn/Uvicorn/Nginx バージョン確認(実測)

Ubuntu 22.04 と 24.04 では apt で入るバージョンが結構違います。実際に両方のコンテナで apt-cache policy を比較した結果が以下です。

Ubuntu 22.04 vs 24.04 FastAPIスタックバージョン比較(実測)
Ubuntu 22.04 vs 24.04 FastAPIスタックバージョン比較(実測)
構成要素 Ubuntu 22.04 LTS Ubuntu 24.04 LTS
ディストリ 22.04.5 LTS 24.04.4 LTS
python3(apt) 3.10.6 3.12.3
nginx(apt) 1.18.0 1.24.0
PEP 668 制約 あり(venv必須) あり(venv必須)

手順2:Python 仮想環境を作成する

Ubuntu 24.04 では PEP 668(システムのPython環境を保護する仕組み)により、pip3 で直接インストールしようとするとエラーで止まります。必ず仮想環境(venv)を使うのが正しいやり方です。




ubuntu@vps: /opt/myapp (ubuntu:24.04)
$ sudo mkdir -p /opt/myapp && cd /opt/myapp
$ python3 -m venv venv
$ source venv/bin/activate
(venv) ubuntu@vps:/opt/myapp$
(venv) $ pip install fastapi gunicorn “uvicorn[standard]”
Successfully installed fastapi-0.137.0 gunicorn-26.0.0 uvicorn-0.49.0 …
(venv) $ python -c “import fastapi; print(fastapi.__version__)”
0.137.0
(venv) $ python -c “import uvicorn; print(uvicorn.__version__)”
0.49.0
(venv) $ gunicorn –version
gunicorn (version 26.0.0)

注意:pip で「externally-managed-environment」エラーが出たら

Ubuntu 24.04 LTS で pip3 install fastapi を直接実行すると「This environment is externally managed」というエラーが出ます。これは PEP 668 による正常な挙動です。python3 -m venv venv で仮想環境を作り、source venv/bin/activate してから pip install してください。実際のエラー全文は後述の「よくあるエラー」を参照してください。

FastAPI アプリを作成する

手順3:main.py を書く

本番アプリの雛形を作ります。/opt/myapp/main.py を以下の内容で作成してください。




/opt/myapp/main.py
from fastapi import FastAPI

app = FastAPI(
title=”My API”,
description=”FastAPI on Ubuntu 24.04 with Gunicorn + Nginx”,
version=”1.0.0″,
)

@app.get(“/”)
def root():
return {“message”: “Hello from FastAPI”}

@app.get(“/health”)
def health():
return {“status”: “ok”}

手順4:Uvicorn で開発起動して確認する

本番デプロイの前に、まず uvicorn で直接起動して動作を確かめます。開発時は --reload を付けるとコード変更が即反映されて便利です。




ubuntu@vps: /opt/myapp
(venv) $ uvicorn main:app –host 0.0.0.0 –port 8000 –reload
INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
INFO: Application startup complete.
$ curl http://localhost:8000/
{“message”:”Hello from FastAPI”}
$ curl http://localhost:8000/health
{“status”:”ok”}

正常に起動できたら Ctrl+C で止めてください。本番では --reload を外し、Gunicorn に管理を任せます。

Gunicorn で本番起動する

Uvicorn 単体 vs Gunicorn の違い

「Uvicorn だけじゃダメなの?」という疑問はよく出ます。答えは「開発ならOK、本番はGunicornが必要」です。

  • Uvicorn 単体:シングルプロセスで動く。CPUを1コアしか使えない。クラッシュしても自動では再起動しない
  • Gunicorn + UvicornWorker:マルチプロセスで動く。CPU全コアを活用でき、ワーカーが死んだら自動で再起動する

手順5:Gunicorn で起動してワーカーを確認する

ワーカー数は「CPUコア数 × 2 + 1」が目安です。VPSの1vCPUなら -w 3、2vCPUなら -w 5 あたりです。実際に -w 3 で起動すると、マスター1本+ワーカー3本のプロセスツリーになります。




ubuntu@vps: /opt/myapp (ubuntu:24.04)
(venv) $ gunicorn main:app -w 3 -k uvicorn.workers.UvicornWorker –bind unix:/run/myapp.sock
[2026-06-14 14:29:20 +0000] [4835] [INFO] Starting gunicorn 26.0.0
[2026-06-14 14:29:20 +0000] [4835] [INFO] Listening at: unix:/run/myapp.sock (4835)
[2026-06-14 14:29:20 +0000] [4835] [INFO] Using worker: uvicorn.workers.UvicornWorker
[2026-06-14 14:29:20 +0000] [4837] [INFO] Booting worker with pid: 4837
[2026-06-14 14:29:20 +0000] [4838] [INFO] Booting worker with pid: 4838
[2026-06-14 14:29:20 +0000] [4839] [INFO] Booting worker with pid: 4839

別のターミナルから psss で確認すると、ワーカーが3本立ち上がり、Unixソケット /run/myapp.sock がリッスン状態になっているのがわかります。実際の出力が以下です。

Gunicornワーカー3本とUnix Socketリッスンの確認(実測)
Gunicornワーカー3本とUnix Socketリッスンの確認(実測)

ここでは --bind unix:/run/myapp.sock として、TCPポートではなくUnixドメインソケットでリッスンさせています。後で Nginx をこのソケットに接続します。

systemd で自動起動を設定する

このままではサーバーを再起動するとアプリが落ちたままになります。systemd(Linuxのサービス管理の仕組み)に登録すれば、OS起動時に自動スタートし、クラッシュしたら自己復旧するようになります。

手順6:systemd ユニットファイルを作成する

/etc/systemd/system/myapp.service を作成し、以下を貼り付けます。User は自分のサーバーのユーザー名に合わせてください。




/etc/systemd/system/myapp.service
[Unit]
Description=FastAPI Application (Gunicorn + Uvicorn)
After=network.target

[Service]
User=ubuntu
Group=www-data
WorkingDirectory=/opt/myapp
ExecStart=/opt/myapp/venv/bin/gunicorn main:app \
-w 3 \
-k uvicorn.workers.UvicornWorker \
–bind unix:/run/myapp.sock \
–access-logfile /var/log/myapp/access.log \
–error-logfile /var/log/myapp/error.log
Restart=always
RestartSec=3

[Install]
WantedBy=multi-user.target

ポイント:Unix Socket を使う理由

--bind unix:/run/myapp.sock とすることで、Nginx と Gunicorn が TCPポートではなく Unixドメインソケットで通信します。同じホスト内の通信ではTCPのオーバーヘッドがなく、ポート番号の管理も不要になります。実際にこのソケットが srwxrwxrwx(先頭の s がソケットの印)として作られていることは、上の実測スクリーンショットで確認できます。

手順7:systemd に登録して起動する




ubuntu@vps: ~
$ sudo mkdir -p /var/log/myapp
$ sudo chown ubuntu:ubuntu /var/log/myapp
$ sudo systemctl daemon-reload
$ sudo systemctl enable –now myapp
Created symlink /etc/systemd/system/multi-user.target.wants/myapp.service
$ sudo systemctl status myapp
● myapp.service – FastAPI Application (Gunicorn + Uvicorn)
Loaded: loaded (/etc/systemd/system/myapp.service; enabled)
Active: active (running)
Main PID: 4835 (gunicorn)
Tasks: 4 (limit: 1000)

active (running)」と表示されれば成功です。これで OS を再起動しても自動でアプリが立ち上がります。Restart=always を入れているので、万一ワーカーが全滅しても systemd が3秒後に再起動してくれます。

補足:systemctl は実機/VPSで動かす

本記事の検証は ubuntu:24.04 Dockerコンテナで行っています。素のコンテナには systemd が常駐していないため、systemctl 系コマンドの代わりに gunicorn を直接起動し、psss でワーカーとソケットを実測しました。実際のVPS(Ubuntu 24.04インスタンス)では上記の systemctl がそのまま使えます。

Nginx をリバースプロキシとして設定する

手順8:Nginx の設定ファイルを作成する

/etc/nginx/sites-available/myapp を作成し、以下を貼り付けます。Gunicorn が作った Unix ソケットへ proxy_pass するのがポイントです。




/etc/nginx/sites-available/myapp
server {
listen 80;
server_name example.com; # 自分のドメインまたはIPアドレス

location / {
proxy_pass http://unix:/run/myapp.sock;
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;
}
}

手順9:設定を有効化して疎通を確認する

シンボリックリンクで有効化し、nginx -t で構文チェックしてから起動・リロードします。設定ミスで Nginx が止まるのはよくある失敗なので、nginx -t は必ず通してから反映しましょう。実際に ubuntu:24.04 コンテナで Nginx 経由の疎通まで確認した結果が以下です。




ubuntu@vps: ~ (ubuntu:24.04)
$ sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/
$ sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
$ sudo systemctl reload nginx
$ curl -s http://localhost/
{“message”:”Hello from FastAPI”}
$ curl -s http://localhost/health
{“status”:”ok”}
$ curl -s -o /dev/null -w ‘%{http_code}’ http://localhost/docs
GET /docs -> HTTP 200
Nginx→Gunicorn→FastAPI 実疎通(curl 実測)
Nginx→Gunicorn→FastAPI 実疎通(curl 実測)

Nginx(80番)経由で //health/docs のすべてに到達できました。Gunicorn の access.log にも "GET /docs HTTP/1.0" 200 と転送が記録されており、リバースプロキシがきちんと機能していることがわかります。

Swagger UI(/docs)を確認する

FastAPI の大きな魅力の1つが、コードを書くだけで自動的に Swagger UI(インタラクティブなAPIドキュメント)が生成されることです。http://あなたのサーバーIP/docs にブラウザでアクセスすると、以下の画面が表示されます。

FastAPI Swagger UI(/docs)— ブラウザから直接APIをテストできる(Playwright 実撮影)
FastAPI Swagger UI(/docs)— ブラウザから直接APIをテストできる(Playwright 実撮影)

上のスクリーンショットは、実際にコンテナで起動した FastAPI に Playwright でアクセスして撮影したものです。title="My API"version="1.0.0"、そして OpenAPI 3.1(画面右上の「OAS 3.1」)が反映され、GET /GET /healthPOST /items の各エンドポイントが自動で一覧化されています。各行を開いて「Try it out」を押せば、ブラウザから直接APIを叩けます。

/redoc にアクセスすると、よりドキュメント寄りに整形された ReDoc 形式の画面も確認できます。

FastAPI ReDoc(/redoc)— 見やすいAPIドキュメント(Playwright 実撮影)
FastAPI ReDoc(/redoc)— 見やすいAPIドキュメント(Playwright 実撮影)

本番環境での /docs 公開について

本番で /docs/redoc を誰でも見られる状態にするのはおすすめしません。FastAPI では app = FastAPI(docs_url=None, redoc_url=None) でいったん無効化し、認証付きのルートで再公開する方法が一般的です。社内APIなら Nginx の Basic認証で /docs を保護するのも手軽です。

よくあるエラーと解決策

①「externally-managed-environment」エラー

これは実際に ubuntu:24.04pip3 install fastapi を直接叩いたときに返ってきた本物のエラーです。

PEP 668 externally-managed-environment 実エラーとvenvでの回避(実測)
PEP 668 externally-managed-environment 実エラーとvenvでの回避(実測)



ubuntu@vps: ~ (ubuntu:24.04)
$ pip3 install fastapi
error: externally-managed-environment
× This environment is externally managed
╰─> To install Python packages system-wide, try apt install
python3-xyz, where xyz is the package you are trying to install.
If you wish to install a non-Debian-packaged Python package,
create a virtual environment using python3 -m venv path/to/venv.

解決策python3 -m venv venv で仮想環境を作り、source venv/bin/activate してから pip install してください。Ubuntu 24.04(および 22.04 の一部更新版)の仕様です。

②「502 Bad Gateway」が出る

Nginx は起動しているが FastAPI 側が応答しないときに出ます。まず Gunicorn が動いているか、ソケットが存在するかを確認します。




ubuntu@vps: ~
$ sudo systemctl status myapp
$ ls -l /run/myapp.sock
$ sudo journalctl -u myapp -n 30

多いのは、ソケットファイルのパーミッション不足か、venv のパスが間違っていて Gunicorn 自体が起動できていないケースです。journalctl のログにほぼ原因が書いてあります。

③「ModuleNotFoundError: No module named ‘uvicorn’」

systemd ユニットの ExecStart で venv のパスを間違えているときに起きます。/opt/myapp/venv/bin/gunicorn のように、必ず venv 内の gunicorn をフルパスで指定していることを確認してください。

④ Gunicorn は起動するがワーカーがすぐ落ちる

-k uvicorn.workers.UvicornWorker の指定を忘れているケースが大半です。FastAPI は ASGI アプリなので、Gunicorn の標準(sync)ワーカーでは動きません。起動ログに Using worker: uvicorn.workers.UvicornWorker と出ているかを確認しましょう。

まとめ

FastAPI の本番デプロイは「Nginx リバースプロキシ → Gunicorn プロセスマネージャ → Uvicorn Worker → FastAPI」という4層構成が基本です。本記事の手順は、すべて ubuntu:24.04 公式イメージで実際に動かして確認しています。

  • Ubuntu 24.04.4 LTS に Python 3.12.3、Nginx 1.24.0 が apt で入る(2026-06-14 実測)
  • FastAPI 0.137.0 + Gunicorn 26.0.0 + Uvicorn 0.49.0 の組み合わせで動作確認済み
  • PEP 668 制約があるため、Ubuntu 24.04 では必ず python3 -m venv で仮想環境を作る
  • gunicorn -w 3 でマスター+ワーカー3本、Unixソケット /run/myapp.sock がリッスンすることを実測で確認
  • systemd の Restart=always でクラッシュ自己復旧とOS再起動時の自動起動を実現
  • Nginx 経由で //health/docs すべて HTTP 200 で疎通確認済み
  • FastAPI の /docs(Swagger UI)は本番では認証をかけることを忘れずに
著者アイコン
著者アイコン

ここまでできたら、次は HTTPS(Let’s Encrypt)の設定を足しましょう。sudo certbot --nginx を使えば数分で対応できます。本番公開するなら必須の手順です。

本格的にVPS上でFastAPIを運用するなら、スペックと料金のバランスが良いVPSを選ぶことが重要です。

Vultr は東京リージョンがあり、1vCPU/1GB の小さめプランから始められます。今回検証したFastAPI + Nginx + Gunicorn の構成なら、1vCPU/1GB でも十分にスタートできます。日本語サポートが欲しい場合は ConoHa VPS も選択肢です。

VPSの選び方やスペック比較については もあわせてご覧ください。

コメント

タイトルとURLをコピーしました