Tinyproxy 1.11.1
Overview
This guide shows you how to launch and verify Tinyproxy 1.11.1 on Ubuntu 24.04 from SecureAnyCloud on Amazon EC2. It is one version of the SecureAnyCloud Hardened WireGuard VPN & VPN, Proxy and Remote Access AMIs listing on AWS Marketplace. You choose it as the software version when you subscribe and launch. The listing's guide hub describes the other VPN, proxy and remote access servers in the listing.
Tinyproxy is a small, fast HTTP and HTTPS forward proxy daemon. Clients send their outbound web requests to it, and it fetches them on their behalf. You can use it to give instances in private subnets controlled web access, to put one egress address in front of a group of hosts, or to reach the web from a locked-down network through a single audited point. It has no database and no web console. You configure it with one text file.
The image installs Tinyproxy 1.11.1 from the Ubuntu 24.04 LTS archive, which the Ubuntu security team patches. Unattended security upgrades stay on for your instance.
What you get:
- Tinyproxy 1.11.1 (
tinyproxy.service) listening on TCP 8888 and running as the unprivilegedtinyproxyuser - HTTP Basic proxy authentication with a password generated on your instance's first boot
- Not an open proxy. Only the instance itself and private (RFC 1918 / ULA) source addresses may connect
CONNECTtunnelling limited to the TLS ports 443 and 563, and theViaheader turned off- No metadata access for the proxy.
tinyproxy.servicecannot reach the instance metadata service - A self-test,
/usr/local/sbin/tinyproxy-roundtrip.sh
Default user: ubuntu. Architecture: x86_64. Root volume: 8 GiB gp3.
Security posture
An open forward proxy on the internet is quickly found and abused for spam, credential stuffing and hiding attack traffic. This image is built to prevent that by default:
- Authentication is mandatory. Every request must carry the user SecureAnyCloud and the password created on your instance's first boot. A request with no credentials gets HTTP 407, and a wrong password gets HTTP 401. No password ships in the image, so no two instances share one.
- Private sources only. The
Allowrules admit127.0.0.1,::1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16andfc00::/7. Any other source address is refused with HTTP 403 before authentication, even with the right password. There is noAllow 0.0.0.0/0. - The listing security group opens SSH only. Port 8888 stays closed until you open it to your own VPC or client networks, or reach it through an SSH tunnel. Clients use the instance's private IP.
- No SSRF to instance credentials. A proxy fetches whatever URL a client names, so
tinyproxy.serviceis blocked from the instance metadata service (169.254.169.254, fd00:ec2::254). A request forhttp://169.254.169.254/through the proxy never gets an answer, even with valid credentials. Amazon Time Sync (169.254.169.123) still works. - IMDSv2 required. The AMI is registered with
ImdsSupport v2.0, so instances launched from it refuse token-less (IMDSv1) metadata requests. - Fails closed. Tinyproxy starts only after first boot has written the password and a ready marker. A start-up check refuses to run it without a
BasicAuthline or with an allow-all rule. If first boot cannot finish, the proxy stays stopped, and first boot tries again on the next boot. - The password file is protected.
/etc/tinyproxy/tinyproxy.confholds the password and is readable only by root and thetinyproxygroup./root/tinyproxy-credentials.txtis readable only by root. The password is never written to a log. - Per-instance identity. SSH host keys and the machine ID are generated fresh on every instance.
Prerequisites
- An AWS account and permission to launch EC2 instances
- An EC2 key pair in the Region you launch in
- A VPC subnet for the proxy, and the CIDR ranges of the clients that will use it
Recommended instance type: m5.large. A small proxy for a handful of clients runs comfortably on t3.small or larger.
Connecting to your instance
Version Operating system SSH user
Tinyproxy 1.11.1 on Ubuntu 24.04 Ubuntu 24.04 LTS ubuntu
Launch the instance
Option A: AWS Marketplace console
- Open the SecureAnyCloud Hardened WireGuard VPN & VPN, Proxy and Remote Access AMIs listing on AWS Marketplace. Choose View purchase options, then Subscribe. One subscription covers every version in the listing.
- When the subscription is active, choose Launch your software.
- Choose One-click launch from AWS Marketplace, or Launch from EC2 Console for the full launch wizard. In Version, choose Tinyproxy 1.11.1 on Ubuntu 24.04, then choose your Region.
- Pick an instance type and your key pair.
m5.largeis recommended. The software charge is $0.04 per vCPU per hour. - Set the security group. The listing's default group allows SSH (22) only. Restrict it to your own IP address. You open the proxy port to your clients in Step 5.
- Choose your VPC and subnet. Leave the metadata defaults, because the image already requires IMDSv2. Then choose Launch.
Option B: AWS CLI
Run this on your own workstation. It creates a security group that allows SSH from your management address and the proxy port from your VPC only, and then launches the instance. Replace the AMI ID with the one shown for your Region on the Marketplace launch page. Replace the VPC, subnet, key pair and CIDR ranges with your own:
SG=$(aws ec2 create-security-group --group-name tinyproxy \
--description "Tinyproxy forward proxy" --vpc-id vpc-0123456789abcdef0 \
--query GroupId --output text)
aws ec2 authorize-security-group-ingress --group-id "$SG" --protocol tcp --port 22 --cidr <your-mgmt-cidr>
aws ec2 authorize-security-group-ingress --group-id "$SG" --protocol tcp --port 8888 --cidr 10.0.0.0/16
aws ec2 run-instances \
--image-id ami-0123456789abcdef0 \
--instance-type m5.large \
--key-name my-key-pair \
--security-group-ids "$SG" \
--subnet-id subnet-0123456789abcdef0 \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=tinyproxy}]'You do not need --metadata-options. The AMI already requires IMDSv2.
Connect and read the credentials
Connect as ubuntu with the key pair you chose:
ssh -i ~/.ssh/my-key-pair.pem ubuntu@<public-ip>First boot finishes within a minute of launch. It generates this instance's proxy password, writes it into the Tinyproxy configuration, records the instance's private IP, starts the proxy and runs the self-test. The details are in /root/tinyproxy-credentials.txt, which only root can read. This command prints everything except the password line:
sudo grep -v '^proxy\.pass=' /root/tinyproxy-credentials.txt# Tinyproxy 1.11.1 on Ubuntu 24.04 (sac AWS Marketplace image) - THIS instance.
# The proxy password below was generated on this instance's first boot and exists nowhere else. proxy.user=sac proxy.host=172.31.91.11 proxy.port=8888 proxy.endpoint=172.31.91.11:8888 proxy.public_ip=3.83.230.145 # # NOT AN OPEN PROXY: only localhost and private (RFC1918/ULA) source addresses may connect # (Allow lines in /etc/tinyproxy/tinyproxy.conf), and every request must carry the user and # password above (HTTP 407 without credentials, 401 with wrong ones). The proxy cannot reach the instance metadata service. # # NETWORK ACCESS: the listing security group opens SSH only. To serve clients in your VPC, # add an inbound rule for TCP 8888 ONLY from your VPC CIDR or client security group - never # 0.0.0.0/0 - and point clients at the PRIVATE IP above. Or use an SSH tunnel: # ssh -i <key.pem> -N -L 8888:127.0.0.1:8888 ubuntu@<public-ip> # # Test from a client: # curl -x http://sac:<password>@172.31.91.11:8888 https://example.com/ -sS -o /dev/null -w '%{http_code}\n' # Rotate the password: edit the 'BasicAuth sac <password>' line in # /etc/tinyproxy/tinyproxy.conf, update this file, then:
sudo systemctl restart tinyproxy
# Self-test:
sudo /usr/local/sbin/tinyproxy-roundtrip.sh
# User guide: https://secureanycloud.com/stacks/tinyproxy-1-11-1/Print the password itself only when you need it, with sudo sed -n 's/^proxy\.pass=//p' /root/tinyproxy-credentials.txt. The file contains a proxy.pass= line with the password, which is about 40 characters long.
Confirm the proxy is running
Confirm that tinyproxy.service is active, that first boot has completed, and that Tinyproxy is the process listening on port 8888 on every interface (IPv4 and IPv6). The security group and the Allow rules decide who can reach it.
systemctl is-active tinyproxy.service tinyproxy-firstboot.service tinyproxy -v sudo ss -Htlnp 'sport = :8888'active active tinyproxy 1.11.1 LISTEN 0 1024 0.0.0.0:8888 0.0.0.0:* users:(("tinyproxy",pid=9022,fd=3)) LISTEN 0 1024 [::]:8888 [::]:* users:(("tinyproxy",pid=9022,fd=4))Run the self-test
The shipped self-test checks the whole security posture in one run. It confirms these results:
- An anonymous request is refused with 407, and a wrong password is refused with 401.
- The instance's password fetches a page from a local test server with 200.
- A request for the instance metadata service through the proxy gets no answer, while the same request straight from the instance shell succeeds.
- The only non-loopback listening ports are 22 and 8888.
The test takes about 20 seconds because it waits out the blocked metadata requests.
sudo /usr/local/sbin/tinyproxy-roundtrip.shround-trip OK: anonymous 407, wrong password 401, per-instance password 200 (body proxied); instance metadata through the proxy never answers (connect dropped by the tinyproxy.service IMDS deny) while the host shell reaches it (200); listening tcp: 22 8888Open the proxy to your clients
Add an inbound rule for TCP 8888 to the instance's security group, only from the networks that need the proxy. These can be your VPC CIDR, a subnet or a client security group. Never open 8888 to 0.0.0.0/0. The Allow rules would still refuse every public source, but a restrictive rule also keeps the port private at the network edge:
aws ec2 authorize-security-group-ingress --group-id <sg-id> --protocol tcp --port 8888 --cidr <vpc-cidr>Point clients at the proxy's private IP (proxy.host in the credentials file). On a Linux client, set the standard proxy variables with the user and password from Step 2:
export http_proxy="http://sac:<PROXY_PASS>@<PROXY_HOST>:8888"
export https_proxy="$http_proxy"
export no_proxy="localhost,127.0.0.1,169.254.169.254" curl -sS -o /dev/null -w '%{http_code}\n' https://example.com/Keep 169.254.169.254 in no_proxy on the clients, so each client reads its own instance metadata directly.
Using the proxy from your workstation through SSH
To use the proxy from a machine outside the VPC without opening port 8888, forward the port over SSH. Then point your browser or tools at 127.0.0.1:8888. Requests reach Tinyproxy from 127.0.0.1, which the Allow rules admit. The password is still required:
ssh -i ~/.ssh/my-key-pair.pem -N -L 8888:127.0.0.1:8888 ubuntu@<public-ip>Make requests through the proxy
On the instance, these requests show each layer at work. They send no credentials (407), a wrong password (401), and the instance's password over plain HTTP and HTTPS (CONNECT to port 443). The password is passed to curl on standard input (-K -), so it never appears in a process listing or your shell history.
PROXY_PASS="$(sudo sed -n 's/^proxy\.pass=//p' /root/tinyproxy-credentials.txt)" curl -s -o /dev/null -w 'no credentials: HTTP %{http_code}\n' -x http://127.0.0.1:8888 http://example.com/ printf 'proxy-user = "sac:wrong-password"\n' | curl -K - -s -o /dev/null -w 'wrong password: HTTP %{http_code}\n' -x http://127.0.0.1:8888 http://example.com/ printf 'proxy-user = "sac:%s"\n' "$PROXY_PASS" | curl -K - -s -o /dev/null -w 'with password: HTTP %{http_code} (http)\n' -x http://127.0.0.1:8888 http://example.com/ printf 'proxy-user = "sac:%s"\n' "$PROXY_PASS" | curl -K - -s -o /dev/null -w 'with password: HTTP %{http_code} (https via CONNECT)\n' -x http://127.0.0.1:8888 https://example.com/no credentials: HTTP 407 wrong password: HTTP 401 with password: HTTP 200 (http) with password: HTTP 200 (https via CONNECT)Confirm it is not an open proxy
Check the access rules, the CONNECT ports and the file permissions:
sudo grep -E '^[[:space:]]*(Port|Allow|ConnectPort|DisableViaHeader)' /etc/tinyproxy/tinyproxy.conf
sudo grep -c '^BasicAuth ' /etc/tinyproxy/tinyproxy.conf
sudo stat -c '%a %U:%G %n' /etc/tinyproxy/tinyproxy.conf /root/tinyproxy-credentials.txtPort 8888 Allow 127.0.0.1 Allow ::1 Allow 10.0.0.0/8 Allow 172.16.0.0/12 Allow 192.168.0.0/16 Allow fc00::/7 DisableViaHeader Yes ConnectPort 443 ConnectPort 563 1 640 root:tinyproxy /etc/tinyproxy/tinyproxy.conf 600 root:root /root/tinyproxy-credentials.txtTo see Tinyproxy refuse a public source, run this block. It adds a documentation-range address (192.0.2.88, TEST-NET-1) to the loopback interface, sends a request from it with the correct password, and removes the address again. Tinyproxy answers 403 because the source is not private. The same request from 127.0.0.1 succeeds:
PROXY_PASS="$(sudo sed -n 's/^proxy\.pass=//p' /root/tinyproxy-credentials.txt)"
sudo ip addr add 192.0.2.88/32 dev lo printf 'proxy-user = "sac:%s"\n' "$PROXY_PASS" | curl -K - -s -o /dev/null -w 'from 192.0.2.88 (public): HTTP %{http_code}\n' --interface 192.0.2.88 -x http://192.0.2.88:8888 http://example.com/ printf 'proxy-user = "sac:%s"\n' "$PROXY_PASS" | curl -K - -s -o /dev/null -w 'from 127.0.0.1 (local): HTTP %{http_code}\n' --interface 127.0.0.1 -x http://127.0.0.1:8888 http://example.com/
sudo ip addr del 192.0.2.88/32 dev lofrom 192.0.2.88 (public): HTTP 403 from 127.0.0.1 (local): HTTP 200Metadata access is blocked for the proxy
tinyproxy.service carries an IPAddressDeny rule for the metadata addresses, so a client cannot use the proxy to read the instance's IAM role credentials. A request for the metadata service through the proxy, with the correct password, times out with no answer (000). The same request made directly from the instance shell is answered:
systemctl show -p IPAddressDeny tinyproxy.service PROXY_PASS="$(sudo sed -n 's/^proxy\.pass=//p' /root/tinyproxy-credentials.txt)" printf 'proxy-user = "sac:%s"\n' "$PROXY_PASS" | curl -K - -s -m 5 -o /dev/null -w 'metadata through the proxy: HTTP %{http_code}\n' -x http://127.0.0.1:8888 http://169.254.169.254/latest/meta-data/ || true curl -s -m 5 -o /dev/null -w 'metadata from the shell: HTTP %{http_code} (IMDSv2 token request)\n' -X PUT -H 'X-aws-ec2-metadata-token-ttl-seconds: 60' http://169.254.169.254/latest/api/tokenIPAddressDeny=fd00:ec2::254/128 169.254.169.254/32 168.63.129.16/32 metadata through the proxy: HTTP 000 metadata from the shell: HTTP 200 (IMDSv2 token request)How the fail-closed start works
Three systemd drop-ins sit on top of the packaged unit. The first is the gate, which starts the service only after first boot has written /var/lib/sac/data/tinyproxy-ready and the start-up check passes. The second is the metadata block. The third is process sandboxing:
ls /etc/systemd/system/tinyproxy.service.d/ cat /etc/systemd/system/tinyproxy.service.d/10-sac-gate.conf systemctl show -p ExecStartPre tinyproxy.service | grep -o 'path=[^ ;]*'10-sac-gate.conf 50-sac-imds-deny.conf 60-sac-hardening.conf [Unit]
# No ordering against tinyproxy-firstboot.service: first boot itself restarts tinyproxy once the
# marker exists (an After= here would deadlock that restart). Before the marker exists the unit
# is skipped by the condition, never started. ConditionPathExists=/var/lib/sac/data/tinyproxy-ready [Service] ExecStartPre=/usr/local/sbin/tinyproxy-preflight.sh path=/usr/local/sbin/tinyproxy-preflight.shThe start-up check, /usr/local/sbin/tinyproxy-preflight.sh, refuses to start Tinyproxy in any of these cases. The configuration has no BasicAuth line with a password of at least 20 characters. It contains an Allow rule for the whole internet. It has become world-readable. If you want a different policy, edit that script instead of removing the check.
Allow another of your own networks (optional)
Clients on a private range are already admitted. If your clients use a non-RFC 1918 range, such as a carrier-grade NAT range on a VPN, add an Allow line for it next to the others in /etc/tinyproxy/tinyproxy.conf. Never use 0.0.0.0/0:
Allow 100.64.0.0/10Restart Tinyproxy and run the self-test again:
sudo systemctl restart tinyproxy
sudo /usr/local/sbin/tinyproxy-roundtrip.sh | cut -c1-60round-trip OK: anonymous 407, wrong password 401, per-instanRotate the password (optional)
The password is the BasicAuth SecureAnyCloud <password> line in /etc/tinyproxy/tinyproxy.conf. To rotate it, run this block. It generates a new value inside a root shell, replaces that line and the credentials file entry, and restarts Tinyproxy. The new value never appears on a sudo command line, so it is not written to /var/log/auth.log:
sudo bash -c 'NEW="$(openssl rand -base64 33 | tr -dc A-Za-z0-9)" sed -i "s/^BasicAuth sac .*/BasicAuth sac ${NEW}/" /etc/tinyproxy/tinyproxy.conf sed -i "s/^proxy\.pass=.*/proxy.pass=${NEW}/" /root/tinyproxy-credentials.txt systemctl restart tinyproxy'
sudo /usr/local/sbin/tinyproxy-roundtrip.sh | cut -c1-14Update your clients with the new password. To add more users, add extra BasicAuth <user> <password> lines.
Restrict destinations (optional)
Tinyproxy can also limit where clients may go. To allow only a list of domains, create /etc/tinyproxy/filter with one pattern per line, for example ^example\.com$ and \.amazonaws\.com$. Add these lines to the configuration, then restart Tinyproxy:
Filter "/etc/tinyproxy/filter" FilterType ere FilterDefaultDeny YesSecurity recommendations
- Keep TCP 8888 open only to the networks that need the proxy, and TCP 22 only to your management addresses.
- Keep the
BasicAuthline. The start-up check enforces it, and it keeps a misconfigured security group harmless. - Use a destination filter (Step 12) if the proxy is the only egress for a private subnet.
- Watch
/var/log/tinyproxy/tinyproxy.log, which holds request lines and never passwords, and ship it to your log platform. - Leave unattended security upgrades on, and reboot after kernel updates.
Support and licensing
Tinyproxy is free software maintained by the Tinyproxy project and its contributors, distributed under the GNU General Public License, version 2 or later (GPL-2.0-or-later). This image ships the unmodified Ubuntu 24.04 Tinyproxy package. SecureAnyCloud provides the packaging, the not-an-open-proxy defaults, the per-instance authentication, the metadata block, the fail-closed start, the self-test and 24/7 support.
SecureAnyCloud is not affiliated with or endorsed by the Tinyproxy project. Tinyproxy is used here only to identify the software.
For help with deployment or configuration, email sales@secureanycloud.com or visit SecureAnyCloud support.
Deploy on AWS
Launch Tinyproxy 1.11.1 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