diff --git a/lib/libwebsockets.h b/lib/libwebsockets.h
index f6f57cb19d8d57b43e7eb9dfef834f82948d0d5f..6121978e32b4d61603da4319d65791d0500d7a91 100644
--- a/lib/libwebsockets.h
+++ b/lib/libwebsockets.h
@@ -1077,7 +1077,7 @@ enum lws_callback_reasons {
 	 * including OpenSSL support, this callback allows your user code
 	 * to load extra certifcates into the server which allow it to
 	 * verify the validity of certificates returned by clients.  user
-	 * is the server's OpenSSL SSL_CTX* */
+	 * is the server's OpenSSL SSL_CTX* and in is the lws_vhost * */
 	LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION	= 23,
 	/**< if the libwebsockets vhost was created with the option
 	 * LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT, then this
@@ -1462,6 +1462,8 @@ lws_callback_function(struct lws *wsi, enum lws_callback_reasons reason,
 #define LWS_CB_REASON_AUX_BF__CGI_HEADERS	8
 ///@}
 
+struct lws_vhost;
+
 /*! \defgroup generic hash
  * ## Generic Hash related functions
  *
@@ -2233,8 +2235,6 @@ struct lws_protocols {
 	 * This is part of the ABI, don't needlessly break compatibility */
 };
 
-struct lws_vhost;
-
 /**
  * lws_vhost_name_to_protocol() - get vhost's protocol object from its name
  *
@@ -5526,6 +5526,24 @@ lws_tls_peer_cert_info(struct lws *wsi, enum lws_tls_cert_info type,
 LWS_VISIBLE LWS_EXTERN int
 lws_tls_vhost_cert_info(struct lws_vhost *vhost, enum lws_tls_cert_info type,
 		        union lws_tls_cert_info_results *buf, size_t len);
+
+/**
+ * lws_tls_acme_sni_cert_create() - creates a temp selfsigned cert
+ *				    and attaches to a vhost
+ *
+ * \param vhost: the vhost to acquire the selfsigned cert
+ * \param san_a: SAN written into the certificate
+ * \param san_b: second SAN written into the certificate
+ *
+ *
+ * Returns 0 if created and attached to the vhost.  Returns -1 if problems and
+ * frees all allocations before returning.
+ *
+ * On success, any allocations are destroyed at vhost destruction automatically.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_tls_acme_sni_cert_create(struct lws_vhost *vhost, const char *san_a,
+			     const char *san_b);
 ///@}
 
 /** \defgroup lws_ring LWS Ringbuffer APIs
diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h
index c623eee31692f72406aeeca35be1a860f2b93a65..c309abcc5d97f446ef43dc0351affd6e05a234cc 100644
--- a/lib/private-libwebsockets.h
+++ b/lib/private-libwebsockets.h
@@ -969,6 +969,8 @@ struct http2_settings {
  *    SSL SNI -> wsi -> bind after SSL negotiation
  */
 
