rota: a self hosted proxy rotation platform in Go
A high-performance proxy rotation engine with automated IP management and real-time health monitoring
At a glance
- What is it?
- rota is a Go proxy server that rotates upstream HTTP, HTTPS and SOCKS proxies with health checks, geo tagging, pools and per-user routing, fronted by a Next.js dashboard and a TimescaleDB time series store. It suits operators who need a managed pool of upstream proxies rather than a single tunnel, and it ships as one docker compose stack.
- Who is it for?
- rota is worth deploying when you have many upstream proxies and need routing decisions made for you, because the health checking, geo tagging, pool membership and per-user failover are the parts you would otherwise write yourself. It is the wrong choice for a single upstream, for a workload that needs guaranteed clean IPs rather than many changing ones, and for anyone who cannot run a TimescaleDB and a Caddy tier in production.
- Can I use it commercially?
- Yes. Apache-2.0 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 28 days ago.
- What is it written in?
- Mainly Go, 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
One compose file, two ports, a single origin
rota is described in the project documentation as a self hosted proxy rotation platform: a Go proxy server that rotates thousands of upstream proxies with health checks, pools and per user routing, plus a real time dashboard on TimescaleDB. The claim in the overview is that one `docker compose up` gives you the proxy on port 8000 and everything else behind a single origin.
Looking at the compose file, that claim holds. Three services are visible in the excerpt. A Caddy container listens on `${HTTP_PORT:-80}` and `${HTTPS_PORT:-443}` and is configured with `SITE_ADDRESS`, where a value of `:80` means plain HTTP on localhost and a domain name gives automatic HTTPS in production. Caddy proxies the dashboard and routes `/api` and `/ws` through to the core service, so the browser, the API and the WebSocket stream all share an origin and no API URL has to be configured in the frontend.
The `rota-core` service is the product itself, built from the `./core` directory. It publishes `${PROXY_PORT:-8000}:${PROXY_PORT:-8000}`, with a comment that the proxy must stay reachable on the host while the REST API on 8001 stays internal, reachable only through Caddy at `/api`. Its environment carries the database settings, `LOG_LEVEL`, `PROXY_PORT`, `API_PORT` and the admin credentials.
Caddy waits for the core to be healthy before starting, using a `condition: service_healthy` dependency, which removes a class of first-boot race.
The stack is Go 1.25 for the core, Next.js 16 for the dashboard, TimescaleDB 2.22 for storage and Caddy as the edge. The primary language of the repository is Go.
Rotation strategies and the upstream protocols in play
The proxy engine is where the design decisions are visible. Rotation can be random, round robin, least connections or time based, which is the first question to answer when you adopt it: whether you want even distribution, load aware distribution, or a proxy that changes on a clock.
The upstream protocols supported are HTTP, HTTPS, SOCKS4, SOCKS4A and SOCKS5. That range matters more than it first appears. SOCKS5 with authentication is what makes a commercial proxy provider usable, while plain HTTP upstreams are what most free lists contain, and supporting both means one configuration for both kinds of supply.
The transport layer has deliberate optimisations: pooled keep alive transports, `splice(2)` tunnelling on Linux, and batched telemetry so that the metrics path does not turn into a per request cost. The splice trick in particular is the difference between a proxy that copies bytes through userspace buffers and one that hands the socket over, and it is only available on Linux, so a deployment on another platform loses it.
Around that sit the behaviours you need for unattended operation: timeouts, retries, redirects and rate limiting, plus upstream chaining with Burp and ZAP, which is the hook for sending traffic through an intercepting proxy. Health checks run on a schedule, unhealthy proxies are removed from rotation, and dead proxies are cleaned up. That removal step is what separates a rotation engine from a list of addresses: without it, the rotation eventually cycles exclusively through dead exits and throughput collapses.
Pools, geo data and the per-user routing chain
A rotation engine that treats every upstream as equivalent is not very useful, so rota groups proxies. Pools can be built by geo, by ISP substring or by custom tags, and those groupers can be mixed freely. Each pool then has its own rotation behaviour: round robin, random, or sticky with a set number of requests per IP. The sticky mode is the one that matters for session oriented work, where a client needs the same exit address for a sequence of requests.
Pool membership can be synced automatically or managed by hand, and the documentation mentions cron health checks with live progress, so a pool can be pruned on a schedule with the progress visible in the dashboard rather than only in a log file.
Geo data comes from ip-api.com or from a local MaxMind database, and it resolves to country, region, city and ISP. The geo explorer goes from countries down to cities and shows proxy counts, which is the practical way to answer whether a region actually has usable exits rather than only addresses.
User routing is the other half. A client connects as `http://user:pass@host:8000`, and each user is given a main pool plus an ordered list of fallbacks. When a request fails, rota fails over across that chain automatically and takes a fresh proxy on every retry. Each user also gets a `requests_per_minute` cap, and there is an export API for working proxies.
All of that is tracked. Requests, success rates and response times are recorded per proxy, which is the data that lets you decide whether a pool is worth keeping rather than guessing.
First run: clone, up, then read the password from the logs
The quick start is the shortest path to a running instance, and the documentation says no configuration file is needed for it:
git clone https://github.com/alpkeskin/rota.git
cd rota
docker compose up -d # or: make upand then the password comes out of the core logs:
make password # or: docker compose logs rota-core | grep -i passwordThe Makefile target `make password` does the grep for you and prints a message explaining the situation when it finds nothing, namely that you set `ROTA_ADMIN_PASSWORD` yourself or the credentials were already seeded. That failure mode is worth understanding rather than being surprised by, because the password is generated once and then persisted.
The documentation explains the credential model: first boot credentials are seeded once, and leaving `ROTA_ADMIN_PASSWORD` unset gives a strong random password that is shown in the logs, while setting it in `.env` lets you choose your own. The admin user defaults to `admin`, and the password can be changed later from the dashboard settings.
Two things are exposed. The web UI, the API and the docs are all on `http://localhost`, and the proxy itself is on `localhost:8000`, which is where your clients connect.
For anything beyond a local run, the .env.example file is the reference. The values people actually change are few: `SITE_ADDRESS` for the domain, `ROTA_ADMIN_USER` and `ROTA_ADMIN_PASSWORD` for the admin account, and `PROXY_PORT` for the port the proxy listens on. The advanced section covers the Caddy ports, the TimescaleDB connection settings, `LOG_LEVEL`, and `CORS_ALLOWED_ORIGINS`, which the file notes is irrelevant behind the bundled reverse proxy because the dashboard is same origin.
The Makefile also carries the local development targets. `make dev-core` runs the Go core on the host against a running TimescaleDB, and `make dev-dashboard` starts the Next.js dashboard with pnpm. `make up`, `make build`, `make down`, `make restart`, `make logs` and `make ps` cover the compose lifecycle.
The API is JWT protected and the dashboard keeps state in the URL
The security section of the feature list is short and specific. The API is protected with JWT, and the signing key is persisted so sessions survive restarts, which matters because a regenerated key on every deploy logs everyone out. Admin credentials are hashed with bcrypt and can be changed from the dashboard. Login has brute force protection, both per IP and global, and the.env file flags a setting for trusting X-Forwarded-For and X-Real-IP for that per IP tracking, which is described as spoof safe behind a proxy. WebSocket connections have their origin validated.
On the dashboard side, the interesting design choice is that every filter, sort, page and tab lives in the URL, so a screen is a link. For an operator that means a view of the proxy inventory can be pasted into a message and opened by someone else, and for a dashboard that usually means a lot of state that is lost on refresh. The rest of the dashboard list follows the same practical bent: a live overview over WebSocket with response time and outcome charts, proxy tagging and testing, importing from `.txt`, exporting as `txt`, `json` or `csv`, bulk edit, a live log stream, system metrics, and settings that can be edited without a restart. The description notes a dense hairline design with light, dark and system themes that works at 375 pixels wide.
The time series choice is worth noting. TimescaleDB is not only storing proxy records; response times and outcomes over time are exactly the shape of data it is designed for, and the per proxy tracking in the engine is what feeds the charts in the dashboard.
Where rota is the wrong tool, and what it costs to run
The first thing to say plainly is that a rotation engine multiplies your exposure to the upstream supply. A single proxy is one operator's problem. A pool of thousands fetched from remote lists, each of which may be operated by an unknown party, means your traffic passes through infrastructure you do not control, and the health check only tells you whether a proxy answered, not who operates it. The documentation supports fetching remote `ip:port` lists on a per source schedule with per source protocol and stale proxy cleanup, and the project does not describe any vetting of those sources. If the requirement is a clean, accountable exit address, rotation is the wrong mechanism.
The second limitation is the operational weight. The stack wants a TimescaleDB, a Caddy tier and a core service, with the database addressed through the internal compose network. That is fine for a lab and heavier than you might expect for a personal tool, and the Caddy tier in particular earns its place only when you set `SITE_ADDRESS` to a real domain, since that is what triggers automatic HTTPS.
The third is the gap between what the tool can prove and what you need to prove. Success rates and response times tell you that a proxy is working. They do not tell you that the exit address is not already blocked by the target, and the per-user rate limit and sticky rotation settings are the tools for reducing request pressure rather than for guaranteeing anything about reputation.
The fourth is a legal and terms of service point, and it is yours to check rather than the project's. The topic list includes scraping, and rotating proxies is a technique people reach for when a site blocks them. Whether a given use is permitted is a question about the target's terms and the law where you operate, and the tool takes no position on it. Nothing here is a licence to disregard them.
On maintenance, the repository is not archived and the last push was on 2026-09-25, with releases v2.3.0 on 2026-09-20, v2.2.2 on 2026-08-24 and v2.2.1 on 2026-08-03. That is a release every few weeks, which for a service with a database means the migration path matters as much as the version number. The licence is Apache 2.0, which permits commercial use and modification with the usual notice and patent grant, and the container image is published at ghcr.io/alpkeskin/rota.
The alternative approach is a single managed proxy provider with a rotating endpoint, where the rotation, the health and the geo selection are somebody else's problem and their SLA. The difference in approach is ownership of the failure modes: rota gives you visibility and control over every proxy, every request and every metric, and asks you to run the infrastructure and to find the upstream supply yourself. The managed route gives you a supported service and hides both the supply chain and the observability. rota is the better fit when you need to see and control the pool; the managed service is the better fit when you need someone else to answer for it.
Editorial conclusion
rota is worth deploying when you have many upstream proxies and need routing decisions made for you, because the health checking, geo tagging, pool membership and per-user failover are the parts you would otherwise write yourself. It is the wrong choice for a single upstream, for a workload that needs guaranteed clean IPs rather than many changing ones, and for anyone who cannot run a TimescaleDB and a Caddy tier in production. Before deploying, set SITE_ADDRESS to a real domain so Caddy issues HTTPS, decide whether ROTA_ADMIN_PASSWORD is generated or chosen, and confirm that the proxy sources you feed it are ones you are permitted to use.
Frequently asked questions
How do I start rota with Docker Compose?
The quick start is `git clone https://github.com/alpkeskin/rota.git`, then `cd rota` and `docker compose up -d`, which is also available as `make up`. No configuration file is needed for a local run.
How do I get the admin password for the rota dashboard?
First boot credentials are seeded once. Leave `ROTA_ADMIN_PASSWORD` unset and a strong random password is generated and printed in the core logs, which you can read with `make password`, or set it in `.env` to choose your own.
Which ports does rota expose?
The proxy itself is on `localhost:8000` and is what your clients connect through. The web UI, the API and the docs are all served from `http://localhost`, because Caddy routes `/api` and `/ws` to the core and the REST API on 8001 stays internal.
Which upstream proxy protocols does rota support?
The proxy engine supports HTTP, HTTPS, SOCKS4, SOCKS4A and SOCKS5 upstreams, with rotation by random, round robin, least connections or time based. It also supports upstream chaining with Burp and ZAP.
Can rota limit how fast a single user sends requests?
Yes. Each user gets a main pool plus ordered fallbacks, a `requests_per_minute` cap, and automatic failover across the chain with a fresh proxy on every retry. There is also an export API for working proxies.
How do I get automatic HTTPS for a rota deployment?
Set `SITE_ADDRESS` in `.env` to your domain instead of leaving it at the `:80` default, and Caddy obtains a certificate for it. The Caddy ports can be changed with `HTTP_PORT` and `HTTPS_PORT` if 80 and 443 are already taken.
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/alpkeskin-rota)Was this useful?