Deployment guide

Hoverfly 1.12.17

Overview

This guide covers launching and using the Hoverfly 1.12.17 on Ubuntu 24.04 AMI from SecureAnyCloud on Amazon EC2. It is one version of the SecureAnyCloud developer and API tools listing on AWS Marketplace. You select it as the software version when you subscribe and launch.

Hoverfly, from SpectoLabs, simulates the HTTP and HTTPS APIs your code depends on. Your application or test suite sends its requests through Hoverfly's forward proxy, and Hoverfly answers from a simulation. A simulation is a set of request/response pairs that you record from the real API (capture mode) or write by hand. Your tests then run against a fast, stable stand-in for a third-party API that is slow, rate limited, costly or not built yet. You can reproduce exact responses, delays and failures on demand.

The SecureAnyCloud image runs Hoverfly as a private service. What you get:

  • HTTPS from the first boot. nginx serves Hoverfly's admin API at https://<public-ip>/api/ with a certificate generated on your instance's first boot. Port 80 only redirects to HTTPS. Hoverfly's web dashboard is not served, because its Angular 6 front end is end of life.
  • Two locks on the admin API. Every request needs this instance's API key in an X-Sac-Key header, and then Hoverfly's own admin login (a token from /api/token-auth). Without the key, nginx answers 401 and Hoverfly never sees the request, so nobody else can use Hoverfly's login lockout to lock you out.
  • A private proxy. The proxy listens on 127.0.0.1:8500 only and needs the admin credential. You reach it through an SSH tunnel or from tests that run on the instance. It is never an open relay.
  • A MITM CA that is unique to your instance. To simulate HTTPS, Hoverfly signs certificates with a CA. Hoverfly's built-in CA has its private key published in the Hoverfly source code, so the image does not use it. First boot generates a new CA on your instance (Step 7).
  • No default login. The image contains no key, password, certificate or host name. First boot writes them to /var/lib/sac/data/hoverfly-credentials.txt (root only).
  • No reach into your AWS account. Capture and spy mode, post-serve actions and body files make Hoverfly open connections on your behalf. Hoverfly is blocked at the kernel level from the EC2 instance metadata service (IPv4 and IPv6), from other link-local addresses and from this instance's own loopback services. Public addresses keep working.
  • A locked-down service. Hoverfly runs as its own unprivileged user with no capabilities, a read-only file system apart from its state directory, a 1 GB memory cap, and no way to run any program but itself. The admin API refuses requests that would run commands (post-serve action and middleware writes) or stop the service.
  • Pinned. The official Hoverfly 1.12.17 release, checked against its SHA-256 checksum. The binaries are the unmodified upstream files.
  • Fully patched Ubuntu 24.04 LTS at build time, with unattended security upgrades switched on.

What is on the image: Hoverfly 1.12.17 and hoverctl (/opt/hoverfly/bin/), nginx, Ubuntu 24.04 LTS, cloud-init and the AWS Systems Manager agent. Settings and simulations are in /etc/hoverfly/, and the build record is in /usr/share/doc/sac-hoverfly/. SecureAnyCloud also masks the fwupd-refresh timer, because EC2 has no firmware to update.

Default user: ubuntu. Architecture: x86_64. Recommended instance type: m5.large.

Prerequisites

  • An AWS account subscribed to the listing, an EC2 key pair and a VPC subnet
  • A security group that allows TCP 22 (SSH and the proxy tunnel), TCP 443 (the admin API) and TCP 80 (redirects to HTTPS). Open them to your own networks only. Do not open port 8500, because you reach the proxy through SSH.
1

Launch the instance

In the AWS Marketplace listing, choose Continue to Subscribe, then Continue to Configuration. Select Hoverfly 1.12.17 on Ubuntu 24.04 as the software version, choose your Region, and choose Launch through EC2. Select m5.large, your key pair, a subnet and a security group as described above.

To launch with the AWS CLI instead, replace the values in angle brackets:

