Containerlab on Ubuntu 24.04 on Azure User Guide
Overview
This guide covers the deployment and use of Containerlab on Ubuntu 24.04 on Azure using cloudimg Azure Marketplace images. Containerlab is an open source network emulation orchestrator. You describe a topology in a short YAML file, and Containerlab creates the containers, wires them together with real veth links, applies per node startup configuration, and gives you a lab you can log into, break, fix and destroy in seconds. It is the standard way to test routing designs, automation code and network CI pipelines without touching hardware.
Containerlab is a command line tool. There is no web interface and no product port. Everything in this guide is done over SSH.
Containerlab is actively developed. Version 0.77.0 was released on 28 June 2026, and the upstream repository was last pushed on 17 July 2026. It is not archived and not dormant, it carries roughly 2.7k stars, and the 0.77.0 changelog contains real feature work, including a new cisco_xrd_vrouter node kind, SSH IdentityFile support via node credentials and a graph generation fix. This image ships that release unmodified.
The image installs Containerlab 0.77.0 on top of Docker Engine 29.6.2, and bakes in two container images, both genuinely open source and both pinned by digest: quay.io/frrouting/frr:10.7.0 (GPL-2.0-or-later, 296MB) and alpine:3.24.1 (permissive open source, 13MB). It also ships a working example topology so the image proves itself the moment it boots, rather than leaving you to source images before you can run anything.
Secure by default, no shared credentials. FRRouting's stock configuration carries the well known default vty password zebra. This image never ships that password. On the first boot of every VM, containerlab-firstboot.service mints a unique FRRouting vty password for that VM only and writes it to a root only file. The Docker daemon is bound to its UNIX socket only, with no TCP listener anywhere, and no user is placed in the docker or clab_admins groups, because both memberships are root equivalent. Every command in this guide uses sudo, which is upstream's documented invocation.
What is included:
-
Containerlab 0.77.0 (BSD-3-Clause, Copyright (c) 2021 Nokia), installed system wide and invoked as
sudo containerlab -
Docker Engine 29.6.2 (Apache-2.0) from the official Docker repository, with
docker.serviceandcontainerd.serviceenabled and the daemon on its UNIX socket only -
Two baked, digest pinned, genuinely open container images: FRRouting 10.7.0 and Alpine 3.24.1, so labs deploy with no registry access at all
-
A bundled four node example lab,
/opt/cloudimg/labs/cloudimg-frr-lab.clab.yml, wiringhost1 -- router1 ==OSPF== router2 -- host2across a routed core -
A bundled two node minimal lab,
/opt/cloudimg/labs/cloudimg-smoke.clab.yml, for a fast sanity check -
A per VM FRRouting vty password, generated on first boot and written to
/root/containerlab-credentials.txt(0600 root:root)
Prerequisites
-
Active Azure subscription, SSH public key, VNet + subnet in target region
-
Subscription to the Containerlab listing on Azure Marketplace
-
A Network Security Group rule allowing TCP 22 from your administration network. That is the only port this image needs.
Recommended virtual machine size: Standard_D4s_v5 (4 vCPU, 16 GiB RAM). This is a deliberate recommendation, not a default. Containerlab topologies are memory hungry: a single vendor network operating system node routinely wants 2 to 4 GiB on its own, and multi node fabrics scale close to linearly, so a nine node fabric of vendor nodes can want well over 20 GiB. The bundled example lab is deliberately small (four lightweight containers, roughly 400 MiB) so it runs comfortably even on a 4 GiB VM, but size the VM for the topology you actually intend to build, not for the example.
Step 1: Deploy from the Azure Portal
Search Containerlab in Marketplace, select the cloudimg publisher, and click Create. Configure the Network Security Group to allow TCP 22 from your administration network only. There is no product port to open, so no other inbound rule is required.
Step 2: Deploy from the Azure CLI
RG="netlab-prod"; LOCATION="eastus"; VM_NAME="clab1"
GALLERY_IMAGE_ID="/subscriptions/<sub-id>/resourceGroups/azure-cloudimg/providers/Microsoft.Compute/galleries/cloudimgGallery/images/containerlab-ubuntu-24-04/versions/<version>"
SSH_KEY="$(cat ~/.ssh/id_rsa.pub)"
az group create --name "$RG" --location "$LOCATION"
az vm create \
--resource-group "$RG" --name "$VM_NAME" \
--image "$GALLERY_IMAGE_ID" \
--size Standard_D4s_v5 \
--admin-username azureuser \
--ssh-key-values "$SSH_KEY" \
--public-ip-sku Standard
Step 3: Connect over SSH and read the per VM credentials
Connect as azureuser, the administrative user you named at deployment time:
ssh azureuser@<vm-public-ip>
On first boot the image generated a FRRouting vty password unique to this VM and recorded it, along with the lab paths, in /root/containerlab-credentials.txt. Read it:
sudo cat /root/containerlab-credentials.txt
The file is 0600 root:root, so only root can read it. The key you want is CLAB_FRR_VTY_PASSWORD. It is the password the FRRouting nodes in the bundled lab will ask for when you enter their CLI. Wherever this guide shows <CLAB_FRR_VTY_PASSWORD>, substitute the value from this file. FRR's well known default password zebra is never present on this image, and both first boot and validation fail closed if it ever appears.
Step 4: Confirm Containerlab, Docker and the baked images
Check the tool versions and confirm which container images are already local. Nothing here needs internet access.
sudo containerlab version
version: 0.77.0
commit: 05c2006e3
date: 2026-06-28T08:07:27Z
sudo docker --version
sudo docker info --format 'Server Version: {{.ServerVersion}} Storage: {{.Driver}}'
Docker version 29.6.2, build dfc4efb
Server Version: 29.6.2 Storage: overlayfs
sudo docker images --format 'table {{.Repository}}\t{{.Tag}}\t{{.Size}}'
REPOSITORY TAG SIZE
quay.io/frrouting/frr 10.7.0 296MB
alpine 3.24.1 13MB
Those two images are the complete set baked into this appliance, and both are pinned by digest so the version you get is the version whose licence was checked. No vendor network operating system image is included, for the reasons set out in Step 10.

