自分で作ったWebアプリをサーバーにデプロイする (Node.js・Python)
自分のPCで作ったExpress・Next.js(Node.js)やFlask・FastAPI(Python)のアプリをサーバーで24時間動かし、ドメインでアクセスできるようにするまでの全体の流れです。Ubuntuを前提としています。
全体の流れ
- コードをサーバーに取り込む (GitHub)
- 秘密の値を
.envに入れる - アプリを常時実行する (Node.jsはpm2、Pythonはsystemd)
- 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の途中でサーバーが止まる場合は、スワップを追加してみてください。