Pythonで作ったDiscord Botを、自宅サーバーやVPSで動かしたいとき、起動方法やライブラリの管理に迷うことがあります。
今回は、uvでPythonの環境を管理し、Docker ComposeでBotを常時稼働させる方法を紹介します。Dockerは導入済みとして、ファイルの作成から起動、更新まで進めていきます。
Dockerとuvを使うメリット
Dockerは、アプリと実行環境をまとめて動かすための仕組みです。
Botごとに環境を分けられるので、別のアプリで使うライブラリとの競合を減らせます。
また、DockerfileにPythonのバージョンや起動方法を残せるため、サーバーを移すときも環境を用意しやすくなります。Docker Composeを使えば、起動や停止、再起動の設定も一つのファイルにまとめられます。
uvは、Pythonのライブラリや仮想環境を管理するツールです。
ライブラリの導入が速いことに加えて、必要なライブラリを pyproject.toml 、具体的なバージョンをuv.lockで管理できます。同じロックファイルを使えば、開発環境とサーバー側でライブラリのバージョンをそろえやすくなります。
ただし、Dockerを使っても、サーバーの電源やネット接続が切れればBotは止まります。常時稼働には、サーバー自体を動かし続ける必要があります。
作業前に確認すること
今回はLinuxサーバー、Python 3.12、discord.pyを使います。Botの作成とサーバーへの招待は済ませておいてください。
Dockerが未導入の場合は、Docker Engineの公式インストールページから、使っているOSの手順に進んでください。
まず、次のコマンドでDockerとComposeを確認します。
docker --version
docker compose version
Composeが使えない場合は、公式のCompose導入手順を確認してください。
作業する端末にはuvも必要です。未導入の場合は、uvの公式インストールページに沿って導入します。
uvでBotのプロジェクトを用意する
次のコマンドでプロジェクトを作成し、discord.pyを追加します。
uv init --python 3.12 discord-bot
cd discord-bot
uv add discord.py
pyproject.tomlとuv.lockが作られます。Docker側でも使用するので、両方を残しておきましょう。すでにuvで管理しているBotなら、既存のプロジェクトで進められます。
動作確認用として、main.pyを次の内容にします。
import os
import discord
client = discord.Client(intents=discord.Intents.default())
@client.event
async def on_ready():
print(f"ログインしました: {client.user}", flush=True)
client.run(os.environ["DISCORD_TOKEN"])
この例はログイン確認だけを行います。既存のBotを動かす場合は、そのコードを使い、トークンを環境変数から読み取るようにしてください。
トークンを.envに保存する
プロジェクト内に.envを作成します。
DISCORD_TOKEN=ここにBotのトークンを入力
トークンはBotにログインするための情報です。コードへ直接書かず、GitHubやブログ、スクリーンショットにも載せないようにしましょう。
Gitを使う場合は、.gitignoreにも追加します。
.env
.venv/
__pycache__/
なお、今回のコードは.envを直接読みません。あとでComposeがファイルの内容を環境変数として渡します。
Dockerfileを作成する
続いて、Dockerfileを作成します。
FROM python:3.12-slim-bookworm
COPY --from=ghcr.io/astral-sh/uv:0.12.23 /uv /bin/uv
WORKDIR /app
ENV PYTHONUNBUFFERED=1
COPY pyproject.toml uv.lock ./
RUN uv sync --locked --no-dev --no-install-project --no-cache \
--python /usr/local/bin/python
COPY . .
CMD ["/app/.venv/bin/python", "main.py"]
ここではuvのバージョンを固定しています。更新する場合は、使うバージョンを確認して変更してください。
--lockedは、pyproject.tomlとuv.lockが合わない場合に処理を止める設定です。--no-devは開発用の依存グループを除き、--no-install-projectはBot自身をパッケージとしてインストールせず、必要なライブラリを導入します。
先にライブラリを導入してからコードをコピーすることで、コードだけの変更では、以前のライブラリ導入結果を再利用しやすくなります。
さらに、.dockerignoreを作成します。
.env
.venv/
.git/
__pycache__/
*.pyc
これでトークンや手元の仮想環境を、Dockerイメージに含めずに済みます。
Docker Composeで起動を設定する
compose.yamlを作成します。
services:
bot:
build: .
env_file:
- .env
restart: unless-stopped
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
env_fileでトークンを渡し、restart: unless-stoppedでBotの終了後に自動再起動させます。手動で停止した場合は、Dockerが再起動しても自動では起動しません。
ログには容量とファイル数の上限を設定しています。通常のDiscord Botは外向きに接続するため、この例ではポートを公開する設定は不要です。
ここまでで、主に次のファイルがそろいます。
main.pypyproject.tomlとuv.lockDockerfileとcompose.yaml.env、.gitignore、.dockerignore
Botを起動して確認する
プロジェクトのフォルダーで実行します。
docker compose up -d --build
docker compose ps
docker compose logs -f --tail=100 bot
--buildでイメージを作成し、-dでバックグラウンド起動します。SSH接続を終了しても、サーバー側のBotは動き続けます。
ログに「ログインしました」と出て、Discord上でオンラインになれば接続できています。ログ表示はCtrl + Cで終了できます。この操作ではBotは停止しません。
<トークンを表示せず、Botのログイン成功を確認できるターミナル画面>
サーバーの再起動後も動かすには、Docker自体の自動起動も必要です。systemdを使う一般的なLinux環境では、次のように設定します。
sudo systemctl enable --now docker
コードや設定を変更したときの操作
今回の構成では、コードをイメージに含めています。main.pyを変更したら、もう一度ビルドして反映します。
docker compose up -d --build
ライブラリを追加した場合も、uv addで更新したpyproject.tomlとuv.lockをそろえて、同じコマンドを実行します。
.envだけを変更した場合は、コンテナを作り直します。
docker compose up -d --force-recreate
docker compose restartだけでは、変更した環境変数は反映されません。
停止と再開には、次のコマンドを使います。
docker compose stop
docker compose up -d
起動できないときは、まずログを確認しましょう。トークンの間違いや、コードのエラーが見つかることがあります。自動再起動はプログラムの不具合を直す機能ではありません。
また、SQLiteなどでデータを保存するBotは、保存先をボリュームとして設定する必要があります。コンテナ内だけに保存すると、作り直したときにデータが失われるためです。
uvでライブラリを管理し、Composeに起動設定をまとめておけば、Botの更新やサーバー移行の手順をそろえやすくなります。起動確認後も、必要に応じてログや保存データを確認しながら運用していきましょう。
最後に
_____________________
現在DiscordBotの制作・運用・デバック依頼を受け付けております。
「この機能だけがほしいのに他の機能が多すぎる」「サーバーの専属BOTを作って欲しい」「デバックをしたいが時間がない」「BOTの紹介記事を書いてほしい!」と思っていて、依頼をしたい方は以下のDiscordサーバーへお越しください。
また、coconalaでも受け付けております。お気軽にご相談ください。

※DiscordBotの制作・デバック依頼に関しましては、5000円からの有料で受け付けています。
無償依頼は基本受け付けておりませんのでご了承ください。


コメント