Clone, configure, deploy. A disposable HTTP proxy with a fresh IP in under a minute.
This is a standalone wrapper around terraform-aws-ec2-proxy -- the Terraform module that provisions a Squid forward proxy on EC2. If you want to embed the module in a larger infrastructure stack, use the module directly. If you just want a proxy right now, clone this repo.
git clone https://github.com/ql4b/cloudless-proxy.git
cd cloudless-proxy
cp .env.example .env # edit with your AWS profile/region
source activate
proxy up
eval $(proxy env)
curl http://httpbin.org/ip # shows the proxy's IP- Terraform >= 1.12 installed (path configured in
.envviaTERRAFORM_BIN) - AWS credentials configured (profile, env vars, or IAM role)
- AWS account with a default VPC (or provide
TF_VAR_vpc_idandTF_VAR_subnet_idfor a custom VPC)
| Command | Description |
|---|---|
proxy up |
Provision the ASG scaffolding and wait until the proxy is serving |
proxy down |
Destroy everything |
proxy scale-up |
Scale the ASG to 1 — hand out a fresh proxy (new IP), wait until ready |
proxy scale-down |
Scale the ASG to 0 — stop cost, keep the scaffolding |
proxy recreate |
Terminate current instance + scale back up for a fresh IP |
proxy status |
Show instance state, IP, URL, and ASG desired capacity |
proxy url |
Print the live proxy URL |
proxy test |
Verify the proxy is responding |
proxy env |
Print proxy environment variables for export |
In the underlying module's v3 (ASG) design,
up/scale-up/recreatereturn only once Squid is actually serving (they poll the proxy), so the URL they print is immediately usable. WithTF_VAR_ttl_hoursset, the instance self-terminates after the TTL and the ASG scales itself to zero;proxy scale-uphands out a fresh one on demand without aterraform apply.
source activate # load .env, add bin/ to PATH
proxy up # deploy
eval $(proxy env) # set HTTP_PROXY/HTTPS_PROXY in current shell
# ... do your work ...
proxy down # destroy when doneproxy recreate # terminates current instance, deploys a fresh one
eval $(proxy env) # pick up the new IPCopy .env.example to .env and adjust:
AWS_PROFILE=default # your named AWS CLI profile
AWS_REGION=us-east-1 # region to deploy in
NAMESPACE=myorg # naming prefix
NAME=proxy # resource name
TERRAFORM_VERSION="v1.12.2"
TERRAFORM_BIN="/usr/local/bin/terraform-$TERRAFORM_VERSION"Set these in .env or pass at runtime:
TF_VAR_ttl_hours=2 # disposable mode: auto-terminate after 2h + scale-to-zero
TF_VAR_instance_type=t4g.micro # larger instance if needed
TF_VAR_allowed_cidrs='["203.0.113.0/24"]' # explicit CIDRs (default: auto-detect your IP)
TF_VAR_vpc_id=vpc-abc123 # deploy into a specific VPC (default: region's default VPC)
TF_VAR_subnet_id=subnet-def456 # deploy into a specific public subnetNote:
spotwas removed in the underlying module's v3 (ASG) redesign — the proxy is on-demand only. SettingTF_VAR_spotnow has no effect.
This wrapper manages one proxy at a time, and switching region is a full teardown-and-redeploy — you cannot move a running proxy between regions.
Two things make this a hard rule rather than a suggestion:
- Single local state. There is one
infra/terraform.tfstate, shared across regions. It records the region each resource lives in. - The AWS provider pins resources to their creation region. If you change
AWS_REGIONand re-apply without destroying first, Terraform keeps the old region's resources pinned in state and would create new ones in the target region — stranding the old resources (still billable) and splitting state across two regions.
To protect against that, proxy up/scale-up/scale-down/recreate refuse
to run when the region in state differs from AWS_REGION, and print the
migration steps. (proxy down is not guarded — it must be able to destroy the
deployed region, which is step one of a migration.)
Correct migration sequence:
# 1. Make sure AWS_REGION still points at the CURRENTLY DEPLOYED region.
proxy down # destroy in the old region
# 2. Edit AWS_REGION in .env to the new region, then reload:
source activate
# 3. Deploy in the new region:
proxy upIf you try to skip the teardown, you'll see:
ERROR: region mismatch.
Terraform state holds resources in: us-west-1
AWS_REGION is currently set to: eu-west-1
...
which walks you through the same steps.
cloudless-proxy/
├── .env.example # configuration template
├── activate # shell activation script (loads .env, adds bin/ to PATH)
├── bin/proxy # CLI wrapper (up/down/recreate/status/test/env)
├── tf # terraform wrapper (reads .env, runs terraform in infra/)
└── infra/ # Terraform config (calls terraform-aws-ec2-proxy module)
activateloads your.envand putsbin/and the repo root on$PATHproxyis a bash script that wrapstf apply/tf destroywith ergonomic subcommandstfis a thin wrapper that sources.envand calls terraform with-chdir=infra/infra/contains the Terraform configuration that calls the ql4b/ec2-proxy/aws module from the Terraform Registry
- EC2 on-demand instance (
t4g.nanoARM64, Amazon Linux 2023) in a single-node Auto Scaling Group - Squid HTTP proxy on port 8888
- Security group locked to your IP (auto-detected)
- IMDSv2 enforced, encrypted EBS, no SSH
- SSM access for debugging (
aws ssm start-session) - Optional TTL auto-termination with scale-to-zero (no drift)
~$0.0042/hour for an on-demand t4g.nano in us-east-1. Scale to zero (or set
TF_VAR_ttl_hours) to drop compute cost to zero between uses. Typical usage
(deploy for an hour, then scale down or destroy) costs about a cent.
Source the version-controlled shell-integration.zsh from your ~/.zshrc (or
~/.bashrc) to drive the proxy from any directory without cd-ing into the
repo or running source activate by hand:
CLOUDLESS_PROXY_PATH="$HOME/code/ql4b/cloudless/cloudless-proxy" # your clone path
source "$CLOUDLESS_PROXY_PATH/shell-integration.zsh"That defines: proxy_up, proxy_down, proxy_scale_up, proxy_scale_down,
proxy_recreate, proxy_status, proxy_url, proxy_test, proxy_env,
cloudless_proxy (drop into the activated repo), and proxy_mitm /
proxy_mitm_browser. Action commands run in a subshell (no PATH pollution,
no leftover cwd); proxy_env exports HTTP_PROXY et al into your current shell.
Then from any terminal:
proxy_up # deploy + wait until serving
proxy_env # export HTTP_PROXY into current shell
curl http://httpbin.org/ip
proxy_scale_down # park at $0 (keeps the scaffolding)
# ... later ...
proxy_scale_up # fresh IP, back in ~a minute
proxy_down # tear everything downshell-integration.zsh also defines proxy_mitm, which chains the cloud proxy
with mitmproxy to inspect HTTPS traffic:
proxy_up
proxy_mitm # starts mitmproxy on localhost:8080, upstream through cloud proxy
# point browser or curl at http://127.0.0.1:8080Apache 2.0