LaraDock を使って Docker の Nginx にSSL設定を行って WebSocket でのアクセスを ws から wss で行えるようにする設定を行ったメモ

## 概要
LaraDockのNginxでwsのwss化が簡単にできそうなのでやってみる。

## 環境

[前回](https://qiita.com/hibohiboo/items/fa8b667b0afd3293a2db)のQuoridorn環境を引き続き使う。

[ソース（クライアント）](https://github.com/hibohiboo/quoridorn-mark2)
[ソース(サーバ)](https://github.com/hibohiboo/quoridorn-server)

## サーバ側
### nginxの準備

[LaraDock](http://laradock.io)のnginxのDockerフォルダを使う。

#### Dockerfileの修正

LaraDockはLaravel用なのでPHPの設定が入っている。
今回は使わないので消す。

```diff:virtual-environment/provision/docker/nignx/Dockerfile
FROM nginx:alpine

LABEL maintainer="Mahmoud Zalt <mahmoud@zalt.me>"

# // 省略

- # Set upstream conf and remove the default conf
-  RUN echo "upstream php-upstream { server ${PHP_UPSTREAM_CONTAINER}:${PHP_UPSTREAM_PORT}; }" > /etc/nginx/conf.d/upstream.conf \
-     && rm /etc/nginx/conf.d/default.conf

ADD ./startup.sh /opt/startup.sh
RUN sed -i 's/\r//g' /opt/startup.sh
CMD ["/bin/bash", "/opt/startup.sh"]

EXPOSE 80 443
```


#### 設定の変更
フォルダ内のconfigファイルを以下のように修正する。

```diff:virtual-environment/provision/docker/nginx/sites/default.conf
@@ -1,32 +1,30 @@
+upstream websocket {
+    server node-server:8000;
+}
+
 server {

     listen 80 default_server;
     listen [::]:80 default_server ipv6only=on;

     # For https
-    # listen 443 ssl default_server;
-    # listen [::]:443 ssl default_server ipv6only=on;
-    # ssl_certificate /etc/nginx/ssl/default.crt;
-    # ssl_certificate_key /etc/nginx/ssl/default.key;
+    listen 443 ssl default_server;
+    listen [::]:443 ssl default_server ipv6only=on;
+    ssl_certificate /etc/nginx/ssl/default.crt;
+    ssl_certificate_key /etc/nginx/ssl/default.key;

     server_name localhost;
-    root /var/www/public;
-    index index.php index.html index.htm;


-    location / {
-         try_files $uri $uri/ /index.php$is_args$args;
+
+    location /socket.io/ {
+        proxy_pass http://websocket;
+        proxy_http_version 1.1;
+        proxy_set_header Upgrade $http_upgrade;
+        proxy_set_header Connection "upgrade";
     }


-    location ~ \.php$ {
-        try_files $uri /index.php =404;
-        fastcgi_pass php-upstream;
-        fastcgi_index index.php;
-        fastcgi_buffers 16 16k;
-        fastcgi_buffer_size 32k;
-        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
-        #fixes timeouts
-        fastcgi_read_timeout 600;
-        include fastcgi_params;
+    location /socket.io/socket.io.js {
+        proxy_pass http://websocket;
     }

     location ~ /\.ht {
```

node-serverコンテナの8000番ポートでnode.jsを動かしているので、`upstream websocket`という名前で宣言してそれを使用。
https://ドメイン/socket.io/で来たリクエストを、node.jsのほうにプロキシして流す処理を宣言する。

### docker-compose.ymlの編集

nginxの追加に合わせて修正する。

```diff:virtual-environment/provision/docker/docker-compose.yml
version: "3"

networks:
  backend:
    driver: ${NETWORKS_DRIVER}

volumes:
  mongo:
    driver: ${VOLUMES_DRIVER}

services:
  ### MongoDB ##############################################
  # // 省略
  node-server:
    build: ${QUORIDORN_PATH_ROOT}
    volumes:
      - ${QUORIDORN_PATH_ROOT}:/app
      - /app/node_modules
-     ports:
-       - "${QUORIDORN_SERVER_PORT}:8000"
    command: ["npm", "run", "node-server"]
    networks:
      - backend
    depends_on:
      - mongo


+  ### NGINX Server #########################################
+  nginx:
+    build:
+      context: ./nginx
+      args:
+        - CHANGE_SOURCE=${CHANGE_SOURCE}
+        - http_proxy
+        - https_proxy
+        - no_proxy
+    volumes:
+      - ${NGINX_HOST_LOG_PATH}:/var/log/nginx
+      - ${NGINX_SITES_PATH}:/etc/nginx/sites-available
+      - ${NGINX_SSL_PATH}:/etc/nginx/ssl
+    ports:
+      - "${NGINX_HOST_HTTPS_PORT}:443"
+    depends_on:
+      - node-server
+    networks:
+      - backend
````

もともと公開していた8000番ポートは、nginxによってwssでアクセスされる443からプロキシされるようになるため、不要になる。

### 環境変数の追加

```config:virtual-environment/provision/docker/.env
### NGINX #################################################

NGINX_HOST_HTTP_PORT=80
NGINX_HOST_HTTPS_PORT=443
NGINX_HOST_LOG_PATH=./logs/nginx/
NGINX_SITES_PATH=./nginx/sites/
NGINX_SSL_PATH=./nginx/ssl/
### Environment ###########################################

# If you need to change the sources (i.e. to China), set CHANGE_SOURCE to true
CHANGE_SOURCE=false
```

## クライアントサイドの設定

wsの8000ポートで接続していた部分をwssの443ポートに変える。
443ポートはデフォルトなので、省略できる。

```diff:/public/static/conf/connect.yaml
 # 向き先
 # quoridornServer: "wss://quori-dev.onlinesession.app"
 # quoridornServer: "http://localhost:2222"
-quoridornServer: "ws://192.168.60.79:8000"
+quoridornServer: "wss://192.168.60.79"
```

## 動作確認

`vagrant up`でのdockerの自動立ち上げがうまくいっていない。。。

### 仮想環境の起動

※ サーバ側とクライアント側両方で行う。

```
vagrant up
vagrant ssh
cd virtual-environment/provision/bash
./docker_restart.sh
```

起動したら、 https://192.168.74.60/quoridorn2/ にブラウザでアクセスする。

### SSL証明書の問題

テスト用にオレオレ証明書を使っているため、クライアントから接続しようとすると
`ERR_CERT_AUTHORITY_INVALID`のエラーがでて接続できない。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/e4d33381-45a3-807c-2c51-ee6c1b35a9a0.png)

その場合、先に以下のサーバ側の URL をブラウザで開く。
https://192.168.60.79/socket.io/

詳細設定をクリック。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/2bf17eb6-07b7-9d1a-a4f9-5fc103630905.png)


192.168.50.79 にアクセスする（安全ではありません）をクリック。
安全なのは自分が知ってる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/ac91bf46-16ad-6eba-2c22-5ffa96cd6a84.png)


以下の画面が出れば成功。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/52221051-a2e2-c948-3575-441d70d77942.png)


クライアントの画面に戻って、ページの再読み込みを行う。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/846bf5a4-2d72-e5e2-9c76-8567cf67d4e5.png)


`ERR_CERT_AUTHORITY_INVALID`のエラーが消えて、プレイルームが表示できた！

## 参考

[laradock](https://github.com/laradock/laradock)
[Laradock の Nginx を SSL 化する](https://qiita.com/osakana9114/items/48fb03e51e23dd02871c)
[WSS が繋がらない](http://wiki.brekeke.jp/WSS-%E3%81%8C%E7%B9%8B%E3%81%8C%E3%82%89%E3%81%AA%E3%81%84)
[Nginx によるリバースプロキシの設定方法](https://qiita.com/schwarz471/items/9b44adfbec006eab60b0)
[websocket を使う際の意外な落とし穴](https://blog.mitsuruog.info/2012/10/websocket.html)
[socketi.io](https://socket.io/)
[node.js 超入門 ①node.js で web サーバを作ってみる](https://qiita.com/ritukiii/items/7f28554369d63eb373c3)