CloudProxy manages spinning cloud instances as a proxy pool, and the version numbers disagree
Hide your scrapers IP behind the cloud. Provision proxy servers across different cloud providers to improve your scraping success.
At a glance
- What is it?
- CloudProxy turns an API token from DigitalOcean, AWS, Google Cloud, Hetzner or Vultr into a rotating pool of proxy servers, with a web UI, a Swagger API and rolling replacement. The interesting engineering is in lifecycle management, not in the proxy protocol.
- Who is it for?
- Adopt CloudProxy when your scraping workload needs a rotating cloud proxy pool across several cloud providers and you already hold accounts and API tokens on at least one of them; the fixed pool maintenance and health monitoring are the parts that replace real operations work. Do not adopt it for a single stable egress IP, where a plain forward proxy is simpler and cheaper.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 3 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The unit of work is a cloud instance, not a proxy process
The stated purpose is hiding a scraper's IP behind the cloud by spinning up a pool of proxies on popular cloud providers using nothing but an API token, with no configuration. The reason no configuration is needed is that the abstraction is not a proxy daemon you configure. Each proxy is a cloud VM, created through that provider's own API, and destroying it is how you rotate.
That choice explains the dependency list. There is no proxy server library in the runtime dependencies. Instead there is one SDK per provider: `python-digitalocean`, `boto3` plus `botocore` for AWS, `hcloud` for Hetzner, and `google-api-python-client` for Google Cloud. The orchestration layer is FastAPI with uvicorn and starlette, `apscheduler` for the timed jobs that create and reap instances, `loguru` for logging, and `requests` plus `urllib3` for outbound calls.
So the tool is a control plane for cloud VMs, and the proxy is a payload running on them. The repository layout backs this up: `cloudproxy/providers/user_data.sh` is shipped as package data, meaning instance bootstrap is a shell script injected at provisioning time rather than something in the Python process.
Supported providers are DigitalOcean, AWS, Google Cloud, Hetzner and Vultr, each with its own documentation file under `docs/`. Azure and Scaleway are listed as planned, which is a roadmap item, not a working integration.
Deploying is one container, and the port is 8000
Docker is the recommended deployment, and Python 3.9+ is only needed for development or custom integration. The quick start provisions against DigitalOcean:
docker run -d \
-e PROXY_USERNAME='your_username' \
-e PROXY_PASSWORD='your_password' \
-e DIGITALOCEAN_ENABLED=True \
-e DIGITALOCEAN_ACCESS_TOKEN='your_token' \
-p 8000:8000 \
laffin/cloudproxy:latestFor production the README recommends an env file plus a pinned tag:
version: '3.8'
services:
cloudproxy:
image: laffin/cloudproxy:latest
ports:
- "8000:8000"
env_file:
- .env
restart: unless-stoppedThe compose example uses `:latest` while the surrounding text advises a specific version tag such as `laffin/cloudproxy:0.6.0-beta`. Follow the prose, not the example.
The Dockerfile explains the image shape. A `node:18-slim` build stage compiles the UI from `cloudproxy-ui/`, copying `package*.json` before the source to keep the npm layer cached. The final stage is `python:3.11-slim`, installs `gcc` and `python3-dev`, installs from `requirements.txt` with a pip cache mount, copies the built UI in from the earlier stage, sets `PYTHONPATH=/app`, exposes 8000, and runs `python ./cloudproxy/main.py`. So the runtime image contains a compiled front end served by a Python app.
Running it from source instead means `pip install cloudproxy`, or cloning the repository and using `pip install -e .`.
Proxy auth is mandatory, and ONLY_HOST_IP is the second lock
The environment configuration section is short and the details matter. `PROXY_USERNAME` and `PROXY_PASSWORD` set Basic authentication credentials for the proxy servers, restricted to alphanumeric characters. `ONLY_HOST_IP` set to `True` restricts access to the host server IP only.
The README says both methods can be used simultaneously for enhanced security, which is the sensible default: credentials plus source restriction. What it does not document is how CloudProxy determines the host IP, so if you deploy behind a load balancer or a container network with a dynamic address, that variable is worth testing rather than trusting.
There is one tuning knob for the pool itself. `AGE_LIMIT` sets a proxy age limit in seconds, with 0 meaning disabled and disabled being the default. Set it and CloudProxy recycles instances on a schedule instead of letting them age indefinitely, which is the difference between a pool that rotates on its own and one you have to prune yourself.
Provider-specific variables live in the individual docs files, `docs/digitalocean.md`, `docs/aws.md`, `docs/gcp.md`, `docs/hetzner.md` and `docs/vultr.md`, and the repository carries a `.env.example` at the root as the starting template.
One asymmetry worth flagging: cloud credentials go into the environment of a long-running service that holds the power to create and delete billable VMs in your accounts. Treat `.env` handling as a security decision, not a convenience.
Rolling deployments and fixed pool maintenance
Two features distinguish this from a script that creates VMs. The first is rolling deployments, described as zero-downtime proxy recycling. The second is fixed proxy pool management, described as maintaining a target count.
Fixed pool maintenance is the one that changes how you operate. Rather than a growing pile of instances that you trim manually, you state a target count and the system reconciles toward it, creating instances when the live count is short and destroying them when instances fail health checks. Health monitoring is listed as a separate feature and is what triggers the reconciliation.
Rolling deployment is a different axis: replacing proxies without a window where your scraper has no working egress. For a scraping workload where requests fail whenever the pool is empty, that is the feature that matters most, and it is also the one the README describes in a single line without details on the drain behaviour.
The README also lists automatic proxy rotation and multiple accounts per provider as features. Multi-account support has its own section in the table of contents, which suggests the API-token-per-account model is handled explicitly rather than assumed.
For the control surface, the project exposes Swagger UI interactive API documentation, a modern web interface with real-time updates, and real-time proxy status monitoring. There is also a Python package usage guide at `docs/python-package-usage.md` and two example scripts, `examples/direct_proxy_access.py` and `examples/package_usage.py`, for programmatic use rather than UI.
The end-to-end test suite bills real money
Most projects would not admit this in the README. CloudProxy does, with a warning above its end-to-end command: these tests create real cloud instances and will incur costs.
# Run full end-to-end test
./test_cloudproxy.sh
# Run without cleanup (for debugging)
./test_cloudproxy.sh --no-cleanup --skip-cThat `--no-cleanup` flag is the dangerous one, because it exists precisely for debugging, which is when people are least careful. Leaving orphaned VMs running across several providers is the failure mode that turns a debugging session into an invoice.
The unit tests carry no such warning:
# Run all tests
pytest -v
# Run with coverage
pytest --cov=cloudproxy tests/Those need the `test` extra, which pulls `pytest`, `pytest-cov`, `pytest-mock` and `httpx`. The repository also carries TESTING.md and a `tests/` directory, with codecov and codacy badges at the top of the README.
If you adopt this, run `pytest` in CI and keep `test_cloudproxy.sh` on a schedule against a sandbox account with a spending cap, never as part of a normal commit hook.
Version numbers across three sources do not agree
Start with the divergence, because it affects when you actually get code. The GitHub releases list v0.6.44 as the most recent, published 2025-09-09, followed by v0.6.43 the same day and v0.6.42 in August 2025. The `pyproject.toml` in the repository declares version 0.6.23. The README's deployment examples reference `laffin/cloudproxy:0.6.0-beta`.
So the tagged release, the source tree and the documentation example sit at three different numbers. None of them tells you which is correct for your needs, and the README's own advice to check the releases page for the latest version is the only pointer given.
There is a further wrinkle in the release history itself. The last release is dated 2025-09-09, while the last push to the repository is 2026-09-19. The repository is not archived, so work is landing, but a year of commits past the newest tag means the main branch has moved well beyond what v0.6.44 contains. Anyone reading the source on main is reading unreleased code.
Licence is MIT. The package classifiers include MIT License and the topics are Internet Proxy Servers and System Networking, so there is no copyleft obligation attaching to the code itself. What it does create is obligations in your cloud accounts, which is the cost that actually shows up on the statement.
A last note on scope: the README asks readers to scrape nicely and respectfully. That is a request, not a mechanism. Nothing in CloudProxy rate-limits your scraper or checks robots.txt, and the proxy pool will happily make an aggressive crawler look like many different clients.
Editorial conclusion
Adopt CloudProxy when your scraping workload needs a rotating cloud proxy pool across several cloud providers and you already hold accounts and API tokens on at least one of them; the fixed pool maintenance and health monitoring are the parts that replace real operations work. Do not adopt it for a single stable egress IP, where a plain forward proxy is simpler and cheaper. Before deploying, pin a specific image tag rather than `:latest` as the README recommends, set `PROXY_USERNAME` and `PROXY_PASSWORD` since proxy authentication is not optional, and decide whether `ONLY_HOST_IP` fits your topology, because the README documents both restrictions as combinable but gives no detail on how CloudProxy learns your host IP.
Frequently asked questions
How do I deploy CloudProxy with Docker?
The README's quick start runs `docker run -d` with `PROXY_USERNAME`, `PROXY_PASSWORD`, `DIGITALOCEAN_ENABLED=True`, `DIGITALOCEAN_ACCESS_TOKEN` and `-p 8000:8000` against `laffin/cloudproxy:latest`. For production it recommends an `--env-file .env` and a pinned version tag rather than latest.
Which cloud providers does CloudProxy support?
The README lists DigitalOcean, AWS, Google Cloud, Hetzner and Vultr as supported, each with its own documentation file under docs/. Azure and Scaleway are listed under planned providers.
Do CloudProxy proxies require authentication?
Yes. `PROXY_USERNAME` and `PROXY_PASSWORD` set Basic authentication credentials for the proxy servers and accept alphanumeric characters only. `ONLY_HOST_IP` set to `True` additionally restricts access to the host server IP, and the README says both can be used at the same time.
Is there a way to install CloudProxy as a Python package?
Yes. The README gives `pip install cloudproxy`, or cloning the repository and running `pip install -e .` for development, and points to docs/python-package-usage.md. Python 3.9 or newer is required, and the package declares a `cloudproxy` console script.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/claffin-cloudproxy)Was this useful?