127.0.0.1とlocalhostと0.0.0.0の違い


それぞれの意味について


127.0.0.1

127.0.0.1はループバックアドレスの一つであり、同時に127.0.0.1に対応する仮想的なネットワーク・インターフェースを表します。

ループバックアドレスは自分自身を表す特別なIPアドレスのことです。

ループバックアドレスは同一ホスト内でしか通信を行いません。


localhost

127.0.0.1を表すホスト名のことです。

127.0.0.1とほぼイコールなので当たり前ですが、こちらも同一ホスト内でしか通信を行いません。

何らかの開発用サーバを立ち上げた際に、ブラウザにlocalhost:8080といったアドレスを入力することがあるかと思いますが、それはこのlocalhostです。


0.0.0.0

前者2つとだいぶ異なり、すべてのネットワーク・インターフェースを表します。

ワイルドカードのようなもので、すべての通信を表します。

こちらは別ホストからでもアクセスすることが可能です。


ちょっと試してみる

pythonでいくつか試してみます。

まず雰囲気作りのために簡単なコンテンツを用意します。

$ mkdir test && cd test

$ echo "<h1>Hello<h1>" >> index.html

次に以下のコマンドで開発用サーバを起動します。

$ python3 -m http.server 8000

この状態でブラウザでlocalhost:8000にアクセスすると、Helloの文字を見ることができます。

ところでpythonの開発用サーバの出力1行目を見てみましょう。

$ python3 -m http.server 8000

Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...

on 0.0.0.0 port 8000という記述は、0.0.0.0の8000ポートに対して開発用サーバが起動していることを表します。

0.0.0.0はワイルドカードのようなものでした。

つまりこれは、すべてのネットワーク・インターフェースの8000ポートに対して、サーバが起動している状態です。

この状態ではネットワークが繋がってさえいれば、remoteからアクセスすることが可能です。

次に127.0.0.1を指定して開発用サーバを起動してみましょう。

--bindオプションを利用することで指定できます。

$ python3 -m http.server --bind 127.0.0.1 8000

Serving HTTP on 127.0.0.1 port 8000 (http://127.0.0.1:8000/) ...

127.0.0.1の8000ポートに対してサーバが起動している状態です。

この状態でも同一ホストでブラウザにlocalhost:8000を指定すればHelloが表示されます。

ただしlocalhostはループバックアドレスです.

なので、この状態では仮にネットワークが繋がっていてもremoteからアクセスすることができません。

最後にlocalhostを指定してみましょう。

$ python3 -m http.server --bind localhost 8000

Serving HTTP on 127.0.0.1 port 8000 (http://127.0.0.1:8000/) ...

1行目の出力が127.0.0.1を指定した場合と全く一緒です。

これはlocalhostが127.0.0.1のホスト名であるためです。


bindとは

別ウィンドウを立ち上げて、例えば以下のコマンドを2回叩いてみます。

# わかりやすさのために0.0.0.0を明示

$ python3 -m http.server --bind 0.0.0.0 8000

するとあとから起動した方では以下のようなエラーになります。

OSError: [Errno 48] Address already in use

一方で例えば、以下2つであれば同時に走らせてもエラーにはなりません。

この状態でブラウザからlocalhost:8000にアクセスすると、bindにlocalhostを指定した方のコンソールにアクセスログが出力されます。

$ python3 -m http.server --bind localhost 8000

$ python3 -m http.server --bind 0.0.0.0 8000

1つめと2つめの違いは、IPとポートの組み合わせが一致しているかどうかです。

私は、マシンに8000ポートは一つしかない、と思っていたことがありました。

ただこれは誤りで、実際は一つのネットワーク・インターフェースにつき一つです。

このネットワーク・インターフェースには、127.0.0.1のような仮想的なものも含まれます。

そしてマシンは複数のネットワーク・インターフェースを持つことができ、複数のIPアドレスを持つことが出来ます。

bindオプションは、ネットワークインターフェース(に紐づくIP)とそのポートを指定することで、そのネットワーク・インターフェースを通ってきたアクセスのみを識別して処理を行うことができます。

localhostや0.0.0.0といったちょっと特別なIPを例に挙げましたが、もちろんマシンが持つローカルIPアドレスをbindに指定することもできます。

この仕組はpythonに限った話ではなく、一般的にbind addressと呼ばれます。


参考

https://stackoverflow.com/questions/20778771/what-is-the-difference-between-0-0-0-0-127-0-0-1-and-localhost