diff --git a/Makefile.projbuild b/Makefile.projbuild
new file mode 100644
index 0000000000000000000000000000000000000000..3145eaf4625cf38fc03996744e1e5668b5df5e2d
--- /dev/null
+++ b/Makefile.projbuild
@@ -0,0 +1 @@
+CPPFLAGS += -I$(BUILD_DIR_BASE)/libwebsockets/include
diff --git a/lib/context.c b/lib/context.c
index 4dc1c0f09a79851eec253c319dab51983c0880ca..ca211da7ceb22996a5683be72f0d16116c16f9a3 100644
--- a/lib/context.c
+++ b/lib/context.c
@@ -275,10 +275,10 @@ lws_protocol_init(struct lws_context *context)
 			if (vh->protocols[n].callback(&wsi,
 					LWS_CALLBACK_PROTOCOL_INIT, NULL,
 					(void *)pvo, 0)) {
-				lwsl_err("%s: vhost %s failed init\n", __func__,
+				lws_free(vh->protocol_vh_privs[n]);
+				vh->protocol_vh_privs[n] = NULL;
+				lwsl_err("%s: protocol %s failed init\n", __func__,
 					 vh->protocols[n].name);
-				context->doing_protocol_init = 0;
-				return 1;
 			}
 		}
 
@@ -855,7 +855,8 @@ lws_create_vhost(struct lws_context *context,
 	/* for the case we are adding a vhost much later, after server init */
 
 	if (context->protocol_init_done)
-		lws_protocol_init(context);
+		if (lws_protocol_init(context))
+			goto bail;
 
 	return vh;
 
diff --git a/lib/libwebsockets.h b/lib/libwebsockets.h
index df232cd32c9949b2915be9c52aa6708604581d62..5b9b223603f061a4ca5efc6c55b533406b63e268 100644
--- a/lib/libwebsockets.h
+++ b/lib/libwebsockets.h
@@ -4306,6 +4306,10 @@ lws_sql_purify(char *escaped, const char *string, int len);
  */
 LWS_VISIBLE LWS_EXTERN const char *
 lws_json_purify(char *escaped, const char *string, int len);
+
+LWS_VISIBLE int
+lws_plat_write_cert(struct lws_vhost *vhost, int is_key, int fd, void *buf,
+			int len);
 ///@}
 
 /*! \defgroup ev libev helpers
diff --git a/lib/plat/lws-plat-esp32.c b/lib/plat/lws-plat-esp32.c
index b9b2c63b01c372403b8e39b20d62b26b5af42895..ed614e0607fa819895822ea5d1e95143f9f43b82 100644
--- a/lib/plat/lws-plat-esp32.c
+++ b/lib/plat/lws-plat-esp32.c
@@ -1601,8 +1601,9 @@ lws_esp32_set_creation_defaults(struct lws_context_creation_info *info)
 	part = lws_esp_ota_get_boot_partition();
 	(void)part;
 
+	info->vhost_name = "default";
 	info->port = 443;
-	info->fd_limit_per_thread = 10;
+	info->fd_limit_per_thread = 30;
 	info->max_http_header_pool = 16;
 	info->max_http_header_data = 512;
 	info->pt_serv_buf_size = 2048;
@@ -1612,8 +1613,8 @@ lws_esp32_set_creation_defaults(struct lws_context_creation_info *info)
 	info->options = LWS_SERVER_OPTION_EXPLICIT_VHOSTS |
 		       LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
 
-	info->ssl_cert_filepath = "ssl-pub.pem";
-	info->ssl_private_key_filepath = "ssl-pri.pem";
+//	info->ssl_cert_filepath = "default-cert.pem";
+//	info->ssl_private_key_filepath = "default-key.pem";
 }
 
 int
@@ -1655,34 +1656,147 @@ lws_esp32_get_image_info(const esp_partition_t *part, struct lws_esp32_image *i,
 	return 0;
 }
 
-struct lws_context *
-lws_esp32_init(struct lws_context_creation_info *info, struct lws_vhost **pvh)
+static int
+_rngf(void *context, unsigned char *buf, size_t len)
 {
-	const esp_partition_t *part = lws_esp_ota_get_boot_partition();
-	struct lws_context *context;
-	struct lws_esp32_image i;
-	struct lws_vhost *vhost;
+	if ((size_t)lws_get_random(context, buf, len) == len)
+		return 0;
+
+	return -1;
+}
+
+int
+lws_esp32_selfsigned(struct lws_vhost *vhost)
+{
+	mbedtls_x509write_cert crt;
+	char subject[200];
+	mbedtls_pk_context mpk;
+	int buf_size = 4096, n;
+	uint8_t *buf = malloc(buf_size); /* malloc because given to user code */
+	mbedtls_mpi mpi;
 	nvs_handle nvh;
-	char buf[512];
 	size_t s;
-	int n;
 
-	ESP_ERROR_CHECK(nvs_open("lws-station", NVS_READWRITE, &nvh));
+	lwsl_notice("%s: %s\n", __func__, vhost->name);
+
+	if (!buf)
+		return -1;
+
+	if (nvs_open("lws-station", NVS_READWRITE, &nvh)) {
+		lwsl_notice("%s: can't open nvs\n", __func__);
+		free(buf);
+		return 1;
+	}
+
 	n = 0;
-	s = 1;
-	if (nvs_get_blob(nvh, "ssl-pub.pem", NULL, &s) == ESP_OK)
-		n = 1;
-	s = 1;
-	if (nvs_get_blob(nvh, "ssl-pri.pem", NULL, &s) == ESP_OK)
+	if (!nvs_get_blob(nvh, vhost->alloc_cert_path, NULL, &s))
+		n |= 1;
+	if (!nvs_get_blob(nvh, vhost->key_path, NULL, &s))
 		n |= 2;
+
 	nvs_close(nvh);
+	if (n == 3) {
+		lwsl_notice("%s: certs exist\n", __func__);
+		return 0; /* certs already exist */
+	}
+
+	lwsl_notice("%s: creating selfsigned initial certs\n", __func__);
+
+	mbedtls_x509write_crt_init(&crt);
+
+	mbedtls_pk_init(&mpk);
+	if (mbedtls_pk_setup(&mpk, mbedtls_pk_info_from_type(MBEDTLS_PK_RSA))) {
+		lwsl_notice("%s: pk_setup failed\n", __func__);
+		goto fail;
+	}
+	lwsl_notice("%s: generating 2048-bit RSA keypair... "
+		    "this may take a minute or so...\n", __func__);
+	n = mbedtls_rsa_gen_key(mbedtls_pk_rsa(mpk), _rngf, vhost->context,
+				2048, 65537);
+	if (n) {
+		lwsl_notice("%s: failed to generate keys\n", __func__);
+		goto fail1;
+	}
+	lwsl_notice("%s: keys done\n", __func__);
+
+	/* subject must be formatted like "C=TW,O=warmcat,CN=myserver" */
+
+	lws_snprintf(subject, sizeof(subject) - 1,
+		     "C=TW,ST=New Taipei City,L=Taipei,O=warmcat,CN=%s",
+		     lws_esp32.hostname);
 
-	if (n != 3) {
-		/* we are not configured for SSL yet... fall back to port 80 / http */
-		info->port = 80;
-		info->options &= ~LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
-		lwsl_notice("No SSL certs... using port 80\n");
+	if (mbedtls_x509write_crt_set_subject_name(&crt, subject)) {
+		lwsl_notice("set SN failed\n");
+		goto fail1;
 	}
+	mbedtls_x509write_crt_set_subject_key(&crt, &mpk);
+	if (mbedtls_x509write_crt_set_issuer_name(&crt, subject)) {
+		lwsl_notice("set IN failed\n");
+		goto fail1;
+	}
+	mbedtls_x509write_crt_set_issuer_key(&crt, &mpk);
+
+	lws_get_random(vhost->context, &n, sizeof(n));
+	lws_snprintf(subject, sizeof(subject), "%d", n);
+
+	mbedtls_mpi_init(&mpi);
+	mbedtls_mpi_read_string(&mpi, 10, subject);
+	mbedtls_x509write_crt_set_serial(&crt, &mpi);
+	mbedtls_mpi_free(&mpi);
+
+	mbedtls_x509write_crt_set_validity(&crt, "20171105235959",
+					   "20491231235959");
+
+	mbedtls_x509write_crt_set_key_usage(&crt,
+					    MBEDTLS_X509_KU_DIGITAL_SIGNATURE |
+					    MBEDTLS_X509_KU_KEY_ENCIPHERMENT);
+
+
+	mbedtls_x509write_crt_set_md_alg(&crt, MBEDTLS_MD_SHA256);
+
+	n = mbedtls_x509write_crt_pem(&crt, buf, buf_size, _rngf,
+				      vhost->context);
+	if (n < 0) {
+		lwsl_notice("%s: write crt der failed\n", __func__);
+		goto fail1;
+	}
+
+	lws_plat_write_cert(vhost, 0, 0, buf, strlen((const char *)buf));
+
+	if (mbedtls_pk_write_key_pem(&mpk, buf, buf_size)) {
+		lwsl_notice("write key pem failed\n");
+		goto fail1;
+	}
+
+	lws_plat_write_cert(vhost, 1, 0, buf, strlen((const char *)buf));
+
+	mbedtls_pk_free(&mpk);
+	mbedtls_x509write_crt_free(&crt);
+
+	lwsl_notice("%s: cert creation complete\n", __func__);
+
+	return n;
+
+fail1:
+	mbedtls_pk_free(&mpk);
+fail:
+	mbedtls_x509write_crt_free(&crt);
+	free(buf);
+
+	nvs_close(nvh);
+
+	return -1;
+}
+
+struct lws_context *
+lws_esp32_init(struct lws_context_creation_info *info, struct lws_vhost **pvh)
+{
+	const esp_partition_t *part = lws_esp_ota_get_boot_partition();
+	struct lws_context *context;
+	struct lws_esp32_image i;
+	struct lws_vhost *vhost;
+	struct lws wsi;
+	char buf[512];
 
 	context = lws_create_context(info);
 	if (context == NULL) {
@@ -1706,16 +1820,29 @@ lws_esp32_init(struct lws_context_creation_info *info, struct lws_vhost **pvh)
 
 	lws_set_fops(context, &fops);
 
+	info->options |= LWS_SERVER_OPTION_CREATE_VHOST_SSL_CTX |
+			 LWS_SERVER_OPTION_IGNORE_MISSING_CERT;
+
 	vhost = lws_create_vhost(context, info);
-	if (!vhost)
+	if (!vhost) {
 		lwsl_err("Failed to create vhost\n");
-	else
-		lws_init_vhost_client_ssl(info, vhost); 
+		return NULL;
+	}
+
+	lws_esp32_selfsigned(vhost);
+	wsi.context = vhost->context;
+	wsi.vhost = vhost;
+
+	lws_tls_server_certs_load(vhost, &wsi, info->ssl_cert_filepath,
+			info->ssl_private_key_filepath, NULL, 0, NULL, 0);
+
+	lws_init_vhost_client_ssl(info, vhost);
 
 	if (pvh)
 		*pvh = vhost;
 
-	lws_protocol_init(context);
+	if (lws_protocol_init(context))
+		return NULL;
 
 	return context;
 }
@@ -1763,24 +1890,31 @@ uint16_t lws_esp32_sine_interp(int n)
 
 /* we write vhostname.cert.pem and vhostname.key.pem, 0 return means OK */
 
-int
+LWS_VISIBLE int
 lws_plat_write_cert(struct lws_vhost *vhost, int is_key, int fd, void *buf,
 			int len)
 {
-	char name[64];
+	const char *name = vhost->alloc_cert_path;
+	nvs_handle nvh;
 	int n;
 
-	lws_snprintf(name, sizeof(name) - 1, "%s-%s.pem", vhost->name,
-		     is_key ? "key" : "cert");
+	if (is_key)
+		name = vhost->key_path;
 
-	if (nvs_open("lws-station", NVS_READWRITE, &nvh))
+	if (nvs_open("lws-station", NVS_READWRITE, &nvh)) {
+		lwsl_notice("%s: failed to open nvs\n", __func__);
 		return 1;
+	}
 
-	n = nvs_set_blob(nvh, ssl_names[n], pss->buffer, pss->file_length);
+	n = nvs_set_blob(nvh, name, buf, len);
 	if (n)
 		nvs_commit(nvh);
 
 	nvs_close(nvh);
 
+	lwsl_notice("%s: wrote %s\n", __func__, name);
+
 	return n;
 }
+
+
diff --git a/lib/plat/lws-plat-esp8266.c b/lib/plat/lws-plat-esp8266.c
index 39e1155106e0e5617fc1be9a02c822a0ba2511c6..e4130c7c8e0f94315078f81ecfb2313905d1f190 100644
--- a/lib/plat/lws-plat-esp8266.c
+++ b/lib/plat/lws-plat-esp8266.c
@@ -713,7 +713,7 @@ lws_plat_init(struct lws_context *context,
 	return 0;
 }
 
-int
+LWS_VISIBLE int
 lws_plat_write_cert(struct lws_vhost *vhost, int is_key, int fd, void *buf,
 			int len)
 {
diff --git a/lib/plat/lws-plat-optee.c b/lib/plat/lws-plat-optee.c
index 1bf725770edea53c4fd4c40effff3defa4ebec44..3288b2cc2beb71decd3988ae7f20aefce63c3f68 100644
--- a/lib/plat/lws-plat-optee.c
+++ b/lib/plat/lws-plat-optee.c
@@ -326,7 +326,7 @@ lws_plat_init(struct lws_context *context,
 	return 0;
 }
 
-int
+LWS_VISIBLE int
 lws_plat_write_cert(struct lws_vhost *vhost, int is_key, int fd, void *buf,
 			int len)
 {
diff --git a/lib/plat/lws-plat-unix.c b/lib/plat/lws-plat-unix.c
index dd7ba9726f5b439c0862879d87b5034ef1825bf4..fe302ce7305af03be7decc8ee3a3dbdb9fa694f1 100644
--- a/lib/plat/lws-plat-unix.c
+++ b/lib/plat/lws-plat-unix.c
@@ -870,7 +870,7 @@ lws_plat_init(struct lws_context *context,
 	return 0;
 }
 
-int
+LWS_VISIBLE int
 lws_plat_write_cert(struct lws_vhost *vhost, int is_key, int fd, void *buf,
 			int len)
 {
diff --git a/lib/plat/lws-plat-win.c b/lib/plat/lws-plat-win.c
index c5c0afc8cfcc2761eee7a0d23083138e95d1fa39..031ae51bb710d58c477637308b0cbfe7e6ba585b 100644
--- a/lib/plat/lws-plat-win.c
+++ b/lib/plat/lws-plat-win.c
@@ -755,7 +755,7 @@ int fork(void)
 	exit(0);
 }
 
-int
+LWS_VISIBLE int
 lws_plat_write_cert(struct lws_vhost *vhost, int is_key, int fd, void *buf,
 			int len)
 {
diff --git a/lib/service.c b/lib/service.c
index adf8efc9616fa06f2f8a98b7e3d0d23d1570740b..aed1ac7837517a38a190af3d5088a92c95e89506 100644
--- a/lib/service.c
+++ b/lib/service.c
@@ -983,7 +983,8 @@ lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd,
 	int more;
 
 	if (!context->protocol_init_done)
-		lws_protocol_init(context);
+		if (lws_protocol_init(context))
+			return -1;
 
 	time(&now);
 
diff --git a/lib/tls/mbedtls/server.c b/lib/tls/mbedtls/server.c
index d351b0c3ade9b80c4a95deed8f77bf475f6f3eb2..88970890f55ac9acf3b76a0e28735b02bfcaf940 100644
--- a/lib/tls/mbedtls/server.c
+++ b/lib/tls/mbedtls/server.c
@@ -104,13 +104,20 @@ lws_tls_server_certs_load(struct lws_vhost *vhost, struct lws *wsi,
 			  const char *mem_cert, size_t len_mem_cert,
 			  const char *mem_privkey, size_t mem_privkey_len)
 {
-	int n = lws_tls_generic_cert_checks(vhost, cert, private_key), f = 0;
+	int n, f = 0;
 	const char *filepath = private_key;
 	uint8_t *mem = NULL, *p = NULL;
 	size_t mem_len = 0;
 	lws_filepos_t flen;
 	long err;
 
+	if (!cert || !private_key) {
+		lwsl_notice("%s: no paths\n", __func__);
+		return 0;
+	}
+
+	n = lws_tls_generic_cert_checks(vhost, cert, private_key);
+
 	if (n == LWS_TLS_EXTANT_NO && (!mem_cert || !mem_privkey))
 		return 0;
 
@@ -613,3 +620,4 @@ fail:
 	return -1;
 }
 #endif
+
diff --git a/lib/tls/tls.c b/lib/tls/tls.c
index 9204fa28b416344b853daebfb50aa605f36ee82c..fcc829d0090cfab24b9087c8be0517eed3b91f1c 100644
--- a/lib/tls/tls.c
+++ b/lib/tls/tls.c
@@ -111,7 +111,7 @@ int alloc_file(struct lws_context *context, const char *filename, uint8_t **buf,
 		n = 1;
 		goto bail;
 	}
-	*buf = lws_malloc(s, "alloc_file");
+	*buf = lws_malloc(s + 1, "alloc_file");
 	if (!*buf) {
 		n = 2;
 		goto bail;
@@ -123,6 +123,9 @@ int alloc_file(struct lws_context *context, const char *filename, uint8_t **buf,
 	}
 
 	*amount = s;
+	(*buf)[s] = '\0';
+
+	lwsl_notice("%s: nvs: read %s, %d bytes\n", __func__, filename, (int)s);
 
 bail:
 	nvs_close(nvh);
@@ -286,7 +289,7 @@ lws_tls_check_all_cert_lifetimes(struct lws_context *context)
 
 	return 0;
 }
-
+#if !defined(LWS_WITH_ESP32)
 static int
 lws_tls_extant(const char *name)
 {
@@ -303,7 +306,7 @@ lws_tls_extant(const char *name)
 
 	return n != 1;
 }
-
+#endif
 /*
  * Returns 0 if the filepath "name" exists and can be read from.
  *
@@ -337,8 +340,9 @@ lws_tls_extant(const char *name)
 enum lws_tls_extant
 lws_tls_use_any_upgrade_check_extant(const char *name)
 {
-	char buf[256];
 	int n;
+#if !defined(LWS_WITH_ESP32)
+	char buf[256];
 
 	lws_snprintf(buf, sizeof(buf) - 1, "%s.upd", name);
 	if (!lws_tls_extant(buf)) {
@@ -368,6 +372,21 @@ lws_tls_use_any_upgrade_check_extant(const char *name)
 
 	if (lws_tls_extant(name))
 		return LWS_TLS_EXTANT_NO;
+#else
+	nvs_handle nvh;
+	size_t s = 8192;
+
+	if (nvs_open("lws-station", NVS_READWRITE, &nvh)) {
+		lwsl_notice("%s: can't open nvs\n", __func__);
+		return LWS_TLS_EXTANT_NO;
+	}
+
+	n = nvs_get_blob(nvh, name, NULL, &s);
+	nvs_close(nvh);
+
+	if (n)
+		return LWS_TLS_EXTANT_NO;
+#endif
 
 	return LWS_TLS_EXTANT_YES;
 }