Step 5: Inspect the bundled topology
A Containerlab lab is one YAML file. Read the bundled example before you deploy it, because the file is the whole design:
sudo head -n 30 /opt/cloudimg/labs/cloudimg-frr-lab.clab.yml
# cloudimg example network lab - Containerlab on Ubuntu 24.04 LTS.
#
# host1 ---- eth2:router1:eth1 ==OSPF== eth1:router2:eth2 ---- host2
# 10.0.1.10 10.0.0.0/30 core 10.0.2.10
#
# Every image referenced here is genuinely open source and is ALREADY BAKED INTO THIS IMAGE:
# quay.io/frrouting/frr:10.7.0 GPL-2.0-or-later
# alpine:3.24.1 permissive OSS
#
# To lab a VENDOR network OS (Nokia SR Linux, Arista cEOS, Cisco, Juniper, ...) you must supply that
# image yourself and accept the vendor's own licence terms - see the cloudimg user guide.
name: cloudimg-frr-lab
topology:
nodes:
router1:
kind: linux
image: quay.io/frrouting/frr:10.7.0
binds:
- /opt/cloudimg/labs/frr/daemons:/etc/frr/daemons
- /opt/cloudimg/labs/frr/router1.conf:/etc/frr/frr.conf
router2:
kind: linux
image: quay.io/frrouting/frr:10.7.0
binds:
- /opt/cloudimg/labs/frr/daemons:/etc/frr/daemons
- /opt/cloudimg/labs/frr/router2.conf:/etc/frr/frr.conf
host1:
kind: linux
image: alpine:3.24.1
The addressing plan is:
| Segment | Network | Addresses |
|---|---|---|
| Routed core (router1 to router2) | 10.0.0.0/30 |
router1 10.0.0.1, router2 10.0.0.2 |
| host1 LAN | 10.0.1.0/24 |
host1 10.0.1.10, router1 10.0.1.1 |
| host2 LAN | 10.0.2.0/24 |
host2 10.0.2.10, router2 10.0.2.1 |
| Loopbacks | 10.255.255.0/24 |
router1 10.255.255.1, router2 10.255.255.2 |
The two routers run OSPF across the core link, so host1 and host2 are on different subnets with no static path between them. If they can reach each other, routing genuinely converged. That is what Step 8 proves.
The FRRouting node configs live in /opt/cloudimg/labs/frr/router1.conf and router2.conf and are 0600 root:root, because they hold this VM's vty password. The container reads them through the bind mount as root, so the tighter mode costs nothing.
Step 6: Deploy the lab
sudo containerlab deploy -t /opt/cloudimg/labs/cloudimg-frr-lab.clab.yml
06:41:57 INFO Creating container name=host2
06:41:57 INFO Creating container name=router1
06:41:58 INFO Creating container name=router2
06:41:58 INFO Creating container name=host1
06:41:59 INFO Created link: router1:eth1 ▪┄┄▪ router2:eth1
06:41:59 INFO Created link: host2:eth1 ▪┄┄▪ router2:eth2
06:41:59 INFO Created link: host1:eth1 ▪┄┄▪ router1:eth2
06:41:59 INFO Executed command node=host1 command="ip addr add 10.0.1.10/24 dev eth1" stdout=""
06:41:59 INFO Executed command node=host1 command="ip link set eth1 up" stdout=""
06:41:59 INFO Executed command node=host1 command="ip route add 10.0.2.0/24 via 10.0.1.1" stdout=""
06:41:59 INFO Executed command node=host2 command="ip addr add 10.0.2.10/24 dev eth1" stdout=""
06:41:59 INFO Executed command node=host2 command="ip link set eth1 up" stdout=""
06:41:59 INFO Executed command node=host2 command="ip route add 10.0.1.0/24 via 10.0.2.1" stdout=""
06:41:59 INFO Adding host entries path=/etc/hosts
06:41:59 INFO Adding SSH config for nodes path=/etc/ssh/ssh_config.d/clab-cloudimg-frr-lab.conf
╭───────────────────────────────┬──────────────────────────────┬─────────┬───────────────────╮
│ Name │ Kind/Image │ State │ IPv4/6 Address │
├───────────────────────────────┼──────────────────────────────┼─────────┼───────────────────┤
│ clab-cloudimg-frr-lab-host1 │ linux │ running │ 172.20.20.5 │
│ │ alpine:3.24.1 │ │ 3fff:172:20:20::5 │
├───────────────────────────────┼──────────────────────────────┼─────────┼───────────────────┤
│ clab-cloudimg-frr-lab-host2 │ linux │ running │ 172.20.20.3 │
│ │ alpine:3.24.1 │ │ 3fff:172:20:20::3 │
├───────────────────────────────┼──────────────────────────────┼─────────┼───────────────────┤
│ clab-cloudimg-frr-lab-router1 │ linux │ running │ 172.20.20.2 │
│ │ quay.io/frrouting/frr:10.7.0 │ │ 3fff:172:20:20::2 │
├───────────────────────────────┼──────────────────────────────┼─────────┼───────────────────┤
│ clab-cloudimg-frr-lab-router2 │ linux │ running │ 172.20.20.4 │
│ │ quay.io/frrouting/frr:10.7.0 │ │ 3fff:172:20:20::4 │
╰───────────────────────────────┴──────────────────────────────┴─────────┴───────────────────╯
Node names are always clab-<lab-name>-<node-name>, so the four nodes are clab-cloudimg-frr-lab-router1, -router2, -host1 and -host2. The 172.20.20.0/24 addresses are the management network, a Docker bridge private to this VM. The lab's own data plane addressing is the 10.0.x.x plan from Step 5.

