本文へスキップ
← ガイド一覧

自分で作ったWebアプリをサーバーにデプロイする (Node.js・Python)

自分のPCで作ったExpress・Next.js(Node.js)やFlask・FastAPI(Python)のアプリをサーバーで24時間動かし、ドメインでアクセスできるようにするまでの全体の流れです。Ubuntuを前提としています。

全体の流れ

  1. コードをサーバーに取り込む (GitHub)
  2. 秘密の値を.envに入れる
  3. アプリを常時実行する (Node.jsはpm2、Pythonはsystemd)
  4. Nginxでドメインを接続し、HTTPSを適用する

1. コードを取り込む

GitHubのリポジトリが公開されているなら、そのまま取得します。

git clone https://github.com/my-id/my-app.git
cd my-app

非公開リポジトリの場合 (デプロイキー)

サーバー専用のキーを作ってリポジトリに「読み取り専用」で登録すれば、自分のGitHubのパスワードをサーバーに置かなくて済みます。

ssh-keygen -t ed25519 -f ~/.ssh/deploy_key -N ""
cat ~/.ssh/deploy_key.pub

出力された1行をコピーし、GitHubのリポジトリ → Settings → Deploy keys → Add deploy keyに貼り付けます。(「Allow write access」にはチェックしません)次に、サーバーがこのキーを使うように設定して取得します。

printf 'Host github.com\n  IdentityFile ~/.ssh/deploy_key\n' >> ~/.ssh/config
git clone [email protected]:my-id/my-app.git

2. 秘密の値は.envに

DBのパスワードやAPIキーのような値は、コードに直接書かずに、サーバーの.envファイルに入れます。

nano .env

🔒 .envは.gitignoreに入れて、GitHubにアップロードされないようにしてください。

3-1. Node.jsアプリ (pm2)

Node.jsのインストールは、Discordボットを24時間ホスティングする (discord.js・discord.py)の「Node.jsのインストール」と同じです。

npm ci                                   # package-lock.jsonに基づいてインストール
npm run build                            # ビルド手順があるアプリのみ(Next.jsなど)
sudo npm install -g pm2
pm2 start npm --name my-app -- start     # package.jsonのstartスクリプトで実行
pm2 save
pm2 startup                              # 出力されたコマンドをもう一度コピーして実行

3-2. Pythonアプリ (systemd)

sudo apt install -y python3-venv
python3 -m venv venv
./venv/bin/pip install -r requirements.txt
./venv/bin/pip install uvicorn       # FastAPIの場合
./venv/bin/pip install gunicorn      # Flaskの場合

サービスファイルを作成します。

sudo nano /etc/systemd/system/my-app.service

パスのusernameとmy-appは実際の値に置き換え、ExecStartは2つのうち自分のアプリに合う行を1つだけ残します。(main:appはmain.pyの中のapp、app:appはapp.pyの中のappという意味です)

[Unit]
Description=My Web App
After=network-online.target

[Service]
User=username
WorkingDirectory=/home/username/my-app
EnvironmentFile=/home/username/my-app/.env
# FastAPI
ExecStart=/home/username/my-app/venv/bin/uvicorn main:app --host 127.0.0.1 --port 8000
# Flask
# ExecStart=/home/username/my-app/venv/bin/gunicorn -w 2 -b 127.0.0.1:8000 app:app
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now my-app
sudo systemctl status my-app      # active (running)なら成功

4. ドメインの接続とHTTPS

Webサイトを立ち上げるに沿ってNginxとドメイン、証明書を設定し、「Node.js・Pythonアプリを接続したい場合」の部分にあるproxy_passのポートを、自分のアプリのポート(Node.jsは通常3000、上のPythonの例は8000)に合わせます。

アプリのポート(3000、8000)は、ファイアウォールで開ける必要はありません。 外部にはNginxの80・443だけを開け、アプリにはNginxを通してのみアクセスできるようにするのが安全です。

5. コードを修正した後に更新する

cd ~/my-app
git pull

# Node.js
npm ci && npm run build && pm2 restart my-app

# Python
./venv/bin/pip install -r requirements.txt && sudo systemctl restart my-app

うまくいかないとき

  • まずログを確認してください — pm2 logs my-appまたはjournalctl -u my-app -f
  • 502 Bad Gateway — アプリが停止しているか、Nginxのproxy_passのポートとアプリのポートが異なります。
  • EADDRINUSE / Address already in use — そのポートをすでに別のプログラムが使っています。sudo ss -ltnp | grep 3000で、何が使っているか確認してください。
  • メモリ不足でビルドが止まります — npm run buildの途中でサーバーが止まる場合は、スワップを追加してみてください。

解決しない問題がある場合は、Discordのチケットでお問い合わせください。