ConoHa VPS に Docker Compose で Python API を構築する手順

VPSにAPIサーバーを立てる作業自体は難しくない。難しいのは、予想外のところで詰まることだ。
筆者がConoHa VPSでDocker ComposeによるPython APIサーバーを本番運用していたとき、ある日突然レスポンスが極端に遅くなった。pingは通る。コンテナも生きている。でも全てのリクエストが1秒以上かかる状態になった。原因はConoHaの帯域制限だった。一定量のトラフィックを超えると、通知なしでアクセス速度が絞られる仕様がある。
この記事では、その失敗を含めた実体験をもとに、ConoHa VPSにDocker Composeを使ってPython APIサーバーを構築する手順を一から書く。
この記事でわかること
① ConoHa VPSのOS選択とサーバー初期設定(SSH・ユーザー・ファイアウォール)
② Docker & Docker Composeのインストール手順(2026年版)
③ Python FastAPIをDocker Compose構成で動かすファイル構成
④ Nginxをリバースプロキシとして組み込む設定
⑤ 帯域制限に引っかかったときの症状と対処法
この記事の対象読者
- ConoHa VPSを契約済み、またはこれから契約する予定のエンジニア
- Docker Composeは知っているが、VPSへの本番デプロイが初めて
- PythonでAPIサーバーを書いていて、それをVPSで動かしたい
- AWSやGCPではなく、月額固定のVPSでシンプルに運用したい
逆に、大規模なマイクロサービス構成や、ECS/Cloud Runを使った本番運用を検討している場合はVPSよりマネージドコンテナサービスの方が適している。
なぜ ConoHa VPS を選ぶのか
個人開発・副業プロジェクトのバックエンドAPIをホストするなら、VPSは今でも合理的な選択だ。AWSのEC2をオンデマンドで使うより月額コストが読みやすく、管理の複雑さも少ない。
ConoHa VPSは主要VPSの中でコストパフォーマンスが高い部類に入る。
| プラン | メモリ | vCPU | SSD | 月額(36ヶ月) |
|---|---|---|---|---|
| 1GB | 1GB | 2コア | 100GB | 約¥657 |
| 2GB | 2GB | 3コア | 100GB | 約¥1,210 |
| 4GB | 4GB | 4コア | 100GB | 約¥2,420 |
| 8GB | 8GB | 6コア | 100GB | 約¥4,576 |
Python APIサーバー単体であれば2GBプランで十分動く。PostgreSQLも同じVPSで動かす場合は4GBを選んでおくと安心だ。
VPS各社の詳しい比較はConoHa・Xserver・さくらのVPS比較記事にまとめているので、まだ契約先を迷っている場合はそちらを先に読んでほしい。
前提条件
この記事では以下の環境を前提に書く。
| 項目 | 内容 |
|---|---|
| OS | Ubuntu 24.04 LTS |
| Docker Engine | 26.x(2026年5月時点の最新) |
| Docker Compose | v2.x(docker compose コマンド) |
| Python | 3.12 |
| フレームワーク | FastAPI(flaskやDjangoも構成は大差ない) |
| ローカル環境 | macOS または Linux |
Docker Compose v1(docker-compose)は非推奨
docker-compose(ハイフンあり)コマンドはすでに非推奨・EOL。2026年時点ではdocker compose(スペース区切り)が標準だ。古い記事の手順をコピーするときは注意してほしい。
STEP 1:VPS を契約・OS を選択する
プラン選択の判断軸
Python APIサーバー単体なら2GBプランが現実的な出発点だ。開発初期はリクエスト数も少ないため、スペック過剰になりがちな4GB以上はもったいない。スケールアップはConoHaのコントロールパネルからオンラインで行えるため、必要になってから変更すれば十分だ。
OS は Ubuntu 24.04 LTS を選ぶ
ConoHaのOSテンプレートはUbuntu・CentOS・Debian等から選べる。Dockerの公式サポートが最も手厚く、情報量も多いのはUbuntuだ。LTSを選ぶことでセキュリティアップデートが2029年まで保証される。
ConoHaのAIテンプレートについて
ConoHaにはDifyや各種AIツールがプリインストールされた「AIテンプレート」もある。自分でDockerを管理したい場合は素の Ubuntu を選ぶこと。テンプレートを使うと既存のDocker設定が競合する場合がある。
STEP 2:サーバーの初期設定をする
ConoHaのコントロールパネルからサーバーを作成すると、初期状態ではrootユーザーのパスワードログインが有効になっている。セキュリティ的にこの状態のまま使い続けるのは危険だ。以下の順で初期設定を行う。
2-1. SSH公開鍵をコントロールパネルに登録する
ローカルマシンで鍵ペアを生成する。
ssh-keygen -t ed25519 -C "your_email@example.com"
# ~/.ssh/id_ed25519 と id_ed25519.pub が生成される
cat ~/.ssh/id_ed25519.pub
# 表示された公開鍵をコピーしてConoHaコンパネに登録するConoHaのコントロールパネル → 「SSH Key」→「SSH Keyを追加」で公開鍵を登録しておくと、サーバー作成時に自動で設定される。
2-2. root でログインして一般ユーザーを作る
ssh root@<サーバーのIPアドレス>一般ユーザーを作成してsudo権限を付与する。
adduser deploy
# パスワードを設定する(強力なものを使うこと)
usermod -aG sudo deploy
# rootの公開鍵を新しいユーザーにもコピーする
mkdir -p /home/deploy/.ssh
cp ~/.ssh/authorized_keys /home/deploy/.ssh/
chown -R deploy:deploy /home/deploy/.ssh
chmod 700 /home/deploy/.ssh
chmod 600 /home/deploy/.ssh/authorized_keys2-3. SSH設定を強化する
vim /etc/ssh/sshd_config以下の項目を変更する。
# rootログインを禁止
PermitRootLogin no
# パスワード認証を無効化(公開鍵のみ許可)
PasswordAuthentication no
# ポートをデフォルトから変更(任意だが推奨)
Port 2222設定を反映する。
systemctl restart sshd切断前に必ず別ターミナルで接続確認
sshd_configを変更した後、現在の接続を切る前に別のターミナルから新しい設定で接続できることを確認すること。設定ミスのまま切断するとVPSにアクセスできなくなる。ConoHaにはコンパネからのコンソール接続があるが、手間がかかる。
2-4. ファイアウォール(ufw)を設定する
# SSHポート(変更した場合は2222)を先に許可してから有効化する
sudo ufw allow 2222/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
# ufwを有効化
sudo ufw enable
# 状態確認
sudo ufw statusConoHaのセキュリティグループも確認する
ConoHaにはコントロールパネル上の「セキュリティグループ」機能もある。ufwとConoHaのセキュリティグループの両方でポートを開放しないとつながらないケースがある。うまく接続できないときは両方を確認してほしい。
STEP 3:Docker & Docker Compose をインストールする
2026年時点でのDocker公式推奨インストール方法を使う。Ubuntuのaptリポジトリから直接インストールできるが、バージョンが古い場合があるため、Docker公式のリポジトリを追加する方法が確実だ。
3-1. 旧バージョンを削除する
sudo apt-get remove docker docker-engine docker.io containerd runc3-2. Docker Engine をインストールする
# 必要パッケージをインストール
sudo apt-get update
sudo apt-get install -y ca-certificates curl gnupg
# Docker公式のGPGキーを追加
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
# Dockerのaptリポジトリを追加
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# Docker Engine + Compose プラグインをインストール
sudo apt-get update
sudo apt-get install -y \
docker-ce \
docker-ce-cli \
containerd.io \
docker-buildx-plugin \
docker-compose-plugin3-3. ユーザーをdockerグループに追加する
sudo usermod -aG docker $USER
# グループ変更を即時反映(またはいったんログアウトして再ログイン)
newgrp docker3-4. 動作確認
docker --version
# Docker version 26.x.x, build ...
docker compose version
# Docker Compose version v2.x.x
# ハローワールドで動作確認
docker run hello-worldHello from Docker! と表示されれば成功だ。
STEP 4:Python API サーバーの Docker Compose 構成を作る
FastAPIを使ったシンプルなREST APIサーバーをDocker Composeで構成する。
ディレクトリ構成
myapi/
├── docker-compose.yml
├── .env
├── nginx/
│ └── default.conf
└── app/
├── Dockerfile
├── requirements.txt
└── main.pyapp/requirements.txt
fastapi==0.115.0
uvicorn[standard]==0.30.0app/main.py
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def root():
return {"status": "ok", "message": "API is running"}
@app.get("/health")
def health():
return {"status": "healthy"}app/Dockerfile
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]docker-compose.yml
services:
api:
build: ./app
container_name: myapi
restart: always
expose:
- "8000"
env_file:
- .env
nginx:
image: nginx:alpine
container_name: myapi_nginx
restart: always
ports:
- "80:80"
volumes:
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf
depends_on:
- apirestart: always を指定しておくと、サーバー再起動時にコンテナが自動で立ち上がる。
.env
# APIキーや設定値をここに書く
APP_ENV=production
LOG_LEVEL=info.env はGitにコミットしないこと。.gitignore に追記しておく。
.envnginx/default.conf
server {
listen 80;
server_name _;
location / {
proxy_pass http://api: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;
}
}起動・確認
# プロジェクトディレクトリに移動
cd ~/myapi
# バックグラウンドで起動
docker compose up -d
# ログ確認
docker compose logs -f
# 動作確認
curl http://localhost/
# {"status":"ok","message":"API is running"}ブラウザからVPSのIPアドレスにアクセスして同じレスポンスが返ってくれば成功だ。
STEP 5:HTTPS(Let's Encrypt)を設定する
本番運用するなら必ずHTTPS化する。ドメインを取得してVPSのIPに向けておく必要がある。
Certbotをコンテナで動かす
services:
api:
build: ./app
container_name: myapi
restart: always
expose:
- "8000"
env_file:
- .env
nginx:
image: nginx:alpine
container_name: myapi_nginx
restart: always
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf
- ./certbot/conf:/etc/letsencrypt
- ./certbot/www:/var/www/certbot
depends_on:
- api
certbot:
image: certbot/certbot
volumes:
- ./certbot/conf:/etc/letsencrypt
- ./certbot/www:/var/www/certbotserver {
listen 80;
server_name example.com www.example.com;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
server_name example.com www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
location / {
proxy_pass http://api: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;
}
}証明書の初回取得は以下のコマンドで行う。
docker compose run --rm certbot certonly \
--webroot \
--webroot-path=/var/www/certbot \
--email your@email.com \
--agree-tos \
--no-eff-email \
-d example.com \
-d www.example.com証明書の自動更新はcronで行う。
# crontab -e で以下を追加
0 0 * * 0 cd ~/myapi && docker compose run --rm certbot renew && docker compose restart nginx⚠️ 実体験:帯域制限に引っかかった話
ここからが個人的に一番伝えたい話だ。
本番でAPIサーバーを動かしていたある日、突然レスポンスが極端に遅くなった。最初はアプリのバグかと思ってコードを確認し、コンテナを再起動し、メモリ使用量を確認した。全て問題なかった。でもリクエストは3秒〜5秒かかる状態が続いた。
原因はConoHaの帯域制限だった。
ConoHaの帯域制限の仕様
ConoHaのネットワーク仕様は、インターネット接続が100Mbps共有だ。共有回線のため「他のユーザーに影響が出るレベルのトラフィックが発生した場合」に帯域を制限するという運用になっている。
実際に制限を受けると、通信速度が500kbps〜1Mbps程度まで絞られる。API経由でファイルを扱っていたり、大量のデータを転送していたりすると、この制限に引っかかりやすい。
筆者の場合、バッチ処理でまとめてデータを引き渡すAPIを動かしていた。通常のリクエストよりはるかに大きなペイロードが繰り返し飛ぶ状況で、制限が発動した。ConoHaサポートに問い合わせると「他利用者への影響が懸念されるトラフィックだったため制限した、一定時間後に解除される」という説明を受けた。
対処法
| 状況 | 対処 |
|---|---|
| 一時的なバースト転送が原因 | 待てば解除される(数時間〜半日) |
| 大容量ファイルの転送が常態化している | ファイルはObject StorageやS3に移す |
| 継続的に大量トラフィックが発生する | 帯域拡張オプション(300Mbps)を追加する |
| そもそも転送量が多くなりがちな用途 | Xserver VPSは「データ転送量無制限」を謳っている |
ConoHaは個人開発や中規模のAPIには十分だが、大量のファイル転送やストリーミングを伴うサービスには向かないと理解した上で使うのが正直なところだ。
curl -o /dev/null -s -w "%{speed_download}\n" http://localhost/でローカルの速度を確認- 外部からのアクセスも遅い場合、VPS側のネットワーク制限を疑う
- ConoHaサポートに「帯域制限を受けているか確認したい」と問い合わせると明確な回答をもらえる
トラブルシューティング
コンテナが起動しない
docker compose logs api
docker compose logs nginxエラーメッセージを直接確認するのが一番早い。permission denied 系のエラーは、ファイルのパーミッションかDockerグループの設定を疑う。
ポートが開かない
# コンテナのポートが正しく公開されているか確認
docker compose ps
# ホスト側でポートが使用中か確認
sudo ss -tlnp | grep :80ConoHaのセキュリティグループで80/443が開放されているかも確認する。
コンテナが再起動ループする
# コンテナのexit codeを確認
docker compose ps -a
# ログを追う
docker compose logs --tail=50 apiPythonのImportErrorやモジュール不足が原因の場合が多い。requirements.txt の内容とDockerfileのCOPY順序を確認する。
再起動後にコンテナが起動しない
restart: always を設定しているにもかかわらず再起動後に起動しない場合、Dockerデーモン自体が自動起動していない可能性がある。
sudo systemctl enable docker
sudo systemctl start dockerよくある質問(FAQ)
Q. 2GBプランと4GBプラン、どちらを選べばいい?
Python APIサーバー1本だけなら2GBで十分動く。同じVPSにPostgreSQLやRedisを同居させるなら4GBを選ぶとメモリに余裕が生まれる。あとからスケールアップできるので、まず2GBで始めて様子を見るのが無駄がない。
Q. Flask や Django でも同じ手順で動く?
基本的には同じだ。Dockerfile の CMD と requirements.txt の中身が変わるだけで、Docker Compose構成やNginxの設定はほぼそのまま使える。DjangoはWSGIなので gunicorn を経由させる点だけ異なる。
CMD ["gunicorn", "myproject.wsgi:application", "--bind", "0.0.0.0:8000"]Q. データベースも同じdocker-compose.ymlに入れていいか?
開発・小規模な本番用途なら問題ない。コンテナが落ちたときのデータ保護のために、ボリュームマウントを必ず設定すること。
services:
db:
image: postgres:16-alpine
restart: always
volumes:
- postgres_data:/var/lib/postgresql/data
environment:
POSTGRES_DB: mydb
POSTGRES_USER: myuser
POSTGRES_PASSWORD: mypassword
volumes:
postgres_data:Q. デプロイの自動化はどうすればいい?
GitHub Actionsを使うのが一般的だ。mainブランチにマージされたら、SSH経由でVPSに接続して docker compose pull && docker compose up -d を実行するワークフローを組む。リポジトリのSecretにSSH秘密鍵を登録しておけば安全に自動化できる。
Q. ConoHa VPSの転送量制限はどのくらいから制限されるのか?
公式には「他のユーザーに影響が出るレベル」としか明記されていない。実例では1日14GiB程度の転送で制限を受けたケースが報告されている。毎日数GiBを超えるデータ転送が予想される場合は、ConoHaのネットワーク帯域拡張オプション(100Mbps→300Mbps)の追加か、Xserver VPSへの乗り換えを検討する方がいい。
Q. セキュリティで最低限やっておくことは?
以下が最低ラインだ。
- rootログイン禁止(
PermitRootLogin no) - パスワード認証無効化(
PasswordAuthentication no) - ufw でSSH・80・443のみ開放
- 定期的な
sudo apt-get upgradeの実施 - HTTPS化(Let's Encrypt)
まとめ:今日からできるアクション
ConoHa VPSにDocker Composeで Python APIサーバーを立てる手順を一通り書いた。
- VPS契約:2GBプランから始め、必要に応じてスケールアップ
- 初期設定:SSHキー認証・一般ユーザー作成・ufw設定を必ずやる
- Docker インストール:公式リポジトリから
docker-compose-pluginまで一括で入れる - Docker Compose構成:
restart: alwaysを必ず指定して再起動後の自動起動を確保 - 帯域制限に注意:大容量のデータ転送が継続する用途には向かない
SES・常駐案件から副業・個人開発に軸足を移したいエンジニアにとって、VPSに自前のAPIサーバーを立てる経験は実績として語りやすい。SES脱出とキャリア設計の話と合わせて、ポートフォリオに活かしてほしい。
36ヶ月プランで月額¥657〜。Docker対応・データ転送量の制限ポリシーを理解した上で使えば、コスパ最強のVPSだ。まず公式サイトでプランを確認してみよう。
ConoHa VPS のプランを確認する →