aws ec2 run-instances --region <region> --image-id <ami-id-from-the-listing> \
  --instance-type m5.large --key-name <your-key-pair> \
  --security-group-ids <your-security-group> --subnet-id <your-subnet> \
  --metadata-options HttpTokens=required,HttpEndpoint=enabled \
  --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=hoverfly}]'
2

Connect to your instance

On Hoverfly 1.12.17 on Ubuntu 24.04, the SSH user is ubuntu. Connect with your key pair:

ssh -i <your-key.pem> ubuntu@<public-ip>
3

Check the services

First boot takes under a minute. It generates the certificate, the API key, the admin password, the token signing secret and the MITM CA, then starts Hoverfly and nginx. Check that everything is running:

systemctl is-active hoverfly nginx hoverfly-firstboot hoverfly-egress-guard
sudo test -f /var/lib/sac/data/hoverfly-firstboot.done && echo FIRSTBOOT_DONE /opt/hoverfly/bin/hoverfly -version
active active active active FIRSTBOOT_DONE v1.12.17

Only SSH and nginx listen on the network. Hoverfly's admin API (8888) and proxy (8500) listen on loopback:

sudo ss -lntp | awk 'NR>1 && $4 !~ /^127\.0\.0\.5[34]/ {print $4, $6}' | sed -E 's/,pid=[0-9]+,fd=[0-9]+//g' | sort -u
0.0.0.0:22 users:(("sshd"),("systemd")) 0.0.0.0:443 users:(("nginx"),("nginx"),("nginx")) 0.0.0.0:80 users:(("nginx"),("nginx"),("nginx")) 127.0.0.1:8500 users:(("hoverfly")) 127.0.0.1:8888 users:(("hoverfly")) [::]:22 users:(("sshd"),("systemd")) [::]:443 users:(("nginx"),("nginx"),("nginx")) [::]:80 users:(("nginx"),("nginx"),("nginx"))
4

Get your URL and credentials

Run sudo cat /var/lib/sac/data/hoverfly-credentials.txt to see your settings. Only root can read the file. It holds the following values, all generated for this instance:

sudo sed -n 's/^\(HOVERFLY_[A-Z0-9_]*\)=.*/\1/p' /var/lib/sac/data/hoverfly-credentials.txt
HOVERFLY_URL HOVERFLY_HOST HOVERFLY_GATE_HEADER HOVERFLY_API_KEY HOVERFLY_ADMIN_USER HOVERFLY_ADMIN_PASSWORD HOVERFLY_PROXY_ADDRESS HOVERFLY_MITM_CA_CERT HOVERFLY_MITM_CA_SHA256_FINGERPRINT HOVERFLY_TLS_CERT HOVERFLY_TLS_SHA256_FINGERPRINT
  • HOVERFLY_URL is https://<public-ip>/api/, the admin API. Send HOVERFLY_API_KEY in the X-Sac-Key header with every request.
  • HOVERFLY_GATE_HEADER names that header, X-Sac-Key.
  • HOVERFLY_ADMIN_USER (admin) and HOVERFLY_ADMIN_PASSWORD are Hoverfly's own login, for the admin API's tokens and for the proxy.
  • HOVERFLY_PROXY_ADDRESS is the proxy, 127.0.0.1:8500 on the instance.
  • HOVERFLY_MITM_CA_CERT and HOVERFLY_MITM_CA_SHA256_FINGERPRINT are this instance's MITM CA (Step 7).
  • HOVERFLY_TLS_CERT and HOVERFLY_TLS_SHA256_FINGERPRINT are the admin API's own certificate. The certificate is self-signed, so when a client reports it, compare its SHA-256 fingerprint with HOVERFLY_TLS_SHA256_FINGERPRINT before you trust the connection.

The instance's private IP address and its EC2 DNS names are served too, so clients inside your VPC can use them.

5

Use the admin API

