diff --git a/ocpp-server/.gitignore b/ocpp-server/.gitignore
index c9808bf..56c45b8 100644
--- a/ocpp-server/.gitignore
+++ b/ocpp-server/.gitignore
@@ -397,3 +397,4 @@ FodyWeavers.xsd
 *.sln.iml
 
 *parameters.json
+*parameters.bicepparam
diff --git a/ocpp-server/Makefile b/ocpp-server/Makefile
index 5acb8c7..7b95b78 100644
--- a/ocpp-server/Makefile
+++ b/ocpp-server/Makefile
@@ -1,9 +1,11 @@
 THIS_FILE := $(lastword $(MAKEFILE_LIST))
 RG_NAME := OCPP
 RG_LOCATION := switzerlandnorth
+BICEP_PARAMS := main.parameters.bicepparam
 WEBAPP_NAME := $(shell az webapp list -g $(RG_NAME) --query "[0].name" -o tsv)
 STORAGE_NAME := $(shell az storage account list -g $(RG_NAME) --query "[?starts_with(name,'webdeploy')].name" -o tsv)
 EXPIRY := $(shell date -u -d "15 minutes" '+%Y-%m-%dT%H:%MZ')
+TEST_SERVER := wss.jmservera.online
 
 preparecli:
 	az upgrade
@@ -11,18 +13,22 @@ preparecli:
 	az bicep upgrade
 	npm install -g @azure/web-pubsub-tunnel-tool
 	@echo "Tools prepared, now you can start using the makefile"
-build: $(wildcard api/**/*.cs)
-	@echo "Building"
+build: build-api build-node
+build-node: $(wildcard client/*.js)
+	@echo "Building node client"
+	cd client && npm install
+build-api: $(wildcard api/**/*.cs)
+	@echo "Building api"
 	dotnet build api/api.sln
 test:
 	@echo "Testing"
 	dotnet test api/api.sln
 test-client:
 	@echo "Testing a simple node client"
-	node client/index.js wss://wss.jmservera.online station2 goodpwd
+	node client/index.js wss://$(TEST_SERVER) station2 goodpwd
 test-client-badauth:
 	@echo "Testing a simple node client"
-	node client/index.js wss://wss.jmservera.online station1 badpwd
+	node client/index.js wss://$(TEST_SERVER) station1 badpwd
 clean:
 	@echo "Cleaning"
 	dotnet clean api/api.sln
@@ -41,10 +47,10 @@ start-tunnel:
 	awps-tunnel run --hub OcppService -c "$$WebPubSubConnectionString" -s $$SubId -g $(RG_NAME) --upstream http://localhost:5110
 stop-tunnel:
 	ps axf | grep awps-tunnel | grep -v grep | awk '{print "kill -9 " $$1}' | sh
