DevOctane
ConoHa VPSDocker ComposePythonVPS

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

2026.05.2640 min read
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の中でコストパフォーマンスが高い部類に入る。

プランメモリvCPUSSD月額(36ヶ月)
1GB1GB2コア100GB約¥657
2GB2GB3コア100GB約¥1,210
4GB4GB4コア100GB約¥2,420
8GB8GB6コア100GB約¥4,576

Python APIサーバー単体であれば2GBプランで十分動く。PostgreSQLも同じVPSで動かす場合は4GBを選んでおくと安心だ。

VPS各社の詳しい比較はConoHa・Xserver・さくらのVPS比較記事にまとめているので、まだ契約先を迷っている場合はそちらを先に読んでほしい。


前提条件

この記事では以下の環境を前提に書く。

項目内容
OSUbuntu 24.04 LTS
Docker Engine26.x(2026年5月時点の最新)
Docker Composev2.x(docker compose コマンド)
Python3.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鍵ペアの生成
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)
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_keys

2-3. SSH設定を強化する

SSHデーモン設定の変更
vim /etc/ssh/sshd_config

以下の項目を変更する。

sshd_config 変更箇所
# rootログインを禁止
PermitRootLogin no
 
# パスワード認証を無効化(公開鍵のみ許可)
PasswordAuthentication no
 
# ポートをデフォルトから変更(任意だが推奨)
Port 2222

設定を反映する。

SSHサービス再起動
systemctl restart sshd

切断前に必ず別ターミナルで接続確認
sshd_configを変更した後、現在の接続を切る前に別のターミナルから新しい設定で接続できることを確認すること。設定ミスのまま切断するとVPSにアクセスできなくなる。ConoHaにはコンパネからのコンソール接続があるが、手間がかかる。

2-4. ファイアウォール(ufw)を設定する

ufw設定
# SSHポート(変更した場合は2222)を先に許可してから有効化する
sudo ufw allow 2222/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
 
# ufwを有効化
sudo ufw enable
 
# 状態確認
sudo ufw status

ConoHaのセキュリティグループも確認する
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 runc

3-2. Docker Engine をインストールする

Dockerインストール(公式リポジトリから)
# 必要パッケージをインストール
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-plugin

3-3. ユーザーをdockerグループに追加する

dockerグループへの追加
sudo usermod -aG docker $USER
 
# グループ変更を即時反映(またはいったんログアウトして再ログイン)
newgrp docker

3-4. 動作確認

Dockerの動作確認
docker --version
# Docker version 26.x.x, build ...
 
docker compose version
# Docker Compose version v2.x.x
 
# ハローワールドで動作確認
docker run hello-world

Hello 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.py

app/requirements.txt

app/requirements.txt
fastapi==0.115.0
uvicorn[standard]==0.30.0

app/main.py

app/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

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

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:
      - api

restart: always を指定しておくと、サーバー再起動時にコンテナが自動で立ち上がる。

.env

.env
# APIキーや設定値をここに書く
APP_ENV=production
LOG_LEVEL=info

.env はGitにコミットしないこと。.gitignore に追記しておく。

.gitignore
.env

nginx/default.conf

nginx/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をコンテナで動かす

docker-compose.yml(HTTPS対応版)
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/certbot
nginx/default.conf(HTTPS対応版)
server {
    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;
    }
}

証明書の初回取得は以下のコマンドで行う。

Let's Encrypt 証明書取得
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で行う。

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には十分だが、大量のファイル転送やストリーミングを伴うサービスには向かないと理解した上で使うのが正直なところだ。

帯域制限を受けたときの確認手順
  1. curl -o /dev/null -s -w "%{speed_download}\n" http://localhost/ でローカルの速度を確認
  2. 外部からのアクセスも遅い場合、VPS側のネットワーク制限を疑う
  3. ConoHaサポートに「帯域制限を受けているか確認したい」と問い合わせると明確な回答をもらえる

トラブルシューティング

コンテナが起動しない

ログ確認
docker compose logs api
docker compose logs nginx

エラーメッセージを直接確認するのが一番早い。permission denied 系のエラーは、ファイルのパーミッションかDockerグループの設定を疑う。

ポートが開かない

ポート確認
# コンテナのポートが正しく公開されているか確認
docker compose ps
 
# ホスト側でポートが使用中か確認
sudo ss -tlnp | grep :80

ConoHaのセキュリティグループで80/443が開放されているかも確認する。

コンテナが再起動ループする

再起動ループのデバッグ
# コンテナのexit codeを確認
docker compose ps -a
 
# ログを追う
docker compose logs --tail=50 api

PythonのImportErrorやモジュール不足が原因の場合が多い。requirements.txt の内容とDockerfileのCOPY順序を確認する。

再起動後にコンテナが起動しない

restart: always を設定しているにもかかわらず再起動後に起動しない場合、Dockerデーモン自体が自動起動していない可能性がある。

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 でも同じ手順で動く?

基本的には同じだ。DockerfileCMDrequirements.txt の中身が変わるだけで、Docker Compose構成やNginxの設定はほぼそのまま使える。DjangoはWSGIなので gunicorn を経由させる点だけ異なる。

Django + Gunicorn の場合のCMD
CMD ["gunicorn", "myproject.wsgi:application", "--bind", "0.0.0.0:8000"]

Q. データベースも同じdocker-compose.ymlに入れていいか?

開発・小規模な本番用途なら問題ない。コンテナが落ちたときのデータ保護のために、ボリュームマウントを必ず設定すること。

PostgreSQL を追加する場合
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サーバーを立てる手順を一通り書いた。

  1. VPS契約:2GBプランから始め、必要に応じてスケールアップ
  2. 初期設定:SSHキー認証・一般ユーザー作成・ufw設定を必ずやる
  3. Docker インストール:公式リポジトリから docker-compose-plugin まで一括で入れる
  4. Docker Compose構成restart: always を必ず指定して再起動後の自動起動を確保
  5. 帯域制限に注意:大容量のデータ転送が継続する用途には向かない

SES・常駐案件から副業・個人開発に軸足を移したいエンジニアにとって、VPSに自前のAPIサーバーを立てる経験は実績として語りやすい。SES脱出とキャリア設計の話と合わせて、ポートフォリオに活かしてほしい。

ConoHa VPS で個人開発を始めよう

36ヶ月プランで月額¥657〜。Docker対応・データ転送量の制限ポリシーを理解した上で使えば、コスパ最強のVPSだ。まず公式サイトでプランを確認してみよう。

ConoHa VPS のプランを確認する →
DO
この記事を書いた人
DevOctane

バックエンド/インフラエンジニア歴8年。SES客先常駐から大手自社開発企業へ転職後、フリーランスとして独立。AWS・コンテナ・FinOps・バックエンド領域を中心に現場で培った知識を発信しています。