やりたかったこと
Node.jsで作ったアプリをVPS上でnginxを使って公開したかった。 ポート3000で動いているアプリを80番・443番ポートで外部公開するためにリバースプロキシの設定が必要だった。
リバースプロキシの仕組み
クライアント → nginx(80/443)→ Node.jsアプリ(3000)
nginxがリクエストを受けてバックエンドのアプリに転送する。 直接アプリのポートを公開しなくて済むのでセキュリティ面でも有利。
基本的なリバースプロキシ設定
/etc/nginx/sites-available/myapp を作成する。
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
シンボリックリンクを作成して有効化する。
sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
Node.jsアプリ側の設定
アプリはlocalhost(127.0.0.1)でlistenするだけでよい。
const express = require('express');
const app = express();
app.listen(3000, '127.0.0.1', () => {
console.log('Server running on port 3000');
});
外部に直接ポート3000を公開しない場合はファイアウォールで塞いでおく。
sudo ufw deny 3000
sudo ufw allow 80
sudo ufw allow 443
WebSocketのプロキシ設定
WebSocketを使う場合は追加のヘッダーが必要。
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
Upgrade と Connection ヘッダーがないとWebSocketのハンドシェイクが失敗する。
複数アプリを同一サーバーで動かす
ドメインやパスで振り分けることができる。
# ドメインで振り分け
server {
listen 80;
server_name app1.example.com;
location / {
proxy_pass http://localhost:3000;
}
}
server {
listen 80;
server_name app2.example.com;
location / {
proxy_pass http://localhost:4000;
}
}
# パスで振り分け
server {
listen 80;
server_name example.com;
location /api/ {
proxy_pass http://localhost:3000/;
}
location / {
proxy_pass http://localhost:4000;
}
}
SSL(HTTPS)対応
CertbotでSSLを設定すると /etc/nginx/sites-available/myapp が自動で書き換えられる。
sudo certbot --nginx -d example.com
Certbotが proxy_pass の設定はそのままにしてSSLの設定だけ追加してくれる。
ハマったポイント
proxy_set_header Host $host;を忘れるとバックエンド側でホスト名が取れないproxy_http_version 1.1;を指定しないとWebSocketが接続できないproxy_pass http://localhost:3000/;の末尾スラッシュの有無でパスの扱いが変わる(末尾スラッシュありだとlocationのパス部分が除去される)- Node.jsアプリが127.0.0.1でlistenしていないと
502 Bad Gatewayになる nginx -tでテストしてからreloadしないと設定ミスで本番が落ちる
リバースプロキシの設定後にHTTPSも対応させたい場合はnginxにLet’s EncryptのSSL証明書を設定する方法(certbot)で無料のSSL証明書を取得できる。
関連記事
- nginxの基本的な設定ファイルの書き方
- nginx 502 Bad Gatewayエラーの原因と解決方法
- CertbotでnginxにSSL証明書を設定する方法
- VPSにDockerとnginxをセットアップする手順
- Linuxのファイアウォール設定(ufw)
おすすめのVPS/ドメイン
VPSを使って本番環境を構築するなら、以下のサービスがおすすめです。