Skip to main content

Azure Virtual Machine Behind Application Gateway

This guide walks through deploying JAMS Web Client on Azure using a single Windows VM behind an Azure Application Gateway. The Application Gateway terminates public HTTPS traffic and forwards requests to the JAMS Gateway on the VM. All six JAMS services run on the same instance and communicate internally through the Gateway.

All six JAMS services (Gateway, Identity, API, UI, MCP, JAX) are installed on a single Azure Windows VM. An Azure Application Gateway sits in front, terminates public HTTPS traffic, and forwards to the Gateway on the VM.

warning

Important difference from AWS ALB: Azure Application Gateway validates the backend VM's TLS certificate by default. The installer-generated self-signed certificate must be explicitly trusted in Application Gateway before backend connections will succeed. Steps 2 and 3 below cover this.

Before You Begin

  • Azure Windows Server VM with JAMS Web Client installed via the installer.
  • Azure Application Gateway (v2 Standard_v2 or WAF_v2) created and its DNS name or public IP available.
  • Application Gateway must be in the same VNet as the VM or in a peered VNet.
  • NSG on the VM allowing inbound HTTPS (443) from the Application Gateway subnet.

1. Configuring the Application Gateway

Listener:

  • Protocol: HTTPS, Port: 443
  • Certificate: upload a PFX certificate for the public-facing domain or reference one from Azure Key Vault.

Backend pool:

  • Add the VM by its private IP address or FQDN

Backend HTTP settings:

  • Protocol: HTTPS, Port: 443
  • Request timeout: 700 seconds (see warning below)
  • Override with new host name: No
  • Trusted root certificate: upload the JAMS cert root (covered in Step 3)
warning

Request timeout: Set the Backend HTTP Settings request timeout to at least 700 seconds. The Azure Application Gateway default is only 20 seconds, far lower than the AWS ALB default, and will cause MCP SSE streaming sessions to be cut mid-response. This is the most commonly missed setting in the Azure setup.

Health probe: Create a custom health probe:

  • Protocol: HTTPS
  • Host: VM private IP or host name
  • Path: /api/system/health
  • Interval: 30 seconds, Timeout: 10 seconds, Unhealthy threshold: 3
  • Associate with the Backend HTTP settings created above

Routing rule: Link the listener | backend pool | backend HTTP settings.

2. Configuring the TLS certificate on the VM

Same as the AWS setup. The JAMS installer generates a self-signed certificate at Shared\Certificates\default.pfx that already includes DNS:localhost, the machine hostname, and 127.0.0.1 in its SANs.

Import it into LocalMachine\Root so internal service-to-service calls validate correctly:

Import-PfxCertificate `
-FilePath "C:\Program Files\JAMS\Shared\Certificates\default.pfx" `
-CertStoreLocation Cert:\LocalMachine\Root `
-Password (ConvertTo-SecureString "" -AsPlainText -Force)

3. Uploading the Backend Root Certificate to the Application Gateway

Unlike AWS ALB, Azure Application Gateway validates the backend VM's certificate. Since the JAMS installer generates a self-signed certificate, its public key must be uploaded to Application Gateway as a trusted root certificate.

Export the public certificate from the PFX:

$pfx = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2(
"C:\Program Files\JAMS\Shared\Certificates\default.pfx", "")
$certBytes = $pfx.Export([System.Security.Cryptography.X509Certificates.X509ContentType]::Cert)
[System.IO.File]::WriteAllBytes("C:\jams-backend-cert.cer", $certBytes)

Upload to Application Gateway

  1. In the Azure Portal, open the Application Gateway.
  2. Go to Backend settings | select the JAMS backend HTTP settings.
  3. Under Trusted root certificate, click Add certificate.
  4. Upload the jams-backend-cert.cer file exported above.
  5. Save the backend settings.

This step tells Application Gateway to trust the specific self-signed certificate the JAMS Gateway presents. Without it, Application Gateway rejects the backend connection and the health probe fails, making the VM appear unhealthy.

4. Updating Shared\settings.json

Update the settings.json file C:\Program Files\JAMS\Shared:

{
"Kestrel": {
"Certificates": {
"Default": {
"Path": "../Shared/Certificates/default.pfx",
"Password": ""
}
}
},
"Gateway": {
"Url": "https://<your-appgateway-dns-or-ip>",
"InternalUrl": "https://localhost:443",
"AllowSelfSigned": false
}
}
warning

AllowSelfSigned must be explicitly set to false. The Gateway, API, UI, and Identity services ship with AllowSelfSigned: true in their base configuration, meaning TLS certificate validation and JWT issuer validation are disabled by default. Setting AllowSelfSigned: false in Shared\settings.json is what activates production-grade security for these services. Without this override, they will run with all validation disabled even in a production environment.

note

The JAMS installer automatically selects the HTTPS port: it tries 443 first, and falls back to 901 if port 443 is already in use on the machine. Check which port the Gateway actually bound to after installation. It is shown in Shared\JAMS Gateway\settings.json under Urls. Update Gateway:InternalUrl and the Application Gateway backend pool port to match if it is not 443.

5. Restarting All Services

After updating Shared\settings.json, restart all six JAMS services.

"JAMS Gateway","JAMS Identity","JAMS API","JAMS Web UI","JAMS MCP","JAX" | ForEach-Object { Restart-Service $_ }

6. Verifying the Updates

  1. Browser test: Go to https://<appgateway-dns-or-ip>. The JAMS Web Client login page should appear with no certificate warning.
  2. Backend health: In Application Gateway | Backend health, confirm the VM shows as Healthy. If it shows Unhealthy, the trusted root certificate upload in Step 3 is likely incomplete.
  3. Login and API calls: Log in to the JAMS Web Client with your credentials. Click Jobs from the main menu. Verify you see the expected list of Jobs. Successfully logging in and viewing the Jobs confirms the full chain is working correctly.

Troubleshooting

SymptomLikely CauseSolution
Backend health shows Unhealthy in Application Gateway.The trusted root certificate was not uploaded or the wrong certificate was uploaded.Re-export the public certificate from the JAMS PFX and re-upload in Step 3. Confirm the certificate thumbprint matches default.pfx.
401 Unauthorized error on JAMS MCP or JAX after login.The certificate is not in LocalMachine\Root, or it is missing DNS:localhost in SAN.Complete Step 2. Confirm the installer-generated certificate was not replaced with a custom certificate lacking DNS:localhost.
JAMS MCP streaming sessions drop after 20 seconds.Application Gateway request timeout at its default of 20 seconds.Set Backend HTTP Settings request timeout to 700 seconds (Step 1).
Browser shows a certificate warning.Application Gateway listener certificate is self-signed or expired.Replace the listener certificate with one from a public CA or Azure Key Vault.
Services fail to start.Incorrect PFX path or wrong password in Shared\settings.json.Verify the Path and Password values. The installer-generated PFX has an empty password.
Gateway:Url shows localhost in tokens.Shared\settings.json were not saved or services were not restarted.Confirm the file is saved and run the restart command from Step 5.
Backend unhealthy - gateway port mismatch.Installer selected port 901 instead of 443; backend pool targets wrong port.Check Shared\JAMS Gateway\settings.json Urls. Update the App Gateway backend pool port and Gateway:InternalUrl to match.