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 ユーザで node
プロセスを動かすことは危険だが、
このようにポート転送することで一般ユーザで起動することが出来る。
ElasticBeanstalk では node
プロセスは 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
とあるので node
は 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 が設定されているため、
8081 ポートが Listen される。
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) {
// 省略
});