ExpressフレームワークでCSSやJQueryのアクセスでHTTP500が発生する時の対策法


Node.jsのアプリケーションで、数回に一回程度、CSSやJQueryのアクセス時にHTTP500 Internal Server Error が発生して、ウェブ画面の表示や動作が壊れる障害があり、対策についての備忘録です。

Expressフレームワークの express-generator でテンプレート・アプリケーションを生成すると、次のディレクトリ構造が作られる。そして、public ディレクトの stylesheets に CSSファイルを置いて、また、javascriptsの下にjquery.js 等を置いて、利用したところ、本問題に直面した。

~~~
.
├── app.js
├── bin
│   └── www
├── package.json
├── public
│   ├── images
│   ├── javascripts
│   └── stylesheets
│       └── style.css
├── routes
│   ├── index.js
│   └── users.js
└── views
    ├── error.pug
    ├── index.pug
    └── layout.pug
~~~


## 問題判別

調べた結果では、Node.jsのHTTP500の発生原因は解りませんでしたが、CSSファイルやJQueryなどスタティックなコンテンツの要求の応答の課程でHTTP500が発生していることが解ってきました。 また、この障害は３種類 (FireFox, Chrome, Safari)で同様に発生してました。
また、Node.js のバージョンを 6.11 から 8.6へ、バージョンを上げてみましたが、改善しませんでした。

![スクリーンショット 2017-10-03 22.26.10.png](https://qiita-image-store.s3.amazonaws.com/0/42829/e10d811d-4cd5-b40a-bd08-e10935ff7ab1.png "スクリーンショット 2017-10-03 22.26.10.png")


## 対策

回避策として、次の図の様に、public コンテンツ以下は、Nginxのコンテナで応答して、それ以外のNode.jsの処理は、Node.jsのコンテナへ転送する対策を試みました。

![スクリーンショット 2017-10-03 22.43.19.png](https://qiita-image-store.s3.amazonaws.com/0/42829/60e67d65-560d-c149-6ad6-228f0ddddaf9.png "スクリーンショット 2017-10-03 22.43.19.png")


この結果、CSSやJQuery等の静的ファイルのロードで、HTTP500が発生する事が無くなり、ウェブ画面が壊れる障害が事が無くなりました。

![スクリーンショット 2017-10-03 22.53.04.png](https://qiita-image-store.s3.amazonaws.com/0/42829/bf6c0cbf-df3e-ec3c-5480-0f0b01b6933a.png "スクリーンショット 2017-10-03 22.53.04.png")


## nginxリバースプロキシ設定ファイル

Nginxの設定ファイルは次の２つです。 最初、キャッシュ・プロキシーの設定だけを試しましたが改善が見られず、locationの設定を追加してところ、動作が改善して安定しました。

~~~file:default.conf
proxy_cache_path /var/cache/nginx keys_zone=zone1:1m max_size=1g inactive=24h;
proxy_temp_path  /var/cache/nginx_tmp;
~~~

~~~file:nginx.conf
server {
    listen                                  80;
    server_name                             _;
    root                                    /usr/share/nginx/html;

    proxy_redirect                          off;
    proxy_set_header Host                   $host;
    proxy_set_header X-Real-IP              $remote_addr;
    proxy_set_header X-Forwarded-Host       $host;
    proxy_set_header X-Forwarded-Server     $host;
    proxy_set_header X-Forwarded-For        $proxy_add_x_forwarded_for;
    proxy_cache zone1;
    location / {
	proxy_pass http://node_app:3000/;
    }

    location /javascripts/ {
	alias /usr/share/nginx/html/javascripts/;
    }

    location /stylesheets/ {
	alias /usr/share/nginx/html/stylesheets/;
    }

    location /images/ {
	alias /usr/share/nginx/html/images/;
    }

}
~~~


## Dockerコンテナのファイル

次の２つが、コンテナを作るためのDockerfileです。

~~~file:Dockerfile.nginx
FROM nginx:latest
ADD ./nginx_conf/default.conf /etc/nginx/conf.d/default.conf
ADD ./nginx_conf/nginx.conf /etc/nginx/conf.d/nginx.conf
COPY ./webapp1/public /usr/share/nginx/html
~~~


~~~file:Dockerfile.nodejs
FROM ubuntu:latest
RUN apt-get update && apt-get install curl -y
RUN curl -sL https://deb.nodesource.com/setup_6.x | /bin/bash -
RUN apt-get install nodejs -y
ADD /webapp1 /webapp1
ENV NODE_ENV development
EXPOSE 3000
CMD ["node", "/webapp1/bin/www"]
~~~


## docker-composeのYAMLファイル

NginxコンテナとNode.jsコンテナを連携して起動するためのファイルです。

~~~file:docker-compose.yaml
version: '3'

services:
    proxy_cache:
        build:
            context: .
            dockerfile: Dockerfile.nginx
        ports:
            - "4040:80"
        depends_on:
            - node_app
    node_app:
        build:
            context: .
            dockerfile: Dockerfile.nodejs
	ports:
            - "3000:3000"
~~~


## まとめ

Node.js の Express フレームワークで、publicの下に静的コンテンツを置くのは、要注意である。 そして、時々、スタイルシートやJQueryがロードされずウェブ画面の表示や動作が安定しない場合、静的コンテンツの処理をNginxでオフロードすると効果的である。 Dockerコンテナを適用することで、サーバーを増やさず効率良く対処できた。 さらに、この方法は、Kubernetesの利用時にも適用できると見込まれる。