ApacheでSSL化したサイトから内部で動くWebSocketに接続がしたい。
対処療法的な対策をしたので正しいかどうかはわかりませんがちゃんと動作させるまでできました。
設定的にはこの記事の続きです。
サーバ環境:Ubuntu16.04 Apache/2.4.34
ws:とwss:
設定前にhttpの代わりにws、httpsの代わりにwssを使っていて同様の扱いでいいのか気になったので2通り動かして試してみます。
サーバHTTPS | サーバLOCAL | |
クライアントHTTPS | wss:成功 | wss:エラー1 |
ws: エラー2 | ws: 成功 | |
クライアントLOCAL | wss:成功 | wss:エラー1 |
ws: エラー3 | ws: 成功 |
エラー1:failed: Error in connection establishment: net::ERR_SSL_PROTOCOL_ERROR
エラー2:VM11852:1 Mixed Content:…This request has been blocked; this endpoint must be available over WSS.failed: Error in connection establishment: net::ERR_SSL_PROTOCOL_ERROR
エラー3:failed: Error during WebSocket handshake: Unexpected response code: 302
サーバをSSL化していればwss、それ以外はwsプロトコルを使わないとERR_SSL_PROTOCOL_ERROR
になることがわかります。
またSSLサイトでwsを使うとブラウザ制限(エラー2)に引っかかります。
エラー3はサーバ設定でポート443のみ設定していたため、ポート80のリダイレクト設定に引っかかったせいです。
とりあえずhttp、httpsの関係と同じと考えてよさそうです。
サーバ(Apatche)設定
どのファイルをいじるかなどは前の記事で。
1 2 3 4 |
ProxyPass /subdir/wss ws://localhost:8080/subdir/wss ProxyPassReverse /subdir/wss ws://localhost:8080/subdir/wss ProxyPass /subdir http://localhost:8080/subdir ProxyPassReverse /subdir http://localhost:8080/subdir |
ProxyPassは先に一致したものが使われるので、wssの方を先に書きます。
WebSocketサービスは8080で動いているのでwsプロトコルで渡します。
ここはRewriteしてもいいと思います。
クライアント(javascript)設定
SSL化しているのでwssで接続します。
localhostでテストすることも考えて以下のようにしています。
1 2 3 4 |
var pro = "wss:"; if (window.location.protocol == "http:") pro = "ws:"; var url = pro + "//" + window.location.host + "/subdir/wss"; var ws = new WebSocket(url); |
ところでSSL化したサイトから接続する場合、wss接続を試みてプロキシでws接続になるのですが特に問題ないようです。
セキュアな通信が必要な場合にはこの辺がネックになるかもしれない。
gorilla/websocket
golangでWebSocketを実装するときにgorilla/websocketを使いましたが、CORS設定があったのでこれを設定する必要があります(golang.org/x/net/websocketだとないらしい)。
UpgraderのCheckOriginを設定するとクロスドメインでアクセスできます。
1 2 3 4 5 6 7 |
var wsupgrader = websocket.Upgrader{ ReadBufferSize: 1024, WriteBufferSize: 1024, CheckOrigin: func(r *http.Request) bool { return true }, } |
ちょっと制限を加えるならこんな感じに。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
CheckOrigin: func(r *http.Request) bool { origin := r.Header["Origin"] if len(origin) == 0 { return true } u, err := url.Parse(origin[0]) if err != nil { return false } if u.Host == "localhost:8080" || u.Host == "yoursite.domain" { return true } return false }, |
ただこれだとlocalhost:8080からアクセス出来てしまうのでデプロイするときは、サイトドメインだけにした方がいいです。
気になる点
数年前のissueやstackoverflowを見るとwss://localhost:xxxx
で接続できたという内容があったりします。
1年前のある記事では同じような設定でポート8888にwssしてるなぁ。
同じような設定にしてもできないのは何か足りないのか前はできてたのか。