{"id":10225,"date":"2019-05-19T12:45:50","date_gmt":"2019-05-19T10:45:50","guid":{"rendered":"https:\/\/pi3g.com\/?p=10225"},"modified":"2019-05-19T12:54:09","modified_gmt":"2019-05-19T10:54:09","slug":"envoy-websockets-per-route-configuration-javascript-test-setup","status":"publish","type":"post","link":"https:\/\/pi3g.com\/de\/envoy-websockets-per-route-configuration-javascript-test-setup\/","title":{"rendered":"envoy Websockets per Routenkonfiguration, JavaScript-Testaufbau"},"content":{"rendered":"<p>In my article yesterday I discussed the <a href=\"https:\/\/pi3g.com\/2019\/05\/18\/envoy-docker-and-websockets-debugging-and-configuration\/\" target=\"_blank\">configuration &amp; test of envoy for proxying websockets<\/a> at length.<\/p>\n<p>Today I would like to add some additional information.<\/p>\n<h1>correct syntax for websocket upgrade per route<\/h1>\n<p>You can enable websocket upgrade per route. No need to add it globally:<\/p>\n<blockquote>\n<p>&#8211; name: envoy.http_connection_manager<br \/>&nbsp;&nbsp;&nbsp; config:<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #upgrade_configs:<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #&nbsp; &#8211; upgrade_type: websocket<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; stat_prefix: ingress_https<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; use_remote_address: true<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xff_num_trusted_hops: 0<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; route_config:<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; virtual_hosts:<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8211; name: picockpit_withport<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; domains: [&#8220;picockpit.local:443&#8221;]<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; routes:<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8211; match: { prefix: &#8220;\/mqtt\/webclient&#8221; }<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; route:<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cluster: target_dwebsocket<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; upgrade_configs:<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8211; upgrade_type: &#8220;websocket&#8221;<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; enabled: true<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8211; match: {prefix: &#8220;\/&#8221;}<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; route: {cluster: target_picockpit}<\/p>\n<\/blockquote>\n<p>Please note that I decided to mirror the configuration including the port, and without \u2013 just in case:<\/p>\n<blockquote>\n<p>&#8211; name: picockpit<br \/>&nbsp;&nbsp; domains: [&#8220;picockpit.local&#8221;]<br \/>&nbsp;&nbsp; routes:<br \/>&nbsp;&nbsp;&nbsp;&nbsp; &#8211; match: { prefix: &#8220;\/mqtt\/webclient&#8221; }<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; route:<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cluster: target_dwebsocket<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; upgrade_configs:<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8211; upgrade_type: &#8220;websocket&#8221;<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; enabled: true<br \/>&nbsp;&nbsp;&nbsp;&nbsp; &#8211; match: {prefix: &#8220;\/&#8221;}<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; route: {cluster: target_picockpit}<\/p>\n<\/blockquote>\n<p>Please see below (Update 3) for combining both in a single stanza, which is more elegant, and Update 2 for my doubts about the port notation being required for the JavaScript client.<\/p>\n<h1>Enabled globally by default?<\/h1>\n<p>Please note that the envoy documentation <a href=\"https:\/\/www.envoyproxy.io\/docs\/envoy\/latest\/intro\/arch_overview\/websocket.html\" target=\"_blank\">seems to imply that websocket upgrades are enabled by default globally<\/a>. I have not tested this. <\/p>\n<p>Maybe you only need to specify the domain <strong>including<\/strong> the port, <a href=\"https:\/\/pi3g.com\/2019\/05\/18\/envoy-docker-and-websockets-debugging-and-configuration\/\" target=\"_blank\">as discussed in my article<\/a>, for websocket connections to work.<\/p>\n<h1>Javascript test<\/h1>\n<p>A simple JavaScript test client would look like this:<\/p>\n<blockquote>\n<p>function connect(){<br \/>&nbsp;&nbsp;&nbsp;&nbsp; console.log(&#8220;Building up websocket&#8221;);<br \/>&nbsp;&nbsp;&nbsp;&nbsp; var socket = new WebSocket(&#8220;wss:\/\/key:secret@picockpit.local\/mqtt\/webclient&#8221;);<br \/>&nbsp;&nbsp;&nbsp;&nbsp; socket.onerror = function(event){<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; console.log(&#8220;an error has been encountered&#8221;);<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; console.log(event);<br \/>&nbsp;&nbsp;&nbsp;&nbsp; }<\/p>\n<p>&nbsp;&nbsp;&nbsp; socket.onopen = function(){<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; console.log(&#8220;Socket has been opened.&#8221;);<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; console.log(&#8216;Socket Status: &#8216;+ socket.readyState);<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; socket.send(&#8220;Hello server!&#8221;);<br \/>&nbsp;&nbsp;&nbsp;&nbsp; }<br \/>&nbsp;&nbsp;&nbsp;&nbsp; socket.onmessage = function(msg){<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; console.log(&#8220;received message&#8221;);<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; console.log(msg);<br \/>&nbsp;&nbsp;&nbsp;&nbsp; }<br \/>&nbsp;&nbsp;&nbsp;&nbsp; console.log(&#8220;Finished with first websocket&#8221;);<br \/>\n}<\/p>\n<p>connect();<\/p>\n<\/blockquote>\n<p>\nIn combination <a href=\"https:\/\/pi3g.com\/2019\/05\/18\/envoy-docker-and-websockets-debugging-and-configuration\/\" target=\"_blank\">with my other post<\/a>, and the simple websocket echo client, you would get a \u201cHello server!\u201d back as a message:<\/p>\n<p><a href=\"https:\/\/pi3g.com\/wp-content\/uploads\/2019\/05\/image-13.png\"><img loading=\"lazy\" decoding=\"async\" width=\"901\" height=\"184\" title=\"image\" style=\"display: inline; background-image: none;\" alt=\"image\" src=\"https:\/\/pi3g.com\/wp-content\/uploads\/2019\/05\/image_thumb-13.png\" border=\"0\"><\/a><\/p>\n<h1>Update 2<\/h1>\n<p>It seems that the JavaScript client is not using the domain:port authority syntax. Therefore the first stanza is probably not needed<\/p>\n<p><a href=\"https:\/\/pi3g.com\/wp-content\/uploads\/2019\/05\/image-14.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1047\" height=\"186\" title=\"image\" style=\"display: inline; background-image: none;\" alt=\"image\" src=\"https:\/\/pi3g.com\/wp-content\/uploads\/2019\/05\/image_thumb-14.png\" border=\"0\"><\/a><\/p>\n<p>This should be enough, then:<\/p>\n<blockquote><p>&#8211; name: picockpit<br \/>&nbsp; domains: [&#8220;picockpit.local&#8221;]<br \/>&nbsp; routes:<br \/>&nbsp;&nbsp;&nbsp; &#8211; match: { prefix: &#8220;\/mqtt\/webclient&#8221; }<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; route:<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cluster: target_dwebsocket<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; upgrade_configs:<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8211; upgrade_type: &#8220;websocket&#8221;<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; enabled: true<br \/>&nbsp;&nbsp;&nbsp;&nbsp; &#8211; match: {prefix: &#8220;\/&#8221;}<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; route: {cluster: target_picockpit}<\/p><\/blockquote>\n<h1>Update 3<\/h1>\n<p>The simplest way is to probably just match for both domain variations and have the same code:<\/p>\n<blockquote>\n<p>&#8211; name: envoy.http_connection_manager<br \/>&nbsp;&nbsp; config:<br \/>&nbsp;&nbsp;&nbsp;&nbsp; #upgrade_configs:<br \/>&nbsp;&nbsp;&nbsp;&nbsp; #&nbsp; &#8211; upgrade_type: websocket<br \/>&nbsp;&nbsp;&nbsp;&nbsp; stat_prefix: ingress_https<br \/>&nbsp;&nbsp;&nbsp;&nbsp; use_remote_address: true<br \/>&nbsp;&nbsp;&nbsp;&nbsp; xff_num_trusted_hops: 0<br \/>&nbsp;&nbsp;&nbsp;&nbsp; route_config:<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; virtual_hosts:<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8211; name: picockpit_withport<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong> domains: [&#8220;picockpit.local:443&#8221;, &#8220;picockpit.local&#8221;]<\/strong><br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; routes:<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #- match: { prefix: &#8220;\/mqtt\/webclient&#8221; }<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8211; match: { prefix: &#8220;\/mqtt&#8221; }<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; route:<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cluster: target_dwebsocket<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; upgrade_configs:<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8211; upgrade_type: &#8220;websocket&#8221;<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; enabled: true<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8211; match: {prefix: &#8220;\/&#8221;}<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; route: {cluster: target_picockpit}<\/p>\n<\/blockquote>\n","protected":false},"excerpt":{"rendered":"<p>In meinem gestrigen Artikel habe ich die Konfiguration und den Test von envoy f\u00fcr das Proxying von Websockets ausf\u00fchrlich besprochen. Heute m\u00f6chte ich einige zus\u00e4tzliche Informationen hinzuf\u00fcgen. korrekte Syntax f\u00fcr Websocket-Upgrade pro Route Sie k\u00f6nnen Websocket-Upgrade pro Route aktivieren. Sie m\u00fcssen es nicht global hinzuf\u00fcgen: - name: envoy.http_connection_manager config:      #upgrade_configs:      # - upgrade_type: websocket ...<\/p>","protected":false},"author":830,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":"","_links_to":"","_links_to_target":""},"categories":[402],"tags":[481,600,602],"class_list":["post-10225","post","type-post","status-publish","format-standard","hentry","category-development","tag-envoy","tag-javascript","tag-websockets"],"_links":{"self":[{"href":"https:\/\/pi3g.com\/de\/wp-json\/wp\/v2\/posts\/10225","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/pi3g.com\/de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/pi3g.com\/de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/pi3g.com\/de\/wp-json\/wp\/v2\/users\/830"}],"replies":[{"embeddable":true,"href":"https:\/\/pi3g.com\/de\/wp-json\/wp\/v2\/comments?post=10225"}],"version-history":[{"count":3,"href":"https:\/\/pi3g.com\/de\/wp-json\/wp\/v2\/posts\/10225\/revisions"}],"predecessor-version":[{"id":10230,"href":"https:\/\/pi3g.com\/de\/wp-json\/wp\/v2\/posts\/10225\/revisions\/10230"}],"wp:attachment":[{"href":"https:\/\/pi3g.com\/de\/wp-json\/wp\/v2\/media?parent=10225"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/pi3g.com\/de\/wp-json\/wp\/v2\/categories?post=10225"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/pi3g.com\/de\/wp-json\/wp\/v2\/tags?post=10225"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}