Step 7: Inspect the running lab
inspect re-reads the topology and reports the live state of every node. Use it any time you want to know what is running:
sudo containerlab inspect -t /opt/cloudimg/labs/cloudimg-frr-lab.clab.yml
06:42:07 INFO Parsing & checking topology file=cloudimg-frr-lab.clab.yml
╭───────────────────────────────┬──────────────────────────────┬─────────┬───────────────────╮
│ Name │ Kind/Image │ State │ IPv4/6 Address │
├───────────────────────────────┼──────────────────────────────┼─────────┼───────────────────┤
│ clab-cloudimg-frr-lab-host1 │ linux │ running │ 172.20.20.5 │
│ │ alpine:3.24.1 │ │ 3fff:172:20:20::5 │
├───────────────────────────────┼──────────────────────────────┼─────────┼───────────────────┤
│ clab-cloudimg-frr-lab-host2 │ linux │ running │ 172.20.20.3 │
│ │ alpine:3.24.1 │ │ 3fff:172:20:20::3 │
├───────────────────────────────┼──────────────────────────────┼─────────┼───────────────────┤
│ clab-cloudimg-frr-lab-router1 │ linux │ running │ 172.20.20.2 │
│ │ quay.io/frrouting/frr:10.7.0 │ │ 3fff:172:20:20::2 │
├───────────────────────────────┼──────────────────────────────┼─────────┼───────────────────┤
│ clab-cloudimg-frr-lab-router2 │ linux │ running │ 172.20.20.4 │
│ │ quay.io/frrouting/frr:10.7.0 │ │ 3fff:172:20:20::4 │
╰───────────────────────────────┴──────────────────────────────┴─────────┴───────────────────╯
Step 8: Log into a router and verify OSPF
Each FRRouting node has a full network operating system CLI, vtysh, which will feel familiar if you have used any traditional router shell. Open it interactively on router1:
sudo docker exec -it clab-cloudimg-frr-lab-router1 vtysh
That command is interactive, so run it yourself in a terminal rather than from a script: it needs a real TTY and will refuse to start without one.
vtysh prompts for this VM's vty password. Enter the value of CLAB_FRR_VTY_PASSWORD from /root/containerlab-credentials.txt. From the router1# prompt you can run show ip ospf neighbor, show ip route ospf, show interface brief, configure terminal and the rest of the FRRouting command set.
The same checks can be run non interactively, which is what the blocks below show. vtysh -u runs a command in unprivileged mode. Confirm the routing daemon first:
sudo docker exec clab-cloudimg-frr-lab-router1 vtysh -u -c 'show version' </dev/null | sed -n 1p
FRRouting 10.7.0_git (router1) on Linux(6.17.0-1010-azure).
Now check the OSPF adjacency across the core link:
sudo docker exec clab-cloudimg-frr-lab-router1 vtysh -c 'show ip ospf neighbor' </dev/null
Neighbor ID Pri State Up Time Dead Time Address Interface RXmtL RqstL DBsmL
10.255.255.2 1 Full/- 9.083s 3.923s 10.0.0.2 eth1:10.0.0.1 0 0 0
Router2, identified by its loopback 10.255.255.2, is in state Full over eth1 on the core link 10.0.0.1 to 10.0.0.2. Full is the terminal OSPF adjacency state, meaning both routers have exchanged and synchronised their complete link state databases.
Next, confirm router1 has actually learned router2's networks by OSPF rather than having them configured:
sudo docker exec clab-cloudimg-frr-lab-router1 vtysh -c 'show ip route ospf' </dev/null
Codes: K - kernel route, C - connected, L - local, S - static,
R - RIP, O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP,
T - Table, v - VNC, V - VNC-Direct, A - Babel, F - PBR,
f - OpenFabric, t - Table-Direct,
> - selected route, * - FIB route, q - queued, r - rejected, b - backup
t - trapped, o - offload failure
IPv4 unicast VRF default:
O>* 10.0.2.0/24 [110/20] via 10.0.0.2, eth1, weight 1, 00:00:03
O>* 10.255.255.2/32 [110/10] via 10.0.0.2, eth1, weight 1, 00:00:03
The O code marks both routes as OSPF learned, > marks them selected and * marks them installed in the forwarding table. Router1 has learned host2's LAN, 10.0.2.0/24, and router2's loopback, both via the core neighbour 10.0.0.2, with the standard OSPF administrative distance of 110.
You can confirm the interface addressing that underpins this from the node itself:
sudo docker exec clab-cloudimg-frr-lab-router1 ip -br addr
lo UNKNOWN 127.0.0.1/8 10.255.255.1/32 ::1/128
eth0@if27 UP 172.20.20.2/24 3fff:172:20:20::2/64 fe80::8019:8aff:fefa:33e6/64
eth1@if29 UP 10.0.0.1/30 fe80::a8c1:abff:fe0a:d86d/64
eth2@if31 UP 10.0.1.1/24 fe80::a8c1:abff:feb6:2419/64
eth0 is the management bridge, eth1 is the routed core to router2, eth2 is host1's LAN gateway, and the loopback carries the OSPF router ID 10.255.255.1.
Step 9: Prove end to end connectivity
The decisive test. host1 (10.0.1.10) and host2 (10.0.2.10) are on different subnets, two router hops apart, with no direct link. A successful ping can only happen if Containerlab wired the veth links correctly and OSPF converged across the core.
First, confirm host1's view of the network:
sudo docker exec clab-cloudimg-frr-lab-host1 ip route
default via 172.20.20.1 dev eth0
10.0.1.0/24 dev eth1 scope link src 10.0.1.10
10.0.2.0/24 via 10.0.1.1 dev eth1
172.20.20.0/24 dev eth0 scope link src 172.20.20.5
Host1 reaches host2's subnet only via its router, 10.0.1.1. Now ping across the routed core:
sudo docker exec clab-cloudimg-frr-lab-host1 ping -c 4 10.0.2.10
PING 10.0.2.10 (10.0.2.10): 56 data bytes
64 bytes from 10.0.2.10: seq=0 ttl=62 time=0.106 ms
64 bytes from 10.0.2.10: seq=1 ttl=62 time=0.091 ms
64 bytes from 10.0.2.10: seq=2 ttl=62 time=0.090 ms
64 bytes from 10.0.2.10: seq=3 ttl=62 time=0.090 ms
--- 10.0.2.10 ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max = 0.090/0.094/0.106 ms
Four of four packets, zero loss. Note the ttl=62: packets left host1 with a TTL of 64 and were decremented twice, once by each router, which is direct evidence that traffic was genuinely routed through router1 and router2 rather than bridged.

