Toxiproxy on Ubuntu 24.04 on Azure User Guide
Overview
This guide covers the deployment and configuration of Toxiproxy on Ubuntu 24.04 on Azure using cloudimg Azure Marketplace images. Toxiproxy is a TCP proxy for deterministic resilience and chaos testing. It sits between your application and its upstream dependencies (databases, caches, queues, APIs) and injects controllable failures called toxics: latency, bandwidth limits, timeouts, connection resets and data slicing. Because the failures are deterministic and scriptable, you can reproduce a slow database or a flaky network exactly, on demand, in a test suite or a staging environment, instead of waiting for it to happen in production.
The image installs the official Toxiproxy binaries (server and CLI, pinned at build) and runs toxiproxy-server under systemd, so a working proxy is available within minutes of launch.
A self contained demo, working on first boot. The image bundles a small HTTP upstream on the loopback interface and a demo proxy that forwards a public port to it, with a sample latency toxic already applied. So toxiproxy-cli list shows a real, failure injecting proxy immediately, and a request through the demo port reaches the upstream with a visible injected delay. Point the demo proxy, or a new proxy, at your own dependency to reproduce network failures.
Security by design — the control API is loopback only. The Toxiproxy control API is unauthenticated and can create proxies to arbitrary destinations, which would be a serious exposure if it were reachable from the network. This image therefore binds the control API to the loopback interface only (127.0.0.1:8474). You drive it with the toxiproxy-cli command line tool over SSH or from within the virtual machine; only the demo proxy's data port and SSH are ever opened.
What is included:
-
Toxiproxy (official pinned server + CLI binaries), run under systemd as the unprivileged
toxiproxyuser (toxiproxy.service) -
The control API on
127.0.0.1:8474, bound to loopback only and never exposed to the network -
A self contained demo: a bundled loopback upstream (
toxiproxy-demo-upstream.service) and a demo proxy on port 8080 with a sample latency toxic, restored on every boot -
A shipped round trip self test that proves the demo proxy forwards traffic, that a latency toxic changes the observed round trip, and that the control API is loopback only
-
Unattended security upgrades left enabled so the server keeps receiving patches
Prerequisites
-
Active Azure subscription, SSH public key, VNet + subnet in the target region
-
Subscription to the Toxiproxy listing on Azure Marketplace
-
Network Security Group rules allowing TCP 22 (admin) and TCP 8080 (the demo proxy data port). Do not open TCP 8474 — the control API is intentionally loopback only
Recommended virtual machine size: Standard_B2s (2 vCPU, 4 GB RAM) for typical use. Heavier proxy throughput should use Standard_D2s_v5 or larger.
Step 1: Deploy from the Azure Portal
Search Toxiproxy in Marketplace, select the cloudimg publisher, and click Create. Configure the Network Security Group to allow TCP 8080 (the demo proxy) from the clients that will use it, and TCP 22 for administration. Leave port 8474 closed — the control API is driven locally, not over the network.
Step 2: Deploy from the Azure CLI
RG="resilience-test"; LOCATION="eastus"; VM_NAME="toxiproxy1"
GALLERY_IMAGE_ID="/subscriptions/<sub-id>/resourceGroups/azure-cloudimg/providers/Microsoft.Compute/galleries/cloudimgGallery/images/toxiproxy-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 the demo proxy + admin ports on the VM's NSG (NOT 8474):
az vm open-port --resource-group "$RG" --name "$VM_NAME" --port 8080 --priority 1001
az vm open-port --resource-group "$RG" --name "$VM_NAME" --port 22 --priority 1002
Step 3: First boot
On first boot the image resolves the VM public IP, starts the bundled upstream and Toxiproxy, restores the demo proxy with its sample latency toxic, and writes a per VM instance info file. This completes within a minute. SSH in as azureuser and read the instance details:
sudo cat /root/toxiproxy-credentials.txt
The file records this VM's connection facts (host, control API endpoint, and the demo proxy name, listen port and upstream). Toxiproxy has no authentication store, so there is no password to rotate — the control API is protected by being bound to loopback only.
Step 4: Confirm the server is running
toxiproxy.service and the bundled toxiproxy-demo-upstream.service are active. The control API listens on 127.0.0.1:8474 (loopback), the demo upstream on 127.0.0.1:8899 (loopback), and the demo proxy on 8080 (reachable on the VM).
systemctl is-active toxiproxy.service
systemctl is-active toxiproxy-demo-upstream.service
/usr/local/bin/toxiproxy-server --version
ss -tln | grep -E ':8474|:8080|:8899'
Expected output:
active
active
toxiproxy-server version 2.12.0
LISTEN 0 5 127.0.0.1:8899 0.0.0.0:*
LISTEN 0 4096 127.0.0.1:8474 0.0.0.0:*
LISTEN 0 4096 *:8080 *:*

Step 5: See the demo proxy and its sample toxic
List the proxies, then inspect the demo. The demo forwards the public port 8080 to the bundled loopback upstream, and carries a sample downstream latency toxic.
toxiproxy-cli list
toxiproxy-cli inspect demo
Expected output:
demo [::]:8080 127.0.0.1:8899 enabled 1
cloudimg_latency type=latency stream=downstream toxicity=1.00 attributes=[ jitter=0 latency=500 ]