The commands in this guide run on the instance. Save these helper functions once. They read the root-only credentials file with sudo each time and hand the secrets to curl through file descriptors, so no key or password lands in your shell history or the process list:

cat > ~/hoverfly-env.sh <<'EOF' CF=/var/lib/sac/data/hoverfly-credentials.txt
H=$(sudo sed -n 's/^HOVERFLY_HOST=//p' $CF)
# api: the admin API through nginx, with this instance's API key and certificate api() { curl -s --cacert /etc/ssl/hoverfly/hoverfly.crt --resolve "$H:443:127.0.0.1" \
  -K <(sudo sed -n 's/^HOVERFLY_API_KEY=\(.*\)/header = "X-Sac-Key: \1"/p' $CF) "$@"; } # token: log in to Hoverfly and print a token token() { sudo sed -n 's/^HOVERFLY_ADMIN_PASSWORD=\(.*\)/{"username":"admin","password":"\1"}/p' $CF | api -H 'Content-Type: application/json' --data-binary @- "https://$H/api/token-auth" | jq -r .token; } # admin: an admin API call with the key and the token in $TOKEN admin() { api -K <(printf 'header = "Authorization: Bearer %s"\n' "$TOKEN") "$@"; } # pxy: a request through Hoverfly's proxy with the admin credential pxy() { curl -s -x http://127.0.0.1:8500 \
  -K <(sudo sed -n 's/^HOVERFLY_ADMIN_PASSWORD=\(.*\)/proxy-user = "admin:\1"/p' $CF) "$@"; } EOF

Now log in and ask Hoverfly for its mode and version. jq -e prints the answer and fails if the answer is not what you expect:

. ~/hoverfly-env.sh api "https://$H/api/health" | jq -e 'select(.message == "Hoverfly is healthy")'
TOKEN=$(token) admin "https://$H/api/v2/hoverfly/mode" | jq -e 'select(.mode == "simulate")' admin "https://$H/api/v2/hoverfly/version" | jq -e 'select(.version == "v1.12.17")'
{ "message": "Hoverfly is healthy" } { "mode": "simulate", "arguments": { "matchingStrategy": "strongest" } } { "version": "v1.12.17" }

Without the key, nginx answers 401 with its own WWW-Authenticate: SacKey challenge. With the key but no token, Hoverfly itself answers 401:

. ~/hoverfly-env.sh curl -s --cacert /etc/ssl/hoverfly/hoverfly.crt --resolve "$H:443:127.0.0.1" -o /dev/null \
  -w 'no key: %{http_code} %header{www-authenticate}\n' "https://$H/api/v2/hoverfly/mode" api -o /dev/null -w 'key, no token: %{http_code}\n' "https://$H/api/v2/hoverfly/mode"
no key: 401 SacKey realm="Hoverfly", header="X-Sac-Key" key, no token: 401
6

Send requests through the proxy

The image starts in simulate mode with a small sample simulation, /etc/hoverfly/simulations/startup.json, for a made-up API at api.sac-sample.test. That host does not exist, so every answer below comes from Hoverfly. Without the proxy credential, the proxy answers 407:

. ~/hoverfly-env.sh curl -s -o /dev/null -w 'no proxy credential: %{http_code}\n' -x http://127.0.0.1:8500 http://api.sac-sample.test/widgets pxy http://api.sac-sample.test/widgets | jq -e 'select(.[0].name == "Acme Sprocket")' pxy -H 'Content-Type: application/json' -d '{"name":"Gear"}' http://api.sac-sample.test/widgets | jq -e 'select(.name == "Gear")' pxy http://api.sac-sample.test/status | jq -e 'select(.servedFrom == "bodyFile")'
no proxy credential: 407 [ { "id": 1, "name": "Acme Sprocket", "color": "blue" }, { "id": 2, "name": "Acme Cog", "color": "green" } ] { "id": 3, "name": "Gear", "created": true } { "service": "sac-sample", "status": "ok", "servedFrom": "bodyFile" }

