diff --git a/CMakeLists.txt b/CMakeLists.txt
index 346940280339f52009b5d0082b2406670b00c64d..661260125c87f4522c81a9a5e9a8b19e926d4bbb 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -95,13 +95,14 @@ option(LWS_WITH_HTTP_PROXY "Support for rewriting HTTP proxying" OFF)
 option(LWS_WITH_LWSWS "Libwebsockets Webserver" OFF)
 option(LWS_WITH_PLUGINS "Support plugins for protocols and extensions" OFF)
 option(LWS_WITH_ACCESS_LOG "Support generating Apache-compatible access logs" OFF)
-
+option(LWS_WITH_SERVER_STATUS "Support json + jscript server monitoring" OFF)
 
 if (LWS_WITH_LWSWS)
  message(STATUS "LWS_WITH_LWSWS --> Enabling LWS_WITH_PLUGINS and LWS_WITH_LIBUV")
  set(LWS_WITH_PLUGINS 1)
  set(LWS_WITH_LIBUV 1)
  set(LWS_WITH_ACCESS_LOG 1)
+ set(LWS_WITH_SERVER_STATUS 1)
 endif()
 
 if (LWS_WITH_PLUGINS AND NOT LWS_WITH_LIBUV)
@@ -1199,6 +1200,10 @@ if (NOT LWS_WITHOUT_TESTAPPS)
 			      "plugins/protocol_lws_mirror.c")
 		create_plugin(protocol_lws_status
 			      "plugins/protocol_lws_status.c")
+if (LWS_WITH_SERVER_STATUS)
+		create_plugin(protocol_lws_server_status
+			      "plugins/protocol_lws_server_status.c")
+endif()
 	endif(LWS_WITH_PLUGINS AND LWS_WITH_SHARED)
 
 	#
@@ -1399,6 +1404,11 @@ if (LWS_WITH_PLUGINS)
 		PERMISSIONS  OWNER_WRITE OWNER_EXECUTE GROUP_EXECUTE WORLD_EXECUTE OWNER_READ GROUP_READ WORLD_READ
 		DESTINATION share/libwebsockets-test-server/plugins
 		COMPONENT plugins)
+if (LWS_WITH_SERVER_STATUS)
+	install(FILES plugins/server-status.html
+		DESTINATION share/libwebsockets-test-server/server-status
+			COMPONENT examples)
+endif()
 endif()
 
 # Install the LibwebsocketsConfig.cmake and LibwebsocketsConfigVersion.cmake
@@ -1466,6 +1476,7 @@ message(" LWS_WITH_HTTP_PROXY = ${LWS_WITH_HTTP_PROXY}")
 message(" LIBHUBBUB_LIBRARIES = ${LIBHUBBUB_LIBRARIES}")
 message(" PLUGINS = ${PLUGINS_LIST}")
 message(" LWS_WITH_ACCESS_LOG = ${LWS_WITH_ACCESS_LOG}")
+message(" LWS_WITH_SERVER_STATUS = ${LWS_WITH_SERVER_STATUS}")
 message("---------------------------------------------------------------------")
 
 # These will be available to parent projects including libwebsockets using add_subdirectory()
