Skip to content

Serial console

Captured 2026-07-28 from one CE of this deployment. sitecli/capture-manifest.json records which node, and scripts/capture-sitecli.sh --check re-verifies the command surface against a live CE.

Azure Serial Console attaches to the node’s emulated serial port through the Azure platform. It does not traverse the F5 Distributed Cloud control plane, the node’s data plane, or any network path the node controls — which is exactly why it works when nothing else does.

Reach for it when a CE never came up: registration failed, the site is absent from the tenant, or the node is up but has no route out. In all of those cases the debug API has no tunnel to relay through. SSH survives a failed registration, but only if its key was already written at first boot and you can reach the node’s internal address from inside the VNet — neither of which is true of a node you are meeting for the first time.

Try Site Console before this one if the node has any working network path: it also survives a failed registration, needs no key, and does not evict the person already looking at the node. Serial console is what is left when the network path is the thing that is broken.

Azure requires boot diagnostics on the VM before it will attach a serial console. This is enabled by terraform/modules/ce-node:

boot_diagnostics {}

An empty block selects Azure-managed storage, so there is no diagnostics storage account, lifecycle policy or access key to own. Confirm it on a node:

Terminal window
az vm show -g <resource-group> -n <vm-name> --query diagnosticsProfile
{ "bootDiagnostics": { "enabled": true } }

Attaching needs an interactive session, but whether it would attach is two API calls. Both are useful in a health check.

The service must be enabled for the subscription — an administrator can disable it tenant-wide:

Terminal window
az rest --method get --url \
"https://management.azure.com/subscriptions/<sub>/providers/Microsoft.SerialConsole/consoleServices/default?api-version=2018-05-01"
{ "properties": { "disabled": false } }

Then ask for a connection to a specific node’s serial port:

Terminal window
az rest --method post \
--headers "Content-Type=application/json" --body '{}' --url \
"https://management.azure.com/subscriptions/<sub>/resourceGroups/<rg>/providers/Microsoft.Compute/virtualMachines/<vm>/providers/Microsoft.SerialConsole/serialPorts/0/connect?api-version=2018-05-01"

A connectionString beginning wss:// — on this deployment eastus.gateway.serialconsole.azure.com — means the console is attachable right now. Before boot diagnostics was enabled, this call had nothing to attach to.

  1. Install the extension once:

    Terminal window
    az extension add --name serial-console
  2. Attach:

    Terminal window
    az serial-console connect -g <resource-group> -n <vm-name>
  3. You land at the node’s own login prompt, not a shell, behind the appliance’s audit banner. Serial console proves the channel works; it does not bypass authentication.

Captured from f5-xc-ce-vm-01, elided in the middle where the systemd unit output adds nothing:

+-----------------------------------------------+
Connected to the serial port of the VM.
If no login prompt is displayed, press ENTER.
+-----------------------------------------------+
Probing EDD (edd=off to disable)... ok
Memory KASLR using RDRAND RDTSC...
init_cea_offsets KASLR using RDRAND RDTSC...
Poking KASLR using RDRAND RDTSC...
Welcome to Red Hat Enterprise Linux 9.2024.6.3 (Plow) dracut-057-44.git20230822.el9 (Initramfs)!
[ OK ] Started Dispatch Password …ts to Console Directory Watch.
... [320 lines of systemd unit output elided]
[ OK ] Started Serial Getty on ttyS0.
[ OK ] Reached target Login Prompts.
[ OK ] Started OpenSSH server daemon.
[ OK ] Started Container Runtime Interface for OCI (CRI-O).
[ 19.960784] cloud-init[1311]: Cloud-init v. 23.1.1-12.el9_3 running 'modules:config' at Sun, 26 Jul 2026 13:13:54 +0000. Up 19.84 seconds.
[ OK ] Finished Apply the settings specified in cloud-config.
Starting Execute cloud user/final scripts...
[ OK ] Started Docker Application Container Engine.
Starting Argo Watch service...
Starting VP Manager image load...
[ OK ] Started Argo Watch service.
[ 21.544663] cloud-init[1512]: Cloud-init v. 23.1.1-12.el9_3 running 'modules:final' at Sun, 26 Jul 2026 13:13:56 +0000. Up 21.41 seconds.
[ 22.751629] cloud-init[1512]: Cloud-init v. 23.1.1-12.el9_3 finished at Sun, 26 Jul 2026 13:13:57 +0000. Datasource DataSourceAzure [seed=/var/lib/waagent]. Up 22.37 seconds
[ OK ] Finished Execute cloud user/final scripts.
[ OK ] Started libcontainer conta…f4b59f3b96c31ee10cd95f6eb371c.
UNAUTHORIZED ACCESS TO THIS DEVICE IS PROHIBITED
All actions performed on this device are audited
f5-xc-ce-vm-01 login: [ 123.107074] Warning: Deprecated Driver is detected: iptables will not be maintained in a future major release and may be disabled
[ 123.144641] Warning: Deprecated Driver is detected: ip6tables will not be maintained in a future major release and may be disabled

Four things in that transcript are worth noticing, because they answer questions the debug API cannot:

  • cloud-init completedDatasource DataSourceAzure, finished at 22.37 seconds. A node that never registers usually failed here, and this is where you see it.
  • Both container runtimes started. Container Runtime Interface for OCI (CRI-O) and Docker Application Container Engine are each [ OK ], which is the boot-time proof of the dual-runtime behaviour that surprises people in crictl and Docker.
  • VP Manager image load and Argo Watch servicevpm and Argo coming up.
  • The prompt is the node’s own, behind its audit banner. Serial console gets you a login prompt, not a session.

What you can see here that the API cannot show you

Section titled “What you can see here that the API cannot show you”
  • cloud-init running, failing, or never starting — the usual cause of a node that never registers.
  • Registration attempts against register.ves.volterra.io, including a configuration error or a token the tenant rejected.
  • Kernel and boot messages from before any agent was running.
  • The node when it has no working network path, which defeats every other route.

For a node that is ONLINE, prefer the debug API: it is scriptable, it produces evidence you can re-run, and it does not occupy the single serial port.