The POST answer is a template: Hoverfly copies name from your request body into the response. Hoverfly reads the /status answer from a body file in /srv/hoverfly/body-files/.

7

Use HTTPS and your instance's MITM CA

To answer an HTTPS request, Hoverfly acts as a man in the middle. It makes a certificate for the host your client asked for and signs it with a certificate authority (CA). Your client accepts that certificate only if it trusts the CA.

The MITM CA is unique to your instance. Hoverfly's built-in CA is the same for every Hoverfly user, and its private key is published in the Hoverfly source code. A client that trusts it would accept a certificate for any web site from anyone, so this image never uses it. First boot generates a new CA on your instance (RSA 3072, valid for 10 years, allowed to sign server certificates only), and Hoverfly starts with it:

  • The certificate (public, safe to copy) is /etc/hoverfly/hoverfly-ca.crt. Its SHA-256 fingerprint is HOVERFLY_MITM_CA_SHA256_FINGERPRINT in the credentials file.
  • The private key never leaves the instance. It is /etc/hoverfly/ca/ca.key, mode 0600, owned by the hoverfly service user, inside a directory that only that user and root can open. It is not in the credentials file, nothing prints it, and you never need to copy it.

Check the certificate, the key permissions and the credentials file:

openssl x509 -in /etc/hoverfly/hoverfly-ca.crt -noout -subject -ext basicConstraints
sudo stat -c '%n %a %U:%G' /etc/hoverfly/ca/ca.key
sudo grep -c 'PRIVATE KEY' /var/lib/sac/data/hoverfly-credentials.txt || true
subject=O = sac Hoverfly, CN = Hoverfly per-instance MITM CA 0aca677d X509v3 Basic Constraints: critical CA:TRUE, pathlen:0 /etc/hoverfly/ca/ca.key 600 hoverfly:hoverfly 0

Send an HTTPS request through the proxy, and verify Hoverfly's certificate against this CA only (--cacert):

. ~/hoverfly-env.sh pxy --cacert /etc/hoverfly/hoverfly-ca.crt https://api.sac-sample.test/widgets | jq -e 'select(.[1].name == "Acme Cog")'
[ { "id": 1, "name": "Acme Sprocket", "color": "blue" }, { "id": 2, "name": "Acme Cog", "color": "green" } ]

hoverfly-ca-presented shows which CA Hoverfly actually presents. It opens a TLS connection through the proxy and reads the certificate chain that Hoverfly sends. It then checks that the issuing CA is this instance's CA and not one of Hoverfly's public default CAs:

sudo hoverfly-ca-presented
HOVERFLY_CA_PRESENTED_SHA256=90:45:FF:7E:9D:29:28:A2:1E:CE:0A:26:1D:90:0C:84:30:6F:F9:58:16:45:59:81:C4:5F:F7:42:16:19:74:34 HOVERFLY_CA_INSTANCE_SHA256=90:45:FF:7E:9D:29:28:A2:1E:CE:0A:26:1D:90:0C:84:30:6F:F9:58:16:45:59:81:C4:5F:F7:42:16:19:74:34 HOVERFLY_CA_PROOF_OK

The fingerprint differs on every instance.

Trust the CA in your test clients

Trust the CA only on machines and tools that you use for testing, and remove it when you finish. First copy the certificate to your machine and check its fingerprint against HOVERFLY_MITM_CA_SHA256_FINGERPRINT:

