質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.37%
nginx

nginixは軽量で高性能なwebサーバーの1つです。BSD-likeライセンスのもとリリースされており、あわせてHTTPサーバ、リバースプロキシ、メールプロキシの機能も備えています。MacOSX、Windows、Linux、上で動作します。

Elastic Load Balancing

Elastic Load Balancingは、Amazon社が提供する、 EC2インスタンス間で自動的にトラフィックの負荷分散を行うサービスです。

AWS(Amazon Web Services)

Amazon Web Services (AWS)は、仮想空間を機軸とした、クラスター状のコンピュータ・ネットワーク・データベース・ストーレッジ・サポートツールをAWSというインフラから提供する商用サービスです。

Q&A

解決済

1回答

14084閲覧

ELB配下のEC2でnginxのリバースプロキシを使っている環境のみアクセス元IPが取得できない

CyberMergina

総合スコア295

nginx

nginixは軽量で高性能なwebサーバーの1つです。BSD-likeライセンスのもとリリースされており、あわせてHTTPサーバ、リバースプロキシ、メールプロキシの機能も備えています。MacOSX、Windows、Linux、上で動作します。

Elastic Load Balancing

Elastic Load Balancingは、Amazon社が提供する、 EC2インスタンス間で自動的にトラフィックの負荷分散を行うサービスです。

AWS(Amazon Web Services)

Amazon Web Services (AWS)は、仮想空間を機軸とした、クラスター状のコンピュータ・ネットワーク・データベース・ストーレッジ・サポートツールをAWSというインフラから提供する商用サービスです。

4グッド

5クリップ

投稿2016/02/09 06:09

編集2016/02/15 09:04

ELB × nginx(リバースproxy) × Nodeサーバーの環境で、Nodeサーバー側のシステムにアクセス元IPアドレスを渡したい。

□ 状態(追記しました)

  • リスナー設定
TCP(80) -> TCP(80) SSL(443) -> TCP(80)

□ 今分かっていること

  • ELB × nginxの環境で、$remote_addrがELBのアドレスになる
  • ELB側でアクセス元IPアドレスがヘッダーの「X-Forwarded-For」に渡されている

ということは把握しています。
リバースプロキシを使用しない場合は「X-Forwarded-For」からアクセス元IPアドレスはとれました。

ですが、nginxでリバースプロキシを使用する場合は「X-Forwarded-For」にもELBのアドレスが入ってます。
(これはnginx側でセットされたのでしょうか・・・)

□ nginxの変数
$remote_addr, $proxy_add_x_forwarded_for にはELBのアドレス
$http_x_forwarded_for は空

何か情報をお持ちの方がいらっしゃいましたら、ご教授願います。
よろしくお願いします。


/etc/nginx/nginx.conf

conf:nginx.conf

