Spring XD のフロントに Nginx を置いたらハマった話

この手のトラブルに慣れている人には、なんてことない話かもしれませんが、しばらくハマって疲弊したのでメモしておきます。

Spring XD は、9393 ポートで起動するので、これを 80 ポートからアクセスできるようにしようと、奮闘した話です。

べつに そのまま使用していてもよいのですが、やはり格好がつかないですし、何より あまりいろんなポートを自由に開けておくというのも抵抗があります。
そこで、Nginx をフロントに配し、プロキシしてやろうと。まあ当たり前ですね。

#環境

  - Ubuntu 14.04
  - Nginx 1.4.6
  - Java 1.8.0_66
  - Spring XD 1.3.0.RELEASE
  - Flo for Spring XD 1.0.0 GA (flo-spring-xd-admin-ui-client-1.3.0.RELEASE)

```
$ cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=14.04
DISTRIB_CODENAME=trusty
DISTRIB_DESCRIPTION="Ubuntu 14.04.3 LTS"
$ uname -a
Linux 133-130-119-232 3.16.0-51-generic #69~14.04.1-Ubuntu SMP Wed Oct 7 15:32:41 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux
$ nginx -v
nginx version: nginx/1.4.6 (Ubuntu)
$ java -version
java version "1.8.0_66"
Java(TM) SE Runtime Environment (build 1.8.0_66-b17)
Java HotSpot(TM) 64-Bit Server VM (build 25.66-b17, mixed mode)
$ ./xd-shell
 _____                           __   _______
/  ___|          (-)             \ \ / /  _  \
\ `--. _ __  _ __ _ _ __   __ _   \ V /| | | |
 `--. \ '_ \| '__| | '_ \ / _` |  / ^ \| | | |
/\__/ / |_) | |  | | | | | (_| | / / \ \ |/ /
\____/| .__/|_|  |_|_| |_|\__, | \/   \/___/
      | |                  __/ |
      |_|                 |___/
eXtreme Data
1.3.0.RELEASE | Admin Server Target: http://localhost:9393
Welcome to the Spring XD shell. For assistance hit TAB or type "help".
xd:>
```

以前セットアップした環境とは異なりますが、Spring XD、Flo については以下記事と同様のものをを引き続き利用します。

- [Spring XD のセットアップを試してみた話](http://qiita.com/yo1000/items/a8c92cc5931e79080a5d)
- [Flo for Spring XD でグラフィカルに XD をあつかう話](http://qiita.com/yo1000/items/855d6307ad2db2d90200)

#だめだった設定

はじめは簡単に、以下のような設定をおこなっていました。
これは、うまくいかなかった設定です。

```conf:/etc/nginx/sites-enabled/default
server {
        listen 80 default_server;
        listen [::]:80 default_server ipv6only=on;

        root /usr/share/nginx/html;
        index index.html index.htm;

        # Make site accessible from http://localhost/
        server_name localhost;

        proxy_redirect   off;
        proxy_set_header Host               $host;
        proxy_set_header X-Forwarded-For    $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Host   $host;
        proxy_set_header X-Forwarded-Server $host;
        proxy_set_header X-Real-IP          $remote_addr;

        location / {
                # First attempt to serve request as file, then
                # as directory, then fall back to displaying a 404.
               try_files $uri $uri/ =404;
                # Uncomment to enable naxsi on this location
                # include /etc/nginx/naxsi.rules
        }

        location /spring-xd/ {
                proxy_pass http://localhost:9393/;
        }
}
```

どうなるか...というと、こうなる。
<img width="801" alt="スクリーンショット 2015-12-05 3.06.34.png" src="https://qiita-image-store.s3.amazonaws.com/0/47993/2b6d5c0b-bdc9-80bf-7238-dcf61c1c04cb.png">

画面に、`Error retrieving security info from /security/info (timeout: 20000ms)` なんてメッセージが表示されて、うんともすんとも言わない。

これ何が起きているのでしょうか。
404 がレスポンスされている `info` を詳しく見てみます。

>- General
    - Request URL:http://`host.name`/security/info
    - Request Method:GET
    - Status Code:404 Not Found
    - Remote Address:`ip.add.re.ss`:80
- Request Header
    - Accept:application/json, text/plain, */*
    - Accept-Encoding:gzip, deflate, sdch
    - Accept-Language:ja,en-US;q=0.8,en;q=0.6
    - Connection:keep-alive
    - Host:`host.name`
    - Referer:http://`host.name`/spring-xd/admin-ui/
    - User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.73 Safari/537.36

`proxy_pass` を設定したにも関わらず、`/spring-xd/**` ではなく、直接 `/security/info` にリクエストしているようです。
調べてみると、その答えは js の中にありました。

```js:main.js
var initInjector = angular.injector(['ng']);
var $http = initInjector.get('$http');
var securityInfoUrl = '/security/info';
var timeout = 20000;
var promiseHttp = $http.get(securityInfoUrl, {timeout: timeout});
```

コンテキストルート、全く考慮されてません。

Spring XD のフロントは、AngularJS で実装されています。
この実装がひとつの原因となり、Nginx で設定した 間に挟まるはずの `/spring-xd/` を無視して、直接エンドポイントまでアクセスしにきていたのでした。

なお、これの他にも `*.json` に向けてアクセスしてきていたものも、同様にコンテキストルートを無視したものになっており、同じく対処が必要であることがわかりました。

#よかった設定

さて、それではこれらを踏まえて、改めて Nginx を設定し直します。

以下のような設定にて、ひととおり期待通りの動作となりました。
こちらの設定が 唯一の正解というわけでもありませんが、参考まで。

```conf:/etc/nginx/sites-enabled/default
server {
        listen 80 default_server;
        listen [::]:80 default_server ipv6only=on;

        root /usr/share/nginx/html;
        index index.html index.htm;

        # Make site accessible from http://localhost/
        server_name localhost;

        proxy_redirect   off;
        proxy_set_header Host               $host;
        proxy_set_header X-Forwarded-For    $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Host   $host;
        proxy_set_header X-Forwarded-Server $host;
        proxy_set_header X-Real-IP          $remote_addr;

        location / {
                # First attempt to serve request as file, then
                # as directory, then fall back to displaying a 404.
               try_files $uri $uri/ =404;
                # Uncomment to enable naxsi on this location
                # include /etc/nginx/naxsi.rules
        }

        # Spring XD
        location /spring-xd/ {
                proxy_pass http://localhost:9393/;
        }

        location /security/info {
                if ($http_referer ~* /spring-xd/admin-ui/$) {
                        proxy_pass http://localhost:9393$request_uri;
                }
        }

        location ~ \.json$ {
                if ($http_referer ~* /spring-xd/admin-ui/$) {
                        proxy_pass http://localhost:9393$request_uri;
                }
        }
}
```

追加した `location /security/info` と、`location ~ \.json$` で、設定済みのコンテキストルート `/spring-xd/admin-ui/` をリファラの末尾に持つリクエストに限り、コンテキストルートを無視したリクエストをプロキシしてあげるようにしてみました。

できた！よさそうですね。
<img width="790" alt="スクリーンショット 2015-12-05 3.48.47.png" src="https://qiita-image-store.s3.amazonaws.com/0/47993/2a20a4a6-b394-8246-dd6e-ba8186f00d17.png">

これで、同環境内への、他のリクエストを引っ掛けてしまうこともなく、無事に目的を果たすことができました。
Nginx のように、簡単に if なんかでリクエストを処理できてしまうのは、本当にありがたいですね。