scp -i <your-key.pem> ubuntu@<public-ip>:/etc/hoverfly/hoverfly-ca.crt ./hoverfly-ca.crt openssl x509 -in hoverfly-ca.crt -noout -fingerprint -sha256
  • curl and most command-line tools: pass the file, as above: curl --cacert hoverfly-ca.crt .... Many tools also read an environment variable: REQUESTS_CA_BUNDLE=hoverfly-ca.crt for Python requests, NODE_EXTRA_CA_CERTS=hoverfly-ca.crt for Node.js, and SSL_CERT_FILE for many others. For Java, import the certificate into a test trust store (keytool -importcert -alias hoverfly -file hoverfly-ca.crt -keystore hoverfly-test.jks) and start the JVM with -Djavax.net.ssl.trustStore=hoverfly-test.jks.
  • The system trust store: on a Linux test machine or CI runner (Ubuntu and Debian), name the file after the instance so that you can remove it later.
sudo cp hoverfly-ca.crt /usr/local/share/ca-certificates/hoverfly-<public-ip>.crt
sudo update-ca-certificates
# when you are done:
sudo rm /usr/local/share/ca-certificates/hoverfly-<public-ip>.crt && sudo update-ca-certificates --fresh

On macOS, add the certificate to the System keychain with Keychain Access, or run sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain hoverfly-ca.crt. On Windows, import it into Trusted Root Certification Authorities from an administrator prompt with certutil -addstore -f Root hoverfly-ca.crt. Chrome and Edge use the system store.

A browser: in Firefox, open Settings > Privacy & Security > Certificates > View Certificates > Authorities > Import, choose hoverfly-ca.crt and select Trust this CA to identify websites. Then set the browser's HTTP and HTTPS proxy to 127.0.0.1 port 8500 through the SSH tunnel in Step 10. When the browser asks, sign in as admin with HOVERFLY_ADMIN_PASSWORD. Use a separate browser profile for testing.

If you think the CA has been exposed, or when you hand the instance to someone else, replace it with sudo hoverfly-mint-ca (Step 13) and remove the old certificate from your trust stores.

8

Load your own simulation

A simulation is a JSON document of request/response pairs. Write one, load it with PUT /api/v2/simulation (which replaces the current simulation), and call it through the proxy. This example simulates a small Task API, then restores the sample:

. ~/hoverfly-env.sh
TOKEN=$(token)
cd "$(mktemp -d)" cat > task-simulation.json <<'JSON' { "data": { "pairs": [ { "request": { "method": [{"matcher": "exact", "value": "GET"}], "destination": [{"matcher": "exact", "value": "task.example.test"}], "path": [{"matcher": "exact", "value": "/tasks"}] }, "response": { "status": 200, "body": "[{\"id\":1,\"title\":\"Write the simulation\",\"done\":true}]", "headers": {"Content-Type": ["application/json"]} } } ] }, "meta": {"schemaVersion": "v5.3"} } JSON admin -X PUT -H 'Content-Type: application/json' --data-binary @task-simulation.json "https://$H/api/v2/simulation" | jq -e '.data.pairs | length' pxy http://task.example.test/tasks | jq -e 'select(.[0].title == "Write the simulation")' admin -X PUT -H 'Content-Type: application/json' --data-binary @/etc/hoverfly/simulations/startup.json "https://$H/api/v2/simulation" | jq -e '.data.pairs | length'
1 [ { "id": 1, "title": "Write the simulation", "done": true } ] 3

Hoverfly keeps simulations in memory and loads /etc/hoverfly/simulations/startup.json at every start. To keep your own simulation across restarts, copy it there with sudo install -m 0644 my-simulation.json /etc/hoverfly/simulations/startup.json and restart Hoverfly. The original sample stays in /etc/hoverfly/simulations/sac-sample.json.

Request bodies are limited to 32 MB. Hoverfly reads a simulation's bodyFile paths from /srv/hoverfly/body-files/.

9

Capture a real API

In capture mode Hoverfly forwards each request to the real API and records the request and response as a new pair. Switch to capture, send traffic, then switch back to simulate, and Hoverfly answers from the recording without calling the real API. This example records https://example.com/, exports the recording, then restores the sample:

