ElasticBeanstalk 上の NodeJS が80番ポートへのアクセスを受けるまでの流れ

Elastic Beanstalk の NodeJS Platform でアプリケーションを作成すると
80 ポートでアクセスできる Web アプリケーションが簡単に出来上がる。

しかし NodeJS は 80 番ポートとは異なるポート 8081 番を Listen しており、
どういった経路で 80 番からのアクセスを受けているのか調べた。

ポート転送の流れ (結論)

  • iptables (PREROUTING)
    • 転送ポート: 80 --> 8080
  • nginx (Proxy)
    • 転送ポート: 8080 --> 8081
  • node (Server)

まず 80 番ポートへのアクセスを iptables が 8080 に変換し、
次に LISTEN 8080 の状態で起動している nginx が 8081 に転送、
次に LISTEN 8081 の状態で起動している NodeJS がリクエストを処理する。

一般的に 0 ~ 1023 番のポートは「well known port」と呼ばれ、Linux では root 権限がないとポートの Listen が出来ない。

root ユーザで nodejs プロセスを動かすことは危険だが、
この構成にすることで nodejs を一般ユーザで起動することが出来る。

ElasticBeanstalk では nodejs プロセスは nodejs ユーザが起動していた。

上記の情報元

EC2 インスタンスに入って上記を調べた時のメモ。
関係のない出力内容は一部割愛。

iptables の設定

80 で受けたアクセスを 8080 へ転送する NAT が作成されている。
PREROUTING チェインのため EC2 インスタンスがアクセスを受けた時にまず処理される。

$ sudo iptables -t nat -S PREROUTING -v
-A PREROUTING -i eth0 -p tcp -m tcp --dport 80 -c 0 0 -j REDIRECT --to-ports 8080

nginx の設定

8080 で受けたアクセスを 8081 に転送するプロキシ設定。
本題とは関係ないが通信の gzip 圧縮・展開もこの層で行われる。

$ cat /etc/nginx/conf.d/00_elastic_beanstalk_proxy.conf
upstream nodejs {
    server 127.0.0.1:8081;
}

server {
    listen 8080;

    location / {
        proxy_pass  http://nodejs;
        proxy_set_header   Connection "";
        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;
    }
}

gzip on;
gzip_comp_level 4;
gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript;

関連プロセスの Port Listen 状況

node が 8081, nginx が 8080 をそれぞれ Listen していることが分かる。

$ sudo netstat -anp
tcp        0      0 :::8081                     :::*                        LISTEN      2969/node
tcp        0      0 0.0.0.0:8080                0.0.0.0:*                   LISTEN      2977/nginx

NodeJS 起動時の環境変数

PORT=8081 とあるので nodejs は 8081 を Listen する。

$ sudo od -S1 -An /proc/$(ps aux | grep ^nodejs | perl -anlE 'say $F[1]' | tail -1)/environ
PATH=/usr/local/sbin:/usr/local/bin:/usr/bin:/usr/sbin:/sbin:/bin:/opt/elasticbeanstalk/node-install/node-v6.11.5-linux-x64/bin
SHELL=/bin/sh
TERM=linux
EB_NODE_COMMAND=node app.js
USER=nodejs
PWD=/var/app/current
HOME=/tmp
SHLVL=1
UPSTART_INSTANCE=
LOGNAME=nodejs
PORT=8081
UPSTART_JOB=nodejs
NODE_HOME=/opt/elasticbeanstalk/node-install/node-v6.11.5-linux-x64
_=/opt/elasticbeanstalk/node-install/node-v6.11.5-linux-x64/bin/node

NodeJS のデフォルトのアプリケーションソース

上記で分かるように環境変数 PORT が定義されているため、
8081 ポートが Listen される。

app.js
var port = process.env.PORT || 3000,
    http = require('http'),
    fs = require('fs'),
    html = fs.readFileSync('index.html');

var log = function(entry) {
    fs.appendFileSync('/tmp/sample-app.log', new Date().toISOString() + ' - ' + entry + '\n');
};

var server = http.createServer(function (req, res) {
    // 省略
});
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.