-infra: $(wildcard infra/**/*.bicep) $(wildcard infra/**/*.parameters.json)
+infra: $(wildcard infra/**/*.bicep) $(wildcard infra/*.parameters.bicepparam)
 	@echo "Deploying infra to Azure"
 	az group create -n $(RG_NAME) -l $(RG_LOCATION)
-	az deployment group create -g $(RG_NAME) --template-file infra/main.bicep --parameters infra/main.parameters.json
+	az deployment group create -g $(RG_NAME) --template-file infra/main.bicep --parameters infra/$(BICEP_PARAMS)
 	@echo "Setting up user secrets"
 	CONNECTION_STRING='$(shell az webpubsub list -g $(RG_NAME) --query "[0].name" -o tsv | az webpubsub key show -g $(RG_NAME) -n @- --query "primaryConnectionString" -o tsv)'; \
 	dotnet user-secrets set 'WEBPUBSUB_SERVICE_CONNECTION_STRING' "$$CONNECTION_STRING" --project api/OcppServer/OcppServer.csproj	
@@ -67,4 +73,4 @@ deploy:
 	@echo "Waiting for infra to be ready"
 	sleep 60 
 	@$(MAKE) -f $(THIS_FILE) publish
-.PHONY: test clean watch start secrets test-client
+.PHONY: test clean watch start secrets test-client infra
diff --git a/ocpp-server/README.md b/ocpp-server/README.md
index 0c6afa7..1f23eaa 100644
--- a/ocpp-server/README.md
+++ b/ocpp-server/README.md
@@ -11,32 +11,23 @@ You need:
 * An **Azure KeyVault** with a wildcard certificate for the domain you will assign to the Application Gateway. The App Gateway uses it to publish the Web PubSub endpoint and the Web App.
 * A **User Assigned Managed Identity** with read access to the KeyVault where the SSL certificate is stored.
 * A **Public DNS Zone in Azure**, where the script will create or update the A records for the Web PubSub service. Your user needs modify permissions to these DNS records, and they will be created with a resource reference.
-* A **main.parameters.json** file in the root of the project with the following content:
-
-  ```json
-  {
-    "parameters": {
-      "keyVaultSecretId": {
-        "value": "<Keyvault Secret Identifier (sid) for the SSL Certificate, you can omit the version number to get always the latest one>"
-      },
-      "keyVaultIdentityName": {
-        "value": "<NAME OF THE Managed Identity that has cert read access rights in the KeyVault>"
-      },
-      "keyVaultIdentityRG": {
-        "value": "<RESOURCE GROUP OF THE MANAGED IDENTITY>"
-      },
-      "customDnsZoneName": {
-        "value": "<BASE DOMAIN NAME FOR THE PUBSUB SERVICE IN THE APPP GATEWAY, EX: mydomain.com>"      
-      },
-      "pubsubARecordName": {
-        "value": "<SUBDOMAIN NAME USED FOR THE WEB PUBSUB SERVICE, EX: wss (for wss.mydomain.com)>"
-      },
-      "dnsZoneRG": {
-        "value": "<NAME OF THE RG WHERE THE DNS SERVICE>"
-      }
-    }
-  }
-  ```
+* A **main.parameters.bicepparam** file in the root of the project with the following content:
+
+```bicep
+using 'main.bicep'
+
+param pubsubKeyVaultCertName = '<KeyVault name of the SSL Certificate for the pub sub service>'
+param webKeyVaultCertName ='<KeyVault name of the SSL Certificate for the web test service, can be the same cert if you have a wildcard one>'
+param keyVaultName = '<Name of the KeyVault>'
+param keyVaultIdentityRG ='<NAME OF THE Managed Identity that has cert read access rights in the KeyVault>'
+param customDnsZoneName ='<RESOURCE GROUP OF THE MANAGED IDENTITY>'
+param pubsubARecordName ='<SUBDOMAIN NAME USED FOR THE WEB PUBSUB SERVICE, EX: wss (for wss.mydomain.com)>'
+param dnsZoneRG ='<NAME OF THE RG WHERE THE DNS SERVICE>'
+```
+
+## (Optional) Configure Let's encrypt with your KeyVault and Azure DNS
+
+If you don't have a certificate, you can use the Let's Encrypt service to generate a free certificate for your domain. [This amazing project](https://github.com/shibayan/keyvault-acmebot/wiki/Getting-Started) automates the process of generating the certificate and merging it into your KeyVault. Just follow the instructions, configure the permissions and create a certificate for your domain.
 
 ## Project Structure
 
@@ -60,3 +51,47 @@ This makefile recipe deploys the infra into your Azure subscription, compiles th
 The App Service and Web Pub Sub endpoints are protected with Private Endpoints, and published through an Application Gateway.
 
 ![Infra](./img/Architecture.svg)
+
+## FAQ
+
+## The client fails with UNABLE_TO_VERIFY_LEAF_SIGNATURE
+
+If you merged your certificate in KeyVault using a PEM or PFX format, you may need to create the CSR again, generate a new certificate and merge it in p7b format. Take a look to this FAQ section: [Create and merge a certificate signing request in Key Vault](https://learn.microsoft.com/en-us/azure/key-vault/certificates/create-certificate-signing-request?tabs=azure-portal#faqs)
+
+After renewing the certificate, you can deploy the infra again with the new certificate, or reconfigure the App Gateway to use the new certificate in the **Listeners TLS Certificates** section.
+
+Example error in the nodejs client:
+
+```js
+node:events:495
+      throw er; // Unhandled 'error' event
+      ^
+
+Error: unable to verify the first certificate
+    at TLSSocket.onConnectSecure (node:_tls_wrap:1659:34)
+    at TLSSocket.emit (node:events:517:28)
+    at TLSSocket._finishInit (node:_tls_wrap:1070:8)
+    at ssl.onhandshakedone (node:_tls_wrap:856:12)
+Emitted 'error' event on WebSocket instance at:
+    at emitErrorAndClose (/home/jmservera/source/miscdemos/ocpp-server/client/node_modules/ws/lib/websocket.js:1041:13)
+    at ClientRequest.<anonymous> (/home/jmservera/source/miscdemos/ocpp-server/client/node_modules/ws/lib/websocket.js:881:5)
+    at ClientRequest.emit (node:events:517:28)
+    at TLSSocket.socketErrorListener (node:_http_client:501:9)
+    at TLSSocket.emit (node:events:517:28)
+    at emitErrorNT (node:internal/streams/destroy:151:8)
+    at emitErrorCloseNT (node:internal/streams/destroy:116:3)
+    at process.processTicksAndRejections (node:internal/process/task_queues:82:21) {
+  code: 'UNABLE_TO_VERIFY_LEAF_SIGNATURE'
+}
+```
+
+Example error with curl:
+
+```bash
+curl: (60) SSL certificate problem: unable to get local issuer certificate
+More details here: https://curl.se/docs/sslcerts.html
+
+curl failed to verify the legitimacy of the server and therefore could not
+establish a secure connection to it. To learn more about this situation and
+how to fix it, please visit the web page mentioned above.
+```
diff --git a/ocpp-server/infra/main.bicep b/ocpp-server/infra/main.bicep
index d2a417a..6f5c474 100644
--- a/ocpp-server/infra/main.bicep
+++ b/ocpp-server/infra/main.bicep
@@ -1,18 +1,22 @@
 @secure()
-@description('Secret ID for the TLS Certificate stored in Key Vault')
-param keyVaultSecretId string
+@description('Name of the TLS Certificate stored in Key Vault for the pubsub service public endpoint')
+param pubsubKeyVaultCertName string
+@description('Name of the TLS Certificate stored in Key Vault for the web service public endpoint')
+param webKeyVaultCertName string
+@description('Name of the Key Vault where the certificates are stored')
+param keyVaultName string
 @description('User Assigned Managed Identity name with Get permissions fo the Key Vault Certificate')
 param keyVaultIdentityName string
 @description('Resource Group name where the User Assigned Managed Identity was created')
 param keyVaultIdentityRG string = resourceGroup().name
 @description('Custom DNS Zone Name used for publishing the Web PubSub service endpoint securely')
-param customDnsZoneName string = 'jmservera.online'
+param customDnsZoneName string
 @description('A Record Name for the Web PubSub service endpoint, used as prefix of the DnsZoneName')
 param pubsubARecordName string = 'wss'
 @description('A Record Name for the Web service endpoint, used as prefix of the DnsZoneName')
 param webARecordName string = 'www'
 @description('Resource Group name where the DNS Zone was created')
-param dnsZoneRG string = 'domainnames'
+param dnsZoneRG string
 @description('The name for your new Web PubSub Hub. It should be the same name than the class implementing it in the asp.net core project')
 param pubSubHubName string = 'OcppService'
 
@@ -39,7 +43,7 @@ module hub './modules/webPubSubHub.bicep' = {
   name: 'webPubSubHub'
   params: {
     serviceName: webPubSub.outputs.serviceName
-    hubName: 'OcppService'
+    hubName: pubSubHubName
     webAppName: webApp.outputs.webSiteName
   }
 }
@@ -87,9 +91,11 @@ module appGw './modules/appgw.bicep' = {
     location: resourceGroup().location
     pubSubServiceName: webPubSub.outputs.serviceName
     gwSubnetId: virtualNetwork.outputs.gwSubnetId
-    keyVaultSecretId: keyVaultSecretId
+    webKeyVaultCertName: webKeyVaultCertName
+    pubsubKeyVaultCertName: pubsubKeyVaultCertName
     webHostName: webHostName
     pubsubHostName: pubsubHostName
+    keyVaultName: keyVaultName
     keyVaultIdentityName: keyVaultIdentityName
     keyVaultIdentityRG: keyVaultIdentityRG
     webServiceName: webApp.outputs.webSiteName
@@ -98,7 +104,7 @@ module appGw './modules/appgw.bicep' = {
 }
 
 // update A record with appGW public IP
-module wssdns './modules/dns.bicep' = {
+module wssdns './modules/dns.bicep' = if (customDnsZoneName != '') {
   name: 'dnsServicePubSub'
   scope: resourceGroup(dnsZoneRG)
   params: {
@@ -108,7 +114,7 @@ module wssdns './modules/dns.bicep' = {
   }
 }
 
-module wwwdns './modules/dns.bicep' = {
+module wwwdns './modules/dns.bicep' = if (customDnsZoneName != '') {
   name: 'dnsServiceWeb'
   scope: resourceGroup(dnsZoneRG)
   params: {
diff --git a/ocpp-server/infra/main.parameters.bicepparam.example b/ocpp-server/infra/main.parameters.bicepparam.example
new file mode 100644
index 0000000..5ce766c
--- /dev/null
+++ b/ocpp-server/infra/main.parameters.bicepparam.example
@@ -0,0 +1,9 @@
+using 'main.bicep'
+
+param pubsubKeyVaultCertName = '<KeyVault name of the SSL Certificate for the pub sub service>'
+param webKeyVaultCertName ='<KeyVault name of the SSL Certificate for the web test service, can be the same cert if you have a wildcard one>'
+param keyVaultName = '<Name of the KeyVault>'
+param keyVaultIdentityRG ='<NAME OF THE Managed Identity that has cert read access rights in the KeyVault>'
+param customDnsZoneName ='<RESOURCE GROUP OF THE MANAGED IDENTITY>'
+param pubsubARecordName ='<SUBDOMAIN NAME USED FOR THE WEB PUBSUB SERVICE, EX: wss (for wss.mydomain.com)>'
+param dnsZoneRG ='<NAME OF THE RG WHERE THE DNS SERVICE>'
\ No newline at end of file
diff --git a/ocpp-server/infra/modules/appgw.bicep b/ocpp-server/infra/modules/appgw.bicep
index d7e2ea1..7ca5720 100644
--- a/ocpp-server/infra/modules/appgw.bicep
+++ b/ocpp-server/infra/modules/appgw.bicep
@@ -11,13 +11,15 @@ param skuSize string = 'Standard_v2'
 param skuTier string = 'Standard_v2'
 param skuCapacity int = 1
 @secure()
-param keyVaultSecretId string
 param pubsubHostName string
 param webHostName string
+param keyVaultName string
 param keyVaultIdentityName string
 param keyVaultIdentityRG string
 param webServiceName string
-param pubsubHubName string 
+param pubsubHubName string
+param webKeyVaultCertName string
+param pubsubKeyVaultCertName string
 
 var ocppRuleSetName = 'ocppRuleSet'
 var pubsubBackendPoolName = 'pubsubBackend'
@@ -27,6 +29,25 @@ var pubsubListenerName = 'pubsubListener'
 var webBackendPoolName = 'webBackend'
 var webListenerName = 'webListener'
 var webBackendSettingsName = 'webBackendSettings'
+var webtls = 'webtls'
+var pubsubtls = 'pubsubtls'
+
+var isWildcard = (webKeyVaultCertName == pubsubKeyVaultCertName)
+
+resource keyVault 'Microsoft.KeyVault/vaults@2021-06-01-preview' existing = {
+  name: keyVaultName
+  scope: resourceGroup(keyVaultIdentityRG)
+}
+
+resource pubsubKeyVaultCertificate 'Microsoft.KeyVault/vaults/secrets@2024-04-01-preview' existing = {
+  name: pubsubKeyVaultCertName
+  parent: keyVault
+}
+
+resource webKeyVaultCertificate 'Microsoft.KeyVault/vaults/secrets@2024-04-01-preview' existing = {
+  name: webKeyVaultCertName
+  parent: keyVault
+}
 
 resource webPubSub 'Microsoft.SignalRService/webPubSub@2021-10-01' existing = {
   name: pubSubServiceName
@@ -167,14 +188,29 @@ resource appGw 'Microsoft.Network/applicationGateways@2023-02-01' = {
         }
       }
     ]
-    sslCertificates: [
-      {
-        name: 'pubsubtls'
-        properties: {
-          keyVaultSecretId: keyVaultSecretId
-        }
-      }
-    ]
+    sslCertificates: isWildcard
+      ? [
+          {
+            name: pubsubtls
+            properties: {
+              keyVaultSecretId: pubsubKeyVaultCertificate.properties.secretUri
+            }
+          }
+        ]
+      : [
+          {
+            name: pubsubtls
+            properties: {
+              keyVaultSecretId: pubsubKeyVaultCertificate.properties.secretUri
+            }
+          }
+          {
+            name: webtls
+            properties: {
+              keyVaultSecretId: webKeyVaultCertificate.properties.secretUri
+            }
+          }
+        ]
     httpListeners: [
       {
         name: pubsubListenerName
@@ -191,7 +227,7 @@ resource appGw 'Microsoft.Network/applicationGateways@2023-02-01' = {
           }
           protocol: 'Https'
           sslCertificate: {
-            id: resourceId('Microsoft.Network/applicationGateways/sslCertificates', appgwName, 'pubsubtls')
+            id: resourceId('Microsoft.Network/applicationGateways/sslCertificates', appgwName, pubsubtls)
           }
           hostName: pubsubHostName
           customErrorConfigurations: []
@@ -213,7 +249,11 @@ resource appGw 'Microsoft.Network/applicationGateways@2023-02-01' = {
           }
           protocol: 'Https'
           sslCertificate: {
-            id: resourceId('Microsoft.Network/applicationGateways/sslCertificates', appgwName, 'pubsubtls')
+            id: resourceId(
+              'Microsoft.Network/applicationGateways/sslCertificates',
+              appgwName,
+              isWildcard ? pubsubtls : webtls
+            )
           }
           hostName: webHostName
           customErrorConfigurations: []