概要
発端
- Xserverにおいて、listenした特定ポートにアクセスしても応答がない
- 直接、特定ポートへアクセスできないため、なんらかの形でNAPTを実現する必要があった
- root特権を得られないという提供サービスの性質上、サブドメインと.htaccessとへの追加設定で実現できた
- 明示的に、こうした情報がGoogle先生から得られなかったのでここに記す
得られた知見
- Xserverでは、PUSH通信サービスは運用できない
- WebSocket通信で400エラーが生じるため
- nginx設定でNAPTを構成できないことによる
- ただし、polling方式によるPULL通信はできるので、独自Webサービスそのものは提供できる
- Socket.IOはPUSH/PULL両通信方式をデフォルトで試みる
- 通信効率やサーバ負荷を考えると、PULL通信では大規模なものは不適
結論
- フロントで動くWebサーバを変更できず、特定ポートでWebサービスを提供する場合
- 正しくプロキシを構成すれば良い
- 別サーバを立てる
- 無理やり動かす
- 本稿では、Xserverで10080ポートで稼働させた設定を記す
設定例
- 10080ポートでSocket.IOベースのWebサービスを起動
- サブドメインを追加設定(Rewriteルールがややこしくなるため)
- io.connect()でwebsocketを外す
- .htaccessに以下を追記
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule socket.io/socket.io.js http://localhost:10080/socket.io/socket.io.js [L,P]
RewriteRule ^(.*) http://localhost:10080/$1 [L,P]
</IfModule>
経緯
- Xserverはapacheが動作していると早合点
- .htaccessを設定できたため
- 実は、nginxが動作
- 特定ポートへの通信は許可されていない
-
http://www.example.com:nnnn/
では全て応答なし
-
- 従って、
http://www.example.com/
だけの入力で、localhost:nnnnに通信するよう、NAPTの仕組みを導入する必要がある
試行錯誤
- .htaccessにProxyPass=> 500エラー
- .htaccessにLocation=> 500エラー
- .htaccessでmod_rewrite(
www.example.com
-> localhost:10080へ)- 通常の書き方ではURL書き換えのリダイレクトになるので[P]を使う
- listenしている10080ポートからの応答に成功、だがSocket.IO的に失敗
- socket.IOのクライアント側で404 エラー
404 エラー?
- Failed to load resource: the server responded with a status of 404 (Not Found)
<script src="/socket.io/socket.io.js"><!-- ここが見つからない -->
www.example.com/socket.io/socket.io.js
は存在しない。
localhost:10080/socket.io/socket.io.js
として
アクセスさせないといけない。
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule socket.io/socket.io.js http://localhost:10080/socket.io/socket.io.js [L,P]
RewriteRule ^(.*) http://localhost:10080/$1 [L,P]
</IfModule>
続 404 not found
- io.connect()でサービス接続時にエラー
- socket.io/以下のRequestを、localhost:10080へ全て転送する必要がある
GET http://www.example.com/socket.io/?EIO=3&transport=polling&t=MPXhUo6 404 (Not Found)
webclient.js:95 connect_error Error: xhr poll error
at o.r.onError (socket.io.js:7)
at i.<anonymous> (socket.io.js:7)
at i.r.emit (socket.io.js:6)
at i.onError (socket.io.js:7)
at socket.io.js:7
まだ出るエラー; 400 エラー?
* WebSocket connection to 'ws://www.example.com/socket.io/?EIO=3&transport=websocket&sid=A-YcIDGgXoCEvPYyAAA
' failed: Error during WebSocket handshake: Unexpected response code: 400
- Socket.IOは、PUSH/PULL通信方法を用意していて, xhr-polling, websocket, polling等、うまくいくものの通信でコネクションを張る
- そのうちPULL通信方式はmod_rewriteで解決
- PUSH通信方式のWebSocket通信で失敗
- nginx + Socket.IOの組み合わせで必ず出る
- 解決するには、正確にNAPTがなされなければならない
- なお、AWSで生じるのはロードバランサーのせい
- この場合の解決はこちら
最終設定
- io.connect()時に、websocketを外す(敗北)
const server = io.connect(this.host,
{'transports': ["xhr-polling","polling"],
'reconnection': true,
'reconnectionDelay': 1000,
'reconnectionDelayMax' : 5000,
'reconnectionAttempts': 5
})
まとめ
- 通常ならmod_rewriteでのNAPT構成のためにプロキシ設定だけで終わると思われるところ
- Socket.IOの事情で、難航した。
- 何かのお役に立てればと。FYI.
余談
- どうもathenaのX-Window Systemと思ってしまう。astec-xとか。