. ~/hoverfly-env.sh
TOKEN=$(token) admin -X PUT -H 'Content-Type: application/json' -d '{"mode":"capture"}' "https://$H/api/v2/hoverfly/mode" | jq -e 'select(.mode == "capture")' pxy --cacert /etc/hoverfly/hoverfly-ca.crt -o /dev/null -w 'captured: %{http_code}\n' https://example.com/ admin -X PUT -H 'Content-Type: application/json' -d '{"mode":"simulate"}' "https://$H/api/v2/hoverfly/mode" | jq -e 'select(.mode == "simulate")' admin "https://$H/api/v2/simulation" > ~/my-recording.json jq -e '.data.pairs[].request.destination[0].value | select(. == "example.com")' ~/my-recording.json pxy --cacert /etc/hoverfly/hoverfly-ca.crt -o /dev/null -w 'replayed: %{http_code}\n' https://example.com/ admin -X PUT -H 'Content-Type: application/json' --data-binary @/etc/hoverfly/simulations/startup.json "https://$H/api/v2/simulation" | jq -e '.data.pairs | length' rm ~/my-recording.json
{ "mode": "capture", "arguments": {} } captured: 200 { "mode": "simulate", "arguments": { "matchingStrategy": "strongest" } } "example.com" replayed: 200 3

Hoverfly's other modes work the same way. Spy answers from the simulation and forwards anything it has no pair for. Modify and synthesize change or generate responses with middleware, which is off in this image. Diff compares the real API with the simulation. See the Hoverfly documentation for matchers, templating, delays and state.

hoverctl, Hoverfly's command-line client, is also installed. It talks to the admin API on 127.0.0.1:8888 and logs in with hoverctl login (user admin and HOVERFLY_ADMIN_PASSWORD). Enter the password carefully, because three wrong logins within ten minutes lock every user out of Hoverfly until it restarts.

10

Use Hoverfly from your own machine

The proxy is not open to the network. Forward it over SSH, then point your client or test suite at 127.0.0.1:8500 with the admin credential. To keep the password out of your shell history, put it in a curl config file:

ssh -i <your-key.pem> -N -L 8500:127.0.0.1:8500 ubuntu@<public-ip> & printf 'proxy-user = "admin:%s"\n' '<HOVERFLY_ADMIN_PASSWORD>' > hoverfly-proxy.cfg && chmod 600 hoverfly-proxy.cfg curl -x http://127.0.0.1:8500 -K hoverfly-proxy.cfg --cacert hoverfly-ca.crt https://api.sac-sample.test/widgets

The admin API is reachable on port 443. Copy its certificate, check the fingerprint against HOVERFLY_TLS_SHA256_FINGERPRINT, and send the key with every call:

scp -i <your-key.pem> ubuntu@<public-ip>:/etc/ssl/hoverfly/hoverfly.crt ./hoverfly-admin.crt openssl x509 -in hoverfly-admin.crt -noout -fingerprint -sha256 printf 'header = "X-Sac-Key: %s"\n' '<HOVERFLY_API_KEY>' > hoverfly-key.cfg && chmod 600 hoverfly-key.cfg curl --cacert hoverfly-admin.crt -K hoverfly-key.cfg https://<public-ip>/api/health

