
💫 Alternativa a Ngrok FRP • ⚡ Rápido • 🪶 Ligero • 0️⃣ Dependencias • 🔌 Conectable • 😈 Interceptación TLS • 🔒 DNS sobre HTTPS • 🔥 VPN del pobre • ⏪ Reverso & ⏩ Adelante • 👮🏿 framework "Servidor Proxy" • 🌐 framework "Servidor Web" • ➵ ➶ ➷ ➠ framework "PubSub" • 👷 framework "Trabajo" aceptador y ejecutor
Rápido y Escalable
Escale verticalmente usando todos los núcleos disponibles en el sistema
Ejecuciones sin hilos usando asyncio
Diseñado para manejar decenas de miles de conexiones / seg
# 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
=============================
Consulte Desplegar proxy.py en producción al implementar aplicaciones de nivel de producción usando proxy.py.
Instale desde `PyPi````console ❯ pip install --upgrade proxy.py
o desde la rama `master` de GitHub```console
❯ pip install git+https://github.com/abhinavsingh/proxy.py.git@master
❯ pip install git+https://github.com/abhinavsingh/proxy.py.git@develop
## Usando Docker
Los contenedores multiplataforma están disponibles a través de:
- Docker Hub
- La etiqueta `latest` apunta a la última versión `stable`
- `docker pull abhinavsingh/proxy.py:latest`
- Registro de contenedores de GitHub (GHCR)
- La etiqueta `latest` apunta a la última versión `develop`
- `docker pull ghcr.io/abhinavsingh/proxy.py:latest`
Las versiones estables de contenedores están disponibles para las siguientes plataformas:
- `linux/386`
- `linux/amd64`
- `linux/arm/v6`
- `linux/arm/v7`
- `linux/arm64/v8`
- `linux/ppc64le`
- `linux/s390x`
### Versión estable desde Docker Hub
Ejecuta el contenedor más reciente de `proxy.py`:```console
❯ docker run -it -p 8899:8899 --rm abhinavsingh/proxy.py:latest
El demonio de Docker extraerá automáticamente la imagen de la plataforma correspondiente. Para ejecutar un contenedor de plataforma objetivo específica en servidores compatibles con múltiples plataformas:```console ❯ docker run -it -p 8899:8899 --rm --platform linux/arm64/v8 abhinavsingh/proxy.py:latest
### Versión de Desarrollo desde GHCR
Ejecuta el contenedor de `proxy.py` desde el código más reciente en la rama 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)
La imagen de `docker` actualmente está rota en `macOS` debido a incompatibilidad con [vpnkit](https://github.com/moby/vpnkit/issues/469).
## Usando HomeBrew
Las fórmulas actualizadas para `HomeBrew` se mantienen en la rama `develop` bajo el directorio `helper/homebrew`.
- `stable` fórmulas instalan el paquete desde la rama `master`.
- `develop` fórmulas instalan el paquete desde la rama `develop`.
### Versión Estable con 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
# Iniciar proxy.py
## Desde la línea de comandos cuando se instala mediante PIP
Cuando `proxy.py` se instala mediante `pip`,
se coloca un ejecutable llamado `proxy` en tu `$PATH`.
### Ejecutarlo
Simplemente escribe `proxy` en la línea de comandos para iniciar con la configuración predeterminada.```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
Cosas a notar de los registros anteriores:
Loaded plugin
proxy.py cargará proxy.http.proxy.HttpProxyPlugin por defectohttp(s) a la instancia de proxy.pyStarted N threadless workers
proxy.py iniciará tantos procesos worker como núcleos de CPU tenga la máquina--num-workers para personalizar el número de procesos workerStarted N acceptors
proxy.py iniciará tantos procesos acceptor como núcleos de CPU tenga la máquina--num-acceptors para personalizar el número de procesos acceptorTodos los registros anteriores son de nivel INFO, el --log-level por defecto para proxy.py
Iniciemos proxy.py con registro de nivel 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
Puedes usar una sola letra para personalizar el nivel de registro. Ejemplo:
- `d = DEBUG`
- `i = INFO`
- `w = WARNING`
- `e = ERROR`
- `c = CRITICAL`
Como podemos ver en los registros anteriores, antes de iniciar:
- `proxy.py` intentó establecer el límite de archivos abiertos `ulimit` en el sistema
- El valor predeterminado para `--open-file-limit` utilizado es `1024`
- La bandera `--open-file-limit` no tiene efecto en sistemas operativos `Windows`
Consulta [flags](#flags) para la lista completa de opciones de configuración disponibles.
## Desde la línea de comandos usando el repositorio fuente
Si estás intentando ejecutar `proxy.py` desde el código fuente,
no hay un archivo binario llamado `proxy` en el código fuente.
Para iniciar `proxy.py` desde el código fuente, sigue estas instrucciones:
- Clona el repositorio ```console
❯ git clone https://github.com/abhinavsingh/proxy.py.git
❯ cd proxy.py
Crear un entorno virtual de Python 3 ```console ❯ python3 -m venv venv ❯ source venv/bin/activate
Instalar dependencias ```console ❯ make lib-dep
Generar proxy/common/_scm_version.py
NOTA: El siguiente paso no es necesario para instalaciones editables.
Este archivo escribe la versión detectada por SCM en el archivo proxy/common/_scm_version.py. ```console
❯ ./write-scm-version.sh
Opcionalmente, ejecute las pruebas ```console ❯ make
Ejecuta proxy.py ```console
❯ python -m proxy
Vea Guía para desarrolladores y contribuyentes de plugins
si planea trabajar con el código fuente de proxy.py.
Por defecto, el binario docker se inicia con banderas de red IPv4:
--hostname 0.0.0.0 --port 8899
Puede anular la bandera desde la línea de comandos al iniciar el contenedor Docker. Por ejemplo, para verificar la versión de proxy.py dentro del contenedor Docker, ejecute:
❯ docker run -it \
-p 8899:8899 \
--rm abhinavsingh/proxy.py:latest \
-v
https
Agregue soporte para enlaces cortos en sus navegadores/aplicaciones favoritos.
Inicie proxy.py como:```console
❯ proxy
--plugins proxy.plugin.ShortLinkPlugin
Ahora puedes acelerar tu experiencia de navegación diaria visitando tu sitio web favorito usando nombres de dominio de un solo carácter :). Esto funciona en todos los navegadores.
Los siguientes enlaces cortos están habilitados por defecto:
| Enlace Corto | URL de Destino |
| :--------: | :---------------: |
| 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
Modifica el cuerpo de la solicitud POST antes de enviar la solicitud al servidor upstream.
Inicia `proxy.py` como:```console
❯ proxy \
--plugins proxy.plugin.ModifyPostDataPlugin
Por defecto el plugin reemplaza el contenido del cuerpo POST con el valor fijo b'{"key": "modified"}'
y fuerza Content-Type: application/json.
Verifica lo mismo usando `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" }
Nota a partir de la respuesta anterior:
1. Los datos POST fueron modificados `"data": "{\"key\": \"modified\"}"`.
Los datos originales del comando `curl` eran `{"key": "value"}`.
2. Nuestro comando `curl` no añadió ningún encabezado `Content-Type`,
pero nuestro plugin sí añadió uno `"Content-Type": "application/json"`.
Lo mismo se puede verificar observando el campo `json` en la salida anterior: ```
"json": {
"key": "modified"
},
Content-Length para coincidir con la longitud
del cuerpo modificado.Respuestas simuladas para la API REST de tu servidor. Úselo para probar y desarrollar aplicaciones del lado del cliente sin necesidad de un servidor REST API upstream real.
Inicie proxy.py como:```console
❯ proxy
--plugins proxy.plugin.ProposedRestApiPlugin
Verificar la respuesta de la API simulada usando `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"}]}
Verifique lo mismo al inspeccionar los registros de proxy.py:```console
... [redacted] ... - access_log:1210 - ::1:64792 - GET None:None/v1/users/ - None None - 0 byte
El registro de acceso muestra `None:None` como servidor `ip:port`. `None` simplemente significa que la conexión al servidor nunca se realizó, ya que la respuesta fue devuelta por nuestro plugin.
Ahora modifique `ProposedRestApiPlugin` para que devuelva respuestas simuladas de la API REST según lo esperado por sus clientes.
### RedirectToCustomServerPlugin
Redirige todas las solicitudes `http` entrantes a un servidor web personalizado.
Por defecto, redirige las solicitudes de los clientes al servidor web integrado,
que también se ejecuta en el puerto `8899`.
Inicie `proxy.py` y habilite el servidor web integrado:```console
❯ proxy \
--enable-web-server \
--plugins proxy.plugin.RedirectToCustomServerPlugin
Verifique usando `curl -v -x localhost:8899 http://google.com```` ... [redacted] ... < HTTP/1.1 404 NOT FOUND < Server: proxy.py v1.0.0 < Connection: Close <
La respuesta `404` anterior fue devuelta por el servidor web `proxy.py`.
Verifique lo mismo inspeccionando los registros de `proxy.py`.
Junto con el registro de solicitud del proxy, también debe ver un registro de solicitud del servidor web http.```
... [redacted] ... - access_log:1241 - ::1:49525 - GET /
... [redacted] ... - access_log:1157 - ::1:49524 - GET localhost:8899/ - 404 NOT FOUND - 70 bytes
Elimina tráfico inspeccionando el host ascendente.
Por defecto, el plugin elimina tráfico para facebook.com y www.facebok.com.
Inicie proxy.py como:```console
❯ proxy
--plugins proxy.plugin.FilterByUpstreamHostPlugin
Verifique usando `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
Arriba 418 I'm a tea pot es enviado por nuestro plugin. Verifícalo inspeccionando los registros de 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
Almacena en caché las respuestas del servidor upstream.
Inicia `proxy.py` como:```console
❯ proxy \
--plugins proxy.plugin.CacheResponsesPlugin
También puede usar la bandera --cache-requests para habilitar el almacenamiento en caché de paquetes de solicitud para inspección.
Verifique usando 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"
}
Obtén la ruta al archivo de caché de los registros de `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
Verificar el contenido del archivo de caché `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
El plugin `CacheResponsesPlugin` también puede almacenar en caché automáticamente las respuestas por `content-type`.
Para probar esto, debes estar ejecutando en modo [Intercepción TLS](#tls-interception)
y luego pasar el flag `--cache-by-content-type`. Ejemplo:```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
Haz algunas solicitudes al servidor proxy y verás datos en el directorio ~/.proxy/cache.
Deberías ver 2 carpetas:
content: Contiene archivos jpg, css, js, html, pdf, etc. analizados por tipo de contenidoresponses: Contiene las respuestas brutas tal como se recibieron (por supuesto descifradas debido a la intercepción)Modifica las respuestas del servidor ascendente.
Inicia proxy.py como:```console
❯ proxy
--plugins proxy.plugin.ManInTheMiddlePlugin
Verificar usando `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
1. Convertir dirección IP a entero
2. Convertir entero a dirección IP
3. Convertir dominio a dirección IP
4. Obtener dirección IP desde nombre de host
5. Obtener nombre de host desde dirección IP
6. Obtener registros DNS
7. Búsqueda Whois
8. Búsqueda de dirección MAC```console
❯ proxy --port 9001
Ahora, inicia proxy.py con ProxyPoolPlugin (en el puerto predeterminado 8899), apuntando a nuestros proxies upstream en los puertos 9000 y 9001.```console
❯ proxy
--plugins proxy.plugin.ProxyPoolPlugin
--proxy-pool localhost:9000
--proxy-pool localhost:9001
Realiza una solicitud curl a través del proxy `8899`:
`curl -v -x localhost:8899 http://httpbin.org/get`
Verifica que el proxy `8899` reenvíe las solicitudes a los proxies upstream revisando los registros respectivos.
Si un proxy upstream requiere credenciales, pásalas como argumentos. Ejemplo:
`--proxy-pool user:[email protected]:port`
### FilterByClientIpPlugin
Rechaza el tráfico de direcciones IP específicas. Por defecto, este plugin bloquea el tráfico de `127.0.0.1` y `::1`.
Inicia `proxy.py` como:```console
❯ proxy \
--plugins proxy.plugin.FilterByClientIpPlugin
Envíe una solicitud usando 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 <
Modifica el plugin a tu gusto, p. ej., permitir solo direcciones IP específicas.
### ModifyChunkResponsePlugin
Este plugin demuestra cómo modificar respuestas codificadas en fragmentos. Para ello, este plugin utiliza el núcleo de `proxy.py` para analizar la respuesta codificada en fragmentos. Luego, reconstruimos la respuesta usando fragmentos personalizados codificados de forma rígida, ignorando los fragmentos originales recibidos del servidor ascendente.
Inicia `proxy.py` como:```console
❯ proxy \
--plugins proxy.plugin.ModifyChunkResponsePlugin
Verifique usando curl -v -x localhost:8899 http://httpbin.org/stream/5:```console
... [redacted] ...
modify
chunk
response
plugin
Modifica `ModifyChunkResponsePlugin` a tu gusto. Por ejemplo, en lugar de enviar fragmentos codificados, analiza y modifica los fragmentos `JSON` originales recibidos del servidor ascendente.
### ModifyRequestHeaderPlugin
Este plugin demuestra cómo modificar las cabeceras de las solicitudes HTTPS salientes en modo de intercepción TLS.
Inicia `proxy.py` como:```console
❯ proxy \
--plugins proxy.plugin.ModifyRequestHeaderPlugin \
... [TLS interception flags] ...
Verifique usando 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
Este plugin usa `Cloudflare` hospedado `DNS-over-HTTPS` [API](https://developers.cloudflare.com/1.1.1.1/encrypted-dns/dns-over-https/make-api-requests/dns-json) (json).
`DoH` requiere un cliente compatible con HTTP2. Desafortunadamente `proxy.py` aún no lo proporciona, por lo que usamos una dependencia. Instálala:```console
❯ pip install "httpx[http2]"
Ahora inicie proxy.py como:```console
❯ proxy
--plugins proxy.plugin.CloudflareDnsResolverPlugin
Por defecto, `CloudflareDnsResolverPlugin` se ejecuta en modo `security` y proporciona protección contra malware.
Usa `--cloudflare-dns-mode family` para habilitar también la protección de contenido adulto.
### CustomDnsResolverPlugin
Este plugin demuestra cómo usar una implementación de resolución DNS personalizada con `proxy.py`.
Este plugin de ejemplo actualmente usa el mecanismo de resolución incorporado de Python. Personaliza el código
a tu gusto. Por ejemplo, consulta tu servidor DNS personalizado, implementa `DoH` u otros mecanismos.
Inicia `proxy.py` como:```console
❯ proxy \
--plugins proxy.plugin.CustomDnsResolverPlugin
El callback HttpProxyBasePlugin.resolve_dns también se puede usar para configurar la network interface que debe utilizarse como source_address para la conexión con el servidor upstream.
Ver este hilo para más detalles.
PD: No existe un plugin con ese nombre, pero CustomDnsResolverPlugin se puede personalizar fácilmente según sus necesidades.
Intenta resolver el nombre del programa (application) para las solicitudes de proxy que se originan en la máquina local.
Si se identifica, la IP del cliente en los registros de acceso se reemplaza con el nombre del programa.
Inicie proxy.py como:```console
❯ proxy
--plugins proxy.plugin.ProgramNamePlugin
Haz una solicitud utilizando `curl`:```console
❯ curl -v -x localhost:8899 https://httpbin.org/get
Debes ver líneas de registro como estas:```console ... [redacted] ... - [I] server.access_log:419 - curl:58096 - CONNECT httpbin.org:443 - 6010 bytes - 1824.62ms
Aviso `curl` en lugar de `::1` o `127.0.0.1` como IP del cliente.
[](#programnameplugin) Si `ProgramNamePlugin` no funciona de manera fiable en su sistema operativo, por favor contribuya enviando una solicitud de extracción y/o abriendo un issue. ¡¡¡Gracias!!!
## Plugins del Servidor Web HTTP
### Ruta del Servidor Web
Demuestra el enrutamiento integrado del servidor web mediante un plugin.
Inicie `proxy.py` como:```console
❯ proxy --enable-web-server \
--plugins proxy.plugin.WebServerPlugin
Verifica usando curl -v localhost:8899/http-route-example, debería devolver:```console
HTTP route response
## Plugins de Proxy Inverso
Extiende el servidor web integrado para agregar capacidades de proxy inverso.
### Proxy Inverso
Inicia `proxy.py` como:```console
❯ proxy --enable-reverse-proxy \
--plugins proxy.plugin.ReverseProxyPlugin
Con la configuración predeterminada, el plugin ReverseProxyPlugin es equivalente a la siguiente configuración de Nginx:```console
location /get {
proxy_pass http://httpbin.org/get;
}
Verifique usando `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"
}
Con el ejemplo anterior, a veces puede ver:```console
Esto está sucediendo porque nuestro plugin de proxy inverso predeterminado `ReverseProxyPlugin` está configurado
con un servidor upstream `http` y otro `https`. Y, por defecto, `ReverseProxyPlugin` preserva el
encabezado de host original. Mientras que esto funciona con upstreams `https`, no funciona de manera confiable con
upstreams `http`. Para solucionar este problema use los flags `--rewrite-host-header`.
Example:
```bash
some-command --rewrite-host-header
``````console
❯ proxy --enable-reverse-proxy \
--plugins proxy.plugin.ReverseProxyPlugin \
--rewrite-host-header
Esto asegurará que el campo de cabecera Host esté configurado como httpbin.org y funcione tanto con upstream http como https.
NOTA: Si usar
--rewrite-host-headero no depende de tu caso de uso.
Al usar múltiples plugins, dependiendo de la funcionalidad del plugin, puede valer la pena considerar el orden en que se pasan los plugins en la línea de comandos.
Los plugins se llaman en el mismo orden en que se pasan. Por ejemplo, supongamos que estamos usando tanto FilterByUpstreamHostPlugin como RedirectToCustomServerPlugin. La idea es descartar todas las solicitudes http entrantes para facebook.com y www.facebook.com y redirigir otras solicitudes http a nuestro servidor web incorporado.
Por lo tanto, en este escenario es importante usar FilterByUpstreamHostPlugin antes de RedirectToCustomServerPlugin. Si habilitamos RedirectToCustomServerPlugin antes de FilterByUpstreamHostPlugin, las solicitudes facebook también se redirigirán al servidor web incorporado, en lugar de ser descartadas.
Por defecto, proxy.py usa el protocolo http para la comunicación con los clientes, por ejemplo curl, navegador. Para habilitar el cifrado de extremo a extremo usando tls / https, primero genera certificados. Clona el repositorio y ejecuta:```console
make https-certificates
Inicia `proxy.py` como:```console
❯ proxy \
--cert-file https-cert.pem \
--key-file https-key.pem
Verifique usando 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"
}
Si quieres evitar pasar la bandera `--proxy-cacert`, también considera firmar los certificados SSL generados. Ejemplo:
Primero, genera los certificados CA:```console
make ca-certificates
Luego, firma el certificado SSL:```console make sign-https-certificates
Ahora reinicie el servidor con el indicador `--cert-file https-signed-cert.pem`. Tenga en cuenta que también debe confiar en el certificado `ca-cert.pem` generado en su llavero de sistema.
# Intercepción TLS
Por defecto, `proxy.py` no descifrará el tráfico `https` entre el cliente y el servidor. Para habilitar la intercepción TLS, primero genere los certificados CA raíz:```console
❯ make ca-certificates
También habilitemos CacheResponsePlugin para que podamos verificar la respuesta descifrada del servidor. Inicie proxy.py como:```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) También proporcione la ruta explícita del paquete CA necesaria para la validación de certificados de pares. Consulte la bandera `--ca-file`.
Verifique la intercepción TLS usando `curl````console
❯ curl -v -x localhost:8899 --cacert ca-cert.pem https://httpbin.org/get
[Más información sobre cada tarea se puede encontrar en la página de resumen o dentro de la interfaz de usuario. Cuando DrHeader esté en ejecución, puedes ir a http://localhost:5000/info]```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" }
La línea `issuer` confirma que la respuesta fue interceptada.
También verifica el contenido del archivo de respuesta en caché. Obtén la ruta al archivo de caché de los registros de `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"
}
¡Viola!!! Si eliminas las banderas CA, los datos cifrados se encontrarán en el archivo en caché en lugar de texto plano.
Ahora usa las banderas CA con otros
ejemplos de plugins para verlos funcionar con tráfico https.
Para interceptar tráfico TLS de un servidor que utiliza un certificado autofirmado,
añade la bandera --insecure-tls-interception para deshabilitar la validación obligatoria del certificado TLS.
NOTA: Esta bandera deshabilita la verificación del certificado para todos los servidores.
Notas importantes sobre la intercepción TLS con contenedor Docker:
Desde v2.2.0, el contenedor docker de proxy.py también incluye openssl. Esto permite a proxy.py
generar certificados sobre la marcha para la intercepción TLS.
Por razones de seguridad, el contenedor docker de proxy.py no incluye
certificados CA.
Así es como iniciar un contenedor docker de proxy.py
con intercepción TLS:
-v /tmp/ca-certificates:/tmp/ca-certificates monta nuestro directorio de certificados CA en el entorno del contenedor.
--plugins proxy.plugin.CacheResponsesPlugin habilita CacheResponsesPlugin para que podamos inspeccionar el tráfico interceptado.--ca-* habilitan la Intercepción TLS.curl. Puede omitir el flag --cacert si el certificado CA ya es de confianza para el sistema. ```console
❯ curl -v issuer de los encabezados de respuesta. ```console
cat para ver el volcado de respuesta: ```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 es una alternativa directa para ngrok y frpgrout viene empaquetado dentro de 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
## Autenticación de Grout
Grout soporta autenticación para proteger tus archivos, carpetas y servicios de accesos no autorizados. Usa la bandera `--basic-auth` para exigir autenticación. Ejemplo:```console
grout /path/to/folder --basic-auth user:pass
grout https://localhost:8080 --basic-auth u:p
Por defecto, Grout permite el acceso a todas las rutas en los servicios. Use la bandera --path para restringir el acceso solo a ciertas rutas en su servicio web. Ejemplo:```console
grout https://localhost:8080 --path /worker/
grout https://localhost:8080 --path /webhook/ --path /callback/
## Grout Wildcard Domains
Por defecto, el cliente Grout sirve tráfico entrante en un subdominio dedicado.
Sin embargo, algunos servicios (por ejemplo, Kubernetes) pueden querer servir tráfico en subdominios ad hoc.
Iniciar un cliente Grout dedicado para cada subdominio ad hoc puede no ser una solución práctica.
Para tales escenarios, Grout soporta dominios wildcard. Aquí se explica cómo configurar tu propio dominio wildcard para usar con clientes Grout.
1. Elige un dominio, p. ej. `custom.example.com`
2. Tu servicio desea servir tráfico para `custom.example.com` y `*.custom.example.com`
3. Si planeas usar `https://`, necesitas configurar un balanceador de carga:
- Configura un balanceador de carga HTTPS (LB)
- Configura el LB con un certificado generado para `custom.example.com` y `*.custom.example.com`
- Dirige el tráfico a las direcciones IP públicas del servicio Grout
4. Contacta al equipo de Grout en [email protected] para incluir `custom.example.com` en la lista blanca. El equipo de Grout se asegurará de que realmente eres dueño del dominio y de que has configurado un certificado SSL válido como se describió anteriormente
Inicia Grout con la bandera `--wildcard`. Ejemplo:```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
Solo disponible con
--wildcard
Junto con la ruta predeterminada, también puede proporcionar rutas adicionales que tienen prioridad cuando el campo host coincide. Ejemplo:```console
grout https://localhost:8080 custom.example.com
--wildcard
--tunnel-route-url stream.example.com=http://localhost:7001
Puede proporcionar múltiples rutas personalizadas repitiendo esta bandera.
## Complemento de Cliente Grout
`GroutClientBasePlugin` le permite enrutar tráfico dinámicamente a diferentes upstreams. A continuación se muestra una implementación simple con una descripción sobre cómo usarlo.```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
Vea grout_client.py para más información. Para probarlo, comience pasando --plugin proxy.plugin.grout_client.GroutClientPlugin al iniciar el cliente grout.
❯ docker run --rm -it
--entrypoint grout
-v ~/.proxy:/root/.proxy
abhinavsingh/proxy.py:latest
http://host.docker.internal:29876
Sobre:
- Cambiamos `--entrypoint` a `grout`
- Reemplazamos `localhost` con `host.docker.internal`, para que `grout` pueda enrutar tráfico al puerto `29876` ejecutándose en la máquina host
- *(Opcional)* Montar la carpeta `~/.proxy` de la máquina host, para que las credenciales de `grout` puedan persistir entre reinicios del contenedor
## Cómo funciona Grout
- La infraestructura de `grout` tiene 2 componentes: cliente y servidor
- El cliente de `grout` tiene 2 componentes: un cliente ligero y un cliente pesado
- El cliente ligero de `grout` es parte de `proxy.py` de código abierto (Licencia BSD 3-Clause)
- El cliente pesado de `grout` y los servidores están alojados en [jaxl.io](https://jaxl.io)
y son propiedad intelectual de [Jaxl Innovations Private Limited](https://jaxl.com)
- El servidor de `grout` tiene 3 componentes: un servidor de registro, un servidor proxy inverso y un servidor de túneles
## `grout` autoalojado
- El cliente pesado de `grout` y los servidores también pueden alojarse en tus infraestructuras GCP, AWS, Cloud
- Con una versión autoalojada, tu tráfico fluye a través de la red que controlas y en la que confías
- Los desarrolladores de `grout` en [jaxl.io](https://jaxl.io) proporcionan imágenes GCP, AWS y Docker para soluciones autoalojadas
- Por favor, envía un correo electrónico a [[email protected]](mailto:[email protected]) para empezar.
# Proxy a través de túnel SSH
**Esto es un trabajo en progreso y puede no funcionar como está documentado**
Requiere `paramiko` para funcionar. Instala las dependencias usando `pip install "proxy.py[tunnel]"`
## Proxy de solicitudes remotas localmente
|
+------------+ | +----------+
| LOCAL | | | REMOTE |
| HOST | <== SSH ==== :8900 == | PROXY |
+------------+ | +----------+
:8899 proxy.py |
|
FIREWALL
(allow tcp/22)
### Qué
Proxy de solicitudes HTTP(s) realizadas en un servidor proxy `remoto` a través del servidor `proxy.py` ejecutándose en `localhost`.
### Cómo
- El puerto `remoto` solicitado se reenvía a través de la conexión SSH.
- `proxy.py` ejecutándose en `localhost` maneja y responde a
las solicitudes proxy `remotas`.
### Requisitos
1. `localhost` DEBE tener acceso SSH al servidor `remoto`
2. El servidor `remoto` DEBE estar configurado para proxy de solicitudes HTTP(s)
a través del número de puerto reenviado, p. ej., `:8900`.
- Los puertos `remoto` y `localhost` PUEDEN ser el mismo, p. ej., `:8899`.
- Se eligió `:8900` en el diagrama ASCII con fines de diferenciación.
### Pruébalo
Inicia `proxy.py` como:```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...
Haga una solicitud HTTP proxy en el servidor remote y verifique que la respuesta contiene la dirección IP pública de localhost como origen:```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"
}
Además, verifique que los registros de `proxy.py` en `localhost` contengan la IP `remote` como IP del cliente.```console
access_log:328 - remote:52067 - GET httpbin.org:80
|
+------------+ | +----------+
| LOCAL | | | REMOTE |
| HOST | === SSH =====> | SERVER |
+------------+ | +----------+
| :8899 proxy.py
|
FIREWALL
(allow tcp/22)
No planificado.
Si tienes un caso de uso válido, por favor abre un issue. Siempre eres bienvenido a enviar contribuciones a través de pull-requests para añadir esta funcionalidad :)
Para hacer proxy de solicitudes locales de forma remota, utiliza el Proxy Pool Plugin.
Inicia proxy.py en modo incrustado con la configuración por defecto usando el método proxy.main. Ejemplo:```python
import proxy
if name == 'main': proxy.main()
Personaliza las banderas de inicio pasándolas como kwargs:```python
import ipaddress
import proxy
if __name__ == '__main__':
proxy.main(
hostname=ipaddress.IPv6Address('::1'),
port=8899
)
Nota:
main es equivalente a iniciar proxy.py desde la línea de comandos.main no acepta ningún args (solo kwargs).main consumirá automáticamente cualquier sys.argv disponible como args.main se bloqueará hasta que proxy.py se cierre.Inicie proxy.py en modo integrado sin bloqueo con la configuración predeterminada
usando el administrador de contexto Proxy: Ejemplo:```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()
Ten en cuenta que:
1. `Proxy` es similar a `main`, excepto que `Proxy` no bloqueará.
2. Internamente, `Proxy` es un administrador de contexto que iniciará
`proxy.py` al ser llamado y lo detendrá una vez que el ámbito termine.
3. A diferencia de `main`, las banderas de inicio con `Proxy` también se pueden personalizar
usando `args` y `kwargs`. p. ej. `Proxy(['--port', '8899'])` o
pasando banderas como kwargs, p. ej. `Proxy(port=8899)`.
4. A diferencia de `main`, `Proxy` no inspeccionará `sys.argv`.
## Puerto Efímero
Usa `--port=0` para vincular `proxy.py` a un puerto aleatorio asignado por el kernel.
En modo embebido, puedes acceder a este puerto. Ejemplo:```python
import proxy
if __name__ == '__main__':
with proxy.Proxy(port=0) as p:
print(p.flags.port)
proxy.sleep_loop()
flags.port le dará acceso al puerto aleatorio asignado por el kernel.
Los usuarios pueden usar la bandera --plugins varias veces para cargar múltiples plugins.
Consulte Incapaz de cargar plugins si tiene problemas.
Cuando se usa en modo embebido, tiene algunas opciones más. Ejemplo:
bytes al método proxy.main o al administrador de contexto proxy.Proxy.type de la clase del plugin. Esto es especialmente útil si planea definir plugins en tiempo de ejecución.Ejemplo, cargar un solo plugin usando la bandera --plugins:```python
import proxy
if name == 'main': proxy.main(plugins=['proxy.plugin.CacheResponsesPlugin'])
Para simplificar, también puedes pasar la lista de plugins como un argumento de palabra clave a `proxy.main` o al constructor `Proxy`.
Ejemplo:```python
import proxy
from proxy.plugin import FilterByUpstreamHostPlugin
if __name__ == '__main__':
proxy.main(plugins=[
b'proxy.plugin.CacheResponsesPlugin',
FilterByUpstreamHostPlugin,
])
proxy.TestCasePara configurar y limpiar proxy.py para tus clases de unittest de Python, simplemente usa proxy.TestCase en lugar de unittest.TestCase.
Ejemplo:```python
import proxy
class TestProxyPyEmbedded(proxy.TestCase):
def test_my_application_with_proxy(self) -> None:
self.assertTrue(True)
Tenga en cuenta que:
1. `proxy.TestCase` anula el método `unittest.TestCase.run()` para configurar y cerrar `proxy.py`.
2. El servidor `proxy.py` escuchará en un puerto disponible aleatorio del sistema.
Este puerto aleatorio está disponible como `self.PROXY.flags.port` dentro de sus casos de prueba.
3. Solo se inicia un único acceptor y worker de forma predeterminada (`--num-workers 1 --num-acceptors 1`) para una configuración y cierre más rápidos.
4. Más importante aún, `proxy.TestCase` también garantiza que el servidor `proxy.py`
esté en funcionamiento antes de proceder con la ejecución de las pruebas. Por defecto,
`proxy.TestCase` esperará `10 segundos` para que el servidor `proxy.py` se inicie;
en caso de fallo, se generará una excepción `TimeoutError`.
## Sobrescribir banderas de inicio
Para sobrescribir las banderas de inicio predeterminadas, defina una variable `PROXY_PY_STARTUP_FLAGS` en su clase de prueba.
Ejemplo:```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)
See test_embed.py for full working example.
unittest.TestCaseSi por alguna razón no puedes usar directamente proxy.TestCase, entonces simplemente sobrescribe unittest.TestCase.run tú mismo para configurar y desmontar proxy.py. Ejemplo:```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)
o simplemente configurar / finalizar `proxy.py` dentro de los métodos de clase `setUpClass` y `teardownClass`.
# Utilidades
## Sockets TCP
### new_socket_connection
Intenta crear una conexión IPv4, luego IPv6 y finalmente una conexión de doble pila hacia la dirección proporcionada.```python
>>> conn = new_socket_connection(('httpbin.org', 80))
>>> ...[ use connection ]...
>>> conn.close()
socket_connection es un decorador + administrador de contexto conveniente alrededor de new_socket_connection que asegura que conn.close sea implícito.
Como administrador de contexto:```python
with socket_connection(('httpbin.org', 80)) as conn: ... [ use connection ] ...
Como un decorador:```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
### Uso de la 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
Consulte pki.py y test_pki.py para ver ejemplos de uso.
Utilice el módulo proxy.common.pki para:
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
## Documentación Interna
### Leer la Documentación
- Visita [proxypy.readthedocs.io](https://proxypy.readthedocs.io/)
- Construye localmente usando:
`make lib-doc`
### pydoc
El código está bien documentado. Obtén el código fuente y ejecuta:
`pydoc3 proxy`
### pyreverse
Genera diagramas UML de jerarquía a nivel de clase para un análisis en profundidad:
`make lib-pyreverse`
# Ejecutar Dashboard
El Dashboard está actualmente en desarrollo y aún no incluido en los paquetes `pip`.
Para ejecutar el dashboard, debes clonar el código fuente.
Dashboard está escrito en Typescript y SCSS, así que construyámoslo primero usando:```console
❯ make dashboard
También construye el Chrome DevTools embebido si planeas usarlo:```console
❯ make devtools
Ahora inicie `proxy.py` con el plugin de panel y sobrescribiendo el directorio raíz para el servidor estático:```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
Actualmente, habilitar el panel también habilitará todos los plugins del panel.
Visite el panel:```console ❯ open http://localhost:8899/dashboard/
## Inspeccionar Tráfico
***Esto es un trabajo en progreso y puede que no funcione como está documentado***
Espere a que se cargue `Chrome Dev Console` incrustado. Actualmente, los detalles sobre todo el tráfico que fluye a través de `proxy.py` se envían a la pestaña `Inspeccionar Tráfico`. Sin embargo, los payloads recibidos aún no están integrados con la consola de desarrollador incrustada.
La funcionalidad actual se puede verificar abriendo la `Dev Console` del panel e inspeccionando la conexión websocket que el panel estableció con el servidor `proxy.py`.
[](https://github.com/abhinavsingh/proxy.py)
# Chrome DevTools Protocol
Para escenarios donde quieras acceso directo al endpoint websocket del protocolo `Chrome DevTools`, inicie `proxy.py` como:```console
❯ proxy --enable-devtools --enable-events
Ahora apunta tu instancia CDT a ws://localhost:8899/devtools.
proxy.py con el flag --enable-metrics para métricas internas a través de un endpoint de prometheusprometheus.yaml para que recolecte del endpoint /metrics, por ejemplo http://localhost:8899/metrics--metrics-path--enable-metrics internamente también habilita --enable-events y el plugin del servidor webA continuación se enumeran algunas estrategias para usar proxy.py en tus proyectos privados/de producción/corporativos.
DEBES
evitar bifurcarel repositorio "solo" para poner tu código de plugin en el directorioproxy/plugin. La bifurcación es un flujo de trabajo recomendado para los contribuyentes del proyecto, NO para los usuarios del proyecto.
--plugin, --plugins o el argumento plugin.proxy.py.Se recomienda encarecidamente que uses proxy.py mediante requirements.txt o configuraciones similares de gestión de dependencias. Esto te permitirá aprovechar las actualizaciones periódicas de rendimiento, correcciones de errores, parches de seguridad y otras mejoras que ocurren en el ecosistema de proxy.py. Ejemplo:
Usa la opción --pre para depender de la última pre-release
❯ pip install proxy.py --pre
Las pre-releases son similares a depender del código de la rama develop, solo que las pre-releases pueden no apuntar al HEAD. Esto puede ocurrir porque las pre-releases NO están disponibles en PyPi después de cada fusión de PR.
Usa TestPyPi con la opción --pre para depender del código de la rama develop
❯ pip install -i https://test.pypi.org/simple/ proxy.py --pre
Se pone a disposición una pre-release en TestPyPi después de cada fusión de PR.
Usa el código de la última versión stable
Si te gusta desplegar contenedores, simplemente construye tu imagen a partir de las imágenes base del contenedor proxy.py.
Usa GHCR para construir desde el código de la rama develop:
FROM ghcr.io/abhinavsingh/proxy.py:latest as base
PD: Yo uso la última versión de GHCR para varios proyectos de nivel de producción
Usa DockerHub para construir desde el código de la última versión stable:
FROM abhinavsingh/proxy.py:latest as base
PD: En mi humilde opinión, la estrategia basada en contenedores es el mejor enfoque y la única estrategia que yo mismo uso.
Oye, pero sigues haciendo cambios que rompen la compatibilidad en la rama develop.
Te escucho. Y por lo tanto, para tus aplicaciones de nivel de producción, DEBES integrar el CI/CD de la aplicación con proxy.py. Debes asegurarte de que tu aplicación se construya y pase sus pruebas por cada fusión de PR en el repositorio ascendente de proxy.py.
Si tu repositorio de aplicación es público, en ciertos escenarios, los autores de PR pueden enviar PRs de parche para todas las dependencias para mantener la incompatibilidad hacia atrás y el CI/CD en verde.
La integración de CI/CD asegura que tu aplicación continúe construyéndose con el código más reciente de proxy.py. Dependiendo de dónde alojes tu código, usa la estrategia listada a continuación:
GitHub
Pendiente
Google Cloud Build
Pendiente
AWS
Pendiente
Azure
Pendiente
Otros
Pendiente
En algún momento, dejaremos de usar la segregación de la rama
mastery simplemente mantendremos una ramadevelop. Ya que los dependientes pueden mantener la estabilidad mediante integraciones de CI/CD. Actualmente, es difícil para un proyecto de nivel de producción depender ciegamente de la ramadevelop.
La rama master contiene el código stable más reciente y está disponible a través del repositorio PyPi y contenedores Docker a través de los registros docker.io y ghcr.io.
Los problemas reportados para versiones stable se consideran con la máxima prioridad. Sin embargo, actualmente no retroportamos correcciones a versiones anteriores. Por ejemplo, si reportaste un problema en v2.3.1, pero la rama master actual ahora contiene v2.4.0rc1. Entonces, la corrección llegará en v2.4.0rc2.
La rama develop contiene cambios de vanguardia
La rama de desarrollo se mantiene estable (la mayoría de las veces). Pero, si deseas 100% de confiabilidad y servir usuarios en entorno de producción, SIEMPRE usa la versión estable.
Se crea una solicitud de extracción vX.Y.ZrcN una vez al mes que fusiona develop → master. A continuación se muestra cómo fluye el código desde una solicitud de extracción hasta la próxima versión estable.
La versión de desarrollo se despliega de develop → test.pypi.org después de cada fusión de solicitud de extracción
La versión alfa se despliega de develop → pypi.org antes de fusionar la solicitud de extracción vX.Y.Z.rcN de develop → rama master. Puede haber múltiples versiones alfa antes de fusionar la solicitud de extracción rc
La versión beta se despliega de master → pypi.org. Las versiones beta se realizan en preparación de las versiones rc y pueden omitirse si no son necesarias
El candidato de lanzamiento se despliega de master → pypi.org. Los candidatos de lanzamiento siempre están disponibles antes de la versión estable final
v1.xproxy.py solía generar nuevos hilos para manejar las solicitudes de los clientes.
v2.0+proxy.py agregó soporte para ejecución sin hilos de solicitudes de clientes usando asyncio.
v2.4.0+La ejecución sin hilos se activó por defecto para Python 3.8+ en entornos mac y linux.
La ejecución sin hilos de proxy.py ha sido reportada como segura en estos entornos por nuestros usuarios. Si tienes problemas, vuelve al modo con hilos usando el flag --threaded.
Para windows y Python < 3.8, aún puedes probar el modo sin hilos iniciando proxy.py con el flag --threadless.
Si el modo sin hilos te funciona, considera enviar un PR editando el método _env_threadless_compliant en el archivo proxy/common/constants.py.
La implementación original sin hilos usaba el modo de ejecución remote. Esto también se muestra en Arquitectura de alto nivel como arte ASCII.
En el modo de ejecución remote, los aceptores delegan el procesamiento de las conexiones entrantes de clientes a un proceso trabajador remoto. Por defecto, los aceptores delegan las conexiones de forma round-robin. El trabajador que procesa la solicitud puede o no estar ejecutándose en el mismo núcleo de CPU que el aceptor. Esta arquitectura escala bien para alto rendimiento, pero resulta en la creación de dos procesos por núcleo de CPU.
Por ejemplo, si hay N CPU en la máquina, por defecto se inician N aceptores y N procesos trabajadores. Puedes ajustar el número de procesos usando los flags --num-acceptors y --num-workers. Puede que necesites más trabajadores que aceptores o viceversa según tu caso de uso.
En v2.4.x, se agregó el modo de ejecución local, principalmente para reducir la cantidad de procesos generados por defecto. Este modelo funciona bien para casos de uso diario de un solo usuario y para escenarios de pruebas de desarrolladores. En el modo de ejecución local, los aceptores delegan las conexiones de clientes a un hilo compañero, en lugar de a un proceso remoto. El modo de ejecución local asegura afinidad de CPU, a diferencia del modo remote donde el aceptor y el trabajador pueden estar ejecutándose en diferentes núcleos de CPU.
--local-executor 1 se estableció como predeterminado en la serie v2.4.x. En el modo de ejecución local, el flag --num-workers no tiene efecto, ya que no se inician trabajadores remotos.
Para usar el modo de ejecución remote, usa el flag --local-executor 0. Luego usa --num-workers para ajustar el número de procesos trabajadores.
proxy.py está estrictamente tipado y usa anotaciones de typing de Python. Ejemplo:```python
my_strings : List[str] = [] #############^^^^^^^^^#####
Por lo tanto, se requiere una versión de Python que entienda las anotaciones typing. Asegúrate de usar `Python 3.6+`. Verifica la versión antes de ejecutar `proxy.py`: `❯ python --version` Todas las anotaciones `typing` se pueden reemplazar con anotaciones `comment-only`. Ejemplo:```python
>>> my_strings = [] # List[str]
>>> ################^^^^^^^^^^^
Esto permitirá que proxy.py se ejecute en Python pre-3.6, incluso en 2.7.
Sin embargo, dado que todas las versiones futuras de Python serán compatibles con las anotaciones typing, esto no se ha considerado.
Asegúrese de que los módulos de los plugins se puedan descubrir agregándolos a PYTHONPATH. Ejemplo:
`PYTHONPATH=/path/to/my/app proxy --plugins my_app.proxyPlugin````console ...[redacted]... - Loaded plugin proxy.HttpProxyPlugin ...[redacted]... - Loaded plugin my_app.proxyPlugin
O, simplemente pase la ruta completamente calificada como parámetro, por ej.
`proxy --plugins /path/to/my/app/my_app.proxyPlugin`
Aquí hay un ejemplo rápido de trabajo:
- Contenidos de la carpeta `/tmp/plug````console
╰─ ls -1 /tmp/plug ─╯
my_plugin.py
MyPlugin personalizada```console
╰─ cat /tmp/plug/my_plugin.py ─╯
from proxy.http.proxy import HttpProxyBasePluginclass MyPlugin(HttpProxyBasePlugin): pass
Este es un plugin vacío para demostrar el uso de plugins externos. Debes implementar los métodos necesarios para que tus plugins funcionen con tráfico real
- Inicia `proxy.py` con `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
Asegúrate de que proxy.py esté escuchando en la interfaz de red correcta. Prueba las siguientes opciones:
--hostname ::--hostname 0.0.0.0Probablemente sea un problema de integración del navegador con el llavero del sistema.
Primero verifica que la autenticación básica funcione usando curl
curl -v -x username:password@localhost:8899 https://httpbin.org/get
Consulta este hilo para obtener más detalles.
Es un problema de compatibilidad con vpnkit.
Consulta moby/vpnkit agota los recursos de docker y Conexión rechazada: El proxy no pudo conectar para más contexto.
Hay disponible una plantilla inicial de fluentd.conf.
Copia este archivo de configuración como proxy.py.conf en
/etc/google-fluentd/config.d/
Actualiza el campo path a la ruta del archivo de registro utilizada con la opción --log-file.
Por defecto se sigue la ruta /tmp/proxy.log.
Recarga google-fluentd:
sudo service google-fluentd restart
Ahora los registros de proxy.py se pueden explorar usando
el visor de registros de GCE.
ValueError: filedescriptor out of range in selectproxy.py está diseñado para manejar miles de conexiones por segundo
sin fugas de sockets.
--open-file-limit para personalizar ulimit -n.--backlog para mayor concurrencia.Si nada ayuda, abre un issue
con las solicitudes por segundo enviadas y la salida del siguiente script de depuración:
import socket
import select
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
s.connect(('127.0.0.1', 8899))
except Exception as e:
print("Could not connect to proxy.py:", e)
raise SystemExit(1)
# Print the file descriptor number
print("Socket FD:", s.fileno())
# Try to select on it
r, w, e = select.select([s], [], [], 1)
print("Readable:", r, "Writable:", w, "Error:", e)
``````console
❯ ./helper/monitor_open_files.sh <proxy-py-pid>
A veces puedes ver None:None en los registros de acceso. Simplemente significa
que nunca se estableció una conexión con el servidor upstream, es decir,
upstream_host=None, upstream_port=None.
Puede haber varias razones para que no haya conexión upstream; algunas obvias incluyen:
Con la Intercepción TLS activada, ocasionalmente puedes ver las siguientes excepciones:```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
Algunos clientes pueden lanzar `TLSV1_ALERT_UNKNOWN_CA` si no pueden verificar el certificado del servidor porque está firmado por una CA emisora desconocida. Que es el caso cuando estamos realizando interceptación TLS. Esto puede deberse a varias razones, por ejemplo, fijación de certificados, etc.
Otra excepción que podrías ver es `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
En el futuro, podríamos admitir la entrega de contenido HTTPS original para dichos clientes mientras seguimos realizando la intercepción TLS en segundo plano. Esto mantendrá a los clientes satisfechos sin afectar nuestra capacidad de intercepción TLS. Desafortunadamente, esta funcionalidad no está disponible actualmente.
Otro ejemplo con la excepción 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
# Guía para desarrolladores de plugins y colaboradores
## Arquitectura de alto nivel```console
+-------------+
| |
| Proxy([]) |
| |
+------+------+
|
|
+-----------v--------------+
| |
| AcceptorPool(...) |
| |
+------------+-------------+
|
+-----------------+ | +-----------------+
| | | | |
| Acceptor(..) <-------------+-----------> Acceptor(..) |
| | | |
+---+-------------+ +---------+-------+
| |
| |
| +------++------++------++------++------+ |
| | || || || || | |
+----> || || || || <-----+
| || || || || |
+------++------++------++------++------+
Threadless Worker Processes
proxy.py está hecho con el rendimiento en mente. Por defecto, proxy.py intentará utilizar todos los núcleos de CPU disponibles para aceptar nuevas conexiones de clientes. Esto se logra iniciando AcceptorPool, que escucha en el puerto del servidor configurado. Luego, AcceptorPool inicia procesos Acceptor (--num-acceptors) para aceptar conexiones entrantes de clientes. Además, si --threadless está habilitado, se configura ThreadlessPool, que inicia procesos Threadless (--num-workers) para manejar las conexiones entrantes de clientes.
Cada proceso Acceptor delega la conexión de cliente aceptada a un proceso threadless a través de la clase Work. Actualmente, HttpProtocolHandler es la clase de trabajo predeterminada.
HttpProtocolHandler simplemente asume que los clientes entrantes seguirán la especificación HTTP. Las implementaciones específicas de proxy HTTP y servidor HTTP se escriben como complementos de HttpProtocolHandler.
Consulte la documentación de HttpProtocolHandlerPlugin para conocer los hooks de ciclo de vida disponibles. Use HttpProtocolHandlerPlugin para agregar nuevas funciones para clientes http(s). Por ejemplo, consulte HttpWebServerPlugin.
Dentro de proxy.py, todo es un complemento.
Habilitamos complementos de proxy server usando la bandera --plugins.
El proxy server HttpProxyPlugin es un complemento de HttpProtocolHandler.
Además, el proxy server permite complementos a través de la especificación HttpProxyBasePlugin.
Todos los ejemplos de complementos del proxy server implementaban
HttpProxyBasePlugin. Consulte la documentación de HttpProxyBasePlugin para conocer los hooks de ciclo de vida disponibles. Use HttpProxyBasePlugin para modificar el comportamiento del protocolo proxy http(s) entre el cliente y el servidor upstream. Por ejemplo,
FilterByUpstreamHostPlugin.
También habilitamos el web server incorporado usando --enable-web-server.
El web server HttpWebServerPlugin es un complemento de HttpProtocolHandler
e implementa la especificación .
Las instancias de clases de complemento se crean por solicitud. Es importante destacar que las instancias de complemento se crean dentro del contexto del núcleo de CPU donde se recibió la solicitud.
Por la razón anterior, las variables globales en sus complementos pueden no funcionar como se espera. Su código de complemento, por diseño, debe ser sin estado.
Para gestionar estados globales, tiene un par de opciones:
proxy.py.A veces, un complemento puede necesitar pasar contexto adicional a otros complementos que le siguen en la cadena de procesamiento. Por ejemplo, este contexto adicional también puede ser volcado como parte de los registros de acceso.
Para pasar contexto de procesamiento, use el método on_access_log del complemento. Consulte cómo el complemento Program Name modifica la clave client_ip predeterminada en el contexto y la actualiza al nombre del programa detectado.
Como resultado, cuando habilitamos Program Name Plugin, vemos el nombre del programa del cliente local en lugar de la dirección IP en los registros de acceso.
Los contribuyentes deben iniciar proxy.py desde el código fuente para verificar y desarrollar nuevas características / correcciones.
Consulte Ejecutar proxy.py desde la línea de comandos usando el código fuente del repositorio para más detalles.
En
macOS
debe instalar Python usando pyenv, ya que el Python instalado mediante homebrew tiende a
ser problemático. Consulte el hilo vinculado para más detalles.
El hook pre-commit asegura que las pruebas pasen.
cd /path/to/proxy.pyln -s $(PWD)/git-pre-commit .git/hooks/pre-commitEl hook pre-push asegura que el lint y las pruebas pasen.
cd /path/to/proxy.pyln -s $(PWD)/git-pre-push .git/hooks/pre-pushCada pull request se prueba usando GitHub actions.
Consulte el flujo de trabajo de GitHub para la lista de pruebas.
Algunos proyectos populares que usan proxy.py
Para la lista completa, consulte usado por
Consulte el directorio Benchmark sobre cómo ejecutar comparaciones de benchmarks con otros servidores web OSS.
Para ejecutar el benchmark independiente de proxy.py, use el siguiente comando desde la raíz del repositorio:```console
❯ ./benchmark/compare.sh
# Banderas```console
❯ 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 ...]
Comma separated plugins. You may use --plugins flag
multiple times.
--enable-dashboard Default: False. Enables proxy.py dashboard.
--basic-auth BASIC_AUTH
Default: No authentication. Specify colon separated
user:password to enable basic authentication.
--enable-ssh-tunnel Default: False. Enable SSH tunnel.
--work-klass WORK_KLASS
Default: proxy.http.HttpProtocolHandler. Work klass to
use for work execution.
--pid-file PID_FILE Default: None. Save "parent" process ID to a file.
--openssl OPENSSL Default: openssl. Path to openssl binary. By default,
assumption is that openssl is in your PATH.
--data-dir DATA_DIR Default: ~/.proxypy. Path to proxypy data directory.
--ssh-listener-klass SSH_LISTENER_KLASS
Default: proxy.core.ssh.listener.SshTunnelListener. An
implementation of BaseSshTunnelListener
--disable-http-proxy Default: False. Whether to disable
proxy.HttpProxyPlugin.
--disable-headers DISABLE_HEADERS
Default: None. Comma separated list of headers to
remove before dispatching client request to upstream
server.
--ca-key-file CA_KEY_FILE
Default: None. CA key to use for signing dynamically
generated HTTPS certificates. If used, must also pass
--ca-cert-file and --ca-signing-key-file
--insecure-tls-interception
Default: False. Disables certificate verification
--ca-cert-dir CA_CERT_DIR
Default: ~/.proxy/certificates. Directory to store
dynamically generated certificates. Also see --ca-key-
file, --ca-cert-file and --ca-signing-key-file
--ca-cert-file CA_CERT_FILE
Default: None. Signing certificate to use for signing
dynamically generated HTTPS certificates. If used,
must also pass --ca-key-file and --ca-signing-key-file
--ca-file CA_FILE Default: /Users/abhinavsingh/Dev/proxy.py/.venv3122/li
b/python3.12/site-packages/certifi/cacert.pem. Provide
path to custom CA bundle for peer certificate
verification
--ca-signing-key-file CA_SIGNING_KEY_FILE
Default: None. CA signing key to use for dynamic
generation of HTTPS certificates. If used, must also
pass --ca-key-file and --ca-cert-file
--auth-plugin AUTH_PLUGIN
Default: proxy.http.proxy.auth.AuthPlugin. Auth plugin
to use instead of default basic auth plugin.
--cache-requests Default: False. Whether to also write request packets
in the cache file.
--cache-by-content-type
Default: False. Whether to extract content by type
from responses. Extracted content type is written to
the cache directory e.g. video.mp4.
--cache-dir CACHE_DIR
Default: /Users/abhinavsingh/.proxy/cache. Flag only
applicable when cache plugin is used with on-disk
storage.
--proxy-pool PROXY_POOL
List of upstream proxies to use in the pool
--enable-web-server Default: False. Whether to enable
proxy.HttpWebServerPlugin.
--enable-static-server
Default: False. Enable inbuilt static file server.
Optionally, also use --static-server-dir to serve
static content from custom directory. By default,
static file server serves out of installed proxy.py
python module folder.
--static-server-dir STATIC_SERVER_DIR
Default: "public" folder in directory where proxy.py
is placed. This option is only applicable when static
server is also enabled. See --enable-static-server.
--min-compression-length MIN_COMPRESSION_LENGTH
Default: 20 bytes. Sets the minimum length of a
response that will be compressed (gzipped).
--enable-reverse-proxy
Default: False. Whether to enable reverse proxy core.
--rewrite-host-header
Default: False. If used, reverse proxy server will
rewrite Host header field before sending to upstream.
--enable-metrics Default: False. Enables metrics.
--metrics-path METRICS_PATH
Default: /metrics. Web server path to serve proxy.py
metrics.
--pac-file PAC_FILE A file (Proxy Auto Configuration) or string to serve
when the server receives a direct file request. Using
this option enables proxy.HttpWebServerPlugin.
--pac-file-url-path PAC_FILE_URL_PATH
Default: /. Web server path to serve the PAC file.
--cloudflare-dns-mode CLOUDFLARE_DNS_MODE
Default: security. Either "security" (for malware
protection) or "family" (for malware and adult content
protection)
--filtered-upstream-hosts FILTERED_UPSTREAM_HOSTS
Default: Blocks Facebook. Comma separated list of IPv4
and IPv6 addresses.
--filtered-client-ips-mode FILTERED_CLIENT_IPS_MODE
Default: blacklist. Can be either "whitelist"
(restrict access to specific IPs)or "blacklist" (allow
everything except specific IPs).
--filtered-client-ips FILTERED_CLIENT_IPS
Default: 127.0.0.1,::1. Comma separated list of IPv4
and IPv6 addresses.
--filtered-url-regex-config FILTERED_URL_REGEX_CONFIG
Default: No config. Comma separated list of IPv4 and
IPv6 addresses.
Proxy.py not working? Report at:
https://github.com/abhinavsingh/proxy.py/issues/new
ValueError: filedescriptor out of range in selectConsulte Threads vs Threadless y Modo de Ejecución Threadless Remoto vs Local para controlar el número de núcleos de CPU utilizados.
Vea Benchmark para más detalles y para saber cómo ejecutar benchmarks localmente.
Ligero
~5-20 MB de RAM
~25 MBProgramable
--plugins proxy.plugin.ProxyPoolPlugin--enable-web-server --plugins proxy.plugin.WebServerPlugin--enable-reverse-proxy --plugins proxy.plugin.ReverseProxyPluginPuede escuchar en múltiples direcciones y puertos
--hostnames para proporcionar direcciones adicionales--ports para proporcionar puertos adicionales--port para sobrescribir el puerto predeterminado 8899Panel de Control en Tiempo Real
--enable-dashboardhttp://localhost:8899/dashboardproxy.py en tiempo de ejecucióntypescriptSeguro
proxy.pyPrivado
Man-In-The-Middle
Protocolos http soportados para solicitudes de proxy
http(s)
http1http1.1 con pipelinehttp2websocketsSoporte para Protocolo HAProxy
--enable-proxy-protocolSoporte para servidor de archivos estáticos
--enable-static-server y --static-server-dirOptimizado para cargas y descargas de archivos grandes
--client-recvbuf-size, --server-recvbuf-size, --max-sendbuf-sizeSoporte para IPv4 e IPv6
--hostnameSoporte para sockets de dominio Unix
--unix-socket-pathSoporte para autenticación básica
--basic-authSoporte para PAC (Configuración Automática de Proxy)
--pac-file y --pac-file-url-pathStarted server on ::1:8899
proxy.py escucha en IPv6 ::1, que es el equivalente de IPv4 127.0.0.1proxy.py desde un host externo, use --hostname :: o --hostname 0.0.0.0 o vincúlese a cualquier otra interfaz disponible en su máquina.proxy.py vista por los servidores upstream.Port 8899
--port para personalizar el puerto TCP por defecto.Como de costumbre, simplemente usa:
❯ pip install proxy.py
La versión estable se despliega de master → pypi.org
HttpProtocolHandlerPluginTambién existe una bandera --disable-http-proxy. Deshabilita el proxy server incorporado.
Use esta bandera junto con --enable-web-server para ejecutar proxy.py como un servidor http(s) programable.