1http { 2 include /etc/nginx/mime.types; 3 default_type application/octet-stream; 4 5 log_format main '$remote_addr - $remote_user [$time_local] "$request" ' 6 '$status $body_bytes_sent "$http_referer" ' 7 '"$http_user_agent" "$http_x_forwarded_for"'; 8 9 access_log /var/log/nginx/access.log main; 10 11 sendfile on; 12 tcp_nopush on; 13 tcp_nodelay on; 14 15 16 keepalive_timeout 65; 17 types_hash_max_size 2048; 18 19 include /etc/nginx/conf.d/*.conf; 20 index index.html index.htm; 21 22# set_real_ip_from 10.0.0.0/8; 23# real_ip_header X-Forwarded-For; 24 25}

/etc/nginx/conf.d/default.conf

conf:default.conf

1server { 2server { 3 listen 80 proxy_protocol; 4 server_name hoge.hoge.jp; 5 proxy_request_buffering off; 6 7 set_real_ip_from XX.XX.0.0/XX; # VPC CIDR 8 real_ip_header proxy_protocol; 9 10 location /demo/ { # デモページ(html) 11 proxy_pass http://demo.localhost/; 12 } 13 14 location / { # socket.io用のjsファイルを読み込むのに使用します。 15 proxy_pass http://0.0.0.0:1000; 16 } 17 18 location /socket.io/ { # websocket通信 19 proxy_pass http://0.0.0.0:2000; 20 proxy_set_header X-Real-IP $proxy_protocol_addr; 21 proxy_read_timeout 150; 22 proxy_set_header Host $host:$server_port; 23 proxy_set_header X-Forwarded-For $proxy_protocol_addr; 24 proxy_set_header X-Forwarded-Proto http; 25 proxy_http_version 1.1; 26 proxy_set_header Upgrade $http_upgrade; 27 proxy_set_header Connection "upgrade"; 28 } 29 30}

□ 進捗

AWSのELBにProxyProtocolを有効にするような設定が必要?

参考

AWS wiki
How to configure AWS ELB and Nginx for WebSocket protocol? [closed]
Using Proxy Protocol With Nginx

>ProxyProtocolを有効にしました。(追記:2016/02/10 16:28)
恐らくあと少しで解決しそうです・・・!

TaichiYanagiyaさんの案①を参考に設定すると、nginxのログにはアクセス元IPが出てきました!

'$proxy_protocol_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent "$http_referer" ' '"$http_user_agent"';
- - [10/Feb/2016:16:15:01 +0900] "PROXY TCP4 [アクセス元IP] XXX.XXX.XXX.XXX 5602 443" 400 172 "-" "-"

但し、BadRequestが出ています・・・
もう少し調べてみます・・・!

>ProxyProtocolを有効にしました。(追記:2016/02/10 19:21)

ひとまず、現状の設定ファイルの内容に更新しました。
ProxyProtocolを有効にしたことで、Bad Requestが発生しています。

AWSのProxyProtocol使用の前提条件に「プロキシサーバーとロードバランサーの両方で有効になっていること」とありました。
http://blog.serverworks.co.jp/tech/2013/08/01/elb-proxy-protocol/
Nodeサーバー側でも何らかの処理が必要になるのでしょうか・・・?

その方面で検索するとこちらの記事を発見しましたので、調べてみます。

>ProxyProtocolを有効にし、BadRequestは解決。ただ、他のVHと共存できない(追記:2016/02/15 18:04)

  • TCPで通信するVirtualHostのみにした際、BadRequestは解決し、ログファイルにも「"PROXY ..."」ではなく「"GET ..."」という形でログが残るようになっていました

ただ、他にHTTPで通信しているVirtualHost(Server Nameで分けている)が接続できなくなった。

構造は以下の通りになっています。

[ELB1] server_name hoge.jp HTTPS(443) -> HTTP(80) HTTP(80) -> HTTP(80) [nginx] root(/var/www/html) [ELB2] server_name node.hoge.jp SSL(443) -> TCP(80) TCP(80) -> TCP(80) [nginx(Reverce Proxy)] / -> 3000port(Nodeサーバー) /socket.io/ -> 4000port(WSサーバー) [ELB3] server_name main.hoge.jp HTTPS(443) -> HTTP(80) HTTP(80) -> HTTP(80) [nginx] root(/var/www/main)

※インスタンスは1つ
※現在、最小構成にしているのでProxyサーバー、Appサーバーなど分けていません。

proxy protocolを有効にするとELB1ELB3が接続できなくなります。
(ELBのヘルスチェックで引っかかる)

TCPとHTTPの共存は厳しいのでしょうか・・・?

takotakot, EKD, hato_pato, ikuwow👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

default.conf の proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 箇所でヘッダを追加していますので、この設定をはずせばいいです。

という単純な問題ではない?

###(2016/02/10 12:40 追記)
ELB で ProxyProtocol を有効にした場合、nginx で listen ディレクティブに proxy_protocol を付ける必要があるようです。
とすると、ELB 80番ポートも HTTP から TCP に変更し、X-Forwarded-For の替わりに ProxyProtocol でアクセス元IPを拾うといいと思います。

(ELBリスナー設定) TCP 80 -> TCP 80 SSL 443 -> TCP 80 (インスタンス側 80番ポートについて ProxyProtocol を有効にする) (ELBヘルスチェック設定) TCP:80 (他は任意) (nginx設定) server { listen 80 proxy_protocol; set_real_ip_from 10.0.0.0/8; real_ip_header proxy_protocol; (中略) location /socket.io/ { proxy_pass http://0.0.0.0:2000; #proxy_set_header X-Real-IP $remote_addr; # こちらでもOK? proxy_set_header X-Real-IP $proxy_protocol_addr; proxy_read_timeout 150; proxy_set_header Host $host:$server_port; #proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # こちらでもOK? proxy_set_header X-Forwarded-For $proxy_protocol_addr; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; } }

参考: How to Configure NGINX to Accept the Proxy Protocol

あるいは、現在の 80番ポートをそのまま利用するのであれば、ProxyProtocol 用に別のポートを用意する方法も考えられます。

(ELBリスナー設定) HTTP 80 -> HTTP 80 SSL 443 -> TCP 8080 (インスタンス側 8080番ポートについて ProxyProtocol を有効にする) (ELBヘルスチェック設定) HTTP:80 (他は任意) (nginx設定) server { listen 80; set_real_ip_from 10.0.0.0/8; real_ip_header X-Forwarded-For; location / { proxy_pass http://0.0.0.0:1000; # これは通常の HTML? } } server { listen 8080 proxy_protocol; set_real_ip_from 10.0.0.0/8; real_ip_header proxy_protocol; location /socket.io/ { proxy_pass http://0.0.0.0:2000; # (他、1つ目の設定と同じ) } }

投稿2016/02/09 10:01

編集2016/02/10 03:44
TaichiYanagiya

総合スコア12173

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

CyberMergina

2016/02/10 00:21

回答ありがとうございます。 「X-Forwarded-For」の設定を外しても、「X-Forwarded-For」の情報が渡されなくなるだけで、アクセス元のIPが取得できるようにならないのです・・・
takotakot

2016/02/10 01:19

> リバースプロキシを使用しない場合は「X-Forwarded-For」からアクセス元IPアドレスはとれました。 ということは、その情報をそのまま次の backend に渡すだけです。それもおかしいなら https://blog.hello-world.jp.net/nginx/1014/ こういう話ではなく?
TaichiYanagiya

2016/02/10 01:55

ELB が WebSocket を扱えないので、WebSocket のリスナーのプロトコルを HTTP ではなく SSL または TCP にしているのでしょうか。 SSL, TCP だと "X-Forwarded-For" が付かないので、ヘッダからはアクセス元の IPアドレスを拾えないと思います。 CyberMergina さんが調べられたとおり、WebSocket の場合は ProxyProtocol が必要みたいです。
TaichiYanagiya

2016/02/10 03:46

回答を修正し、設定例を追記しました。
CyberMergina

2016/02/10 06:38

[> takotakotさん > ということは、その情報をそのまま次の backend に渡すだけです。 リバースプロキシを介す場合は、nginxのアクセスログを見ても X-Forwarded-Forにはアクセス元のIPアドレスではなく、ELBのアドレスが渡されてしまっているのです・・・ URLの掲載ありがとうございます。 /etc/nginx/nginx.conf のファイルの方にリンク先で紹介されている指定も してみたのですが、今のところ上手くいっていません。
CyberMergina

2016/02/10 06:41 編集

[> TaichiYanagiyaさん ELB が WebSocket を扱えないので、WebSocket のリスナーのプロトコルを HTTP ではなく SSL または TCP にしているのでしょうか。 はい、その通りです。(記載しておくべき情報でしたね・・・すみません) > SSL, TCP だと "X-Forwarded-For" が付かないので、ヘッダからはアクセス元の IPアドレスを拾えないと思います。 > CyberMergina さんが調べられたとおり、WebSocket の場合は ProxyProtocol が必要みたいです。 な、なるほど! 設定例の追記ありがとうございます!試してみます!!
TaichiYanagiya

2016/02/10 14:09

ELB が付ける先頭行の「PROXY TCP4 ...」を nginx 側で正しく扱えていないようですね。 設定の「listen 80 proxy_protocol;」でいいはずですが、nginx の再起動(reload ではなく restart)は行なっていますでしょうか。
CyberMergina

2016/02/12 00:54

[>TaichiYanagiyaさん 返事が遅くなってしまい、申し訳ありません。 >ELB が付ける先頭行の「PROXY TCP4 ...」を nginx 側で正しく扱えていないようですね。 そうみたいです・・・設定を見直してみたりしているのですが今のところ解決しておりません。 『nginx の再起動』についてですが、サービスの再起動を行うようにしています。(=service nginx restart)
TaichiYanagiya

2016/02/15 01:18

nginx のバージョンはいくつでしょうか。 1.8.0 では最初の listen ディレクティブに proxy_protocol が付いていないと有効にならないバグがあり、1.8.1 で修正されています(http://nginx.org/en/CHANGES-1.8)。 VirtualHostなどで他に listen はありませんでしょうか。 *) Bugfix: the "proxy_protocol" parameter of the "listen" directive did not work if not specified in the first "listen" directive for a listen socket.
CyberMergina

2016/02/15 02:00

[> TaichiTanagiyaさん 情報ありがとうございます!確認してみたところ、nginxのバージョンは1.8.0でした; 入れ替えを行ってみます!
CyberMergina

2016/02/15 02:57

[> TaichiTanagiyaさん nginxのバージョンを1.8.1にあげましたが、変わらずでした・・・
TaichiYanagiya

2016/02/15 03:13

切り分けのため、ELB を経由せずに localhost から 80番ポートに telnet などで接続し、「PROXY TCP4 ...」を入力するとどうなりますか? $ telnet 127.0.0.1 80 PROXY TCP4 100.100.100.100 200.200.200.200 0 80<リターン> GET / HTTP/1.0<リターン> <リターン>
CyberMergina

2016/02/15 04:37

"PROXY TCP4 100.100.100.100 200.200.200.200 0 80" のアドレスの部分をログからコピペしてホストPC内の仮想環境から実行しました。 結果は同じくBadRequestページが返りました。 <html> <head><title>400 Bad Request</title></head> <body bgcolor="white"> <center><h1>400 Bad Request</h1></center> <hr><center>nginx</center> </body> </html> Connection closed by foreign host. コネクション切れてしまったので、「GET / HTTP/1.0」はもう一度telnetで接続して実行しました。 この場合はレスなしでした。
TaichiYanagiya

2016/02/15 05:02

そうすると、nginx 内の問題ですね。 80番ポートで listen する他の VirtualHost などがあれば、すべて無効にするとどうでしょうか。
CyberMergina

2016/02/15 06:52 編集

serverの設定を1つだけにしてみましたが、変わらずBadRequestでした。 $ cat socket.conf(他のファイルはリネームして、新しく作成しました) server { listen 80 ; server_name hoge.hoge.com; proxy_request_buffering off; location / { proxy_pass http://0.0.0.0:3000; } } $ curl http://hoge.hoge.com <html> <head><title>400 Bad Request</title></head> <body bgcolor="white"> <center><h1>400 Bad Request</h1></center> <hr><center>nginx</center> </body> </html> $ curl http://0.0.0.0:3000 <!DOCTYPE html> <html> <head> <title>DEMO PAGE</title> </head> <body> <h1>DEMO PAGE</h1> </body> </html> (※ちなみに、この時にProxyプロトコルを無効にすると、ドメインからアクセスできます・・・)
TaichiYanagiya

2016/02/15 06:49

「listen 80;」ではなく「listen 80 proxy_protocol;」にする必要があるのですが、転記ミスでしょうか?
CyberMergina

2016/02/15 06:53

ファイル置き換えた時に書き間違えていました! もう一度確認してみます・・・!すみません・・・
CyberMergina

2016/02/15 07:23

他の80番でLISTENしているVirtual Hostの設定を消すと、正常に動作しました! + access.log [アクセス元IP] - - [15/Feb/2016:16:13:51 +0900] "GET / HTTP/1.1" 200 191 "-" "curl/7.44.0" "-" + socket.conf server { listen 80 proxy_protocol; server_name hoge.hoge.jp; proxy_request_buffering off; location / { proxy_pass http://0.0.0.0:3000; set_real_ip_from XX.XX.0.0/XX; real_ip_header proxy_protocol; proxy_set_header X-Real-IP $proxy_protocol_addr; proxy_read_timeout 150; proxy_set_header X-Forwarded-For $proxy_protocol_addr; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; } } FQDNやサブディレクトリまで入れたパスをみて、 複数に環境を分けているので、少し整理してみます!!
TaichiYanagiya

2016/02/15 09:50

ELB1, ELB3 からの接続を 80番以外のポートで待ち受けるしかないと思います。
CyberMergina

2016/02/15 10:00

> ELB1, ELB3 からの接続を 80番以外のポートで待ち受けるしかないと思います。 内部のポート番号が重なっていることが原因だったのでしょうか・・・ ひとまず、ELB2の方を別ポートにしました。 併せて「セキュリティグループ」にポート番号追加、 nginxのlistenを修正。 無事に動作することが確認できました。 (ELB2の方でも大丈夫ですかね・・・) [> takotakot さん ご回答いただきありがとうございました。 [> TaichiYanagiya さん ご丁寧に最後までお付き合いいただきありがとうございました。 (!) 解決策等散らばりすぎたので、別途まとめます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.37%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問