Most HTTP clients take a proxy setting (HTTP_PROXY and HTTPS_PROXY, for example http://admin:<password>@127.0.0.1:8500) and a CA file (Step 7). Hoverfly does not send CORS headers, and the admin API refuses state-changing requests from other web sites. Keep browser code away from the admin API, and drive it from your test harness instead.

11

See what the front door refuses

Without the key, every path answers 401. A wrong key gets the same 401, so there is no lockout to trip, and the key is 192 random bits. With the key, the dashboard is not served and the endpoints that would run commands or stop Hoverfly are refused. Another web site cannot change the mode, plain HTTP only redirects, and unknown host names get no answer:

. ~/hoverfly-env.sh
TOKEN=$(token) C=(curl -s --cacert /etc/ssl/hoverfly/hoverfly.crt --resolve "$H:443:127.0.0.1") "${C[@]}" -o /dev/null -w 'no key: %{http_code}\n' "https://$H/api/v2/simulation" "${C[@]}" -o /dev/null -w 'wrong key: %{http_code}\n' -K <(printf 'header = "X-Sac-Key: %s"\n' "$(openssl rand -hex 24)") "https://$H/api/v2/simulation" api -o /dev/null -w 'dashboard: %{http_code}\n' "https://$H/dashboard" admin -o /dev/null -w 'post-serve action: %{http_code}\n' -X PUT -H 'Content-Type: application/json' -d '{"actionName":"x","binary":"sh","script":"id"}' "https://$H/api/v2/hoverfly/post-serve-action" admin -o /dev/null -w 'middleware: %{http_code}\n' -X PUT -H 'Content-Type: application/json' -d '{"binary":"sh","script":"id"}' "https://$H/api/v2/hoverfly/middleware" admin -o /dev/null -w 'shutdown: %{http_code}\n' -X DELETE "https://$H/api/v2/shutdown" admin -o /dev/null -w 'cross-site mode change: %{http_code}\n' -X PUT -H 'Origin: https://evil.example' -H 'Content-Type: application/json' -d '{"mode":"capture"}' "https://$H/api/v2/hoverfly/mode" curl -s -o /dev/null -w 'plain http: %{http_code} %header{location}\n' --resolve "$H:80:127.0.0.1" "http://$H/api/health" curl -sk -o /dev/null -w 'unknown host name: %{http_code}\n' --resolve "other.example:443:127.0.0.1" https://other.example/api/health || true
no key: 401 wrong key: 401 dashboard: 404 post-serve action: 403 middleware: 403 shutdown: 403 cross-site mode change: 403 plain http: 301 https://<public-ip>/api/health unknown host name: 000

You can see Hoverfly's outbound restrictions in its unit and in the nftables rules for its service account. The metadata addresses 169.254.169.254 and fd00:ec2::254 fall inside the listed ranges:

systemctl show -p IPAddressDeny --value hoverfly | tr ' ' '\n' | sort
sudo nft list table inet sac_hoverfly_egress | grep -oE '(oifname "lo"|ip6? daddr \{).*(accept|reject.*)' | sed -E 's/counter packets [0-9]+ bytes [0-9]+ //'
168.63.129.16/32 169.254.0.0/16 fd00:ec2::254/128 fe80::/10 oifname "lo" ip daddr 127.0.0.53 udp dport 53 accept oifname "lo" ip daddr 127.0.0.53 tcp dport 53 accept oifname "lo" ct state new reject ip daddr { 168.63.129.16, 169.254.0.0/16 } reject with icmp port-unreachable ip6 daddr { fd00:ec2::254, fe80::/10 } reject with icmpv6 port-unreachable

As a result, a capture, a spy request, a remote post-serve action or a body file URL that points at the metadata service or at this instance's own ports never connects. Public addresses work normally.

12

Run the self-test

The image includes a self-test. It checks every refusal of the gate (including 25 wrong keys followed by the right one), Hoverfly's own login, the refused endpoints, the proxy over HTTP and HTTPS, the CA Hoverfly presents, the request policy, the listening ports and the certificate:

sudo /usr/local/sbin/hoverfly-selftest
HOVERFLY_SELFTEST_OK
13

Rotate the key, the password or the CA

Each helper generates a new secret, puts it in force and writes it to the credentials file. None of them prints a secret. A new API key works at once, and the old one stops working:

sudo hoverfly-rotate-key
hoverfly-rotate-key: a new API key is in force; read it with:
sudo grep HOVERFLY_API_KEY= /var/lib/sac/data/hoverfly-credentials.txt

A new admin password and token signing secret restart Hoverfly. Every issued token stops working, and the simulation reloads from startup.json, so save your own simulation first (Step 8):

sudo hoverfly-rotate-password
hoverfly-rotate-password: a new admin password is in force; read it with:
sudo grep HOVERFLY_ADMIN_PASSWORD= /var/lib/sac/data/hoverfly-credentials.txt

A new MITM CA also restarts Hoverfly. Replace the old certificate in your trust stores with the new /etc/hoverfly/hoverfly-ca.crt. To rotate the CA, run:

sudo hoverfly-mint-ca
sudo hoverfly-ca-presented | tail -n 1
hoverfly-mint-ca: MITM CA SHA-256 fingerprint 18:D5:1A:47:2A:DE:FE:7D:D6:95:00:9A:3D:4D:7F:CC:89:79:65:97:1B:81:A6:C1:D9:E9:CF:D5:B4:A1:26:19 HOVERFLY_CA_PROOF_OK
14

Use your own domain name

Point a DNS record at the instance, then set the name. The helper generates a new certificate for the name and the instance's addresses, pins nginx to those names so that other host names get no answer, and prints the new fingerprint:

sudo hoverfly-set-hostname <your-domain>

To use a CA-issued certificate instead, replace /etc/ssl/hoverfly/hoverfly.crt and /etc/ssl/hoverfly/hoverfly.key with your own, keeping the key root-only with mode 0600. Then run sudo systemctl reload nginx. If the instance's public IP changes after a stop and start, run sudo hoverfly-set-hostname with the new address, or use an Elastic IP.

15

Security notes

The admin API certificate generated at first boot is a server certificate only, so it cannot sign other certificates. Only the MITM CA can sign certificates, and it can sign server certificates only (pathlen:0). To confirm, run:

openssl x509 -in /etc/ssl/hoverfly/hoverfly.crt -noout -ext basicConstraints,extendedKeyUsage
X509v3 Basic Constraints: critical CA:FALSE X509v3 Extended Key Usage: TLS Web Server Authentication

Hoverfly's public default CA keys. The official Hoverfly binaries contain the private keys of Hoverfly's two public default CAs, as every copy of Hoverfly does. Those keys are public, and the image never uses them: Hoverfly always starts with this instance's CA and refuses to start with a default one. The binaries are byte-identical to the files in the official release zip (hoverfly_bundle_linux_amd64.zip). The build record /usr/share/doc/sac-hoverfly/BUILD-INFO.txt lists the zip's SHA-256 together with each file's. Check them at any time:

cd / && sha256sum -c /usr/share/doc/sac-hoverfly/SHA256SUMS
opt/hoverfly/bin/hoverfly: OK opt/hoverfly/bin/hoverctl: OK opt/hoverfly/LICENSE: OK

Known advisories with no reachable path. The build record lists the advisories that remain in the shipped binaries and explains why none is reachable. For example, the end-of-life dashboard is not served, and the middleware API is off. List them with:

grep -oE '^(GO-[0-9-]+( / GO-[0-9-]+)?|Embedded admin dashboard)' /usr/share/doc/sac-hoverfly/RESIDUALS
GO-2026-6866 / GO-2026-6860 GO-2026-5932 GO-2025-3944 Embedded admin dashboard
16

Keep it up to date

Ubuntu security updates install automatically. To apply everything now:

sudo apt-get update && sudo apt-get upgrade -y

New Hoverfly releases arrive as new versions of the AWS Marketplace listing. Launch the new version and copy your simulations across from /etc/hoverfly/simulations/.

Support

  • Email: sales@secureanycloud.com
  • Website: https://secureanycloud.com

Hoverfly is developed by SpectoLabs and released under the Apache License 2.0. SecureAnyCloud is not affiliated with SpectoLabs. The developer and API tools guide covers the other versions in this listing.

Deploy on AWS

Launch Hoverfly 1.12.17 on Ubuntu 24.04 on AWS with 24/7 support from SecureAnyCloud.

View on Marketplace

Need Help?

Our support team is available 24/7.

sales@secureanycloud.com

Deploy on AWS