Hoverfly on Ubuntu 24.04 on Azure User Guide
Overview
This guide covers the deployment and configuration of Hoverfly on Ubuntu 24.04 on Azure using cloudimg Azure Marketplace images. Hoverfly is a lightweight, open source API simulation and service virtualization tool developed by SpectoLabs. It sits as a proxy in front of the HTTP and HTTPS services your application depends on, and can capture real traffic, replay it as fast deterministic virtual services, spy on requests, or modify responses on the fly. This lets teams develop and test against realistic simulations of third party or internal APIs that are slow, rate limited, costly or not yet built, and reproduce specific responses, latencies and failure modes on demand.
The image installs the pinned official Hoverfly 1.12.10 release, verified by checksum, and runs it under systemd as the unprivileged hoverfly user. Both the hoverfly server and the hoverctl command line tool are installed to /usr/local/bin.
Ready on first boot. The image ships a working demo simulation so Hoverfly is virtualising traffic the moment the VM boots. A single request/response pair virtualises GET http://demo.cloudimg.local/api/health, so sending that request through the proxy returns a canned JSON response, a real service virtualization round trip you can see immediately. You replace the demo with your own captured or authored simulations when you are ready (see Step 7).
Security by design — authentication enabled. Hoverfly's admin API is unauthenticated out of the box. This image enables authentication and generates a unique admin password and a JWT signing secret on each VM's first boot, written to a root only file. Nothing is baked into the image. The admin API requires a JWT (obtained from your admin credentials), and because authentication is enabled the proxy also requires credentials, so it is never an open relay.
Security by design — bound to loopback. Both the admin API (127.0.0.1:8888) and the proxy (127.0.0.1:8500) are bound to loopback only. The admin API is fronted by an nginx reverse proxy on port 80 so it is reachable off the box only through Hoverfly's own token authentication. The proxy is kept private by default; you expose it deliberately to trusted clients when you need to (see Step 8). The only inbound ports on the image are SSH 22 and the nginx admin port 80.
What is included:
-
Hoverfly 1.12.10 (pinned, checksum verified), plus
hoverctl, run under systemd as the unprivilegedhoverflyuser (hoverfly.service) -
A working demo simulation so the proxy virtualises traffic on first boot
-
Authentication enabled with a unique admin password and JWT secret generated per VM, nothing baked into the image
-
The admin API and proxy bound to loopback, with nginx fronting the admin API on port 80 behind Hoverfly's own token authentication
-
The proxy is never an open relay — it requires credentials and is not exposed by default
-
Unattended security upgrades left enabled so the OS keeps receiving patches
Prerequisites
-
Active Azure subscription, SSH public key, VNet and subnet in the target region
-
Subscription to the Hoverfly listing on Azure Marketplace
-
Network Security Group rules allowing TCP 22 for administration and TCP 80 for the admin API
Recommended virtual machine size: Standard_B2s (2 vCPU, 4 GB RAM) for development and test use. Simulations serving heavy traffic should use Standard_D2s_v5 or larger.
Step 1: Deploy from the Azure Portal
Search Hoverfly in Marketplace, select the cloudimg publisher, and click Create. Configure the Network Security Group to allow TCP 22 for administration and TCP 80 for the admin API. The Hoverfly proxy is not exposed by default; if you later choose to expose it to trusted clients, open only that port and only from the networks that should reach it (see Step 8).
Step 2: Deploy from the Azure CLI
RG="devtools-prod"; LOCATION="eastus"; VM_NAME="hoverfly1"
GALLERY_IMAGE_ID="/subscriptions/<sub-id>/resourceGroups/azure-cloudimg/providers/Microsoft.Compute/galleries/cloudimgGallery/images/hoverfly-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_B2s \
--admin-username azureuser \
--ssh-key-values "$SSH_KEY" \
--public-ip-sku Standard
# Open SSH and the admin API port on the VM's NSG:
az vm open-port --resource-group "$RG" --name "$VM_NAME" --port 22 --priority 1001
az vm open-port --resource-group "$RG" --name "$VM_NAME" --port 80 --priority 1002
Step 3: First boot
On first boot the image generates a unique admin username and password and a JWT signing secret, enables authentication, starts Hoverfly, proves the authentication round trip and the demo simulation, starts nginx, and writes /root/hoverfly-credentials.txt. This completes within a minute. SSH in as azureuser and read your credentials:
sudo cat /root/hoverfly-credentials.txt
The file records the admin username, the per VM admin password, and the off box admin URL. Store the password somewhere safe; it is unique to this VM and is the only credential that can obtain an admin token or use the proxy.
Step 4: Confirm the service is running
hoverfly.service and nginx.service are active, hoverfly -version reports the pinned release, and the admin API answers /api/health on loopback.
systemctl is-active hoverfly.service nginx.service
hoverfly -version
curl -s http://127.0.0.1:8888/api/health
Expected output:
active
active
v1.12.10
{"message":"Hoverfly is healthy"}