Step 10: Destroy the lab
Labs are disposable, which is the point. Tear it down and the VM returns to a clean state:
sudo containerlab destroy -t /opt/cloudimg/labs/cloudimg-frr-lab.clab.yml --cleanup
06:42:40 INFO Parsing & checking topology file=cloudimg-frr-lab.clab.yml
06:42:40 INFO Parsing & checking topology file=cloudimg-frr-lab.clab.yml
06:42:40 INFO Destroying lab name=cloudimg-frr-lab
06:42:40 INFO Removed container name=clab-cloudimg-frr-lab-host2
06:42:41 INFO Removed container name=clab-cloudimg-frr-lab-router2
06:42:41 INFO Removed container name=clab-cloudimg-frr-lab-host1
06:42:41 INFO Removed container name=clab-cloudimg-frr-lab-router1
06:42:41 INFO Removing host entries path=/etc/hosts
06:42:41 INFO Removing SSH config path=/etc/ssh/ssh_config.d/clab-cloudimg-frr-lab.conf
Confirm nothing survived:
sudo docker ps -aq --filter name=clab-cloudimg-frr-lab- | wc -l
0
Containerlab also removed the /etc/hosts entries and SSH configuration it added, so re-deploying the lab starts from a clean slate. A second, deliberately minimal lab is bundled at /opt/cloudimg/labs/cloudimg-smoke.clab.yml (two Alpine nodes at 10.99.0.1 and 10.99.0.2 across a single link) if you want the fastest possible sanity check that Docker and Containerlab are healthy.
Finally, confirm the VM's network surface is unchanged after all that lab activity:
sudo ss -tlnp
State Recv-Q Send-Q Local Address:Port Peer Address:PortProcess
LISTEN 0 4096 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=1022,fd=3),("systemd",pid=1,fd=129))
LISTEN 0 4096 127.0.0.54:53 0.0.0.0:* users:(("systemd-resolve",pid=550,fd=17))
LISTEN 0 4096 127.0.0.53%lo:53 0.0.0.0:* users:(("systemd-resolve",pid=550,fd=15))
LISTEN 0 4096 [::]:22 [::]:* users:(("sshd",pid=1022,fd=4),("systemd",pid=1,fd=132))
sshd on port 22 is the only network reachable listener. The two systemd-resolved entries on 127.0.0.54 and 127.0.0.53 are loopback only local DNS and are not reachable from the network. There is no Docker API on 2375 or 2376, because the daemon is on its UNIX socket only.