+struct lws_tls_ss_pieces;
+
 struct lws_vhost {
 #if !defined(LWS_WITH_ESP8266)
 	char http_proxy_address[128];
@@ -1004,6 +1006,7 @@ struct lws_vhost {
 #ifdef LWS_OPENSSL_SUPPORT
 	lws_tls_ctx *ssl_ctx;
 	lws_tls_ctx *ssl_client_ctx;
+	struct lws_tls_ss_pieces *ss; /* for acme tls certs */
 #endif
 #if defined(LWS_WITH_MBEDTLS)
 	lws_tls_x509 *x509_client_CA;
@@ -2370,6 +2373,7 @@ LWS_EXTERN void lwsl_emit_stderr(int level, const char *line);
 #define lws_context_init_ssl_library(_a)
 #define lws_ssl_anybody_has_buffered_read_tsi(_a, _b) (0)
 #define lws_tls_check_all_cert_lifetimes(_a)
+#define lws_tls_acme_sni_cert_destroy(_a)
 #else
 #define LWS_SSL_ENABLED(context) (context->use_ssl)
 LWS_EXTERN int openssl_websocket_private_data_index;
@@ -2416,8 +2420,11 @@ lws_tls_check_all_cert_lifetimes(struct lws_context *context);
 LWS_EXTERN int
 lws_context_init_server_ssl(struct lws_context_creation_info *info,
 			    struct lws_vhost *vhost);
+void
+lws_tls_acme_sni_cert_destroy(struct lws_vhost *vhost);
 #else
 #define lws_context_init_server_ssl(_a, _b) (0)
+#define lws_tls_acme_sni_cert_destroy(_a)
 #endif
 LWS_EXTERN void
 lws_ssl_destroy(struct lws_vhost *vhost);
@@ -2457,6 +2464,7 @@ lws_tls_client_create_vhost_context(struct lws_vhost *vh,
 				    const char *ca_filepath,
 				    const char *cert_filepath,
 				    const char *private_key_filepath);
+
 LWS_EXTERN lws_tls_ctx *
 lws_tls_ctx_from_wsi(struct lws *wsi);
 LWS_EXTERN int
diff --git a/lib/server/ssl-server.c b/lib/server/ssl-server.c
index 66edb066ab1a8949356ac550bfb0ac613995c327..c480d33684a2ec26eba0c2c3d2b8c9dda19118ea 100644
--- a/lib/server/ssl-server.c
+++ b/lib/server/ssl-server.c
@@ -90,7 +90,7 @@ lws_context_init_server_ssl(struct lws_context_creation_info *info,
 
 		vhost->protocols[0].callback(&wsi,
 			LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS,
-			vhost->ssl_ctx, NULL, 0);
+			vhost->ssl_ctx, vhost, 0);
 	}
 
 	if (vhost->use_ssl)
diff --git a/lib/tls/mbedtls/server.c b/lib/tls/mbedtls/server.c
index a14bbc18ff0e69a849e7c9ab2a01742eeb65c0e6..f12731b7acd3b21c4a98a8a199d47fc8259a4791 100644
--- a/lib/tls/mbedtls/server.c
+++ b/lib/tls/mbedtls/server.c
@@ -337,3 +337,20 @@ lws_tls_server_accept(struct lws *wsi)
 }
 
 
+struct lws_tls_ss_pieces {
+	mbedtls_x509_crt x509;
+
+};
+
+LWS_VISIBLE int
+lws_tls_acme_sni_cert_create(struct lws_vhost *vhost, const char *san_a,
+			     const char *san_b)
+{
+
+	return 1;
+}
+
+void
+lws_tls_acme_sni_cert_destroy(struct lws_vhost *vhost)
+{
+}
diff --git a/lib/tls/mbedtls/ssl.c b/lib/tls/mbedtls/ssl.c
index 0abc795c48104d2d9619fc0415884c0f152dcea9..391b01aa001a5cc5ef0335425c4661f5398f53d2 100644
--- a/lib/tls/mbedtls/ssl.c
+++ b/lib/tls/mbedtls/ssl.c
@@ -278,6 +278,8 @@ lws_ssl_SSL_CTX_destroy(struct lws_vhost *vhost)
 
 	if (!vhost->user_supplied_ssl_ctx && vhost->ssl_client_ctx)
 		SSL_CTX_free(vhost->ssl_client_ctx);
+
+	lws_tls_acme_sni_cert_destroy(vhost);
 }
 
 void
diff --git a/lib/tls/openssl/lws-genrsa.c b/lib/tls/openssl/lws-genrsa.c
index b86068e200a1fc00a7a55348eb2528e6d4ca25e2..3eabe4c3fc31ee93dd98154fa7a37988e512c91f 100644
--- a/lib/tls/openssl/lws-genrsa.c
+++ b/lib/tls/openssl/lws-genrsa.c
@@ -34,8 +34,7 @@ lws_jwk_destroy_genrsa_elements(struct lws_genrsa_elements *el)
 }
 
 LWS_VISIBLE int