Step 6: Send traffic through the demo proxy
Send an HTTP request through the demo proxy on port 8080. It reaches the bundled upstream and returns HTTP 200, but the response is delayed by the sample 500 millisecond latency toxic — visible in the round trip time.
curl -s -o /dev/null -w 'HTTP %{http_code}, round-trip %{time_total}s\n' http://localhost:8080/
Expected output (about half a second, from the sample toxic):
HTTP 200, round-trip 0.501998s
Step 7: Inject and remove a toxic on demand
This is what Toxiproxy is for: change the network conditions deterministically, on demand. Add a stronger latency toxic, observe the slower round trip, then remove it and confirm the proxy is fast again. Because the flags come before the proxy name, the proxy name is always the last argument.
toxiproxy-cli toxic add -t latency -a latency=2000 -n slow_demo -d demo
curl -s -o /dev/null -w 'with 2000ms toxic: HTTP %{http_code}, round-trip %{time_total}s\n' http://localhost:8080/
toxiproxy-cli toxic remove -n slow_demo demo
Expected output:
Added downstream latency toxic 'slow_demo' on proxy 'demo'
with 2000ms toxic: HTTP 200, round-trip 2.503320s
Removed toxic 'slow_demo' on proxy 'demo'

Step 8: The control API is loopback only
The Toxiproxy control API is unauthenticated, so it must never be reachable from the network. This image binds it to 127.0.0.1:8474. You can prove it: the API answers on the loopback address but is refused on the VM's own network address.
curl -s -o /dev/null -w 'API on 127.0.0.1:8474 -> HTTP %{http_code}\n' http://127.0.0.1:8474/version
PIP=$(hostname -I | awk '{print $1}')
curl -sS -m 3 "http://$PIP:8474/version" >/dev/null 2>&1 \
&& echo "reachable on $PIP:8474 (unexpected)" \
|| echo "control API refused on $PIP:8474 (loopback only, as designed)"
Expected output:
API on 127.0.0.1:8474 -> HTTP 200
control API refused on 10.0.0.19:8474 (loopback only, as designed)

Step 9: Point a proxy at your own dependency
To test your own application, create a proxy in front of the dependency you want to disrupt (a database, cache, API, or the like). Your application then connects to the proxy's listen address instead of the real dependency, and you add or remove toxics to shape the connection. For example, put a proxy in front of a Postgres database:
# Create a proxy: your app connects to port 15432, traffic forwards to the real database.
toxiproxy-cli create -l 0.0.0.0:15432 -u db-internal.example:5432 pg
# Add 3 seconds of latency, then a bandwidth cap, then a timeout — one at a time or together:
toxiproxy-cli toxic add -t latency -a latency=3000 -n lat -d pg
toxiproxy-cli toxic add -t bandwidth -a rate=100 -n slow -d pg
toxiproxy-cli toxic add -t timeout -a timeout=1500 -n to -d pg
# Remove a toxic, or disable the whole proxy to simulate the dependency going down:
toxiproxy-cli toxic remove -n lat pg
toxiproxy-cli toggle pg
Open the proxy's listen port on your VM's Network Security Group only if the client is remote; within the VM, no port needs opening.
Step 10: Toxic types reference
Toxics are applied to the downstream (data returning to the client, -d, the default) or upstream (data flowing to the dependency, -u) direction. The common types and their key attributes:
latency -a latency=<ms> -a jitter=<ms> add delay (optionally jittered)
bandwidth -a rate=<KB/s> cap throughput
slow_close -a delay=<ms> delay the TCP close
timeout -a timeout=<ms> hold then drop with no data (0 = hold forever)
reset_peer -a timeout=<ms> send a TCP RST after the delay
slicer -a average_size=<b> -a delay=<us> slice data into small packets
limit_data -a bytes=<n> close the connection after N bytes
Use --toxicity <0..1> (or --tox) to apply a toxic to only a fraction of connections, which is ideal for simulating intermittent failures.
Step 11: Security recommendations
-
Never open port 8474. The control API is unauthenticated by design. Keep it loopback only and drive it over SSH or from within the VM. If you must reach it from elsewhere, tunnel it over SSH (
ssh -L 8474:127.0.0.1:8474 azureuser@<vm>), never open it on the NSG. -
Scope the demo and your own proxy ports. Allow the proxy data ports (for example 8080) only from the client networks that need them.
-
Treat proxies as test infrastructure. Toxiproxy is intended for test and staging environments; do not place it on a production data path.
-
Keep the OS and Toxiproxy patched. Unattended security upgrades remain enabled on the running VM.
Step 12: Support and Licensing
Toxiproxy is developed by Shopify and distributed under the MIT license. This cloudimg image bundles the unmodified official Toxiproxy binaries. cloudimg provides the packaging, the secure by default posture (control API bound to loopback only), the self contained demo, the systemd integration, and 24/7 support with a guaranteed 24 hour response SLA.
cloudimg is not affiliated with or endorsed by Shopify or the Toxiproxy project. Toxiproxy is a mark of its respective owner and is used here only to identify the software.
Deploy on Azure
Find Toxiproxy 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.