diff --git a/README.lwsws.md b/README.lwsws.md
index 6b821271ea80f0f67142e8b67c0eecad99e32d77..15a8bd31914cfb69bcae8c8fac1fbe177fe01394 100644
--- a/README.lwsws.md
+++ b/README.lwsws.md
@@ -153,6 +153,11 @@ Vhosts can select which plugins they want to offer and give them per-vhost setti
 
 ```
 
+The "x":"y" parameters like "status":"ok" are made available to the protocol during its per-vhost
+LWS_CALLBACK_PROTOCOL_INIT (@in is a pointer to a linked list of struct lws_protocol_vhost_options
+containing the name and value pointers).
+
+
 Other vhost options
 -------------------
 
@@ -265,3 +270,28 @@ dumb increment, mirror and status protocol plugins are provided as examples.
 
 
 
+lws-server-status plugin
+------------------------
+
+One provided protocol can be used to monitor the server status.
+
+Enable the protocol like this on a vhost's ws-protocols section
+
+       "lws-server-status": {
+         "status": "ok",
+         "update-ms": "5000"
+       }
+
+"update-ms" is used to control how often updated JSON is sent on a ws link.
+
+And map the provided HTML into the vhost in the mounts section
+
+       {
+        "mountpoint": "/server-status",
+        "origin": "file:///usr/local/share/libwebsockets-test-server/server-status",
+        "default": "server-status.html"
+       }
+
+You might choose to put it on its own vhost which has "interface": "lo", so it's not
+externally visible.
+
diff --git a/lib/context.c b/lib/context.c
index e746e8cbd08b93f2d883b154fe877fe922ca2313..8ee5ffa75b2b301b2c694040566283f1fceefbba 100644
--- a/lib/context.c
+++ b/lib/context.c
@@ -440,7 +440,6 @@ lws_create_context(struct lws_context_creation_info *info)
 	struct rlimit rt;
 #endif
 
-
 	lwsl_notice("Initial logging level %d\n", log_level);
 	lwsl_notice("Libwebsockets version: %s\n", library_version);
 #if LWS_POSIX
@@ -471,6 +470,8 @@ lws_create_context(struct lws_context_creation_info *info)
 		lwsl_err("No memory for websocket context\n");
 		return NULL;
 	}
+
+	context->time_up = time(NULL);
 #ifndef LWS_NO_DAEMONIZE
 	if (pid_daemon) {
 		context->started_with_parent = pid_daemon;
diff --git a/lib/libwebsockets.c b/lib/libwebsockets.c
index 22368a22af05ebffa0a85ae87f1336fb78dec76a..58d0006401cf11234435bcd55fb088d79beaca41 100644
--- a/lib/libwebsockets.c
+++ b/lib/libwebsockets.c
@@ -2234,6 +2234,8 @@ lws_access_log(struct lws *wsi)
 }
 #endif
 
+#ifdef LWS_WITH_SERVER_STATUS
+
 LWS_EXTERN int
 lws_json_dump_vhost(const struct lws_vhost *vh, char *buf, int len)
 {
@@ -2254,10 +2256,15 @@ lws_json_dump_vhost(const struct lws_vhost *vh, char *buf, int len)
 	buf += snprintf(buf, end - buf,
 			"{\n \"name\":\"%s\",\n"
 			" \"port\":\"%d\",\n"
-			" \"use-ssl\":\"%d\",\n"
+			" \"use_ssl\":\"%d\",\n"
 			" \"sts\":\"%d\",\n"
 			" \"rx\":\"%lu\",\n"
-			" \"tx\":\"%lu\",\n",
+			" \"tx\":\"%lu\",\n"
+			" \"conn\":\"%lu\",\n"
+			" \"trans\":\"%lu\",\n"
+			" \"ws_upg\":\"%lu\",\n"
+			" \"http2_upg\":\"%lu\""
+			,
 			vh->name, vh->listen_port,
 #ifdef LWS_OPENSSL_SUPPORT
 			vh->use_ssl,
@@ -2265,7 +2272,8 @@ lws_json_dump_vhost(const struct lws_vhost *vh, char *buf, int len)
 			0,
 #endif
 			!!(vh->options & LWS_SERVER_OPTION_STS),
-			vh->rx, vh->tx
+			vh->rx, vh->tx, vh->conn, vh->trans, vh->ws_upgrades,
+			vh->http2_upgrades
 	);
 
 	if (vh->mount_list) {
@@ -2277,7 +2285,7 @@ lws_json_dump_vhost(const struct lws_vhost *vh, char *buf, int len)
 				buf += snprintf(buf, end - buf, ",");
 			buf += snprintf(buf, end - buf,
 					"\n  {\n   \"mountpoint\":\"%s\",\n"
-					"  \"origin\":\"%s%s\""
+					"  \"origin\":\"%s%s\"\n"
 					,
 					m->mountpoint,
 					prots[m->origin_protocol],
@@ -2316,3 +2324,34 @@ lws_json_dump_vhost(const struct lws_vhost *vh, char *buf, int len)
 
 	return buf - orig;
 }
+
+
+LWS_EXTERN LWS_VISIBLE int
+lws_json_dump_context(const struct lws_context *context, char *buf, int len)
+{
+	char *orig = buf, *end = buf + len - 1, first = 1;
+	struct lws_vhost *vh = context->vhost_list;
+	time_t t = time(NULL);
+
+	buf += snprintf(buf, end - buf, "{ "
+					"\"uptime\":\"%ld\",\n"
+					"\"wsi_alive\":\"%d\",\n"
+					"\"vhosts\":[\n ",
+					(unsigned long)(t - context->time_up),
+					context->count_wsi_allocated);
+
+	while (vh) {
+		if (!first)
+			if(buf != end)
+				*buf++ = ',';
+		buf += lws_json_dump_vhost(vh, buf, end - buf);
+		first = 0;
+		vh = vh->vhost_next;
+	}
+
+	buf += snprintf(buf, end - buf, "]}\n ");
+
+	return buf - orig;
+}
+
+#endif
diff --git a/lib/libwebsockets.h b/lib/libwebsockets.h
index 0f6687dd93ce43f4cf67f70e8c10f4fd9ebc945c..60bbe4f291a8d454378024fc02c6d5af5b1618df 100644
--- a/lib/libwebsockets.h
+++ b/lib/libwebsockets.h
@@ -1566,6 +1566,9 @@ lws_write_http_mount(struct lws_http_mount *next, struct lws_http_mount **res,
 LWS_EXTERN int
 lws_json_dump_vhost(const struct lws_vhost *vh, char *buf, int len);
 
+LWS_EXTERN int
+lws_json_dump_context(const struct lws_context *context, char *buf, int len);
+
 LWS_VISIBLE LWS_EXTERN void
 lws_set_log_level(int level,
 		  void (*log_emit_function)(int level, const char *line));
diff --git a/lib/output.c b/lib/output.c
index c3fc2c84e0a2a43f39fe1d0a556b839adb780013..451ca0df86801470b9e6a6a11757138d3e788780 100644
--- a/lib/output.c
+++ b/lib/output.c
@@ -251,6 +251,8 @@ LWS_VISIBLE int lws_write(struct lws *wsi, unsigned char *buf, size_t len,
 #ifdef LWS_WITH_ACCESS_LOG
 	wsi->access_log.sent += len;
 #endif
+	if (wsi->vhost)
+		wsi->vhost->tx += len;
 
 	if (wsi->state == LWSS_ESTABLISHED && wsi->u.ws.tx_draining_ext) {
 		/* remove us from the list */
@@ -634,8 +636,11 @@ lws_ssl_capable_read_no_ssl(struct lws *wsi, unsigned char *buf, int len)
 	int n;
 
 	n = recv(wsi->sock, (char *)buf, len, 0);
-	if (n > 0)
+	if (n > 0) {
+		if (wsi->vhost)
+			wsi->vhost->rx += n;
 		return n;
+	}
 #if LWS_POSIX
 	if (LWS_ERRNO == LWS_EAGAIN ||
 	    LWS_ERRNO == LWS_EWOULDBLOCK ||
diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h
index f91a5c132e847a11c398d11f2de19046ad818863..60c038ca46bde293f2206f5b12afef8bfd7fd9d7 100644
--- a/lib/private-libwebsockets.h
+++ b/lib/private-libwebsockets.h
@@ -668,7 +668,7 @@ struct lws_vhost {
 #ifndef LWS_NO_EXTENSIONS
 	const struct lws_extension *extensions;
 #endif
-	unsigned long rx, tx;
+	unsigned long rx, tx, conn, trans, ws_upgrades, http2_upgrades;
 
 	int listen_port;
 	unsigned int http_proxy_port;
@@ -698,6 +698,7 @@ struct lws_vhost {
 
 struct lws_context {
 	time_t last_timeout_check_s;
+	time_t time_up;
 	struct lws_plat_file_ops fops;
 	struct lws_context_per_thread pt[LWS_MAX_SMP];
 #ifdef _WIN32
@@ -1255,6 +1256,7 @@ struct lws {
 	unsigned int socket_is_permanently_unusable:1;
 	unsigned int rxflow_change_to:2;
 	unsigned int more_rx_waiting:1; /* has to live here since ah may stick to end */
+	unsigned int conn_stat_done:1;
 #ifdef LWS_WITH_ACCESS_LOG
 	unsigned int access_log_pending:1;
 #endif
diff --git a/lib/server.c b/lib/server.c
index 761590803304959d17d85361421150c1e914ed3e..41e6339a17891c9b09192257076f8f66f7ecaae4 100644
--- a/lib/server.c
+++ b/lib/server.c
@@ -700,6 +700,23 @@ lws_handshake_server(struct lws *wsi, unsigned char **buf, size_t len)
 		lwsl_debug("%s: wsi->more_rx_waiting=%d\n", __func__,
 				wsi->more_rx_waiting);
 
+		/* select vhost */
+
+		if (lws_hdr_total_length(wsi, WSI_TOKEN_HOST)) {
+			struct lws_vhost *vhost = lws_select_vhost(
+				context, wsi->vhost->listen_port,
+				lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST));
+
+			if (vhost)
+				wsi->vhost = vhost;
+		}
+
+		wsi->vhost->trans++;
+		if (!wsi->conn_stat_done) {
+			wsi->vhost->conn++;
+			wsi->conn_stat_done = 1;
+		}
+
 		wsi->mode = LWSCM_PRE_WS_SERVING_ACCEPT;
 		lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
 
@@ -708,12 +725,14 @@ lws_handshake_server(struct lws *wsi, unsigned char **buf, size_t len)
 		if (lws_hdr_total_length(wsi, WSI_TOKEN_UPGRADE)) {
 			if (!strcasecmp(lws_hdr_simple_ptr(wsi, WSI_TOKEN_UPGRADE),
 					"websocket")) {
+				wsi->vhost->ws_upgrades++;
 				lwsl_info("Upgrade to ws\n");
 				goto upgrade_ws;
 			}
 #ifdef LWS_USE_HTTP2
 			if (!strcasecmp(lws_hdr_simple_ptr(wsi, WSI_TOKEN_UPGRADE),
 					"h2c")) {
+				wsi->vhost->http2_upgrades++;
 				lwsl_info("Upgrade to h2c\n");
 				goto upgrade_h2c;
 			}
@@ -728,17 +747,6 @@ lws_handshake_server(struct lws *wsi, unsigned char **buf, size_t len)
 		lwsl_info("No upgrade\n");
 		ah = wsi->u.hdr.ah;
 
-		/* select vhost */
-
-		if (lws_hdr_total_length(wsi, WSI_TOKEN_HOST)) {
-			struct lws_vhost *vhost = lws_select_vhost(
-				context, wsi->vhost->listen_port,
-				lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST));
-
-			if (vhost)
-				wsi->vhost = vhost;
-		}
-
 		lws_union_transition(wsi, LWSCM_HTTP_SERVING_ACCEPTED);
 		wsi->state = LWSS_HTTP;
 		wsi->u.http.fd = LWS_INVALID_FILE;
diff --git a/lws_config.h.in b/lws_config.h.in
index a9298ff4dda5d53da1d10e36be9e40f0247777ec..87a0c6d2af352cfc39e8834e78a692696c01a9e2 100644
--- a/lws_config.h.in
+++ b/lws_config.h.in
@@ -94,6 +94,7 @@
 
 /* Http access log support */
 #cmakedefine LWS_WITH_ACCESS_LOG
+#cmakedefine LWS_WITH_SERVER_STATUS
 
 /* Maximum supported service threads */
 #define LWS_MAX_SMP ${LWS_MAX_SMP}
diff --git a/plugins/protocol_dumb_increment.c b/plugins/protocol_dumb_increment.c
index fd4eb299cfa64cefe7fea85aadb1a076fbb080a8..5c1a343d98e75fd1ba0b5818a2a6d6598e5adf63 100644
--- a/plugins/protocol_dumb_increment.c
+++ b/plugins/protocol_dumb_increment.c
@@ -59,7 +59,6 @@ callback_dumb_increment(struct lws *wsi, enum lws_callback_reasons reason,
 
 	switch (reason) {
 	case LWS_CALLBACK_PROTOCOL_INIT:
-		lwsl_notice("%s: pvo %p\n", __func__, in);
 		vhd = lws_protocol_vh_priv_zalloc(lws_vhost_get(wsi),
 				lws_protocol_get(wsi),
 				sizeof(struct per_vhost_data__dumb_increment));
@@ -73,6 +72,8 @@ callback_dumb_increment(struct lws *wsi, enum lws_callback_reasons reason,
 		break;
 
 	case LWS_CALLBACK_PROTOCOL_DESTROY:
+		if (!vhd)
+			break;
 		uv_timer_stop(&vhd->timeout_watcher);
 		break;
 
diff --git a/plugins/protocol_lws_mirror.c b/plugins/protocol_lws_mirror.c
index 05614db9ade8194257eff53a5df26fe7658166d1..4b9319c4e5557772d1a195e64decd8db728998d3 100644
--- a/plugins/protocol_lws_mirror.c
+++ b/plugins/protocol_lws_mirror.c
@@ -66,6 +66,8 @@ callback_lws_mirror(struct lws *wsi, enum lws_callback_reasons reason,
 		break;
 
 	case LWS_CALLBACK_PROTOCOL_DESTROY: /* per vhost */
+		if (!v)
+			break;
 		lwsl_info("%s: mirror protocol cleaning up %p\n", __func__, v);
 		for (n = 0; n < ARRAY_SIZE(v->ringbuffer); n++)
 			if (v->ringbuffer[n].payload) {
diff --git a/plugins/protocol_lws_server_status.c b/plugins/protocol_lws_server_status.c
new file mode 100644
index 0000000000000000000000000000000000000000..588ada555ca6ac113754110c5c825c5c6e1db35b
--- /dev/null
+++ b/plugins/protocol_lws_server_status.c
@@ -0,0 +1,147 @@
+/*
+ * libwebsockets-test-server - libwebsockets test implementation
+ *
+ * Copyright (C) 2010-2016 Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ * The person who associated a work with this deed has dedicated
+ * the work to the public domain by waiving all of his or her rights
+ * to the work worldwide under copyright law, including all related
+ * and neighboring rights, to the extent allowed by law. You can copy,
+ * modify, distribute and perform the work, even for commercial purposes,
+ * all without asking permission.
+ *
+ * The test apps are intended to be adapted for use in your code, which
+ * may be proprietary.  So unlike the library itself, they are licensed
+ * Public Domain.
+ */
+#include "../lib/libwebsockets.h"
+#include <string.h>
+
+#define LWS_SS_VERSIONS 3
+
+struct lws_ss_dumps {
+	char buf[32768];
+	int length;
+};
+
+static struct lws_ss_dumps d[LWS_SS_VERSIONS];
+static int last_dump;
+static uv_timer_t timeout_watcher;
+static struct lws_context *context;
+static int tow_flag;
+
+struct per_session_data__server_status {
+	int ver;
+	int pos;
+};
+
+static const struct lws_protocols protocols[];
+
+static void
+uv_timeout_cb_server_status(uv_timer_t *w
+#if UV_VERSION_MAJOR == 0
+		, int status
+#endif
+)
+{
+	int n;
+
+	last_dump = (last_dump + 1) % LWS_SS_VERSIONS;
+	n = lws_json_dump_context(context, d[last_dump].buf + LWS_PRE,
+			sizeof(d[0].buf) - LWS_PRE);
+	d[last_dump].length = n;
+
+	lws_callback_on_writable_all_protocol(context, &protocols[0]);
+}
+
+static int
+callback_lws_server_status(struct lws *wsi, enum lws_callback_reasons reason,
+			   void *user, void *in, size_t len)
+{
+	struct lws_protocol_vhost_options *pvo =
+			(struct lws_protocol_vhost_options *)in;
+	int m, period = 1000;
+
+	switch (reason) {
+
+	case LWS_CALLBACK_ESTABLISHED:
+		lwsl_info("%s: LWS_CALLBACK_ESTABLISHED\n", __func__);
+		lws_callback_on_writable(wsi);
+		break;
+
+	case LWS_CALLBACK_PROTOCOL_INIT: /* per vhost */
+		if (tow_flag)
+			break;
+		while (pvo) {
+			if (!strcmp(pvo->name, "update-ms"))
+				period = atoi(pvo->value);
+			pvo = pvo->next;
+		}
+		context = lws_get_context(wsi);
+		uv_timer_init(lws_uv_getloop(context, 0), &timeout_watcher);
+		uv_timer_start(&timeout_watcher,
+				uv_timeout_cb_server_status, 2000, period);
+		tow_flag = 1;
+		break;
+
+	case LWS_CALLBACK_PROTOCOL_DESTROY: /* per vhost */
+		if (!tow_flag)
+			break;
+		uv_timer_stop(&timeout_watcher);
+		tow_flag = 0;
+		break;
+
+	case LWS_CALLBACK_SERVER_WRITEABLE:
+		m = lws_write(wsi, (unsigned char *)
+				d[last_dump].buf + LWS_PRE, d[last_dump].length,
+			      LWS_WRITE_TEXT);
+		if (m < 0)
+			return -1;
+		break;
+
+	case LWS_CALLBACK_RECEIVE:
+		break;
+
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static const struct lws_protocols protocols[] = {
+	{
+		"lws-server-status",
+		callback_lws_server_status,
+		sizeof(struct per_session_data__server_status),
+		1024,
+	},
+};
+
+LWS_VISIBLE int
+init_protocol_lws_server_status(struct lws_context *context,
+			     struct lws_plugin_capability *c)
+{
+	if (c->api_magic != LWS_PLUGIN_API_MAGIC) {
+		lwsl_err("Plugin API %d, library API %d",
+			 LWS_PLUGIN_API_MAGIC, c->api_magic);
+		return 1;
+	}
+
+	c->protocols = protocols;
+	c->count_protocols = ARRAY_SIZE(protocols);
+	c->extensions = NULL;
+	c->count_extensions = 0;
+
+	return 0;
+}
+
+LWS_VISIBLE int
+destroy_protocol_lws_server_status(struct lws_context *context)
+{
+	return 0;
+}
+
diff --git a/plugins/protocol_lws_status.c b/plugins/protocol_lws_status.c
index 76d2563e6d693221bb5c010494a62a647ce51969..38281b7682b0cc33dbbfd84106fc00df2f61f991 100644
--- a/plugins/protocol_lws_status.c
+++ b/plugins/protocol_lws_status.c
@@ -102,8 +102,7 @@ callback_lws_status(struct lws *wsi, enum lws_callback_reasons reason,
 		    void *user, void *in, size_t len)
 {
 	struct per_session_data__lws_status *pss =
-			(struct per_session_data__lws_status *)user,
-			**pp;
+			(struct per_session_data__lws_status *)user, **pp;
 	char name[128], rip[128];
 	int m;
 
diff --git a/plugins/server-status.html b/plugins/server-status.html
new file mode 100644
index 0000000000000000000000000000000000000000..0ecebb4b17fa23876ae425a05773a6b8c6d9946e
--- /dev/null
+++ b/plugins/server-status.html
@@ -0,0 +1,219 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset=utf-8 http-equiv="Content-Language" content="en"/>
+ <title>LWS Server Status</title>
+<style type="text/css">
+	span.title { font-size:18pt; font: Arial; font-weight:normal;
+			text-align:center; color:#000000; }
+	span.mount { font-size:10pt; font: Arial; font-weight:normal;
+			text-align:center; color:#000000; }
+	.browser { font-size:18pt; font: Arial; font-weight:normal; text-align:center; color:#ffff00; vertical-align:middle; text-align:center; background:#d0b070; padding:12px; -webkit-border-radius:10px; -moz-border-radius:10px; border-radius:10px;}
+	.group2 { vertical-align:middle;
+		text-align:center;
+		background:#f0f0e0; 
+		padding:12px; 
+		-webkit-border-radius:10px; 
+		-moz-border-radius:10px;
+		border-radius:10px; }
+	.explain { vertical-align:middle;
+		text-align:center;
+		background:#f0f0c0; padding:12px;
+		-webkit-border-radius:10px;
+		-moz-border-radius:10px;
+		border-radius:10px;
+		color:#404000; }
+	td.wsstatus { vertical-align:middle; width:200px; height:50px;
+		text-align:center;
+		background:#f0f0c0; padding:6px;
+		-webkit-border-radius:8px;
+		-moz-border-radius:8px;
+		border-radius:8px;
+		color:#404000; }
+	td.l { vertical-align:middle;
+		text-align:center;
+		background:#d0d0b0; 
+		padding:3px; 
+		-webkit-border-radius:3px; 
+		-moz-border-radius:3px;
+		border-radius:3px; }
+	td.c { vertical-align:middle;
+		text-align:center;
+		background:#c0c0a0; 
+		padding:3px; 
+		-webkit-border-radius:3px; 
+		-moz-border-radius:3px;
+		border-radius:3px; }
+	td.t { vertical-align:middle;
+		text-align:center;
+		background:#e0e0c0; 
+		padding:3px; 
+		-webkit-border-radius:3px; 
+		-moz-border-radius:3px;
+		border-radius:3px; }
+	.content { vertical-align:top; text-align:center; background:#fffff0; padding:12px; -webkit-border-radius:10px; -moz-border-radius:10px; border-radius:10px; }
+	.canvas { vertical-align:top; text-align:center; background:#efefd0; padding:12px; -webkit-border-radius:10px; -moz-border-radius:10px; border-radius:10px; }
+.tabs {
+  position: relative;   
+  min-height: 750px; /* This part sucks */
+  clear: both;
+  margin: 25px 0;
+}
+.tab {
+  float: left;
+}
+.tab label {
+  background: #eee; 
+  padding: 10px; 
+  border: 1px solid #ccc; 
+  margin-left: -1px; 
+  position: relative;
+  left: 1px; 
+}
+.tab [type=radio] {
+  display: none;   
+}
+.content {
+  position: absolute;
+  top: 28px;
+  left: 0;
+  background: white;
+  right: 0;
+  bottom: 0;
+  padding: 20px;
+  border: 1px solid #ccc; 
+}
+[type=radio]:checked ~ label {
+  background: white;
+  border-bottom: 1px solid white;
+  z-index: 2;
+}
+[type=radio]:checked ~ label ~ .content {
+  z-index: 1;
+}
+</style>
+</head>
+
+<body>
+<header></header>
+<article>
+
+<table><tr><td align=center>
+<div id="conninfo">...</div>
+</td></tr>
+
+
+</table>
+
+</article>
+
+<script>
+
+/*
+ * We display untrusted stuff in html context... reject anything
+ * that has HTML stuff in it
+ */
+
+function san(s)
+{
+	if (s.search("<") != -1)
+		return "invalid string";
+	
+	return s;
+}
+
+	var pos = 0;
+
+function get_appropriate_ws_url()
+{
+	var pcol;
+	var u = document.URL;
+
+	/*
+	 * We open the websocket encrypted if this page came on an
+	 * https:// url itself, otherwise unencrypted
+	 */
+
+	if (u.substring(0, 5) == "https") {
+		pcol = "wss://";
+		u = u.substr(8);
+	} else {
+		pcol = "ws://";
+		if (u.substring(0, 4) == "http")
+			u = u.substr(7);
+	}
+
+	u = u.split('/');
+
+	/* + "/xxx" bit is for IE10 workaround */
+
+	return pcol + u[0] + "/xxx";
+}
+
+
+	var socket_status, jso, s;
+
+	if (typeof MozWebSocket != "undefined") {
+		socket_status = new MozWebSocket(get_appropriate_ws_url(),
+				   "lws-server-status");
+	} else {
+		socket_status = new WebSocket(get_appropriate_ws_url(),
+				   "lws-server-status");
+	}
+
+
+	try {
+		socket_status.onopen = function() {
+		} 
+
+		socket_status.onmessage =function got_packet(msg) {
+			document.getElementById("conninfo").innerHTML = "<pre>"+msg.data+"</pre>";
+			jso = JSON.parse(msg.data);
+			
+			s="<table><tr><td class=\"c\">" +
+			  "Context</td><td>Uptime: " + san(jso.uptime) + "<br>" +
+			  "Current wsi alive: " + san(jso.wsi_alive) +
+			  "</td></tr>";
+			var n;
+			for (n = 0; n < jso.vhosts.length; n++) {
+				s = s + "<tr><td class=\"l\">vhost " + (n + 1) +
+				"</td><td><b>" + san(jso.vhosts[n].name) + ":" +
+				san(jso.vhosts[n].port) +
+				"</b><br>" +
+				"ssl " + san(jso.vhosts[n].use_ssl) + ", " +
+				"sts " + san(jso.vhosts[n].sts) + "<br>" +
+				"rx " + san(jso.vhosts[n].rx) + ", " +
+				"tx " + san(jso.vhosts[n].tx) + "<br>" +
+				"total connections " + san(jso.vhosts[n].conn) + ", " +
+				"total http transactions " + san(jso.vhosts[n].trans) + "<br>" +
+				"Upgrades to ws " + san(jso.vhosts[n].ws_upg) + ", " +
+				"to http2 " + san(jso.vhosts[n].http2_upg) + "<br>" +
+				"<table><tr><td class=t colspan=2>Mounts</td></tr>";
+				
+				var m;
+				for (m = 0; m < jso.vhosts[n].mounts.length; m++) {
+					s = s + "<tr><td>";
+					s = s + san(jso.vhosts[n].mounts[m].mountpoint) +
+						"</td><td>" +
+						san(jso.vhosts[n].mounts[m].origin);
+					s = s + "</td></tr>"
+				}
+				s = s + "</table>";
+				s = s + "</td></tr>";
+			}
+			s = s + "</table>";
+			
+			document.getElementById("conninfo").innerHTML = s;
+		} 
+
+		socket_status.onclose = function(){
+			document.getElementById("s_statustd").style.backgroundColor = "#ff4040";
+			document.getElementById("s_status").textContent = " websocket connection CLOSED ";
+		}
+	} catch(exception) {
+		alert('<p>Error' + exception);  
+	}
+</script>
+
+</body>
+</html>