-lws_genrsa_create(struct lws_genrsa_ctx *ctx,
-				 struct lws_genrsa_elements *el)
+lws_genrsa_create(struct lws_genrsa_ctx *ctx, struct lws_genrsa_elements *el)
 {
 	int n;
 
@@ -129,7 +128,8 @@ lws_genrsa_new_keypair(struct lws_context *context, struct lws_genrsa_ctx *ctx,
 	{
 		const BIGNUM *mpi[5];
 
-		RSA_get0_key(ctx->rsa, &mpi[JWK_KEY_N], &mpi[JWK_KEY_E], &mpi[JWK_KEY_D]);
+		RSA_get0_key(ctx->rsa, &mpi[JWK_KEY_N], &mpi[JWK_KEY_E],
+			     &mpi[JWK_KEY_D]);
 		RSA_get0_factors(ctx->rsa, &mpi[JWK_KEY_P], &mpi[JWK_KEY_Q]);
 #else
 	{
diff --git a/lib/tls/openssl/server.c b/lib/tls/openssl/server.c
index 084585011f6144e9fd3908a4446bb1876488bc17..5e0b3e14cee5c871b0aaec1dd4e1cbdd5af89d48 100644
--- a/lib/tls/openssl/server.c
+++ b/lib/tls/openssl/server.c
@@ -100,7 +100,8 @@ lws_ssl_server_name_cb(SSL *ssl, int *ad, void *arg)
 	 */
 	vh = context->vhost_list;
 	while (vh) {
-		if (!vh->being_destroyed && vh->ssl_ctx == SSL_get_SSL_CTX(ssl))
+		if (!vh->being_destroyed &&
+		    vh->ssl_ctx == SSL_get_SSL_CTX(ssl))
 			break;
 		vh = vh->vhost_next;
 	}
@@ -125,7 +126,7 @@ lws_ssl_server_name_cb(SSL *ssl, int *ad, void *arg)
 		return SSL_TLSEXT_ERR_OK;
 	}
 
-	lwsl_info("SNI: Found: %s:%d\n", servername, vh->listen_port);
+	lwsl_notice("SNI: Found: %s:%d\n", servername, vh->listen_port);
 
 	/* select the ssl ctx from the selected vhost for this conn */
 	SSL_set_SSL_CTX(ssl, vhost->ssl_ctx);
@@ -432,3 +433,149 @@ lws_tls_server_accept(struct lws *wsi)
 	return LWS_SSL_CAPABLE_ERROR;
 }
 
+struct lws_tls_ss_pieces {
+	X509 *x509;
+	EVP_PKEY *pkey;
+	RSA *rsa;
+};
+
+LWS_VISIBLE LWS_EXTERN int
+lws_tls_acme_sni_cert_create(struct lws_vhost *vhost, const char *san_a,
+			     const char *san_b)
+{
+	GENERAL_NAMES *gens = sk_GENERAL_NAME_new_null();
+	GENERAL_NAME *gen = NULL;
+	ASN1_IA5STRING *ia5 = NULL;
+	X509_NAME *name;
+	BIGNUM *bn;
+	int n;
+
+	if (!gens)
+		return 1;
+
+	vhost->ss = lws_zalloc(sizeof(*vhost->ss), "sni cert");
+	if (!vhost->ss) {
+		GENERAL_NAMES_free(gens);
+		return 1;
+	}
+
+	vhost->ss->x509 = X509_new();
+	if (!vhost->ss->x509)
+		goto bail;
+
+	ASN1_INTEGER_set(X509_get_serialNumber(vhost->ss->x509), 1);
+	X509_gmtime_adj(X509_get_notBefore(vhost->ss->x509), 0);
+	X509_gmtime_adj(X509_get_notAfter(vhost->ss->x509), 3600);
+
+	vhost->ss->pkey = EVP_PKEY_new();
+	if (!vhost->ss->pkey)
+		goto bail0;
+
+	bn = BN_new();
+	if (!bn)
+		goto bail1;
+	if (BN_set_word(bn, RSA_F4) != 1) {
+		BN_free(bn);
+		goto bail1;
+	}
+
+	vhost->ss->rsa = RSA_new();
+	if (!vhost->ss->rsa) {
+		BN_free(bn);
+		goto bail1;
+	}
+
+	n = RSA_generate_key_ex(vhost->ss->rsa, 4096, bn, NULL);
+	BN_free(bn);
+	if (n != 1)
+		goto bail2;
+
+	if (!EVP_PKEY_assign_RSA(vhost->ss->pkey, vhost->ss->rsa))
+		goto bail2;
+
+	X509_set_pubkey(vhost->ss->x509, vhost->ss->pkey);
+
+	name = X509_get_subject_name(vhost->ss->x509);
+	X509_NAME_add_entry_by_txt(name, "C",  MBSTRING_ASC,
+				   (unsigned char *)"GB",          -1, -1, 0);
+	X509_NAME_add_entry_by_txt(name, "O",  MBSTRING_ASC,
+				   (unsigned char *)"somecompany", -1, -1, 0);
+	if (X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_UTF8,
+				   (unsigned char *)"temp.acme.invalid",
+				   	   	   -1, -1, 0) != 1) {
+		lwsl_notice("failed to add CN\n");
+		goto bail2;
+	}
+	X509_set_issuer_name(vhost->ss->x509, name);
+
+	/* add the SAN payloads */
+
+	gen = GENERAL_NAME_new();
+	ia5 = ASN1_IA5STRING_new();
+	if (!ASN1_STRING_set(ia5, san_a, -1)) {
+		lwsl_notice("failed to set ia5\n");
+		GENERAL_NAME_free(gen);
+		goto bail2;
+	}
+	GENERAL_NAME_set0_value(gen, GEN_DNS, ia5);
+	sk_GENERAL_NAME_push(gens, gen);
+
+	if (X509_add1_ext_i2d(vhost->ss->x509, NID_subject_alt_name,
+			    gens, 0, X509V3_ADD_APPEND) != 1)
+		goto bail2;
+
+	GENERAL_NAMES_free(gens);
+
+	if (san_b && san_b[0]) {
+		gens = sk_GENERAL_NAME_new_null();
+		gen = GENERAL_NAME_new();
+		ia5 = ASN1_IA5STRING_new();
+		if (!ASN1_STRING_set(ia5, san_a, -1)) {
+			lwsl_notice("failed to set ia5\n");
+			GENERAL_NAME_free(gen);
+			goto bail2;
+		}
+		GENERAL_NAME_set0_value(gen, GEN_DNS, ia5);
+		sk_GENERAL_NAME_push(gens, gen);
+
+		if (X509_add1_ext_i2d(vhost->ss->x509, NID_subject_alt_name,
+				    gens, 0, X509V3_ADD_APPEND) != 1)
+			goto bail2;
+
+		GENERAL_NAMES_free(gens);
+	}
+
+	/* sign it with our private key */
+	if (!X509_sign(vhost->ss->x509, vhost->ss->pkey, EVP_sha256()))
+		goto bail2;
+
+	/* tell the vhost to use our crafted certificate */
+	SSL_CTX_use_certificate(vhost->ssl_ctx, vhost->ss->x509);
+	/* and to use our generated private key */
+	SSL_CTX_use_PrivateKey(vhost->ssl_ctx, vhost->ss->pkey);
+
+	return 0;
+
+bail2:
+	RSA_free(vhost->ss->rsa);
+bail1:
+	EVP_PKEY_free(vhost->ss->pkey);
+bail0:
+	X509_free(vhost->ss->x509);
+bail:
+	lws_free(vhost->ss);
+	GENERAL_NAMES_free(gens);
+
+	return 1;
+}
+
+void
+lws_tls_acme_sni_cert_destroy(struct lws_vhost *vhost)
+{
+	if (!vhost->ss)
+		return;
+
+	EVP_PKEY_free(vhost->ss->pkey);
+	X509_free(vhost->ss->x509);
+	lws_free_set_NULL(vhost->ss);
+}
diff --git a/lib/tls/openssl/ssl.c b/lib/tls/openssl/ssl.c
index 46d21ff8a11e3ec69da916bef7e37c85be48c21f..7dbd3efac518a5a2dce319a30ae471610b722e87 100644
--- a/lib/tls/openssl/ssl.c
+++ b/lib/tls/openssl/ssl.c
@@ -416,6 +416,8 @@ lws_ssl_SSL_CTX_destroy(struct lws_vhost *vhost)
 
 	if (!vhost->user_supplied_ssl_ctx && vhost->ssl_client_ctx)
 		SSL_CTX_free(vhost->ssl_client_ctx);
+
+	lws_tls_acme_sni_cert_destroy(vhost);
 }
 
 void