はじめに
開発中のWebアプリには"localhost"というホスト名で接続するのが一般的ですが、昨今のIPv6のOSサポートにより、いろいろな問題が起きるようになりました。
※ 本記事の再現環境はWindows 10 Proです。Linuxなどの環境では現象は異なるかもしれません。
詳細はいいから、今すぐ解決したい場合
- localhost というホスト名でローカルサーバーに繋らないと思ったら、代わりに 127.0.0.1 を使用してください。恐らく問題は解決します。
詳細
ここからが本記事の本編です。詳細を知りたい人は読んでください。抽象的な説明は避け、実際に遭遇した現象で説明します。
ホスト名 "localhost" とは
かつて、IPv4しか無い時代には "localhost" とは 127.0.0.1 (ループバックデバイス)であることに疑いはありませんでした。
OSがIPv6をサポートした今では、"localhost" は 127.0.0.1(IPv4アドレス) と ::1(IPv6アドレス) の両方を指します。
これがいろいろな問題を引き起こします。
遭遇した問題
Rubygemsのredisクライアントから "localhost" で接続するとredis-serverに接続できない
redis-cli からは "localhost"を使って接続できるので、かなりわかりにくい現象です。
原因は次のようなことだと推測できます。
-
事実:Windowsのredis-serverは 127.0.0.1:6379 のみlistenしており ::1:6379 は listenしていません。
-
推測:Rubyのクライアントは "localhost" は ::1:6379 のみを使う。redis-cliは 127.0.0.1:6379 を使う。
RubyのWEBrickで起動したHTTPサーバーに Google Chrome Extensionから http://localhost/ で接続するとconnectに3秒かかる
実際には次のようになります。
1回目は即connectする。
2回目は3秒かけてconnectする。
3回目は即connectする。
4回目は3秒かけてconnectする。この繰り返しとなります。
.
.
-
事実:WEBRrickは 0.0.0.0:80 をlistenしている。(0.0.0.0はIPv4の全てアドレスという意味。つまりIPv6ではlistenしていない)
-
推測:Google Chromeは localhostを 127.0.0.1 と ::1 に解決し、127.0.0.1 と ::1 をラウンドロビンで使う。もし繋がらない場合は3秒タイムアウトで次のIPアドレスを試している。
RubyのWEBrickで起動したHTTPサーバーに Emacsの内蔵HTTPクライアントから接続できない
詳細は説明しませんが、恐らく localhost が ::1 に解決されるのでしょう。
さいごに
この記事のような現象はサーバーがIPv4とIPv6でlistenするようになるのが一般的になるまで発生し続けるのでしょう。