
💫 Альтернатива Ngrok FRP • ⚡ Быстрый • 🪶 Легковесный • 0️⃣ 0 зависимостей • 🔌 Подключаемый • 😈 Перехват TLS • 🔒 DNS через HTTPS • 🔥 VPN для бедных • ⏪ Обратное и ⏩ Прямое • 👮🏿 Фреймворк 'Прокси-сервер' • 🌐 Фреймворк 'Веб-сервер' • ➵ ➶ ➷ ➠ Фреймворк 'PubSub' • 👷 Фреймворк приёма и выполнения задач
Быстрый и масштабируемый
Масштабируется, используя все доступные ядра системы
Беспоточное выполнение с использованием asyncio
Создан для обработки десятков тысяч соединений в секунду
# On Macbook Pro M2 2022
❯ python --version
Python 3.11.8
❯ oha --version
oha 1.4.3
❯ ./benchmark/compare.sh
CONCURRENCY: 100 workers, DURATION: 1m, TIMEOUT: 1sec
=============================
Benchmarking Proxy.Py
Server (pid:75969) running
Summary:
Success rate: 100.00%
Total: 60.0006 secs
Slowest: 0.2525 secs
Fastest: 0.0002 secs
Average: 0.0019 secs
Requests/sec: 51667.3774
Total data: 56.17 MiB
Size/request: 19 B
Size/sec: 958.64 KiB
Response time histogram:
0.000 [1] |
0.025 [3073746] |■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
0.051 [10559] |
0.076 [4980] |
0.101 [2029] |
0.126 [5896] |
0.152 [2466] |
0.177 [116] |
0.202 [40] |
0.227 [52] |
0.253 [87] |
Response time distribution:
10.00% in 0.0005 secs
25.00% in 0.0007 secs
50.00% in 0.0009 secs
75.00% in 0.0014 secs
90.00% in 0.0021 secs
95.00% in 0.0035 secs
99.00% in 0.0198 secs
99.90% in 0.1262 secs
99.99% in 0.1479 secs
Details (average, fastest, slowest):
DNS+dialup: 0.0018 secs, 0.0004 secs, 0.0031 secs
DNS-lookup: 0.0000 secs, 0.0000 secs, 0.0002 secs
Status code distribution:
[200] 3099972 responses
Error distribution:
[100] aborted due to deadline
=============================
Смотрите Deploying proxy.py in production при развёртывании production-приложений с использованием proxy.py.
Установка из `PyPi````console ❯ pip install --upgrade proxy.py
или из ветки `master` на GitHub```console
❯ pip install git+https://github.com/abhinavsingh/proxy.py.git@master
❯ pip install git+https://github.com/abhinavsingh/proxy.py.git@develop
## Использование Docker
Многоплатформенные контейнеры доступны через:
- Docker Hub
- тег `latest` указывает на последний `stable` релиз
- `docker pull abhinavsingh/proxy.py:latest`
- GitHub container registry (GHCR)
- тег `latest` указывает на последний `develop` релиз
- `docker pull ghcr.io/abhinavsingh/proxy.py:latest`
Релизы контейнеров стабильной версии доступны для следующих платформ:
- `linux/386`
- `linux/amd64`
- `linux/arm/v6`
- `linux/arm/v7`
- `linux/arm64/v8`
- `linux/ppc64le`
- `linux/s390x`
### Стабильная версия из Docker Hub
Запустите последний контейнер `proxy.py`:```console
❯ docker run -it -p 8899:8899 --rm abhinavsingh/proxy.py:latest
Демон Docker автоматически загрузит образ соответствующей платформы. Для запуска контейнера под конкретную целевую платформу на серверах с поддержкой нескольких платформ:```console ❯ docker run -it -p 8899:8899 --rm --platform linux/arm64/v8 abhinavsingh/proxy.py:latest
### Версия для разработки из GHCR
Запустите контейнер `proxy.py` из передового кода в ветке develop:```console
❯ docker run -it -p 8899:8899 --rm ghcr.io/abhinavsingh/proxy.py:latest
❯ git clone https://github.com/abhinavsingh/proxy.py.git ❯ cd proxy.py && make container ❯ docker run -it -p 8899:8899 --rm abhinavsingh/proxy.py:latest
[](https://github.com/moby/vpnkit/issues/469)
`docker` образ в настоящее время не работает на `macOS` из-за несовместимости с [vpnkit](https://github.com/moby/vpnkit/issues/469).
## Использование HomeBrew
Обновлённые формулы для `HomeBrew` хранятся в ветке `develop` в каталоге `helper/homebrew`.
- `stable` формула устанавливает пакет из ветки `master`.
- `develop` формула устанавливает пакет из ветки `develop`.
### Стабильная версия с HomeBrew```console
❯ brew install https://raw.githubusercontent.com/abhinavsingh/proxy.py/develop/helper/homebrew/stable/proxy.rb
❯ brew install https://raw.githubusercontent.com/abhinavsingh/proxy.py/develop/helper/homebrew/develop/proxy.rb
# Запуск proxy.py
## Из командной строки при установке через PIP
Когда `proxy.py` установлен с помощью `pip`,
исполняемый файл с именем `proxy` помещается в ваш `$PATH`.
### Запуск
Просто введите `proxy` в командной строке, чтобы запустить с конфигурацией по умолчанию.```console
❯ proxy
...[redacted]... - Loaded plugin proxy.http.proxy.HttpProxyPlugin
...[redacted]... - Started 8 threadless workers
...[redacted]... - Started 8 acceptors
...[redacted]... - Listening on 127.0.0.1:8899
Что стоит заметить в приведенных логах:
Loaded plugin
proxy.py загрузит proxy.http.proxy.HttpProxyPlugin по умолчаниюhttp(s) в экземпляр proxy.pyStarted N threadless workers
proxy.py запускает столько рабочих процессов, сколько ядер ЦП на машине--num-workers для настройки количества рабочих процессовStarted N acceptors
proxy.py запускает столько процессов-акцепторов, сколько ядер ЦП на машине--num-acceptors для настройки количества процессов-акцепторовВсе приведенные выше логи — это логи уровня INFO, который является значением по умолчанию для --log-level в proxy.py.
Давайте запустим proxy.py с логированием уровня DEBUG:```console
❯ proxy --log-level d
...[redacted]... - Open file descriptor soft limit set to 1024
...[redacted]... - Loaded plugin proxy.http_proxy.HttpProxyPlugin
...[redacted]... - Started 8 workers
...[redacted]... - Started server on ::1:8899
Вы можете использовать одну букву для настройки уровня логирования. Пример:
- `d = DEBUG`
- `i = INFO`
- `w = WARNING`
- `e = ERROR`
- `c = CRITICAL`
Как видно из логов выше, перед запуском:
- `proxy.py` попытался установить лимит открытых файлов `ulimit` в системе
- Используемое по умолчанию значение для `--open-file-limit` равно `1024`
- Флаг `--open-file-limit` не работает в операционных системах `Windows`
См. [флаги](#flags) для полного списка доступных параметров конфигурации.
## Из командной строки с использованием исходного кода репозитория
Если вы пытаетесь запустить `proxy.py` из исходного кода,
в исходном коде нет бинарного файла с именем `proxy`.
Чтобы запустить `proxy.py` из исходного кода, следуйте этим инструкциям:
- Клонируйте репозиторий ```console
❯ git clone https://github.com/abhinavsingh/proxy.py.git
❯ cd proxy.py
Создайте виртуальное окружение Python 3 ```console ❯ python3 -m venv venv ❯ source venv/bin/activate
Установить зависимости ```console ❯ make lib-dep
Сгенерировать proxy/common/_scm_version.py
ПРИМЕЧАНИЕ: Следующий шаг не требуется для редактируемых установок.
Этот файл записывает обнаруженную SCM версию в файл proxy/common/_scm_version.py. ```console
❯ ./write-scm-version.sh
По желанию, запустите тесты ```console ❯ make
Запустите proxy.py ```console
❯ python -m proxy
См. Руководство по разработке плагинов и вкладу, если вы планируете работать с исходным кодом proxy.py.
По умолчанию бинарный файл docker запускается с флагами IPv4 сети:
--hostname 0.0.0.0 --port 8899
Вы можете переопределить флаг из командной строки при запуске docker-контейнера. Например, чтобы проверить версию proxy.py внутри docker-контейнера, выполните:
❯ docker run -it \
-p 8899:8899 \
--rm abhinavsingh/proxy.py:latest \
-v
https
Добавьте поддержку коротких ссылок в ваших любимых браузерах/приложениях.
Запустите proxy.py как:```console
❯ proxy
--plugins proxy.plugin.ShortLinkPlugin
Теперь вы можете ускорить повседневный просмотр, переходя на любимые сайты с помощью односимвольных доменных имён :). Это работает во всех браузерах.
По умолчанию включены следующие короткие ссылки:
| Короткая ссылка | Целевой URL |
| :--------: | :--------------: |
| a/ | `amazon.com` |
| i/ | `instagram.com` |
| l/ | `linkedin.com` |
| f/ | `facebook.com` |
| g/ | `google.com` |
| t/ | `twitter.com` |
| w/ | `web.whatsapp.com` |
| y/ | `youtube.com` |
| proxy/ | `localhost:8899` |
### ModifyPostDataPlugin
Изменяет тело POST-запроса перед отправкой на вышестоящий сервер.
Запустите `proxy.py` как:```console
❯ proxy \
--plugins proxy.plugin.ModifyPostDataPlugin
По умолчанию плагин заменяет содержимое тела POST на жестко заданное b'{"key": "modified"}'
и применяет Content-Type: application/json.
Проверьте это с помощью `curl -x localhost:8899 -d '{"key": "value"}' http://httpbin.org/post````console { "args": {}, "data": "{"key": "modified"}", "files": {}, "form": {}, "headers": { "Accept": "/", "Content-Length": "19", "Content-Type": "application/json", "Host": "httpbin.org", "User-Agent": "curl/7.54.0" }, "json": { "key": "modified" }, "origin": "1.2.3.4, 5.6.7.8", "url": "https://httpbin.org/post" }
Примечание из ответа выше:
1. Данные POST были изменены `"data": "{\"key\": \"modified\"}"`.
Исходные данные команды `curl` были `{"key": "value"}`.
2. Наша команда `curl` не добавляла заголовок `Content-Type`,
но наш плагин добавил один `"Content-Type": "application/json"`.
То же самое можно проверить, посмотрев на поле `json` в выводе выше: ```
"json": {
"key": "modified"
},
Content-Length для соответствия длине
изменённого тела.Мок-ответы для REST API вашего сервера. Используйте для тестирования и разработки клиентских приложений без необходимости в реальном вышестоящем REST API сервере.
Запустите proxy.py как:```console
❯ proxy
--plugins proxy.plugin.ProposedRestApiPlugin
Проверьте ответ мок-API, используя `curl -x localhost:8899 http://api.example.com/v1/users/````console
{"count": 2, "next": null, "previous": null, "results": [{"email": "[email protected]", "groups": [], "url": "api.example.com/v1/users/1/", "username": "admin"}, {"email": "[email protected]", "groups": [], "url": "api.example.com/v1/users/2/", "username": "admin"}]}
Проверьте то же самое, изучив логи proxy.py:```console
... [redacted] ... - access_log:1210 - ::1:64792 - GET None:None/v1/users/ - None None - 0 byte
Access log shows `None:None` as server `ip:port`. `None` simply means that
the server connection was never made, since response was returned by our plugin.
Now modify `ProposedRestApiPlugin` to returns REST API mock
responses as expected by your clients.
### RedirectToCustomServerPlugin
Redirects all incoming `http` requests to custom web server.
By default, it redirects client requests to inbuilt web server,
also running on `8899` port.
Start `proxy.py` and enable inbuilt web server:```console
❯ proxy \
--enable-web-server \
--plugins proxy.plugin.RedirectToCustomServerPlugin
Проверьте с помощью `curl -v -x localhost:8899 http://google.com```` ... [redacted] ... < HTTP/1.1 404 NOT FOUND < Server: proxy.py v1.0.0 < Connection: Close <
Ответ `404` выше был возвращён с веб-сервера `proxy.py`.
Убедитесь в этом, проверив логи `proxy.py`.
Наряду с журналом запросов прокси вы также должны увидеть журнал запросов http веб-сервера.```
... [redacted] ... - access_log:1241 - ::1:49525 - GET /
... [redacted] ... - access_log:1157 - ::1:49524 - GET localhost:8899/ - 404 NOT FOUND - 70 bytes
Отбрасывает трафик, проверяя вышестоящий хост.
По умолчанию плагин отбрасывает трафик для facebook.com и www.facebok.com.
Запустите proxy.py как:```console
❯ proxy
--plugins proxy.plugin.FilterByUpstreamHostPlugin
Проверьте с помощью `curl -v -x localhost:8899 http://facebook.com`:```console
... [redacted] ...
< HTTP/1.1 418 I'm a tea pot
< Proxy-agent: proxy.py v1.0.0
* no chunk, no close, no size. Assume close to signal end
<
* Closing connection 0
Выше 418 I'm a tea pot отправляется нашим плагином.
Проверьте то же самое, просмотрев логи proxy.py:```console
... [redacted] ... - handle_readables:1347 - HttpProtocolException type raised
Traceback (most recent call last):
... [redacted] ...
... [redacted] ... - access_log:1157 - ::1:49911 - GET None:None/ - None None - 0 bytes
### CacheResponsesPlugin
Кеширует ответы вышестоящего сервера.
Запустите `proxy.py` так:```console
❯ proxy \
--plugins proxy.plugin.CacheResponsesPlugin
Вы также можете использовать флаг --cache-requests для включения кэширования пакетов запросов для проверки.
Проверьте, используя curl -v -x localhost:8899 http://httpbin.org/get:```console
... [redacted] ...
< HTTP/1.1 200 OK
< Access-Control-Allow-Credentials: true
< Access-Control-Allow-Origin: *
< Content-Type: application/json
< Date: Wed, 25 Sep 2019 02:24:25 GMT
< Referrer-Policy: no-referrer-when-downgrade
< Server: nginx
< X-Content-Type-Options: nosniff
< X-Frame-Options: DENY
< X-XSS-Protection: 1; mode=block
< Content-Length: 202
< Connection: keep-alive
<
{
"args": {},
"headers": {
"Accept": "/",
"Host": "httpbin.org",
"User-Agent": "curl/7.54.0"
},
"origin": "1.2.3.4, 5.6.7.8",
"url": "https://httpbin.org/get"
}
Получить путь к файлу кэша из логов `proxy.py`:```console
... [redacted] ... - GET httpbin.org:80/get - 200 OK - 556 bytes
... [redacted] ... - Cached response at /var/folders/k9/x93q0_xn1ls9zy76m2mf2k_00000gn/T/httpbin.org-1569378301.407512.txt
Проверьте содержимое файла кэша `cat /path/to/your/cache/httpbin.org.txt````console HTTP/1.1 200 OK Access-Control-Allow-Credentials: true Access-Control-Allow-Origin: * Content-Type: application/json Date: Wed, 25 Sep 2019 02:24:25 GMT Referrer-Policy: no-referrer-when-downgrade Server: nginx X-Content-Type-Options: nosniff X-Frame-Options: DENY X-XSS-Protection: 1; mode=block Content-Length: 202 Connection: keep-alive
{ "args": {}, "headers": { "Accept": "/", "Host": "httpbin.org", "User-Agent": "curl/7.54.0" }, "origin": "1.2.3.4, 5.6.7.8", "url": "https://httpbin.org/get" }
### CacheByResponseType
`CacheResponsesPlugin` плагин может также автоматически кэшировать ответы по `content-type`.
Чтобы попробовать это, вы должны работать в режиме [TLS Interception](#tls-interception)
и затем передать флаг `--cache-by-content-type`. Пример:```console
❯ proxy \
--plugins proxy.plugin.CacheResponsesPlugin \
--cache-by-content-type \
--ca-key-file ca-key.pem \
--ca-cert-file ca-cert.pem \
--ca-signing-key ca-signing-key.pem
Make a few requests to the proxy server and you shall see data under ~/.proxy/cache directory.
You should see 2 folders:
content: Contains parsed jpg, css, js, html, pdf etc by content typeresponses: Contains raw responses as received (of-course decrypted because of interception)Modifies upstream server responses.
Start proxy.py as:```console
❯ proxy
--plugins proxy.plugin.ManInTheMiddlePlugin
Проверьте с помощью `curl -v -x localhost:8899 http://google.com`:```console
... [redacted] ...
< HTTP/1.1 200 OK
< Content-Length: 28
<
* Connection #0 to host localhost left intact
Hello from man in the middle
Response body Hello from man in the middle is sent by our plugin.
Forward incoming proxy requests to a set of upstream proxy servers.
Let's start 2 upstream proxies first. To simulate upstream proxies, start proxy.py on port 9000 and `9001````console
❯ proxy --port 9000
Please provide the Markdown content to translate.```console
❯ proxy --port 9001
Теперь запустите proxy.py с ProxyPoolPlugin (на порту по умолчанию 8899), указав наши вышестоящие прокси на портах 9000 и 9001.```console
❯ proxy
--plugins proxy.plugin.ProxyPoolPlugin
--proxy-pool localhost:9000
--proxy-pool localhost:9001
Выполните curl-запрос через прокси `8899`:
`curl -v -x localhost:8899 http://httpbin.org/get`
Проверьте, что прокси `8899` перенаправляет запросы к вышестоящим прокси, просмотрев соответствующие логи.
Если вышестоящий прокси требует учетные данные, передайте их как аргументы. Пример:
`--proxy-pool user:[email protected]:port`
### FilterByClientIpPlugin
Отклонять трафик с определенных IP-адресов. По умолчанию этот плагин блокирует трафик с `127.0.0.1` и `::1`.
Запустите `proxy.py` как:```console
❯ proxy \
--plugins proxy.plugin.FilterByClientIpPlugin
Отправьте запрос, используя curl -v -x localhost:8899 http://google.com:```console
... [redacted] ...
Proxy-Connection: Keep-Alive
< HTTP/1.1 418 I'm a tea pot < Connection: close <
Измените плагин по своему вкусу, например, разрешите только определенные IP-адреса.
### ModifyChunkResponsePlugin
Этот плагин демонстрирует, как изменять ответы с чанкованным кодированием. Для этого плагин использует ядро `proxy.py` для разбора ответа с чанкованным кодированием. Затем мы восстанавливаем ответ, используя пользовательские жестко заданные чанки, игнорируя оригинальные чанки, полученные от вышестоящего сервера.
Запустите `proxy.py` как:```console
❯ proxy \
--plugins proxy.plugin.ModifyChunkResponsePlugin
Проверьте, используя curl -v -x localhost:8899 http://httpbin.org/stream/5:```console
... [redacted] ...
modify
chunk
response
plugin
Настройте `ModifyChunkResponsePlugin` по своему вкусу. Например, вместо отправки жестко заданных фрагментов, парсите и модифицируйте исходные фрагменты `JSON`, полученные от вышестоящего сервера.
### ModifyRequestHeaderPlugin
Этот плагин демонстрирует, как изменять исходящие заголовки HTTPS-запросов в режиме перехвата TLS.
Запустите `proxy.py` как:```console
❯ proxy \
--plugins proxy.plugin.ModifyRequestHeaderPlugin \
... [TLS interception flags] ...
Проверьте с помощью curl -x localhost:8899 --cacert ca-cert.pem https://httpbin.org/get:```console
{
"args": {},
"headers": {
... [redacted] ...,
"X-Proxy-Py-Version": "2.4.4rc6.dev15+gf533c711"
},
... [redacted] ...
}
### CloudflareDnsResolverPlugin
Этот плагин использует `DNS-over-HTTPS` [API](https://developers.cloudflare.com/1.1.1.1/encrypted-dns/dns-over-https/make-api-requests/dns-json) (json), размещённый на `Cloudflare`.
`DoH` требует HTTP2-совместимый клиент. К сожалению, `proxy.py` пока этого не предоставляет, поэтому мы используем зависимость. Установите её:```console
❯ pip install "httpx[http2]"
Теперь запустите proxy.py как:```console
❯ proxy
--plugins proxy.plugin.CloudflareDnsResolverPlugin
По умолчанию `CloudflareDnsResolverPlugin` работает в режиме `security` и обеспечивает защиту от вредоносного ПО.
Используйте `--cloudflare-dns-mode family`, чтобы также включить защиту от контента для взрослых.
### CustomDnsResolverPlugin
Этот плагин демонстрирует, как использовать пользовательскую реализацию разрешения DNS с `proxy.py`.
Этот пример плагина в настоящее время использует встроенный механизм разрешения Python. Настройте код
по своему вкусу. Например, запросите свой собственный DNS-сервер, реализуйте `DoH` или другие механизмы.
Запустите `proxy.py` как:```console
❯ proxy \
--plugins proxy.plugin.CustomDnsResolverPlugin
Обратный вызов HttpProxyBasePlugin.resolve_dns также можно использовать для настройки network interface, который должен использоваться в качестве source_address для соединения с вышестоящим сервером.
См. эту тему для получения дополнительной информации.
PS: Нет плагина с таким именем, но CustomDnsResolverPlugin можно легко настроить под ваши нужды.
Пытается определить имя программы (приложения) для прокси-запросов, исходящих с локальной машины.
Если идентифицировано, IP-адрес клиента в журналах доступа заменяется именем программы.
Запустите proxy.py как:```console
❯ proxy
--plugins proxy.plugin.ProgramNamePlugin
Сделайте запрос с помощью `curl`:```console
❯ curl -v -x localhost:8899 https://httpbin.org/get
Вы должны видеть строки журнала, подобные этим:```console ... [redacted] ... - [I] server.access_log:419 - curl:58096 - CONNECT httpbin.org:443 - 6010 bytes - 1824.62ms
Notice `curl` в качестве IP-клиента вместо `::1` или `127.0.0.1`.
[](#programnameplugin) Если `ProgramNamePlugin` работает ненадёжно в вашей операционной системе, пожалуйста, помогите, отправив запрос на слияние и/или открыв задачу. Спасибо!!!
## Плагины HTTP-веб-сервера
### Маршрут веб-сервера
Демонстрирует встроенную маршрутизацию веб-сервера с использованием плагина.
Запустите `proxy.py` следующим образом:```console
❯ proxy --enable-web-server \
--plugins proxy.plugin.WebServerPlugin
Проверьте с помощью curl -v localhost:8899/http-route-example, должен вернуть:```console
HTTP route response
## Плагины обратного прокси
Расширяет встроенный веб-сервер для добавления возможностей обратного прокси.
### Обратный прокси
Запустите `proxy.py` так:```console
❯ proxy --enable-reverse-proxy \
--plugins proxy.plugin.ReverseProxyPlugin
С конфигурацией по умолчанию плагин ReverseProxyPlugin эквивалентен следующей конфигурации Nginx:```console
location /get {
proxy_pass http://httpbin.org/get;
}
Проверьте с помощью `curl -v localhost:8899/get`:```console
{
"args": {},
"headers": {
"Accept": "*/*",
"Host": "localhost",
"User-Agent": "curl/7.64.1"
},
"origin": "1.2.3.4, 5.6.7.8",
"url": "https://localhost/get"
}
В приведённом выше примере вы иногда можете увидеть:```console
Это происходит потому, что наш плагин обратного прокси по умолчанию `ReverseProxyPlugin` настроен с upstream-серверами `http` и `https`. И по умолчанию `ReverseProxyPlugin` сохраняет исходный заголовок Host. Хотя это работает с upstream `https`, это ненадежно работает с upstream `http`. Чтобы обойти эту проблему, используйте флаг `--rewrite-host-header`.
Пример:```console
❯ proxy --enable-reverse-proxy \
--plugins proxy.plugin.ReverseProxyPlugin \
--rewrite-host-header
Это гарантирует, что поле заголовка Host будет установлено как httpbin.org и будет работать как с http, так и с https вышестоящими серверами.
ПРИМЕЧАНИЕ: Использовать
--rewrite-host-headerили нет — зависит от вашего сценария.
При использовании нескольких плагинов, в зависимости от их функциональности, стоит учитывать порядок, в котором плагины передаются в командной строке.
Плагины вызываются в том же порядке, в котором они переданы. Например, предположим, мы используем одновременно FilterByUpstreamHostPlugin и RedirectToCustomServerPlugin. Идея состоит в том, чтобы отбрасывать все входящие http-запросы к facebook.com и www.facebook.com, а остальные http-запросы перенаправлять на наш встроенный веб-сервер.
Следовательно, в этом сценарии важно использовать FilterByUpstreamHostPlugin перед RedirectToCustomServerPlugin. Если мы включим RedirectToCustomServerPlugin до FilterByUpstreamHostPlugin, то запросы к facebook также будут перенаправляться на встроенный веб-сервер, вместо того чтобы быть отброшенными.
По умолчанию proxy.py использует протокол http для связи с клиентами, например curl, браузер. Для включения сквозного шифрования с помощью tls / https сначала сгенерируйте сертификаты. Склонируйте репозиторий и выполните:```console
make https-certificates
Запустите `proxy.py` как:```console
❯ proxy \
--cert-file https-cert.pem \
--key-file https-key.pem
Проверьте, используя curl -x https://localhost:8899 --proxy-cacert https-cert.pem https://httpbin.org/get:```console
{
"args": {},
"headers": {
"Accept": "/",
"Host": "httpbin.org",
"User-Agent": "curl/7.54.0"
},
"origin": "1.2.3.4, 5.6.7.8",
"url": "https://httpbin.org/get"
}
Если вы хотите избежать передачи флага `--proxy-cacert`, рассмотрите также подписание сгенерированных SSL-сертификатов. Пример:
Сначала сгенерируйте сертификаты ЦС:```console
make ca-certificates
Затем, подпишите SSL-сертификат:```console make sign-https-certificates
Теперь перезапустите сервер с флагом `--cert-file https-signed-cert.pem`. Обратите внимание, что вы также должны доверять созданному `ca-cert.pem` в вашей системной связке ключей.
# Перехват TLS
По умолчанию `proxy.py` не расшифровывает трафик `https` между клиентом и сервером. Чтобы включить перехват TLS, сначала сгенерируйте корневые сертификаты CA:```console
❯ make ca-certificates
Давайте также включим CacheResponsePlugin, чтобы мы могли проверить расшифрованный ответ от сервера. Запустите proxy.py как:```console
❯ proxy
--plugins proxy.plugin.CacheResponsesPlugin
--ca-key-file ca-key.pem
--ca-cert-file ca-cert.pem
--ca-signing-key-file ca-signing-key.pem
[](https://github.com/abhinavsingh/proxy.py#user-content-flags) Также укажите явный путь к пакету CA, необходимый для проверки сертификатов сторон. См. флаг `--ca-file`.
Проверьте перехват TLS с помощью `curl````console
❯ curl -v -x localhost:8899 --cacert ca-cert.pem https://httpbin.org/get
pwna: curl "example.com$(pwna)"
pwnb: curl "example.com$(pwna_type b)"```console
GET /get HTTP/1.1 ... [redacted] ... < Connection: keep-alive < { "args": {}, "headers": { "Accept": "/", "Host": "httpbin.org", "User-Agent": "curl/7.54.0" }, "origin": "1.2.3.4, 5.6.7.8", "url": "https://httpbin.org/get" }
Строка `issuer` подтверждает, что ответ был перехвачен.
Также проверьте содержимое файла кэшированного ответа. Получите путь к файлу кэша из журналов `proxy.py`.
`❯ cat /path/to/your/tmp/directory/httpbin.org-1569452863.924174.txt````console
HTTP/1.1 200 OK
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: *
Content-Type: application/json
Date: Wed, 25 Sep 2019 23:07:05 GMT
Referrer-Policy: no-referrer-when-downgrade
Server: nginx
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
Content-Length: 202
Connection: keep-alive
{
"args": {},
"headers": {
"Accept": "*/*",
"Host": "httpbin.org",
"User-Agent": "curl/7.54.0"
},
"origin": "1.2.3.4, 5.6.7.8",
"url": "https://httpbin.org/get"
}
Вуаля!!! Если удалить флаги CA, зашифрованные данные будут найдены в кэшированном файле вместо обычного текста.
Теперь используйте флаги CA с другими
примерами плагинов, чтобы увидеть их работу с трафиком https.
Чтобы перехватывать TLS-трафик от сервера, использующего самоподписанный сертификат,
добавьте флаг --insecure-tls-interception, чтобы отключить обязательную проверку сертификата TLS.
ПРИМЕЧАНИЕ: Этот флаг отключает проверку сертификата для всех серверов.
Важные замечания о перехватывании TLS с контейнером Docker:
Начиная с v2.2.0, контейнер Docker proxy.py также включает openssl. Это позволяет proxy.py
генерировать сертификаты на лету для перехватывания TLS.
По соображениям безопасности контейнер Docker proxy.py не включает
сертификаты CA.
Вот как запустить контейнер Docker proxy.py
с перехватыванием TLS:
-v /tmp/ca-certificates:/tmp/ca-certificates флаг монтирует каталог с нашим сертификатом ЦС в среде контейнера
--plugins proxy.plugin.CacheResponsesPlugin включает CacheResponsesPlugin, чтобы мы могли проверять перехваченный трафик--ca-* флаги включают перехват TLS.curl. Вы можете опустить флаг --cacert, если сертификат ЦС уже доверен системой. ```console
❯ curl -v issuer в заголовках ответа. ```console
cat ответного дампа: ```console
❯ docker exec -it $(docker ps | grep proxy.py | awk '{ print $1 }') cat /tmp/httpbin.org-ae1a927d064e4ab386ea319eb38fe251.txt
HTTP/1.1 200 OK
...[redacted]...
{
...[redacted]...,
"url": "http://httpbin.org/get"
}
grout — это готовая замена для ngrok и frpgrout поставляется в составе proxy.py❯ grout NAME: grout - securely tunnel local files, folders and services to public URLs
USAGE: grout route [name]
DESCRIPTION: grout exposes local networked services behinds NATs and firewalls to the public internet over a secure tunnel. Share local folders, directories and websites, build/test webhook consumers and self-host personal services to public URLs.
EXAMPLES: Share Files and Folders: grout C:\path\to\folder # Share a folder on your system grout /path/to/folder # Share a folder on your system grout /path/to/folder --basic-auth user:pass # Add authentication for shared folder grout /path/to/photo.jpg # Share a specific file on your system
Expose HTTP, HTTPS and Websockets: grout http://localhost:9090 # Expose HTTP service running on port 9090 grout https://localhost:8080 # Expose HTTPS service running on port 8080 grout https://localhost:8080 --path /worker/ # Expose only certain paths of HTTPS service on port 8080 grout https://localhost:8080 --basic-auth u:p # Add authentication for exposed HTTPS service on port 8080
Expose TCP Services: grout tcp://:6379 # Expose Redis service running locally on port 6379 grout tcp://:22 # Expose SSH service running locally on port 22
Custom URLs: grout https://localhost:8080 abhinavsingh # Custom URL for HTTPS service running on port 8080 grout tcp://:22 abhinavsingh # Custom URL for SSH service running locally on port 22
Custom Domains: grout tcp://:5432 abhinavsingh.domain.tld # Custom URL for Postgres service running locally on port 5432
Self-hosted solutions: grout tcp://:5432 abhinavsingh.my.server # Custom URL for Postgres service running locally on port 5432
(*) Wildcard Domains: grout https://host:443 do.main --wildcard # Receive traffic on provided domain and all it's subdomains
(*) Host based routing for Wildcard Domains: grout ... --tunnel-route-url host=https://h:p # When using wildcards, optionally route traffic by incoming host header
SUPPORT: Write to us at [email protected]
Privacy policy and Terms & conditions https://jaxl.com/privacy/
Created by Jaxl™ https://jaxl.io
## Grout Authentication
Grout поддерживает аутентификацию для защиты ваших файлов, папок и сервисов от несанкционированного доступа. Используйте флаг `--basic-auth` для принудительной аутентификации. Пример:
```bash
grout --basic-auth user:pass
``````console
grout /path/to/folder --basic-auth user:pass
grout https://localhost:8080 --basic-auth u:p
По умолчанию Grout разрешает доступ ко всем путям на сервисах. Используйте флаг --path, чтобы ограничить доступ только к определенным путям на вашем веб-сервисе. Пример:```console
grout https://localhost:8080 --path /worker/
grout https://localhost:8080 --path /webhook/ --path /callback/
## Подстановочные домены Grout
По умолчанию клиент Grout обслуживает входящий трафик на выделенном поддомене.
Однако некоторые сервисы (например, Kubernetes) могут захотеть обслуживать трафик на произвольных поддоменах.
Запуск отдельного клиента Grout для каждого произвольного поддомена может быть нецелесообразным решением.
Для таких сценариев Grout поддерживает подстановочные домены. Вот как настроить собственный
подстановочный домен для использования с клиентами Grout.
1. Выберите домен, например `custom.example.com`
2. Ваш сервис хочет обслуживать трафик для `custom.example.com` и `*.custom.example.com`
3. Если вы планируете использовать `https://`, вам необходимо настроить балансировщик нагрузки:
- Настройте балансировщик нагрузки HTTPS (LB)
- Настройте LB с сертификатом, сгенерированным для `custom.example.com` и `*.custom.example.com`
- Направьте трафик на публичные IP-адреса службы Grout
4. Свяжитесь с командой Grout по адресу [email protected], чтобы внести `custom.example.com` в белый список. Команда Grout убедится,
что вы действительно владеете доменом и настроили действующий SSL-сертификат, как описано выше
Запустите Grout с флагом `--wildcard`. Пример:```console
grout https://localhost:8080 custom.example.com --wildcard
2024-08-05 18:24:59,294 - grout - Logged in as [email protected]
2024-08-05 18:25:03,159 - setup - Grouting https://*.custom.domain.com
Доступно только с
--wildcard
Наряду с маршрутом по умолчанию вы также можете указать дополнительные маршруты, которые имеют приоритет при совпадении поля host. Пример:```console
grout https://localhost:8080 custom.example.com
--wildcard
--tunnel-route-url stream.example.com=http://localhost:7001
You can provide multiple custom routes by repeating this flag.
## Grout Client Plugin
`GroutClientBasePlugin` позволяет динамически направлять трафик на различные вышестоящие серверы. Ниже приведена простая реализация с описанием того, как ее использовать.```python
class GroutClientPlugin(GroutClientBasePlugin):
def resolve_route(
self,
route: str,
request: HttpParser,
origin: HostPort,
server: HostPort,
) -> Tuple[Optional[str], HttpParser]:
print(request, origin, server, '->', route)
print(request.header(b'host'), request.path)
#
# Here, we send traffic to localhost:7001 irrespective
# of the original "route" value provided to the grout
# client OR any custom host:upstream mapping provided
# through the --tunnel-route-url flags (when using
# --wildcard).
#
# Optionally, you can also strip path before
# sending traffic to upstrem, like:
# request.path = b"/"
#
# To drop the request, simply return None for route
# return None, request
#
return 'http://localhost:7001', request
См. grout_client.py для дополнительной информации. Чтобы опробовать это, передайте --plugin proxy.plugin.grout_client.GroutClientPlugin при запуске grout-клиента.
❯ docker run --rm -it
--entrypoint grout
-v ~/.proxy:/root/.proxy
abhinavsingh/proxy.py:latest
http://host.docker.internal:29876
Выше:
- Мы изменили `--entrypoint` на `grout`
- Мы заменили `localhost` на `host.docker.internal`, чтобы `grout` мог направлять трафик на порт `29876`, запущенный на хост-машине
- *(Опционально)* Подключите папку `~/.proxy` хост-машины, чтобы учетные данные `grout` сохранялись между перезапусками контейнера
## Как работает Grout
- Инфраструктура `grout` состоит из 2 компонентов: клиента и сервера
- Клиент `grout` имеет 2 компонента: тонкий и толстый клиент
- Тонкий клиент `grout` является частью открытого исходного кода `proxy.py` (лицензия BSD 3-Clause)
- Толстый клиент и серверы `grout` размещаются на [jaxl.io](https://jaxl.io)
и являются авторским правом [Jaxl Innovations Private Limited](https://jaxl.com)
- Сервер `grout` имеет 3 компонента: сервер реестра, обратный прокси-сервер и туннельный сервер
## Самостоятельно размещаемый `grout`
- Толстый клиент и серверы `grout` также могут размещаться на ваших инфраструктурах GCP, AWS, Cloud
- В самостоятельной версии ваш трафик проходит через сеть, которую вы контролируете и которой доверяете
- Разработчики `grout` на [jaxl.io](https://jaxl.io) предоставляют образы GCP, AWS, Docker для самостоятельных решений
- Пожалуйста, напишите на [[email protected]](mailto:[email protected]), чтобы начать.
# Прокси через SSH-туннель
**Это в разработке и может работать не так, как описано**
Для работы требуется `paramiko`. Установите зависимости с помощью `pip install "proxy.py[tunnel]"`
## Прокси удаленных запросов локально
|
+------------+ | +----------+
| LOCAL | | | REMOTE |
| HOST | <== SSH ==== :8900 == | PROXY |
+------------+ | +----------+
:8899 proxy.py |
|
FIREWALL
(allow tcp/22)
### Что
Прокси HTTP(s) запросов, сделанных на `удаленном` прокси-сервере, через сервер `proxy.py`, работающий на `localhost`.
### Как
- Запрашиваемый `удаленный` порт перенаправляется через SSH-соединение.
- `proxy.py`, работающий на `localhost`, обрабатывает и отвечает на
запросы `удаленного` прокси.
### Требования
1. `localhost` ДОЛЖЕН иметь SSH-доступ к `удаленному` серверу
2. `удаленный` сервер ДОЛЖЕН быть настроен на прокси HTTP(s) запросов
через перенаправленный номер порта, например `:8900`.
- Порты `remote` и `localhost` МОГУТ быть одинаковыми, например `:8899`.
- `:8900` выбран в ascii-схеме для различия.
### Попробуйте
Запустите `proxy.py` как:```console
❯ # On localhost
❯ proxy --enable-ssh-tunnel \
--tunnel-username username \
--tunnel-hostname ip.address.or.domain.name \
--tunnel-port 22 \
--tunnel-remote-port 8899 \
--tunnel-ssh-key /path/to/ssh/private.key \
--tunnel-ssh-key-passphrase XXXXX
...[redacted]... [I] listener.setup:97 - Listening on 127.0.0.1:8899
...[redacted]... [I] pool.setup:106 - Started 16 acceptors in threadless (local) mode
...[redacted]... [I] transport._log:1873 - Connected (version 2.0, client OpenSSH_7.6p1)
...[redacted]... [I] transport._log:1873 - Authentication (publickey) successful!
...[redacted]... [I] listener.setup:116 - SSH connection established to ip.address.or.domain.name:22...
...[redacted]... [I] listener.start_port_forward:91 - :8899 forwarding successful...
Сделайте HTTP-прокси запрос к серверу remote и убедитесь, что ответ содержит публичный IP-адрес localhost как источник:```console
❯ # On remote
❯ curl -x 127.0.0.1:8899 http://httpbin.org/get
{
"args": {},
"headers": {
"Accept": "/",
"Host": "httpbin.org",
"User-Agent": "curl/7.54.0"
},
"origin": "x.x.x.x, y.y.y.y",
"url": "https://httpbin.org/get"
}
Также убедитесь, что логи `proxy.py` на `localhost` содержат `remote` IP в качестве IP-адреса клиента.```console
access_log:328 - remote:52067 - GET httpbin.org:80
|
+------------+ | +----------+
| LOCAL | | | REMOTE |
| HOST | === SSH =====> | SERVER |
+------------+ | +----------+
| :8899 proxy.py
|
FIREWALL
(allow tcp/22)
Не запланировано.
Если у вас есть обоснованный сценарий использования, пожалуйста, откройте issue. Вы всегда можете внести свой вклад через pull-запросы для добавления этой функциональности :)
Для проксирования локальных запросов удаленно используйте Плагин Proxy Pool.
Запустите proxy.py во встроенном режиме с конфигурацией по умолчанию,
используя метод proxy.main. Пример:```python
import proxy
if name == 'main': proxy.main()
Настройте флаги запуска, передавая их в качестве kwargs:```python
import ipaddress
import proxy
if __name__ == '__main__':
proxy.main(
hostname=ipaddress.IPv6Address('::1'),
port=8899
)
Обратите внимание:
main эквивалентен запуску proxy.py из командной строки.main не принимает никаких args (только kwargs).main автоматически обработает любые доступные sys.argv как args.main будет блокироваться до завершения работы proxy.py.Запустите proxy.py в неблокирующем встроенном режиме с конфигурацией по умолчанию
используя контекстный менеджер Proxy: Пример:```python
import proxy
if name == 'main': with proxy.Proxy() as p: # Uncomment the line below and # implement your app your logic here proxy.sleep_loop()
Обратите внимание:
1. `Proxy` аналогичен `main`, за исключением того, что `Proxy` не блокирует выполнение.
2. Внутри `Proxy` является контекстным менеджером, который запускает `proxy.py` при вызове и завершает его работу после выхода из области видимости.
3. В отличие от `main`, флаги запуска для `Proxy` также можно настраивать с помощью `args` и `kwargs`. Например: `Proxy(['--port', '8899'])` или передавая флаги как kwargs, например: `Proxy(port=8899)`.
4. В отличие от `main`, `Proxy` не проверяет `sys.argv`.
## Эфемерный порт
Используйте `--port=0`, чтобы привязать `proxy.py` к случайному порту, выделенному ядром.
Во встроенном режиме вы можете получить доступ к этому порту. Пример:```python
import proxy
if __name__ == '__main__':
with proxy.Proxy(port=0) as p:
print(p.flags.port)
proxy.sleep_loop()
flags.port предоставит вам доступ к случайному порту, выделенному ядром.
Пользователи могут использовать флаг --plugins несколько раз для загрузки нескольких плагинов.
См. Не удается загрузить плагины, если у вас возникли проблемы.
При использовании во встроенном режиме у вас есть еще несколько опций. Пример:
bytes методу proxy.main или контекстному менеджеру proxy.Proxy.type класса плагина. Это особенно полезно, если вы планируете определять плагины во время выполнения.Пример загрузки одного плагина с помощью флага --plugins:```python
import proxy
if name == 'main': proxy.main(plugins=['proxy.plugin.CacheResponsesPlugin'])
Для простоты вы также можете передать список плагинов в качестве ключевого аргумента в `proxy.main` или конструктор `Proxy`. Пример:```python
import proxy
from proxy.plugin import FilterByUpstreamHostPlugin
if __name__ == '__main__':
proxy.main(plugins=[
b'proxy.plugin.CacheResponsesPlugin',
FilterByUpstreamHostPlugin,
])
proxy.TestCaseДля настройки и очистки proxy.py в ваших классах Python unittest просто используйте proxy.TestCase вместо unittest.TestCase.
Пример:```python
import proxy
class TestProxyPyEmbedded(proxy.TestCase):
def test_my_application_with_proxy(self) -> None:
self.assertTrue(True)
Обратите внимание:
1. `proxy.TestCase` переопределяет метод `unittest.TestCase.run()` для настройки и демонтажа `proxy.py`.
2. Сервер `proxy.py` будет прослушивать случайный доступный порт в системе.
Этот случайный порт доступен как `self.PROXY.flags.port` в ваших тестовых примерах.
3. По умолчанию запускается только один acceptor и worker (`--num-workers 1 --num-acceptors 1`) для более быстрой настройки и демонтажа.
4. Самое главное, `proxy.TestCase` также гарантирует, что сервер `proxy.py`
запущен и работает перед выполнением тестов. По умолчанию,
`proxy.TestCase` будет ждать `10 секунд` для запуска сервера `proxy.py`,
при неудаче будет вызвано исключение `TimeoutError`.
## Переопределение флагов запуска
Чтобы переопределить флаги запуска по умолчанию, определите переменную `PROXY_PY_STARTUP_FLAGS` в вашем тестовом классе.
Пример:```python
class TestProxyPyEmbedded(TestCase):
PROXY_PY_STARTUP_FLAGS = [
'--num-workers', '2',
'--num-acceptors', '1',
'--enable-web-server',
]
def test_my_application_with_proxy(self) -> None:
self.assertTrue(True)
См. test_embed.py для полного рабочего примера.
unittest.TestCaseЕсли по каким-то причинам вы не можете напрямую использовать proxy.TestCase,
просто переопределите unittest.TestCase.run самостоятельно для настройки и завершения работы proxy.py.
Пример:```python
import unittest
import proxy
class TestProxyPyEmbedded(unittest.TestCase):
def test_my_application_with_proxy(self) -> None:
self.assertTrue(True)
def run(self, result: Optional[unittest.TestResult] = None) -> Any:
with proxy.start([
'--num-workers', '1',
'--num-acceptors', '1',
'--port', '... random port ...']):
super().run(result)
или просто настройка / удаление `proxy.py` внутри методов класса `setUpClass` и `teardownClass`.
# Утилиты
## TCP сокеты
### new_socket_connection
Пытается создать IPv4-соединение, затем IPv6 и, наконец, двухстековое соединение с указанным адресом.```python
>>> conn = new_socket_connection(('httpbin.org', 80))
>>> ...[ use connection ]...
>>> conn.close()
socket_connection — это удобный декоратор + контекстный менеджер, обёртка вокруг new_socket_connection, которая гарантирует, что conn.close выполняется неявно.
В качестве контекстного менеджера:```python
with socket_connection(('httpbin.org', 80)) as conn: ... [ use connection ] ...
Как декоратор:```python
>>> @socket_connection(('httpbin.org', 80))
>>> def my_api_call(conn, *args, **kwargs):
>>> ... [ use connection ] ...
build_http_request(b'GET', b'/') b'GET / HTTP/1.1\r\n\r\n'
build_http_request(b'GET', b'/', conn_close=True) b'GET / HTTP/1.1\r\nConnection: close\r\n\r\n'
import json build_http_request(b'POST', b'/form', headers={b'Content-type': b'application/json'}, body=proxy.bytes_(json.dumps({'email': '[email protected]'}))) b'POST /form HTTP/1.1\r\nContent-type: application/json\r\n\r\n{"email": "[email protected]"}'
build_http_response( status_code: int, protocol_version: bytes = HTTP_1_1, reason: Optional[bytes] = None, headers: Optional[Dict[bytes, bytes]] = None, body: Optional[bytes] = None) -> bytes
## PKI
### Использование API
- `gen_private_key` ```python
gen_private_key(
key_path: str,
password: str,
bits: int = 2048,
timeout: int = 10) -> bool
gen_public_key ```python
gen_public_key(
public_key_path: str,
private_key_path: str,
private_key_password: str,
subject: str,
alt_subj_names: Optional[List[str]] = None,
extended_key_usage: Optional[str] = None,
validity_in_days: int = 365,
timeout: int = 10) -> bool
remove_passphrase ```python
remove_passphrase(
key_in_path: str,
password: str,
key_out_path: str,
timeout: int = 10) -> bool
gen_csr ```python
gen_csr(
csr_path: str,
key_path: str,
password: str,
crt_path: str,
timeout: int = 10) -> bool
sign_csr ```python
sign_csr(
csr_path: str,
crt_path: str,
ca_key_path: str,
ca_key_password: str,
ca_crt_path: str,
serial: str,
alt_subj_names: Optional[List[str]] = None,
extended_key_usage: Optional[str] = None,
validity_in_days: int = 365,
timeout: int = 10) -> bool
Смотрите pki.py и test_pki.py для примеров использования.
Используйте модуль proxy.common.pki для:
proxy.py v2.4.4rc2.dev12+gdc06ea4 : PKI Utility
positional arguments: action Valid actions: remove_passphrase, gen_private_key, gen_public_key, gen_csr, sign_csr
options: -h, --help show this help message and exit --password PASSWORD Password to use for encryption. Default: proxy.py --private-key-path PRIVATE_KEY_PATH Private key path --public-key-path PUBLIC_KEY_PATH Public key path --subject SUBJECT Subject to use for public key generation. Default: /CN=localhost --csr-path CSR_PATH CSR file path. Use with gen_csr and sign_csr action. --crt-path CRT_PATH Signed certificate path. Use with sign_csr action. --hostname HOSTNAME Alternative subject names to use during CSR signing. --openssl OPENSSL Path to openssl binary. By default, we assume openssl is in your PATH
## Внутренняя документация
### Read The Doc
- Посетите [proxypy.readthedocs.io](https://proxypy.readthedocs.io/)
- Соберите локально с помощью:
`make lib-doc`
### pydoc
Код хорошо документирован. Скачайте исходный код и выполните:
`pydoc3 proxy`
### pyreverse
Сгенерируйте UML-диаграммы иерархии классов для углублённого анализа:
`make lib-pyreverse`
# Запуск Dashboard
Dashboard в настоящее время находится в разработке и ещё не включен в пакеты `pip`.
Для запуска dashboard необходимо взять исходный код.
Dashboard написан на Typescript и SCSS, поэтому сначала соберём его с помощью:```console
❯ make dashboard
Также соберите встроенные Chrome DevTools, если планируете их использовать:```console
❯ make devtools
Теперь запустите `proxy.py` с плагином панели управления и переопределением корневого каталога для статического сервера:```console
❯ proxy --enable-dashboard --static-server-dir dashboard/public
...[redacted]... - Loaded plugin proxy.http.server.HttpWebServerPlugin
...[redacted]... - Loaded plugin proxy.dashboard.dashboard.ProxyDashboard
...[redacted]... - Loaded plugin proxy.dashboard.inspect_traffic.InspectTrafficPlugin
...[redacted]... - Loaded plugin proxy.http.inspector.DevtoolsProtocolPlugin
...[redacted]... - Loaded plugin proxy.http.proxy.HttpProxyPlugin
...[redacted]... - Listening on ::1:8899
...[redacted]... - Core Event enabled
В настоящее время включение панели управления также включает все плагины панели управления.
Посетить панель управления:```console ❯ open http://localhost:8899/dashboard/
## Инспекция трафика
***Это в разработке и может работать не так, как описано***
Дождитесь загрузки встроенной `Chrome Dev Console`. В настоящее время информация обо всем трафике, проходящем через `proxy.py`, передается на вкладку `Inspect Traffic`. Однако полученные полезные нагрузки еще не интегрированы со встроенной консолью разработчика.
Текущую функциональность можно проверить, открыв `Dev Console` панели управления и проверив websocket-соединение, которое панель установила с сервером `proxy.py`.
[](https://github.com/abhinavsingh/proxy.py)
# Протокол Chrome DevTools
Для сценариев, где требуется прямой доступ к websocket-конечной точке протокола `Chrome DevTools`, запустите `proxy.py` следующим образом:
```bash
proxy.py --enable-devtools-ws
``````console
❯ proxy --enable-devtools --enable-events
Теперь укажите вашему экземпляру CDT адрес ws://localhost:8899/devtools.
proxy.py с флагом --enable-metrics, чтобы получить доступ к внутренним метрикам через endpoint Prometheusprometheus.yaml для сбора данных с endpoint /metrics, например, http://localhost:8899/metrics--metrics-path--enable-metrics внутренне также включает --enable-events и плагин веб-сервераНиже перечислены несколько стратегий использования proxy.py в ваших частных/production/корпоративных проектах.
Вы ДОЛЖНЫ
избегать форкарепозитория «просто» для того, чтобы разместить код своего плагина в каталогеproxy/plugin. Форк — это рекомендуемый рабочий процесс для участников проекта, а НЕ для пользователей.
--plugin, --plugins или аргумента plugin.proxy.py.Настоятельно рекомендуется использовать proxy.py через requirements.txt или аналогичные системы управления зависимостями. Это позволит вам воспользоваться преимуществами регулярных обновлений производительности, исправлений ошибок, патчей безопасности и других улучшений в экосистеме proxy.py. Пример:
Используйте опцию --pre, чтобы зависеть от последнего pre-release
❯ pip install proxy.py --pre
Используйте TestPyPi с опцией --pre, чтобы зависеть от кода ветки develop
❯ pip install -i https://test.pypi.org/simple/ proxy.py --pre
Пререлиз публикуется на TestPyPi после каждого слияния PR.
Используйте код последнего stable релиза
Как обычно, просто используйте:
❯ pip install proxy.py
Если вы занимаетесь развертыванием контейнеров, просто соберите свой образ из базовых образов контейнера proxy.py.
Используйте GHCR для сборки из кода ветки develop:
FROM ghcr.io/abhinavsingh/proxy.py:latest as base
Примечание: я использую GHCR latest в нескольких production-проектах
Используйте DockerHub для сборки из кода последнего stable релиза:
FROM abhinavsingh/proxy.py:latest as base
Примечание: IMHO, стратегия на основе контейнеров — лучший подход и единственная стратегия, которую я использую сам.
Эй, но вы продолжаете вносить критические изменения в ветку develop.
Я вас слышу. И поэтому для ваших приложений production-уровня вы ДОЛЖНЫ интегрировать CI/CD приложения с proxy.py. Вы должны убедиться, что ваше приложение собирается и проходит свои тесты для каждого слияния PR в вышестоящий репозиторий proxy.py.
Если ваш репозиторий приложения публичный, в определенных сценариях авторы PR могут отправлять PR с исправлениями для всех зависимых проектов, чтобы сохранить обратную совместимость и зеленый CI/CD.
Интеграция CI/CD гарантирует, что ваше приложение продолжает собираться с последним кодом proxy.py. В зависимости от того, где размещен ваш код, используйте стратегию, перечисленную ниже:
GitHub
TBD
Google Cloud Build
TBD
AWS
TBD
Azure
TBD
Другие
TBD
На каком-то этапе мы откажемся от разделения ветки
masterи будем поддерживать только веткуdevelop. Поскольку зависимые проекты могут поддерживать стабильность через интеграции CI/CD. Сейчас сложно production-проекту слепо полагаться на веткуdevelop.
Ветка master содержит последний stable код и доступна через репозиторий PyPi и Docker-контейнеры через реестры docker.io и ghcr.io.
Проблемы, сообщенные для stable релизов, рассматриваются с наивысшим приоритетом. Однако в настоящее время мы не переносим исправления в старые релизы. Например, если вы сообщили о проблеме в v2.3.1, но текущая ветка master теперь содержит v2.4.0rc1. Тогда исправление попадет в v2.4.0rc2.
Ветка develop содержит передовые изменения
Ветка разработки поддерживается стабильной (в большинстве случаев). Но, если вам нужна 100% надежность и обслуживание пользователей в production-среде, ВСЕГДА используйте стабильную версию.
Один раз в месяц создается pull request vX.Y.ZrcN, который сливает develop → master. Ниже показано, как код переходит от pull request к следующему стабильному релизу.
Релиз разработки развертывается из develop → test.pypi.org после каждого слияния pull request
Альфа-релиз развертывается из develop → pypi.org до слияния pull request vX.Y.Z.rcN из ветки develop → master. До слияния rc pull request может быть выпущено несколько альфа-релизов.
Бета-релиз развертывается из master → pypi.org. Бета-релизы выпускаются в рамках подготовки к rc релизам и могут быть пропущены, если в них нет необходимости.
Кандидат на релиз (release candidate) развертывается из master → pypi.org. Кандидаты на релиз всегда публикуются перед финальным стабильным релизом.
v1.xproxy.py раньше создавал новые потоки для обработки клиентских запросов.
v2.0+proxy.py добавил поддержку выполнения клиентских запросов без потоков (threadless) с использованием asyncio.
v2.4.0+Выполнение без потоков было включено по умолчанию для Python 3.8+ на mac и linux.
По сообщениям пользователей, выполнение proxy.py без потоков безопасно в этих средах. Если вы столкнулись с проблемами, вернитесь к многопоточному режиму с помощью флага --threaded.
Для windows и Python < 3.8 вы все еще можете попробовать режим без потоков, запустив proxy.py с флагом --threadless.
Если режим без потоков работает для вас, рассмотрите возможность отправки PR, отредактировав метод _env_threadless_compliant в файле proxy/common/constants.py.
Оригинальная реализация без потоков использовала remote режим выполнения. Это также показано в Высокоуровневая архитектура в виде ASCII-арта.
В remote режиме выполнения акцепторы делегируют обработку входящих клиентских соединений удаленному рабочему процессу. По умолчанию акцепторы распределяют соединения по круговому принципу (round-robin). Рабочий процесс, обрабатывающий запрос, может работать на том же ядре CPU, что и акцептор, а может и нет. Такая архитектура хорошо масштабируется для высокой пропускной способности, но приводит к запуску двух процессов на каждое ядро CPU.
Например, если на машине N-CPU, по умолчанию запускается N акцепторов и N рабочих процессов. Вы можете настроить количество процессов с помощью флагов --num-acceptors и --num-workers. В зависимости от вашего сценария использования вам может понадобиться больше рабочих процессов, чем акцепторов, или наоборот.
В v2.4.x был добавлен local режим выполнения, в основном для уменьшения количества процессов, запускаемых по умолчанию. Эта модель хорошо подходит для повседневных сценариев использования одним пользователем и для тестирования разработчиками. В local режиме выполнения акцепторы делегируют клиентские соединения сопутствующему потоку, а не удаленному процессу. local режим обеспечивает привязку к CPU (CPU affinity), в отличие от remote режима, где акцептор и рабочий процесс могут работать на разных ядрах CPU.
--local-executor 1 был установлен по умолчанию в серии v2.4.x. В local режиме выполнения флаг --num-workers не действует, так как удаленные рабочие процессы не запускаются.
Чтобы использовать remote режим выполнения, используйте флаг --local-executor 0. Затем используйте --num-workers для настройки количества рабочих процессов.
proxy.py строго типизирован и использует аннотации типов Python typing. Пример:```python
my_strings : List[str] = [] #############^^^^^^^^^#####
Следовательно, требуется версия Python, поддерживающая аннотации типов.
Убедитесь, что вы используете `Python 3.6+`.
Проверьте версию перед запуском `proxy.py`:
`❯ python --version`
Все аннотации `typing` могут быть заменены аннотациями `comment-only`. Пример:```python
>>> my_strings = [] # List[str]
>>> ################^^^^^^^^^^^
Это позволит proxy.py работать на Python pre-3.6, даже на 2.7.
Однако, поскольку все будущие версии Python будут поддерживать аннотации typing,
это не было учтено.
Убедитесь, что модули плагинов доступны для поиска, добавив их в PYTHONPATH. Пример:
`PYTHONPATH=/path/to/my/app proxy --plugins my_app.proxyPlugin````console ...[redacted]... - Loaded plugin proxy.HttpProxyPlugin ...[redacted]... - Loaded plugin my_app.proxyPlugin
ИЛИ, просто передайте полностью квалифицированный путь в качестве параметра, например
`proxy --plugins /path/to/my/app/my_app.proxyPlugin`
Вот краткий рабочий пример:
- Содержимое папки `/tmp/plug````console
╰─ ls -1 /tmp/plug ─╯
my_plugin.py
MyPlugin класс```console
╰─ cat /tmp/plug/my_plugin.py ─╯
from proxy.http.proxy import HttpProxyBasePluginclass MyPlugin(HttpProxyBasePlugin): pass
Это пустой плагин для демонстрации использования внешних плагинов. Вы должны реализовать необходимые методы, чтобы ваши плагины работали с реальным трафиком.
- Запустите `proxy.py` с `MyPlugin````console
╰─ PYTHONPATH=/tmp/plug proxy --plugin my_plugin.MyPlugin ─╯
...[redacted]... - Loaded plugin proxy.http.proxy.HttpProxyPlugin
...[redacted]... - Loaded plugin my_plugin.MyPlugin
...[redacted]... - Listening on ::1:8899
Make sure proxy.py is listening on correct network interface.
Try following flags:
--hostname ::--hostname 0.0.0.0Most likely it's a browser integration issue with system keychain.
First verify that basic auth is working using curl
curl -v -x username:password@localhost:8899 https://httpbin.org/get
See this thread for further details.
It's a compatibility issue with vpnkit.
See moby/vpnkit exhausts docker resources and Connection refused: The proxy could not connect for some background.
A starter fluentd.conf template is available.
Copy this configuration file as proxy.py.conf under
/etc/google-fluentd/config.d/
Update path field to log file path as used with --log-file flag.
By default /tmp/proxy.log path is tailed.
Reload google-fluentd:
sudo service google-fluentd restart
Now proxy.py logs can be browsed using
GCE log viewer.
ValueError: filedescriptor out of range in selectproxy.py is made to handle thousands of connections per second
without any socket leaks.
--open-file-limit flag to customize ulimit -n.--backlog flag for higher concurrency.If nothing helps, open an issue
with requests per second sent and output of following debug script:```console
❯ ./helper/monitor_open_files.sh
## None:None в логах доступа
Иногда вы можете увидеть `None:None` в логах доступа. Это просто означает,
что соединение с вышестоящим сервером никогда не устанавливалось, т.е.
`upstream_host=None`, `upstream_port=None`.
Может быть несколько причин отсутствия соединения с вышестоящим сервером,
несколько очевидных включают:
1. Клиент установил соединение, но так и не завершил запрос.
2. Плагин вернул ответ преждевременно, избегая соединения с вышестоящим сервером.
## OSError при обёртывании клиента для TLS Interception
При включённом `TLS Interception` вы иногда можете увидеть следующие исключения:```console
2021-11-06 23:33:34,540 - pid:91032 [E] server.intercept:678 - OSError when wrapping client
Traceback (most recent call last):
...[redacted]...
...[redacted]...
...[redacted]...
ssl.SSLError: [SSL: TLSV1_ALERT_UNKNOWN_CA] tlsv1 alert unknown ca (_ssl.c:997)
...[redacted]... - CONNECT oauth2.googleapis.com:443 - 0 bytes - 272.08 ms
Некоторые клиенты могут вызывать TLSV1_ALERT_UNKNOWN_CA, если они не могут проверить сертификат сервера, поскольку он подписан неизвестным удостоверяющим центром. Это происходит, когда мы осуществляем перехват TLS. Причины могут быть разными, например, пиннинг сертификатов и т. д.
Другое исключение, которое вы можете увидеть, — это CERTIFICATE_VERIFY_FAILED:```console
2021-11-06 23:36:02,002 - pid:91033 [E] handler.handle_readables:293 - Exception while receiving from client connection <socket.socket fd=28, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 8899), raddr=('127.0.0.1', 51961)> with reason SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate in certificate chain (_ssl.c:997)')
Traceback (most recent call last):
...[redacted]...
...[redacted]...
...[redacted]...
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate in certificate chain (_ssl.c:997)
...[redacted]... - CONNECT init.push.apple.com:443 - 0 bytes - 892.99 ms
В будущем мы, возможно, добавим поддержку отправки исходного HTTPS-контента таким клиентам, продолжая при этом выполнять перехват TLS в фоновом режиме. Это позволит сохранить нормальную работу клиентов, не влияя на нашу способность перехватывать TLS. К сожалению, эта возможность в настоящее время недоступна.
Ещё один пример с исключением `SSLEOFError`:```console
2021-11-06 23:46:40,446 - pid:91034 [E] server.intercept:678 - OSError when wrapping client
Traceback (most recent call last):
...[redacted]...
...[redacted]...
...[redacted]...
ssl.SSLEOFError: EOF occurred in violation of protocol (_ssl.c:997)
...[redacted]... - CONNECT stock.adobe.io:443 - 0 bytes - 685.32 ms
+-------------+
| |
| Proxy([]) |
| |
+------+------+
|
|
+-----------v--------------+
| |
| AcceptorPool(...) |
| |
+------------+-------------+
|
+-----------------+ | +-----------------+ | | | | | | Acceptor(..) <-------------+-----------> Acceptor(..) | | | | | +---+-------------+ +---------+-------+ | | | | | +------++------++------++------++------+ | | | || || || || | | +----> || || || || <-----+ | || || || || | +------++------++------++------++------+ Threadless Worker Processes
`proxy.py` создана с прицелом на производительность. По умолчанию `proxy.py` будет стараться использовать все доступные ядра ЦП для приёма новых клиентских подключений. Это достигается запуском `AcceptorPool`, который прослушивает настроенный порт сервера. Затем `AcceptorPool` запускает процессы `Acceptor` (`--num-acceptors`) для приёма входящих клиентских подключений. Наряду с этим, если включён `--threadless`, запускается `ThreadlessPool`, который запускает процессы `Threadless` (`--num-workers`) для обработки входящих клиентских подключений.
Каждый процесс `Acceptor` делегирует принятое клиентское подключение процессу threadless через класс `Work`. В настоящее время классом работы по умолчанию является `HttpProtocolHandler`.
`HttpProtocolHandler` просто предполагает, что входящие клиенты будут следовать спецификации HTTP. Конкретные реализации HTTP-прокси и HTTP-сервера написаны как плагины для `HttpProtocolHandler`.
См. документацию `HttpProtocolHandlerPlugin` для доступных хуков жизненного цикла. Используйте `HttpProtocolHandlerPlugin` для добавления новых функций для http(s)-клиентов. Пример: см. `HttpWebServerPlugin`.
## Всё является плагином
Внутри `proxy.py` всё является плагином.
- Мы включаем плагины `proxy server` с помощью флага `--plugins`.
Прокси-сервер `HttpProxyPlugin` является плагином `HttpProtocolHandler`.
Кроме того, прокси-сервер позволяет подключать плагины через спецификацию `HttpProxyBasePlugin`.
- Все [примеры плагинов](#примеры-плагинов) прокси-сервера реализуют
`HttpProxyBasePlugin`. См. документацию `HttpProxyBasePlugin` для доступных хуков жизненного цикла. Используйте `HttpProxyBasePlugin`, чтобы изменить поведение протокола http(s)-прокси
между клиентом и вышестоящим сервером. Пример:
[FilterByUpstreamHostPlugin](#filterbyupstreamhostplugin).
- Также мы включаем встроенный `web server` с помощью `--enable-web-server`.
Веб-сервер `HttpWebServerPlugin` является плагином `HttpProtocolHandler`
и реализует спецификацию `HttpProtocolHandlerPlugin`.
- Также существует флаг `--disable-http-proxy`. Он отключает встроенный прокси-сервер.
Используйте этот флаг вместе с флагом `--enable-web-server`, чтобы запустить `proxy.py` как программируемый http(s)-сервер.
## Управление состояниями для ваших stateless-плагинов
Экземпляры классов плагинов создаются для каждого запроса. Самое важное: экземпляры плагинов создаются в контексте ядра ЦП, где был получен запрос.
По указанной причине глобальные переменные в ваших плагинах могут работать не так, как ожидается. Ваш код плагина по замыслу должен быть **stateless** (не иметь состояния).
Для управления глобальными состояниями у вас есть несколько вариантов:
1) Использовать [структуры данных, безопасные для многопроцессорной обработки](https://python.readthedocs.io/en/latest/library/multiprocessing.html#sharing-state-between-processes) из Python.
2) Использовать встроенный в `proxy.py` [механизм событий](https://github.com/abhinavsingh/proxy.py/blob/develop/tutorial/eventing.ipynb).
## Передача контекста обработки между плагинами
Иногда плагину может потребоваться передать дополнительный контекст другим плагинам, следующим за ним в цепочке обработки. Например, этот дополнительный контекст можно также выгружать в журналы доступа.
Для передачи контекста обработки используйте метод `on_access_log` плагина. См., как плагин [Program Name](https://github.com/abhinavsingh/proxy.py/blob/develop/proxy/plugin/program_name.py) изменяет ключ `client_ip` по умолчанию в контексте и обновляет его до определённого имени программы.
В результате, когда мы включаем [Program Name Plugin](#programnameplugin), в журналах доступа мы видим имя локальной клиентской программы вместо IP-адреса.
## Руководство по разработке
### Настройка локального окружения
Участники должны запускать `proxy.py` из исходного кода, чтобы проверить и разрабатывать новые функции / исправления.
См. раздел [Запуск proxy.py из командной строки с использованием исходного кода репозитория](#из-командной-строки-с-использованием-исходного-кода-репозитория) для подробностей.
[](https://github.com/abhinavsingh/proxy.py/issues/642) На `macOS` необходимо устанавливать `Python` с помощью `pyenv`, так как `Python`, установленный через `homebrew`, часто бывает проблематичным. Подробнее см. по ссылке в обсуждении.
### Настройка Git-хуков
Pre-commit hook гарантирует, что тесты проходят.
1. `cd /path/to/proxy.py`
2. `ln -s $(PWD)/git-pre-commit .git/hooks/pre-commit`
Pre-push hook гарантирует, что линтинг и тесты проходят.
1. `cd /path/to/proxy.py`
2. `ln -s $(PWD)/git-pre-push .git/hooks/pre-push`
### Отправка Pull Request
Каждый pull request тестируется с помощью GitHub Actions.
См. [GitHub workflow](https://github.com/abhinavsingh/proxy.py/tree/develop/.github/workflows) для списка тестов.
# Проекты, использующие Proxy.Py
Некоторые популярные проекты, использующие `proxy.py`
- [pip](https://github.com/pypa/pip)
- [ray-project](https://github.com/ray-project/ray)
- [aio-libs](https://github.com/aio-libs/aiohttp)
- [Selenium Base](https://github.com/seleniumbase/SeleniumBase)
- [wifipumpkin3](https://github.com/P0cL4bs/wifipumpkin3)
- [MerossIot](https://github.com/albertogeniola/MerossIot)
- [pyshorteners](https://github.com/ellisonleao/pyshorteners)
- [Slack API](https://github.com/slackapi/python-slack-events-api)
- [ibeam](https://github.com/Voyz/ibeam)
- [PyPaperBot](https://github.com/ferru97/PyPaperBot)
Полный список см. на [используется](https://github.com/abhinavsingh/proxy.py/network/dependents?package_id=UGFja2FnZS01MjQ0MDY5Ng%3D%3D)
# Бенчмарки
См. директорию [Benchmark](https://github.com/abhinavsingh/proxy.py/tree/develop/benchmark) для сведений о том, как запускать сравнительные бенчмарки с другими веб-серверами с открытым исходным кодом.
Чтобы запустить отдельный бенчмарк для `proxy.py`, используйте следующую команду из корня репозитория:```console
❯ ./benchmark/compare.sh
❯ proxy -h usage: -m [-h] [--tunnel-hostname TUNNEL_HOSTNAME] [--tunnel-port TUNNEL_PORT] [--tunnel-username TUNNEL_USERNAME] [--tunnel-ssh-key TUNNEL_SSH_KEY] [--tunnel-ssh-key-passphrase TUNNEL_SSH_KEY_PASSPHRASE] [--tunnel-remote-port TUNNEL_REMOTE_PORT] [--threadless] [--threaded] [--num-workers NUM_WORKERS] [--enable-events] [--inactive-conn-cleanup-timeout INACTIVE_CONN_CLEANUP_TIMEOUT] [--enable-proxy-protocol] [--enable-conn-pool] [--key-file KEY_FILE] [--cert-file CERT_FILE] [--client-recvbuf-size CLIENT_RECVBUF_SIZE] [--server-recvbuf-size SERVER_RECVBUF_SIZE] [--max-sendbuf-size MAX_SENDBUF_SIZE] [--timeout TIMEOUT] [--local-executor LOCAL_EXECUTOR] [--backlog BACKLOG] [--hostname HOSTNAME] [--hostnames HOSTNAMES [HOSTNAMES ...]] [--port PORT] [--ports PORTS [PORTS ...]] [--port-file PORT_FILE] [--unix-socket-path UNIX_SOCKET_PATH] [--num-acceptors NUM_ACCEPTORS] [--version] [--log-level LOG_LEVEL] [--log-file LOG_FILE] [--log-format LOG_FORMAT] [--open-file-limit OPEN_FILE_LIMIT] [--plugins PLUGINS [PLUGINS ...]] [--enable-dashboard] [--basic-auth BASIC_AUTH] [--enable-ssh-tunnel] [--work-klass WORK_KLASS] [--pid-file PID_FILE] [--openssl OPENSSL] [--data-dir DATA_DIR] [--ssh-listener-klass SSH_LISTENER_KLASS] [--disable-http-proxy] [--disable-headers DISABLE_HEADERS] [--ca-key-file CA_KEY_FILE] [--insecure-tls-interception] [--ca-cert-dir CA_CERT_DIR] [--ca-cert-file CA_CERT_FILE] [--ca-file CA_FILE] [--ca-signing-key-file CA_SIGNING_KEY_FILE] [--auth-plugin AUTH_PLUGIN] [--cache-requests] [--cache-by-content-type] [--cache-dir CACHE_DIR] [--proxy-pool PROXY_POOL] [--enable-web-server] [--enable-static-server] [--static-server-dir STATIC_SERVER_DIR] [--min-compression-length MIN_COMPRESSION_LENGTH] [--enable-reverse-proxy] [--rewrite-host-header] [--enable-metrics] [--metrics-path METRICS_PATH] [--pac-file PAC_FILE] [--pac-file-url-path PAC_FILE_URL_PATH] [--cloudflare-dns-mode CLOUDFLARE_DNS_MODE] [--filtered-upstream-hosts FILTERED_UPSTREAM_HOSTS] [--filtered-client-ips-mode FILTERED_CLIENT_IPS_MODE] [--filtered-client-ips FILTERED_CLIENT_IPS] [--filtered-url-regex-config FILTERED_URL_REGEX_CONFIG]
proxy.py v2.4.8.dev8+gc703edac.d20241013
options: -h, --help show this help message and exit --tunnel-hostname TUNNEL_HOSTNAME Default: None. Remote hostname or IP address to which SSH tunnel will be established. --tunnel-port TUNNEL_PORT Default: 22. SSH port of the remote host. --tunnel-username TUNNEL_USERNAME Default: None. Username to use for establishing SSH tunnel. --tunnel-ssh-key TUNNEL_SSH_KEY Default: None. Private key path in pem format --tunnel-ssh-key-passphrase TUNNEL_SSH_KEY_PASSPHRASE Default: None. Private key passphrase --tunnel-remote-port TUNNEL_REMOTE_PORT Default: 8899. Remote port which will be forwarded locally for proxy. --threadless Default: True. Enabled by default on Python 3.8+ (mac, linux). When disabled a new thread is spawned to handle each client connection. --threaded Default: False. Disabled by default on Python < 3.8 and windows. When enabled a new thread is spawned to handle each client connection. --num-workers NUM_WORKERS Defaults to number of CPU cores. --enable-events Default: False. Enables core to dispatch lifecycle events. Plugins can be used to subscribe for core events. --inactive-conn-cleanup-timeout INACTIVE_CONN_CLEANUP_TIMEOUT Time after which inactive works must be cleaned up. Increase this value if your backend services are slow to response or when proxy.py is handling a high volume. When running proxy.py on Google Cloud (GCP) you may see 'backend_connection_closed_before_data_sen t_to_client', with curl clients you may see 'Empty reply from server' error when '--inactive-conn- cleanup-timeout' value is low for your use-case. Default 1 seconds --enable-proxy-protocol Default: False. If used, will enable proxy protocol. Only version 1 is currently supported. --enable-conn-pool Default: False. (WIP) Enable upstream connection pooling. --key-file KEY_FILE Default: None. Server key file to enable end-to-end TLS encryption with clients. If used, must also pass --cert-file. --cert-file CERT_FILE Default: None. Server certificate to enable end-to-end TLS encryption with clients. If used, must also pass --key-file. --client-recvbuf-size CLIENT_RECVBUF_SIZE Default: 128 KB. Maximum amount of data received from the client in a single recv() operation. --server-recvbuf-size SERVER_RECVBUF_SIZE Default: 128 KB. Maximum amount of data received from the server in a single recv() operation. --max-sendbuf-size MAX_SENDBUF_SIZE Default: 64 KB. Maximum amount of data to flush in a single send() operation. --timeout TIMEOUT Default: 10.0. Number of seconds after which an inactive connection must be dropped. Inactivity is defined by no data sent or received by the client. --local-executor LOCAL_EXECUTOR Default: 1. Enabled by default. Use 0 to disable. When enabled acceptors will make use of local (same process) executor instead of distributing load across remote (other process) executors. Enable this option to achieve CPU affinity between acceptors and executors, instead of using underlying OS kernel scheduling algorithm. --backlog BACKLOG Default: 100. Maximum number of pending connections to proxy server. --hostname HOSTNAME Default: 127.0.0.1. Server IP address. --hostnames HOSTNAMES [HOSTNAMES ...] Default: None. Additional IP addresses to listen on. --port PORT Default: 8899. Server port. To listen on more ports, pass them using --ports flag. --ports PORTS [PORTS ...] Default: None. Additional ports to listen on. --port-file PORT_FILE Default: None. Save server port numbers. Useful when using --port=0 ephemeral mode. --unix-socket-path UNIX_SOCKET_PATH Default: None. Unix socket path to use. When provided --host and --port flags are ignored --num-acceptors NUM_ACCEPTORS Defaults to number of CPU cores. --version, -v Prints proxy.py version. --log-level LOG_LEVEL Valid options: DEBUG, INFO (default), WARNING, ERROR, CRITICAL. Both upper and lowercase values are allowed. You may also simply use the leading character e.g. --log-level d --log-file LOG_FILE Default: sys.stdout. Log file destination. --log-format LOG_FORMAT Log format for Python logger. --open-file-limit OPEN_FILE_LIMIT Default: 1024. Maximum number of files (TCP connections) that proxy.py can open concurrently. --plugins PLUGINS [PLUGINS ...]
---
[Read more](https://github.com/abhinavsingh/proxy.py)
ValueError: filedescriptor out of range in selectСмотрите Threads vs Threadless и Threadless Remote vs Local Execution Mode, чтобы управлять количеством используемых ядер CPU.
Смотрите Benchmark для получения дополнительной информации и инструкций по запуску бенчмарков локально.
Легковесный
~5-20 MB RAM
~25 MBПрограммируемый
--plugins proxy.plugin.ProxyPoolPlugin--enable-web-server --plugins proxy.plugin.WebServerPlugin--enable-reverse-proxy --plugins proxy.plugin.ReverseProxyPluginМожет слушать несколько адресов и портов
--hostnames для указания дополнительных адресов--ports для указания дополнительных портов--port для переопределения порта по умолчанию 8899Панель управления в реальном времени
--enable-dashboardhttp://localhost:8899/dashboardproxy.py во время выполненияtypescriptБезопасный
proxy.pyПриватный
Человек посередине
Поддерживаемые http протоколы для прокси-запросов
http(s)
http1http1.1 с пайплайномhttp2websocketsПоддержка HAProxy Protocol
--enable-proxy-protocolПоддержка статического файлового сервера
--enable-static-server и --static-server-dirОптимизирован для загрузки и скачивания больших файлов
--client-recvbuf-size, --server-recvbuf-size, --max-sendbuf-sizeПоддержка IPv4 и IPv6
--hostnameПоддержка Unix domain socket
--unix-socket-pathПоддержка базовой аутентификации
--basic-authПоддержка PAC (Proxy Auto-configuration)
--pac-file и --pac-file-url-pathStarted server on ::1:8899
proxy.py прослушивает IPv6 ::1, что эквивалентно IPv4 127.0.0.1proxy.py с внешнего хоста, используйте --hostname :: или --hostname 0.0.0.0 или привяжитесь к любому другому интерфейсу, доступному на вашей машине.proxy.py публичный IP, видимый вышестоящими серверами.Port 8899
--port для настройки порта TCP по умолчанию.Стабильный релиз развертывается из master → pypi.org