Toxiproxy
Overview
This guide covers deploying and configuring Toxiproxy on Ubuntu 24.04 on Azure from the SecureAnyCloud Azure Marketplace image. 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. You do not have to wait for the failure 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 works 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. 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.
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 you get:
- Toxiproxy (official pinned server and 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
- An active Azure subscription, an SSH public key, and a VNet and subnet in the target region
- A subscription to the Toxiproxy listing on Azure Marketplace
- Network security group rules that allow 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. For heavier proxy throughput, useStandard_D2s_v5or larger.
Deploy from the Azure Portal
Search for Toxiproxy in the Marketplace, select the SecureAnyCloud publisher, and select 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. You drive the control API locally, not over the network.
Deploy from the Azure CLI
Create the resource group and VM, then open the demo proxy and SSH ports:
RG="resilience-test"; LOCATION="eastus"; VM_NAME="toxiproxy1" IMAGE_URN="sac1647283583153:toxiproxy-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:toxiproxy-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 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 1002First 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.txtThe file records this VM's connection facts: the host, the 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.
Confirm the server is running
Both toxiproxy.service and the bundled toxiproxy-demo-upstream.service should be 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). Run:
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 *:*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 demoExpected output:
demo [::]:8080 127.0.0.1:8899 enabled 1 sac_latency type=latency stream=downstream toxicity=1.00 attributes=[ jitter=0 latency=500 ]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. The sample 500 millisecond latency toxic delays the response, and the delay shows 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.501998sInject and remove a toxic on demand
This is what Toxiproxy is for: changing 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. Put the flags before the proxy name, so 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 demoExpected 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'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 verify this: 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)Point a proxy at your own dependency
To test your own application, create a proxy in front of the dependency you want to disrupt, such as a database, cache or API. 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 pgOpen 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.
Toxic types reference
A toxic applies to the downstream direction (data returning to the client, -d, the default) or the upstream direction (data flowing to the dependency, -u). The common types and their key attributes are:
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 bytesUse --toxicity <0..1> (or --tox) to apply a toxic to only a fraction of connections. This is ideal for simulating intermittent failures.
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.
Support and Licensing
Shopify develops Toxiproxy and distributes it under the MIT license. This SecureAnyCloud image bundles the unmodified official Toxiproxy binaries. SecureAnyCloud 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.
SecureAnyCloud 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 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 inquiries.
Deploy on Azure
Launch Toxiproxy resilience testing 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
This guide covers deploying and using Toxiproxy on AWS from the SecureAnyCloud AWS Marketplace image. 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.
With toxics, you can reproduce a slow database or a flaky network exactly, on demand. You do not have to wait for the failure to happen in production.
The image installs the official Toxiproxy release binaries (v2.12.0, pinned and SHA256-verified at build time) and runs toxiproxy-server under systemd, so a working proxy is available within minutes of launch with no manual compilation.
A self-contained demo works on first boot. The image ships a bundled loopback HTTP upstream, a proxy named demo that forwards a public port to it, and a sample latency toxic already applied. Listing the proxies and curling through the demo port shows a real, working, failure-injecting proxy the moment the instance boots.
The control API is never exposed unauthenticated. The Toxiproxy control API is unauthenticated and can create proxies to arbitrary destinations, so this image binds it to the loopback interface only (127.0.0.1:8474). For remote and programmatic access, an nginx TLS reverse proxy on port 8443 fronts it, gated by an HTTP Basic credential generated uniquely on each instance at first boot and never baked into the image.
Only SSH (22), the demo proxy's data port (8080) and the authenticated control-API endpoint (8443) are opened. The raw control-API port 8474 is never exposed to the network.
What you get:
- Toxiproxy 2.12.0 (official release binaries, pinned and SHA256-verified at build), run under systemd as the unprivileged
toxiproxyuser (toxiproxy.service) - A self-contained demo: a bundled loopback upstream (
toxiproxy-demo-upstream.service) and a demo proxy on port 8080 with a sample 500 ms latency toxic, live on first boot - The
toxiproxy-clicommand line client for driving the control API locally - An nginx TLS front door on port 8443 for the control API, gated by a per-instance HTTP Basic credential generated on first boot and never baked into the image
- The raw control API bound to loopback only, shown to be refused on the instance's non-loopback address
- Unattended security upgrades left enabled so the operating system keeps receiving patches
Connecting to your instance
Connect over SSH as the default login user for your operating system variant, using the EC2 key pair you selected at launch.
OS variant SSH login user Example
Ubuntu 24.04 ubuntu ssh -i your-key.pem ubuntu@<instance-ip>
Once connected, read the per-instance connection facts and control-API credential from the root-only credentials file:
sudo cat /root/toxiproxy-credentials.txtThis file (mode 0600, root only) holds this instance's public host, the authenticated control-API URL, the per-instance HTTP Basic username and password, and the demo proxy URL. The credential is unique to this instance. First boot generates it, and it differs on every instance.
Confirming the services are running
Toxiproxy runs under systemd alongside the bundled demo upstream and the nginx control-API front door. Check the services and the listening ports:
systemctl is-active toxiproxy-demo-upstream.service toxiproxy.service nginx.serviceactive active activesudo ss -tlnp | grep -E ':8474|:8080|:8443|:8899'LISTEN 0 511 0.0.0.0:8443 0.0.0.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 *:*Note the bind addresses. The raw control API (8474) and the demo upstream (8899) listen on 127.0.0.1 only. The demo proxy data port (8080) and the nginx TLS front door (8443) are network-reachable.
The bundled demo proxy
Drive the control API locally with toxiproxy-cli. List the proxies to see the bundled demo:
export TOXIPROXY_URL=http://127.0.0.1:8474 toxiproxy-cli listdemo [::]:8080 127.0.0.1:8899 enabled 1Inspect it to see the sample latency toxic that ships applied:
toxiproxy-cli inspect demosac_latency type=latency stream=downstream toxicity=1.00 attributes=[ jitter=0 latency=500 ]Seeing a toxic shape traffic
The demo proxy forwards http://<instance-ip>:8080/ to the bundled loopback upstream. With the sample 500 ms latency toxic applied, a request through the proxy takes about half a second. Remove the toxic and the same request returns almost instantly:
# through the proxy, with the sample 500ms toxic curl -s -o /dev/null -w 'http_code=%{http_code} time_total=%{time_total}s\n' http://127.0.0.1:8080/http_code=200 time_total=0.502454s# remove the toxic and try again toxiproxy-cli toxic remove -n sac_latency demo curl -s -o /dev/null -w 'http_code=%{http_code} time_total=%{time_total}s\n' http://127.0.0.1:8080/http_code=200 time_total=0.001751sThe round trip drops from about 500 ms to about 2 ms, which shows the toxic shaping the traffic. Re-add it, or add your own, at any time:
toxiproxy-cli toxic add -t latency -a latency=500 -n sac_latency -d demoSecurity: loopback-only control API and the authenticated front door
The Toxiproxy control API is unauthenticated by design, and this image never exposes it unauthenticated. The raw control API answers only on loopback and is refused on the instance's own non-loopback address:
curl -s -o /dev/null -w ' 127.0.0.1:8474 -> %{http_code}\n' http://127.0.0.1:8474/version
PRIV=$(hostname -I | awk '{print $1}')
curl -s -m 3 -o /dev/null -w " $PRIV:8474 -> %{http_code}\n" http://$PRIV:8474/version || echo " $PRIV:8474 -> connection refused"127.0.0.1:8474 -> 200 172.31.83.36:8474 -> connection refusedFor remote access, the nginx TLS front door on port 8443 requires the per-instance HTTP Basic credential. A request with no credential or a wrong credential is rejected with 401, and only the per-instance credential is accepted:
U=$(sudo grep ^CONTROL_API_USER= /root/toxiproxy-credentials.txt | cut -d= -f2-)
P=$(sudo grep ^CONTROL_API_PASSWORD= /root/toxiproxy-credentials.txt | cut -d= -f2-)
curl -sk -o /dev/null -w ' no credential -> %{http_code}\n' https://127.0.0.1:8443/version
curl -sk -u "$U:wrong" -o /dev/null -w ' wrong credential -> %{http_code}\n' https://127.0.0.1:8443/version
curl -sk -u "$U:$P" -o /dev/null -w ' per-instance credential -> %{http_code}\n' https://127.0.0.1:8443/versionno credential -> 401 wrong credential -> 401 per-instance credential -> 200To call the control API remotely from your workstation, run the command below. The TLS certificate is a per-instance self-signed certificate, so pass -k or trust it.
curl -k -u toxictl:<your-password> https://<public-ip>:8443/proxiesUsing Toxiproxy against your own dependencies
Point a new proxy at your own upstream dependency, then inject toxics to reproduce failure modes. For example, put a proxy in front of a database on db.internal:5432 and add latency:
export TOXIPROXY_URL=http://127.0.0.1:8474 toxiproxy-cli create -l 0.0.0.0:15432 -u db.internal:5432 mydb toxiproxy-cli toxic add -t latency -a latency=2000 -n slow_db -d mydbNow point your application at the proxy (15432) instead of the database directly. It experiences a consistent 2-second delay. Other toxic types include bandwidth, timeout, slow_close, reset_peer and slicer. Remove a toxic with toxiproxy-cli toxic remove -n <name> <proxy> and delete a proxy with toxiproxy-cli delete <proxy>.
Open the matching port in your instance's security group to expose a proxy's data plane to your test clients. Keep the control API loopback-only or behind the authenticated front door, and never expose port 8474 directly.
Support
SecureAnyCloud provides 24/7 technical support for this product by email and live chat. Support covers:
- Contact: sales@secureanycloud.com
- Deployment and initial configuration
- Driving the Toxiproxy control API and the
toxiproxy-clicommand - Designing toxics to reproduce your production failure modes
- Wiring the authenticated control-API front door to your own domain and TLS certificate
SecureAnyCloud is not affiliated with or endorsed by Shopify or the Toxiproxy project. Toxiproxy is distributed under the MIT license. All product and company names are trademarks or registered trademarks of their respective holders.
Deploy on AWS
Launch Toxiproxy with 24/7 support from SecureAnyCloud.
View on Marketplace
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com