クローズドβテストに便利！認証機能付きリバースプロキシ！

#概要

**自分が作ったサービスを、知り合いに触ってもらいたいけど、一般の人全員に公開するにはちょっと・・・**

**最終的には世の中にサービスを公開したいけど、知り合いのテストのためだけにログイン機能を作るのも面倒・・・**

そういう時に、アプリケーションサーバーのコードの変更なしに、簡単に外部のテスト環境を提供することが出来るのが、ngrokとNGINXです。
この記事では、それらの"知り合いレベルで公開するためのちょっとしたテストのための環境"の構築方法を紹介します。

#今回構築するサーバー構成

![image.png](https://qiita-image-store.s3.amazonaws.com/0/139643/20e574d4-c8eb-42f6-7ad1-4cd1b994a2c2.png)

自宅のネットワーク内に、公開したいアプリケーションサーバーがあるとします。
このネットワーク内に、NGINXを立てて、認証機能を追加し、ngrokで外部のネットワークからリクエストが受け取れるように設定します。



#テスト用のアプリケーションサーバーの構築

ここは自分が作ったWebサービスのアプリケーションサーバーを用意します。ここでは、簡単なWebサーバーで代用します。

今回はpythonで作ります。

```shell-session
$ mkdir test_server
$ cd test_server
$ echo Hello > hello.html
$ python3 -m http.server 80  >/dev/null 2>&1 &
```

動作確認をしてみます。

```
$ curl localhost:80/hello.html
Hello
```

これで自分が公開したいアプリケーションサーバーのモックが完成しました。


#認証機能付きリバースプロキシの構築
##必要なソフトウェアのインストール

必要なソフトウェアをインストールします。

| ソフトウェア | 用途 |
|:-:|:-:|
| nginx  |  認証機能付きリバースプロキシ |
| appache2-utils | 認証用設定ファイル作成 |

```shell-session
$ sudo apt-get update && apt-get install nginx apache2-utils
```

##認証用の設定
###Basic認証とは
ここでは非常に基本的なBasic認証というものを行います。

>Basic認証（ベーシックにんしょう、Basic Authentication）とは、HTTPで定義される認証方式の一つ。基本認証と呼ばれることも。

参考：[Basic認証](https://ja.wikipedia.org/wiki/Basic%E8%AA%8D%E8%A8%BC)

###設定ファイルの作成
ここでは、下記の表のようなユーザーを設定します。

| 設定 | 値 |
|:-:|:-:|
| ユーザー名  | kotauchisunsun |
| パスワード  | test|

ユーザー設定はhtpasswdコマンドで以下のように行います。今回、設定ファイルは/etc/nginx/.htpasswdに置いています。

```
htpasswd -c /etc/nginx/.htpasswd kotauchisunsun
New password:                #ここでパスワードのtestを入れる
Re-type new password:        #もう一度testを入れる
Adding password for user kotauchisunsun
```

これでBasic認証用のユーザー設定ファイルの生成は完了です。

参考：[[個人的な備忘録とコピペ用]nginxでBasic認証](https://qiita.com/kotauchisunsun/items/556cdfd812f7ffdc65ac)

##認証機能付きリバースプロキシの構築
###NGINXとは

![image.png](https://qiita-image-store.s3.amazonaws.com/0/139643/97a2beeb-1985-ef5d-3fa2-aeb707bc0627.png)

簡単にNGINXの特徴について説明します．
NGINXは、基本的にはApacheなどと同じWebサーバーです。しかし、非常に高速な動作をするため、リバースプロキシとして負荷分散のために利用されることも多々あります。今回は、このNGINXのBasic認証の機能とリバースプロキシの用いて環境を構築していきます。

参考：[最新のNGINXはアプリケーションサーバー！？NGINX UnitのベンチマークをPHP,Python,Goで計測してみた！！](https://qiita.com/kotauchisunsun/items/b7959b96db6937b26b49)

###NGINXの設定
まず初めに、元の設定ファイルをバックアップしておきます。

```shell-session
$ cp /etc/nginx/sites-enabled/default ~/default.org
```

NGINXの設定ファイルは以下のように変更します。

```shell-session
# diff ~/default.org /etc/nginx/sites-enabled/default 
17,18c17,18
< 	listen 80 default_server;
< 	listen [::]:80 default_server;
---
> 	listen 8000 default_server;        #リバースプロキシをポート8000番で稼働させます。
> 	listen [::]:8000 default_server;   #リバースプロキシをポート8000番で稼働させます。
40c40,42
< 		try_files $uri $uri/ =404;
---
> 		auth_basic "Restrict";                      #Basic認証を有効にします
> 		auth_basic_user_file /etc/nginx/.htpasswd;  #Basic認証のユーザーの設定ファイルのパスを指定します。
> 		proxy_pass http://localhost:80/;            #プロキシ先を指定します
```

NGINXの設定全体を表示すると、以下のようになっています。(設定コピペで動きます。)

```shell-session
$ cat /etc/nginx/sites-enabled/default
##
# You should look at the following URL's in order to grasp a solid understanding
# of Nginx configuration files in order to fully unleash the power of Nginx.
# http://wiki.nginx.org/Pitfalls
# http://wiki.nginx.org/QuickStart
# http://wiki.nginx.org/Configuration
#
# Generally, you will want to move this file somewhere, and start with a clean
# file but keep this around for reference. Or just disable in sites-enabled.
#
# Please see /usr/share/doc/nginx-doc/examples/ for more detailed examples.
##

# Default server configuration
#
server {
	listen 8000 default_server;
	listen [::]:8000 default_server;

	# SSL configuration
	#
	# listen 443 ssl default_server;
	# listen [::]:443 ssl default_server;
	#
	# Self signed certs generated by the ssl-cert package
	# Don't use them in a production server!
	#
	# include snippets/snakeoil.conf;

	root /var/www/html;

	# Add index.php to the list if you are using PHP
	index index.html index.htm index.nginx-debian.html;

	server_name _;

	location / {
		# First attempt to serve request as file, then
		# as directory, then fall back to displaying a 404.
		auth_basic "Restrict";  
		auth_basic_user_file /etc/nginx/.htpasswd;
		proxy_pass http://localhost:80/;
	}

	# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
	#
	#location ~ \.php$ {
	#	include snippets/fastcgi-php.conf;
	#
	#	# With php5-cgi alone:
	#	fastcgi_pass 127.0.0.1:9000;
	#	# With php5-fpm:
	#	fastcgi_pass unix:/var/run/php5-fpm.sock;
	#}

	# deny access to .htaccess files, if Apache's document root
	# concurs with nginx's one
	#
	#location ~ /\.ht {
	#	deny all;
	#}
}


# Virtual Host configuration for example.com
#
# You can move that to a different file under sites-available/ and symlink that
# to sites-enabled/ to enable it.
#
#server {
#	listen 80;
#	listen [::]:80;
#
#	server_name example.com;
#
#	root /var/www/example.com;
#	index index.html;
#
#	location / {
#		try_files $uri $uri/ =404;
#	}
#}
```

以下のコマンドでNGINXを稼働させます。

```shell-session
$ sudo service nginx restart
```

参考：[[個人的な備忘録とコピペ用]nginxでBasic認証](https://qiita.com/kotauchisunsun/items/556cdfd812f7ffdc65ac)
参考：[[個人的な備忘録とコピペ用]nginxでリバースプロキシ](https://qiita.com/kotauchisunsun/items/867c6bac64ba6db82b4d)

#外部ネットワークへの公開
![image.png](https://qiita-image-store.s3.amazonaws.com/0/139643/26012a89-f005-27d3-4b11-992abc2d3c59.png)

今回、ngrokというソフトウェアを使います。
これは一言で言うと、外部のサービスと連携し、ネットワーク外部にあるポートを、ネットワーク内部のポートにフォワーディングしてくれる機能があります。有料プランもありますが、ここでは無料のプランを利用します。

ngrokの設定は非常に簡単です。

```shell-session
# https://ngrok.com/downloadから適切なアーキテクチャのアドレスを探して指定してください。
$ wget https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-amd64.zip
$ unzip ngrok-stable-linux-amd64.zip
$ ./ngrok http 8000
ngrok by @inconshreveable                                                                                                                                                        (Ctrl+C to quit)
                                                                                                                                                                                                 
Session Status                online                                                                                                                                                             
Version                       2.2.8                                                                                                                                                              
Region                        United States (us)                                                                                                                                                 
Web Interface                 http://127.0.0.1:4040                                                                                                                                              
Forwarding                    http://8baf4445.ngrok.io -> localhost:8000                                                                                                                         
Forwarding                    https://8baf4445.ngrok.io -> localhost:8000                                                                                                                        
                                                                                                                                                                                                 
Connections                   ttl     opn     rt1     rt5     p50     p90                                                                                                                        
                              0       1       0.00    0.00    0.00    0.00                                                                                                                       
                                                                                                                                                                                                 
HTTP Requests                                                                                                                                                                                    
-------------                                                                                                                                                                                    
                           
```

これだけで、`https://8baf4445.ngrok.io/`のドメインでサービスを公開することが出来ました。
これらのドメインは起動時に勝手に割り振られます。自分で行う際は、適宜読み替えてください。

参考：[初参加でも大丈夫！ハッカソン参加の"前"に用意しておきたいハッカソン・スターターキット！](https://qiita.com/kotauchisunsun/items/10209f286f683f665f6e)

#動作確認
##ブラウザで動作確認

ブラウザで、`https://8baf4445.ngrok.io/hello.html`にアクセスしてみますと、以下の様な認証画面が表示されます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/139643/fad95bbe-0075-82ef-32b7-a1465154767c.png)

ここで、キャンセルを押して認証を回避しようとすると、このように401 Authorization Requiredエラーが表示され、ユーザーごとにアクセスに制限がかかっていることがわかります。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/139643/5c39c36f-eed1-1673-5e2d-d0b84c9d2db5.png)

先ほど設定した、ユーザー名にはkotauchisunsun、パスワードにtestを入力して、ログインします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/139643/fc39dc9e-5c08-5e52-942b-75e0be1c36c9.png)

この様に、Helloと表示されます。
これにより、先程設定したユーザーのみにサービスが利用可能になっていることがわかります。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/139643/92f6ba33-9117-2dd3-49fe-b1afdb5c0247.png)

ブラウザでユーザーごとに認証されていることが確認できました。

##curlコマンドで動作確認

curlコマンドでも動作を確認することができます。
下記の様に何も設定せずリクエストをすると、先程と同様の401 Authorization Requiredが表示されます。

```shell-session
$ curl https://8baf4445.ngrok.io/hello.html
<html>
<head><title>401 Authorization Required</title></head>
<body bgcolor="white">
<center><h1>401 Authorization Required</h1></center>
<hr><center>nginx/1.6.2</center>
</body>
</html>
```

curlの場合、`-u ユーザー名:パスワード`とすることでBasic認証付きでリクエストすることが出来ます。

```shell-session
$ curl https://8baf4445.ngrok.io/hello.html -u kotauchisunsun:test
Hello
```

curlコマンドでもユーザーごとに認証されていることが確認できました。
これで、ユーザーごとにサービスの利用に制限が可能な、Basic認証付きリバースプロキシを作ることが出来ました！


#まとめ

今回は、簡単にテストを行うためだけに認証機能付きのリバースプロキシを作成しました。
自分自身もNGINXの勉強をすることが目的でしたが、非常に簡単に作れて驚いています。
(ただこの環境はテストのみに使用し、本番運用はやめてください。)
この記事では、ユーザーの認証は1人分しか設定していません。1人分であればngrok単体でも可能ですが、複数ユーザーの認証の対応すると、NGINXを挟むのが良さそうです。
皆さんも、自分でWebサービスを作った時には、こんな感じで環境を構築し、自分の友達や同期にクローズドβテストをお願いしてはいかがでしょうか？