[PATCH] Proxy websocket connections through nginx

This is a patch against v1.5.1 that sets up nginx to proxy the websocket requests handled by websockify running on port 64667. The changes include modifying the nginx config file (kimchi.conf.in) and various Kimchi files to support the URL changes. Tested on Firefox and Chrome browsers (current versions). Rob Lemley (1): Configure nginx to proxy connections to the websocket server so that browsers don't need to connect to port 64667. This helps in networks with restrictive firewalls. src/kimchi/config.py.in | 8 ++++++++ src/kimchi/model/config.py | 2 ++ src/kimchi/proxy.py | 1 + src/kimchi/vnc.py | 4 ++-- src/kimchid.in | 1 + src/nginx/kimchi.conf.in | 15 +++++++++++++++ ui/js/src/kimchi.api.js | 14 +++++++------- ui/spice-html5/pages/spice_auto.html | 2 +- 8 files changed, 37 insertions(+), 10 deletions(-) -- 1.8.3.1

Signed-off-by: Rob Lemley <rob.lemley@rochester.edu> --- src/kimchi/config.py.in | 8 ++++++++ src/kimchi/model/config.py | 2 ++ src/kimchi/proxy.py | 1 + src/kimchi/vnc.py | 4 ++-- src/kimchid.in | 1 + src/nginx/kimchi.conf.in | 15 +++++++++++++++ ui/js/src/kimchi.api.js | 14 +++++++------- ui/spice-html5/pages/spice_auto.html | 2 +- 8 files changed, 37 insertions(+), 10 deletions(-) diff --git a/src/kimchi/config.py.in b/src/kimchi/config.py.in index 7ca1a1f..1d81db2 100644 --- a/src/kimchi/config.py.in +++ b/src/kimchi/config.py.in @@ -98,6 +98,8 @@ class Paths(object): self.ui_dir = self.add_prefix('ui') self.spice_file = os.path.join(self.ui_dir, 'spice-html5/pages/spice_auto.html') + self.console_file = os.path.join(self.ui_dir, + 'pages/websockify/console.html') if __with_spice__ == 'yes': self.spice_dir = self.add_prefix('ui/spice-html5') @@ -207,6 +209,12 @@ class KimchiConfig(dict): 'tools.sessions.timeout': SESSIONSTIMEOUT, 'tools.kimchiauth.on': False }, + '/console.html': { + 'tools.staticfile.on': True, + 'tools.staticfile.filename': paths.console_file, + 'tools.nocache.on': True, + 'tools.kimchiauth.on': True + }, '/novnc': { 'tools.staticdir.on': True, 'tools.staticdir.dir': paths.novnc_dir, diff --git a/src/kimchi/model/config.py b/src/kimchi/model/config.py index fe2a529..85d7092 100644 --- a/src/kimchi/model/config.py +++ b/src/kimchi/model/config.py @@ -41,7 +41,9 @@ class ConfigModel(object): def lookup(self, name): proxy_port = kconfig.get('display', 'display_proxy_port') + ssl_port = kconfig.get('server', 'ssl_port') return {'display_proxy_port': proxy_port, + 'ssl_port': ssl_port, 'version': get_version()} diff --git a/src/kimchi/proxy.py b/src/kimchi/proxy.py index 5dcca65..bc26981 100644 --- a/src/kimchi/proxy.py +++ b/src/kimchi/proxy.py @@ -80,6 +80,7 @@ def _create_proxy_config(options): proxy_port=options.port, kimchid_port=options.cherrypy_port, proxy_ssl_port=options.ssl_port, + display_proxy_port=options.display_proxy_port, cert_pem=cert, cert_key=key, max_body_size=eval(options.max_body_size), dhparams_pem=dhparams_pem) diff --git a/src/kimchi/vnc.py b/src/kimchi/vnc.py index b4194b1..ae04b81 100644 --- a/src/kimchi/vnc.py +++ b/src/kimchi/vnc.py @@ -44,10 +44,10 @@ def new_ws_proxy(): cert = '%s/kimchi-cert.pem' % paths.conf_dir key = '%s/kimchi-key.pem' % paths.conf_dir - params = {'web': os.path.join(paths.ui_dir, 'pages/websockify'), + params = {'listen_host': '127.0.0.1', 'listen_port': config.get('display', 'display_proxy_port'), 'target_cfg': WS_TOKENS_DIR, - 'key': key, 'cert': cert, 'ssl_only': True} + 'ssl_only': False} def start_proxy(): server = WebSocketProxy(**params) diff --git a/src/kimchid.in b/src/kimchid.in index 4ea7a42..de6eec2 100644 --- a/src/kimchid.in +++ b/src/kimchid.in @@ -92,6 +92,7 @@ def main(options): setattr(options, 'ssl_key', config.config.get('server', 'ssl_key')) setattr(options, 'max_body_size', config.config.get('server', 'max_body_size')) + setattr(options, 'display_proxy_port', config.config.get('display', 'display_proxy_port')) kimchi.server.main(options) diff --git a/src/nginx/kimchi.conf.in b/src/nginx/kimchi.conf.in index b0faea3..7d75329 100644 --- a/src/nginx/kimchi.conf.in +++ b/src/nginx/kimchi.conf.in @@ -47,6 +47,15 @@ http { proxy_read_timeout 600; send_timeout 600; + map $http_upgrade $connection_upgrade { + default upgrade; + '' close; + } + + upstream websocket { + server 127.0.0.1:${display_proxy_port}; + } + server { listen ${proxy_ssl_port} ssl; @@ -69,6 +78,12 @@ http { proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_redirect http://127.0.0.1:${kimchid_port}/ https://$host:${proxy_ssl_port}/; } + location /websockify { + proxy_pass http://websocket; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $connection_upgrade; + } } server { diff --git a/ui/js/src/kimchi.api.js b/ui/js/src/kimchi.api.js index 44f58d1..2c4636a 100644 --- a/ui/js/src/kimchi.api.js +++ b/ui/js/src/kimchi.api.js @@ -368,15 +368,15 @@ var kimchi = { type : 'GET', dataType : 'json' }).done(function(data, textStatus, xhr) { - proxy_port = data['display_proxy_port']; + ssl_port = data['ssl_port']; kimchi.requestJSON({ url : "vms/" + encodeURIComponent(vm) + "/connect", type : "POST", dataType : "json" }).done(function() { - url = 'https://' + location.hostname + ':' + proxy_port; + url = 'https://' + location.hostname + ':' + ssl_port; url += "/console.html?url=" + encodeURIComponent("novnc/vnc_auto.html"); - url += "&port=" + proxy_port; + url += "&port=" + ssl_port; /* * From python documentation base64.urlsafe_b64encode(s) * substitutes - instead of + and _ instead of / in the @@ -384,7 +384,7 @@ var kimchi = { * contain = which is not safe in a URL query component. * So remove it when needed as base64 can work well without it. * */ - url += "&path=?token=" + kimchi.urlSafeB64Encode(vm).replace(/=*$/g, ""); + url += "&path=websockify?token=" + kimchi.urlSafeB64Encode(vm).replace(/=*$/g, ""); url += "&kimchi=" + location.port; url += '&encrypt=1'; window.open(url); @@ -400,14 +400,14 @@ var kimchi = { type : 'GET', dataType : 'json' }).done(function(data, textStatus, xhr) { - proxy_port = data['display_proxy_port']; + ssl_port = data['ssl_port']; kimchi.requestJSON({ url : "vms/" + encodeURIComponent(vm) + "/connect", type : "POST", dataType : "json" }).done(function(data, textStatus, xhr) { - url = 'https://' + location.hostname + ':' + proxy_port; - url += "/console.html?url=spice_auto.html&port=" + proxy_port; + url = 'https://' + location.hostname + ':' + ssl_port; + url += "/console.html?url=spice_auto.html&port=" + ssl_port; url += "&listen=" + location.hostname; /* * From python documentation base64.urlsafe_b64encode(s) diff --git a/ui/spice-html5/pages/spice_auto.html b/ui/spice-html5/pages/spice_auto.html index 40afea4..6ef90b9 100644 --- a/ui/spice-html5/pages/spice_auto.html +++ b/ui/spice-html5/pages/spice_auto.html @@ -143,7 +143,7 @@ * to point Kimchi user to a specific console represented by * token value. */ - uri = scheme + host + ":" + port + "/?token=" + token; + uri = scheme + host + ":" + port + "/websockify?token=" + token; try { -- 1.8.3.1

Hi Rob, Could you rebase this patch with the master branch? Also with those changes, we can remove the instructions to open the port 64667 from the README and src/firewalld.xml files. Thanks, Aline Manera On 05/10/2015 18:07, Rob Lemley wrote:
This is a patch against v1.5.1 that sets up nginx to proxy the websocket requests handled by websockify running on port 64667. The changes include modifying the nginx config file (kimchi.conf.in) and various Kimchi files to support the URL changes. Tested on Firefox and Chrome browsers (current versions).
Rob Lemley (1): Configure nginx to proxy connections to the websocket server so that browsers don't need to connect to port 64667. This helps in networks with restrictive firewalls.
src/kimchi/config.py.in | 8 ++++++++ src/kimchi/model/config.py | 2 ++ src/kimchi/proxy.py | 1 + src/kimchi/vnc.py | 4 ++-- src/kimchid.in | 1 + src/nginx/kimchi.conf.in | 15 +++++++++++++++ ui/js/src/kimchi.api.js | 14 +++++++------- ui/spice-html5/pages/spice_auto.html | 2 +- 8 files changed, 37 insertions(+), 10 deletions(-)

Hey Rob. Just a little tip: on new master branch, your changes will be related to Kimchi plugin, located in src/wok/plugins/kimchi directory. BTW, the patch looks like very nice and I can't wait to test it :-D Best regards, Paulo Vital. On Mon, 2015-10-05 at 18:46 -0300, Aline Manera wrote:
Hi Rob,
Could you rebase this patch with the master branch?
Also with those changes, we can remove the instructions to open the port 64667 from the README and src/firewalld.xml files.
Thanks, Aline Manera
On 05/10/2015 18:07, Rob Lemley wrote:
This is a patch against v1.5.1 that sets up nginx to proxy the websocket requests handled by websockify running on port 64667. The changes include modifying the nginx config file (kimchi.conf.in) and various Kimchi files to support the URL changes. Tested on Firefox and Chrome browsers (current versions).
Rob Lemley (1): Configure nginx to proxy connections to the websocket server so that browsers don't need to connect to port 64667. This helps in networks with restrictive firewalls.
src/kimchi/config.py.in | 8 ++++++++ src/kimchi/model/config.py | 2 ++ src/kimchi/proxy.py | 1 + src/kimchi/vnc.py | 4 ++-- src/kimchid.in | 1 + src/nginx/kimchi.conf.in | 15 +++++++++++++++ ui/js/src/kimchi.api.js | 14 +++++++------- ui/spice-html5/pages/spice_auto.html | 2 +- 8 files changed, 37 insertions(+), 10 deletions(-)
_______________________________________________ Kimchi-devel mailing list Kimchi-devel@ovirt.org http://lists.ovirt.org/mailman/listinfo/kimchi-devel
participants (3)
-
Aline Manera
-
Paulo Ricardo Paz Vital
-
Rob Lemley