Step 5: Authenticate to the admin API
Authentication is enabled, so the admin API rejects unauthenticated requests with 401. To use it, obtain a JSON Web Token from your per VM admin credentials by posting to /api/token-auth, then send that token as a Bearer header. The block below reads the credentials from the first boot file and performs the full round trip against the loopback admin API:
sudo bash -c '
U=$(grep "^HOVERFLY_ADMIN_USERNAME=" /root/hoverfly-credentials.txt | cut -d= -f2-)
PW=$(grep "^HOVERFLY_ADMIN_PASSWORD=" /root/hoverfly-credentials.txt | cut -d= -f2-)
echo -n "unauthenticated GET /api/v2/hoverfly -> HTTP "
curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8888/api/v2/hoverfly
TOKEN=$(curl -s -H "Content-Type: application/json" -X POST \
-d "{\"Username\":\"$U\",\"Password\":\"$PW\"}" \
http://127.0.0.1:8888/api/token-auth | jq -r .token)
echo "obtained a JWT (first 40 chars): ${TOKEN:0:40}..."
echo "authenticated GET /api/v2/hoverfly/mode:"
curl -s -H "Authorization: Bearer $TOKEN" http://127.0.0.1:8888/api/v2/hoverfly/mode
echo
'
Expected output (the mode is simulate, the default for serving virtual services):
unauthenticated GET /api/v2/hoverfly -> HTTP 401
obtained a JWT (first 40 chars): eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJ...
authenticated GET /api/v2/hoverfly/mode:
{"mode":"simulate","arguments":{"matchingStrategy":"strongest"}}
The admin API is also reachable off the box at http://<public-ip>/ (nginx forwards port 80 to the loopback admin API), protected by the same token authentication. Replace http://127.0.0.1:8888 with http://<public-ip> in the commands above to manage Hoverfly remotely.

Step 6: Send a request through the proxy
The shipped demo simulation virtualises GET http://demo.cloudimg.local/api/health. Because authentication is enabled, the proxy also requires credentials, so an unauthenticated request is rejected with 407. Supply your admin credentials as HTTP Basic proxy credentials and the proxy returns the simulated response:
sudo bash -c '
U=$(grep "^HOVERFLY_ADMIN_USERNAME=" /root/hoverfly-credentials.txt | cut -d= -f2-)
PW=$(grep "^HOVERFLY_ADMIN_PASSWORD=" /root/hoverfly-credentials.txt | cut -d= -f2-)
echo -n "unauthenticated proxy request -> HTTP "
curl -s -o /dev/null -w "%{http_code}\n" -x http://127.0.0.1:8500 http://demo.cloudimg.local/api/health
echo "authenticated proxy request (the demo simulation):"
curl -s --proxy-user "$U:$PW" -x http://127.0.0.1:8500 http://demo.cloudimg.local/api/health
echo
'
Expected output:
unauthenticated proxy request -> HTTP 407
authenticated proxy request (the demo simulation):
{"status":"ok","service":"cloudimg-hoverfly-demo","virtualized":true}
This is a complete service virtualization round trip: the request never reaches a real demo.cloudimg.local server, Hoverfly answers it from the shipped simulation. Point any HTTP client's proxy at Hoverfly and requests it has a simulation for are answered instantly and deterministically.

Step 7: Capture and author your own simulations
You replace the demo with your own simulations using hoverctl, the Hoverfly command line tool. The typical workflow is to run Hoverfly in capture mode, send your application's real traffic through it to record the responses, then switch back to simulate mode to replay them. Simulations are portable JSON files you can capture once and commit to source control.
The shipped simulation lives at /etc/hoverfly/demo-simulation.json. You can inspect the current simulation through the admin API:
sudo bash -c '
U=$(grep "^HOVERFLY_ADMIN_USERNAME=" /root/hoverfly-credentials.txt | cut -d= -f2-)
PW=$(grep "^HOVERFLY_ADMIN_PASSWORD=" /root/hoverfly-credentials.txt | cut -d= -f2-)
TOKEN=$(curl -s -H "Content-Type: application/json" -X POST \
-d "{\"Username\":\"$U\",\"Password\":\"$PW\"}" \
http://127.0.0.1:8888/api/token-auth | jq -r .token)
curl -s -H "Authorization: Bearer $TOKEN" http://127.0.0.1:8888/api/v2/simulation | jq ".data.pairs[0].request.path"
'
Expected output:
[
{
"matcher": "exact",
"value": "/api/health"
}
]
To capture new simulations with hoverctl, point it at a target and switch modes. For example, to record traffic to a real API and export it to a file:
hoverctl mode capture
# ... send your application's traffic through the proxy on port 8500 ...
hoverctl mode simulate
hoverctl export my-service.json
You can then load a saved simulation on any Hoverfly instance:
hoverctl import my-service.json
See the Hoverfly documentation for the full capture, matching and templating reference.
Step 8: Expose the proxy to trusted clients
The proxy is bound to loopback and is not exposed by the Network Security Group. For an application on another host to use Hoverfly for service virtualization, expose the proxy deliberately. The safest option is an SSH tunnel from the client, which needs no open port:
ssh -L 8500:127.0.0.1:8500 azureuser@<public-ip>
# then on the client, use the proxy at 127.0.0.1:8500 with your admin credentials
If you need the proxy reachable directly, rebind Hoverfly to a routable interface by adding -listen-on-host 0.0.0.0 to the service command in /etc/systemd/system/hoverfly.service, then add a Network Security Group rule for TCP 8500 scoped to the specific client CIDR, never to the whole internet. Authentication remains enforced, so clients still need the admin credentials, but scoping the rule is essential defence in depth.
Step 9: Manage the service
Hoverfly is managed with systemd. Common operations:
systemctl status hoverfly.service --no-pager
To restart the service (for example after editing the simulation or the service command):
sudo systemctl restart hoverfly.service
The runtime environment, including the per VM admin credentials and JWT secret, lives in /etc/default/hoverfly (root only). The BoltDB store that holds users and tokens lives at /var/lib/hoverfly/hoverfly.db.
Step 10: Security recommendations
Both the admin API and the proxy are bound to loopback, and only SSH 22 and the nginx admin port 80 are exposed. You can confirm the listening sockets at any time:
ss -tln | grep -E ':(22|80|8888|8500)\b'

-
Keep the admin API and proxy on loopback. Both are bound to
127.0.0.1and reached off the box only through nginx (admin) or an SSH tunnel (proxy). Do not rebind to0.0.0.0without scoping a Network Security Group rule to specific client networks. -
Terminate TLS in front of nginx. Port 80 is plain HTTP. For production, add a TLS certificate to the nginx server block so admin credentials and tokens are encrypted in transit.
-
Rotate the admin password if it is ever exposed. The password is generated per VM and stored in
/root/hoverfly-credentials.txtand/etc/default/hoverfly. To rotate it, updateHoverflyAdminPassin/etc/default/hoverfly, remove/var/lib/hoverfly/hoverfly.db, and restart the service. -
Scope any proxy exposure tightly. If you expose the proxy on port 8500, restrict the Network Security Group rule to the exact client CIDR. An open forward proxy is an abuse relay.
-
Keep the OS and Hoverfly patched. Unattended security upgrades remain enabled for the OS. Track new Hoverfly releases and update the binaries when you upgrade.
Step 11: Support and Licensing
Hoverfly is developed by SpectoLabs and distributed under the Apache License 2.0, free and open source with no per CPU or per deployment fee. This cloudimg image bundles the unmodified official Hoverfly release. cloudimg provides the packaging, the working demo simulation, the enabled authentication with per VM credentials, the loopback only bindings, the nginx fronted admin API, the no open relay proxy posture, and 24/7 support with a guaranteed 24 hour response SLA.
cloudimg is not affiliated with or endorsed by SpectoLabs. Hoverfly is a mark of its respective owner and is used here only to identify the software.
Deploy on Azure
Find Hoverfly 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.