Hoverfly
Overview
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. It can capture real traffic, replay it as fast, deterministic virtual services, spy on requests, or modify responses on the fly.
With Hoverfly, teams develop and test against realistic simulations of third-party or internal APIs that are slow, rate-limited, costly or not yet built. You can reproduce specific responses, latencies and failure modes on demand.
This image runs on Ubuntu 24.04 and installs the pinned official Hoverfly 1.12.10 release, verified by checksum. It runs 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 virtualises traffic the moment the VM boots. A single request/response pair virtualises GET http://demo.sac.local/api/health. Sending that request through the proxy returns a canned JSON response, a real service virtualization round trip that you can see immediately. Replace the demo with your own captured or authored simulations when you are ready (see Step 7).
Authentication is 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. Because authentication is enabled, the proxy also requires credentials, so it is never an open relay.
Everything is 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. An nginx reverse proxy on port 80 fronts the admin API, so it is reachable off the box only through Hoverfly's own token authentication. The proxy is private by default, and 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 you get:
- 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, and 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
- A proxy that 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
Before you deploy this image you need:
- An active Azure subscription, an SSH public key, and a VNet with a subnet in the target region
- A subscription to the Hoverfly listing on Azure Marketplace
- Network security group (NSG) rules that allow 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. For simulations that serve heavy traffic, use Standard_D2s_v5 or larger.
Deploy from the Azure Portal
Search for Hoverfly in the Marketplace, select the SecureAnyCloud publisher, and select 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).
Deploy from the Azure CLI
Accept the Marketplace terms, create the VM and open ports 22 and 80:
RG="devtools-prod"; LOCATION="eastus"; VM_NAME="hoverfly1" IMAGE_URN="sac1647283583153:hoverfly-ubuntu-24-04:default:latest" SSH_KEY="$(cat ~/.ssh/id_rsa.pub)" az group create --name "$RG" --location "$LOCATION"
# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:hoverfly-ubuntu-24-04:default:latest
az vm create \
--resource-group "$RG" --name "$VM_NAME" \
--image "$IMAGE_URN" \
--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 1002First boot
On first boot, the image generates a unique admin username and password and a JWT signing secret, enables authentication and starts Hoverfly. It then 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.txtThe 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.
Confirm the service is running
Confirm that hoverfly.service and nginx.service are active, that hoverfly -version reports the pinned release, and that 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/healthExpected output:
active active v1.12.10 {"message":"Hoverfly is healthy"}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>/, because nginx forwards port 80 to the loopback admin API. The same token authentication protects it. To manage Hoverfly remotely, replace http://127.0.0.1:8888 with http://<public-ip> in the commands above.
Send a request through the proxy
The shipped demo simulation virtualises GET http://demo.sac.local/api/health. Because authentication is enabled, the proxy also requires credentials, so it rejects an unauthenticated request 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.sac.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.sac.local/api/health echo 'Expected output:
unauthenticated proxy request -> HTTP 407 authenticated proxy request (the demo simulation): {"status":"ok","service":"sac-hoverfly-demo","virtualized":true}This is a complete service virtualization round trip. The request never reaches a real demo.sac.local server, because Hoverfly answers it from the shipped simulation. Point any HTTP client's proxy at Hoverfly, and requests that it has a simulation for are answered instantly and deterministically.
Capture and author your own simulations
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 that you can capture once and commit to source control.
The shipped simulation lives at /etc/hoverfly/demo-simulation.json. 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, 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.jsonThen load the saved simulation on any Hoverfly instance:
hoverctl import my-service.jsonSee the Hoverfly documentation for the full capture, matching and templating reference.
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 credentialsIf 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. Scoping the rule is still essential defence in depth.
Manage the service
Manage Hoverfly with systemd. Check the service status:
systemctl status hoverfly.service --no-pagerRestart the service, for example after you edit the simulation or the service command:
sudo systemctl restart hoverfly.serviceThe 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.
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. 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.1 and reached off the box only through nginx (admin) or an SSH tunnel (proxy). Do not rebind to 0.0.0.0 without 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 that 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.txt and /etc/default/hoverfly. To rotate it, update HoverflyAdminPass in /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.
Support and Licensing
Hoverfly is developed by SpectoLabs and distributed under the Apache License 2.0. It is free and open source, with no per-CPU or per-deployment fee. This image bundles the unmodified official Hoverfly release.
SecureAnyCloud provides the packaging, the working demo simulation, enabled authentication with per-VM credentials, loopback-only bindings, the nginx-fronted admin API, a proxy that is never an open relay, and 24/7 support with a guaranteed 24 hour response SLA.
SecureAnyCloud 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 SecureAnyCloud. Deploy from the Portal or the Azure CLI as shown above.
Need Help?
Email sales@secureanycloud.com for deployment help, configuration questions, or licensing enquiries.
Deploy on Azure
Launch Hoverfly API Simulation Proxy on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.
View this image
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com
Overview
Hoverfly is the open-source API simulation and service virtualization proxy from SpectoLabs. It sits between your application and the APIs it depends on. It can capture real traffic, replay it as fast, deterministic simulations, spy on requests, or modify responses. You can develop and test against slow, flaky, rate-limited or unavailable third-party APIs without ever calling the real service.
Hoverfly is distributed as a single self-contained Go binary plus the hoverctl command-line tool. Both are installed to /usr/local/bin and run under systemd as the unprivileged hoverfly user. A demo simulation is imported at startup, so the moment the instance boots, the proxy is already virtualizing GET http://demo.sac.local/api/health.
What you get:
- Authentication is enabled. Hoverfly's admin API is unauthenticated out of the box, and this image turns on JWT authentication. A unique admin username, password and JWT signing secret are generated on the first boot of every instance, so no shared or default credential ever ships in the image.
- Everything binds to loopback. The admin API on port 8888 and the proxy on port 8500 are bound to
127.0.0.1only. An nginx reverse proxy fronts the admin API on port 80, so it is reachable off the box only through Hoverfly's own JWT gate. - The proxy is never an open relay. The forward proxy on port 8500 stays loopback-only. Because authentication is enabled, it also requires proxy credentials, so it returns HTTP 407 to any unauthenticated request.
Prerequisites
Before you deploy this image you need:
- An Amazon Web Services account where you can launch EC2 instances
- IAM permissions to launch instances, create security groups, and subscribe to AWS Marketplace products
- An EC2 key pair in the target Region for SSH access to the instance
- A VPC and subnet in the target Region, with a security group allowing inbound port 22 from your management network and inbound port 80 from the networks you will reach the admin API on
- The AWS CLI (version 2) installed locally if you plan to deploy from the command line
Launch the Instance from the AWS Marketplace
Sign in to the AWS Management Console, open the EC2 service, and select Launch instance. Under Application and OS Images, choose AWS Marketplace AMIs and search for Hoverfly. Select the SecureAnyCloud listing, choose Select, then choose Continue on the subscription summary.
Pick an instance type of m5.large or another size that suits your workload. Choose your EC2 key pair under Key pair (login). Under Network settings select your VPC and subnet, and either create or select a security group that allows inbound port 22 from your management network and inbound port 80 from the networks you will use. Leave the root volume at the default size or larger.
Select Launch instance. First-boot initialisation takes only a few seconds after the instance state becomes Running and the status checks pass.
Launch the Instance from the AWS CLI
Launch an instance from the SecureAnyCloud Hoverfly Marketplace AMI into an existing subnet and security group. Replace <ami-id> with the AMI ID shown on the Marketplace listing, <key-name> with your EC2 key pair name, <subnet-id> with your subnet ID, and <security-group-id> with a security group that opens ports 22 and 80 as described above.
aws ec2 run-instances \
--image-id <ami-id> \
--instance-type m5.large \
--key-name <key-name> \
--subnet-id <subnet-id> \
--security-group-ids <security-group-id> \
--block-device-mappings '[{"DeviceName":"/dev/sda1","Ebs":{"VolumeSize":20,"VolumeType":"gp3"}}]' \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=hoverfly-01}]'The command prints a JSON document on success. Note the instance ID, then retrieve its public address once it is running with aws ec2 describe-instances --instance-ids <instance-id> --query "Reservations[].Instances[].PublicIpAddress" --output text.
Connect and Retrieve the Admin Credentials
Connect over SSH with the key pair you selected and the public IP address from Step 2. The SSH login user depends on the operating system of the AMI variant you launched:
- Hoverfly on Ubuntu 24.04: SSH login user ubuntu
ssh -i /path/to/your-key.pem ubuntu@<public-ip>The per-instance admin username and password are written to a root-only file on first boot. Read them with sudo:
$
sudo cat /root/hoverfly-credentials.txt HOVERFLY_ADMIN_USERNAME=admin HOVERFLY_ADMIN_PASSWORD=<a unique 24 character password for this instance> HOVERFLY_ADMIN_URL=http://<public-ip>/Keep this password safe. It is unique to this instance and is not stored anywhere else in plaintext. The commands below show it as <HOVERFLY_ADMIN_PASSWORD> and the username as <HOVERFLY_ADMIN_USERNAME>. Substitute the values from this file.
Confirm Hoverfly Is Running
Hoverfly and its nginx front door start automatically. Confirm that both services are active, and check the versions:
sudo systemctl is-active hoverfly.service nginx.servicehoverfly -version hoverctl versionThe admin API and the proxy are bound to loopback only; nginx exposes the admin API on port 80:
sudo ss -tlnp | grep -E '127.0.0.1:8888|127.0.0.1:8500|:80 ' | awk '{print $4}'Prove the Admin API Is Secured
An unauthenticated request to the admin API is rejected with HTTP 401:
curl -s -o /dev/null -w 'unauthenticated admin API: HTTP %{http_code}\n' \
http://127.0.0.1:8888/api/v2/hoverflyObtain a JWT with your per-instance credentials, then call the admin API with the token. The authenticated call returns HTTP 200:
TOKEN=$(curl -s -H 'Content-Type: application/json' -X POST \
--data '{"Username":"<HOVERFLY_ADMIN_USERNAME>","Password":"<HOVERFLY_ADMIN_PASSWORD>"}' \
http://127.0.0.1:8888/api/token-auth | sed -n 's/.*"token":"\([^"]*\)".*/\1/p')
curl -s -o /dev/null -w 'authenticated admin call: HTTP %{http_code}\n' \
-H "Authorization: Bearer $TOKEN" http://127.0.0.1:8888/api/v2/hoverflyFrom your workstation, reach the same admin API off the box through nginx on port 80. Use http://<public-ip>/api/token-auth to obtain a token, and call http://<public-ip>/api/v2/hoverfly with the Authorization: Bearer header.
Run a Service Virtualization Round Trip
The image ships a demo simulation for GET http://demo.sac.local/api/health. Point an HTTP client's proxy at Hoverfly on port 8500 and request that URL.
Without credentials, the proxy returns HTTP 407, because it is never an open relay. With your admin credentials, it returns the simulated response, with no real backend involved:
noauth=$(curl -s -o /dev/null -w '%{http_code}' \
-x http://127.0.0.1:8500 http://demo.sac.local/api/health || true) withauth=$(curl -s -o /dev/null -w '%{http_code}' \
--proxy-user '<HOVERFLY_ADMIN_USERNAME>:<HOVERFLY_ADMIN_PASSWORD>' \
-x http://127.0.0.1:8500 http://demo.sac.local/api/health || true)
echo "proxy without credentials: HTTP $noauth"
echo "proxy with credentials: HTTP $withauth"The simulated response body carries the sac-hoverfly-demo service marker:
curl -s --proxy-user '<HOVERFLY_ADMIN_USERNAME>:<HOVERFLY_ADMIN_PASSWORD>' \
-x http://127.0.0.1:8500 http://demo.sac.local/api/health 2>/dev/null \
| grep -o 'sac-hoverfly-demo' \
|| echo '(supply valid credentials to see the simulated response)'Capture and Import Your Own Simulations
Replace the demo with your own simulations using hoverctl. The typical workflow is to put Hoverfly into capture mode, send real traffic through it to record the request and response pairs, export them to a JSON file, and then import that file to replay it as a virtual service.
These commands change the running mode and the stored simulation, so run them yourself against your instance rather than as part of a health check:
# point hoverctl at this instance's admin API (uses your per instance token) hoverctl login --target local --host 127.0.0.1 --admin-port 8888 # record: switch to capture mode, drive your traffic through the proxy, then export hoverctl mode capture export http_proxy=http://<HOVERFLY_ADMIN_USERNAME>:<HOVERFLY_ADMIN_PASSWORD>@127.0.0.1:8500 curl http://your-upstream-api.example.com/endpoint hoverctl export my-simulation.json # replay: import the simulation and switch back to simulate mode hoverctl import my-simulation.json hoverctl mode simulateSimulations are portable JSON files, so you can version them alongside your code and share them across environments. See the Hoverfly documentation for matchers, templating, delays and stateful simulations.
Exposing the Proxy to Trusted Clients
By default, the proxy on port 8500 is bound to loopback only, so it is reachable only from the instance itself. This is deliberate, because an internet-facing forward proxy is an abuse risk. To use it from another machine, choose one of these options:
- SSH tunnel (recommended for a single client). Forward the port over SSH, then point your client's proxy at your local end.
ssh -i /path/to/your-key.pem -L 8500:127.0.0.1:8500 ubuntu@<public-ip>
# then, locally:
export http_proxy=http://<HOVERFLY_ADMIN_USERNAME>:<HOVERFLY_ADMIN_PASSWORD>@127.0.0.1:8500- Rebind and scope with a security group (for a trusted network). Change the Hoverfly service to listen on all interfaces by editing the
-listen-on-hostvalue in the systemd unit. Then add a security group rule that opens port 8500 only to the specific client CIDR you trust. Because authentication is enabled, the proxy still requires credentials, but you should never open port 8500 to0.0.0.0/0.
The Application Stack
- Hoverfly runs as
hoverfly.serviceunder systemd as the unprivilegedhoverflyuser, with the admin API on127.0.0.1:8888and the proxy on127.0.0.1:8500. - nginx runs as
nginx.serviceand reverse-proxies port 80 to the loopback admin API on 8888. For production use, terminate TLS here by adding a certificate. - Authentication users and issued tokens persist in a small embedded BoltDB store at
/var/lib/hoverfly/hoverfly.db. There is no separate database server to run. - The shipped demo simulation lives at
/etc/hoverfly/demo-simulation.jsonand is imported at startup. - The per-instance secrets live in the systemd environment file
/etc/default/hoverfly(mode 0600, root only).
Add a Domain and HTTPS
Point a DNS record at the instance's public IP. Then terminate TLS either with an AWS Application Load Balancer in front of the instance, or by adding a certificate to nginx on the instance and configuring a server block on port 443 that proxies to 127.0.0.1:8888.
Keep the admin API behind Hoverfly's JWT gate regardless of where TLS terminates.
Upgrades and Maintenance
The operating system receives unattended security updates.
To move to a newer Hoverfly release, download the official release bundle from the SpectoLabs GitHub releases page, verify its checksum, replace the binaries in /usr/local/bin, and restart the service. Always test a new version against your simulations on a non-production instance first.
Support
SecureAnyCloud provides 24/7 technical support for this Hoverfly AMI by email at sales@secureanycloud.com and through live chat. Support covers simulation authoring, hoverctl capture and import, exposing the proxy safely, custom domains and HTTPS, upgrades and troubleshooting.
Hoverfly is developed by SpectoLabs Ltd and licensed under Apache-2.0. This product is not affiliated with or endorsed by SpectoLabs. It is a repackaged open-source software product, with additional charges for SecureAnyCloud support services. All product and company names are trademarks or registered trademarks of their respective holders.
Deploy on AWS
Launch Hoverfly on AWS with 24/7 support from SecureAnyCloud.
View on Marketplace
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com