Step 11: Adding your own vendor network OS images
Containerlab's real power is orchestrating vendor network operating systems, and version 0.77.0 supports more than 60 node kinds, including Nokia SR Linux, Arista cEOS, Cisco (c8000, XRd, IOL), Juniper (cRPD, vJunos), SONiC, Cumulus VX and many more.
This image deliberately bundles none of them. Those images are proprietary and/or require you to obtain them from the vendor and accept the vendor's own licence terms. cloudimg cannot accept those terms on your behalf and cannot redistribute those images, so this appliance ships only the two genuinely open images from Step 4. The bundled example lab therefore uses the generic linux node kind.
To lab a vendor NOS, you supply the image yourself:
-
Obtain the image from the vendor, under your own account and licence. Some vendors publish to a public registry, some require a portal download and some require a support contract.
-
Make it available to Docker on this VM. For a registry image, authenticate to that registry and pull it. For a downloaded tarball, copy it to the VM and load it:
sudo docker load -i /path/to/vendor-image.tar
sudo docker images
- Reference it in your topology with the correct node kind. Copy the bundled lab as a starting point and edit the
kindandimagefields for your nodes. Consult the Containerlab documentation for the exactkindstring and any per kind requirements your vendor's image has:
mkdir -p ~/labs
sudo cp /opt/cloudimg/labs/cloudimg-frr-lab.clab.yml ~/labs/my-lab.clab.yml
sudo chown "$USER":"$USER" ~/labs/my-lab.clab.yml
- Size the VM for it. This is where
Standard_D4s_v5matters. A single vendor NOS node commonly reserves 2 to 4 GiB of RAM and one or more dedicated vCPUs, and requirements add up across the topology. If nodes fail to reachrunning, insufficient memory is the first thing to check.
Licensing note: importing a vendor image binds you to that vendor's licence terms for that image. cloudimg supplies the lab host and the two open images described above, and nothing more.
Step 12: Security recommendations
-
SSH is the only open port. Keep it that way. This appliance has no product port and no web interface. Allow TCP 22 from your administration network only, and do not add inbound NSG rules for anything else.
-
Never expose the Docker socket or the Docker API over TCP. The daemon on this image is bound to its UNIX socket only, and there is deliberately no listener on
2375or2376. An exposed Docker API is a full remote root compromise of the VM, with no authentication in the default configuration. Do not enable a TCP socket, and do not forward/var/run/docker.sockinto anything untrusted. -
Lab nodes are host local by design. Nodes sit on the Docker bridge
172.20.20.0/24, which exists only on this VM. They are reachable from the host, and from each other, but are not routable from your VNet or the internet. Reach them bysudo docker execover your SSH session rather than by publishing ports. -
Membership of
dockerandclab_adminsis root equivalent. No user on this image is in either group, and that is intentional. Every command in this guide usessudo, which is upstream's documented invocation. Adding a user todockersilently grants that user full root on the VM. -
Protect the per VM credential. The FRRouting vty password lives in
/root/containerlab-credentials.txt(0600 root:root), and the FRR node configs that carry it are also0600 root:root. The well known default passwordzebrais never shipped. If you rotate the password, update the node configs and the credentials file together. -
Treat lab configurations as untrusted input. A topology file can bind host paths into nodes and can run arbitrary commands. Review any topology you did not write before deploying it as root.
-
Keep the OS patched. Unattended security upgrades remain enabled on the running VM.
Step 13: Support and Licensing
Containerlab is open source software distributed under the BSD 3-Clause Licence, Copyright (c) 2021 Nokia. Docker Engine is distributed under the Apache License 2.0. The bundled container images are FRRouting 10.7.0 (GPL-2.0-or-later) and Alpine 3.24.1 (permissive open source). This cloudimg image bundles the unmodified upstream Containerlab release. cloudimg provides the packaging, the Docker Engine integration, the digest pinned open image set, the bundled worked example topology, the per VM credential automation, the security hardening, the paired deploy guide, and 24/7 support with a guaranteed 24 hour response SLA.
No proprietary vendor network operating system image is included. If you import one, your use of that image is governed by that vendor's own licence terms.
cloudimg is not affiliated with or endorsed by the Containerlab project, Nokia, the FRRouting project, Docker, Inc. or any network equipment vendor. All names are marks of their respective owners and are used here only to identify the software.
Deploy on Azure
Find Containerlab on Ubuntu 24.04 LTS on the Azure Marketplace, published by cloudimg. Deploy from the Portal or the Azure CLI as shown above.
Need Help?
Email support@cloudimg.co.uk for deployment help, configuration questions, or licensing enquiries.