
💫 Alternative à Ngrok FRP • ⚡ Rapide • 🪶 Léger • 0️⃣ Dépendance • 🔌 Extensible • 😈 Interception TLS • 🔒 DNS sur HTTPS • 🔥 VPN du pauvre • ⏪ Inverse & ⏩ Direct • 👮🏿 Cadriciel "Serveur Proxy" • 🌐 Cadriciel "Serveur Web" • ➵ ➶ ➷ ➠ Cadriciel "PubSub" • 👷 Cadriciel d'accepteur & exécuteur de travaux
Rapide et évolutif
Montez en charge en utilisant tous les cœurs disponibles sur le système
Exécutions sans threads avec asyncio
Conçu pour gérer des dizaines de milliers de connexions / seconde
# Sur 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
=============================
Consultez Déploiement de proxy.py en production lors du déploiement d'applications de niveau production utilisant proxy.py.
Installer depuis `PyPi````console ❯ pip install --upgrade proxy.py
ou depuis GitHub branche `master````console
❯ pip install git+https://github.com/abhinavsingh/proxy.py.git@master
❯ pip install git+https://github.com/abhinavsingh/proxy.py.git@develop
## Utilisation de Docker
Des conteneurs multi-plateformes sont disponibles via :
- Docker Hub
- La balise `latest` pointe vers la dernière version `stable`
- `docker pull abhinavsingh/proxy.py:latest`
- GitHub container registry (GHCR)
- La balise `latest` pointe vers la dernière version `develop`
- `docker pull ghcr.io/abhinavsingh/proxy.py:latest`
Les versions stables des conteneurs sont disponibles pour les plateformes suivantes :
- `linux/386`
- `linux/amd64`
- `linux/arm/v6`
- `linux/arm/v7`
- `linux/arm64/v8`
- `linux/ppc64le`
- `linux/s390x`
### Version stable depuis Docker Hub
Exécutez le dernier conteneur `proxy.py` :```console
❯ docker run -it -p 8899:8899 --rm abhinavsingh/proxy.py:latest
Le démon Docker va automatiquement télécharger l'image correspondant à la plateforme. Pour exécuter un conteneur spécifique à une plateforme cible sur des serveurs supportant plusieurs plateformes :```console ❯ docker run -it -p 8899:8899 --rm --platform linux/arm64/v8 abhinavsingh/proxy.py:latest
### Version de développement depuis GHCR
Exécutez le conteneur `proxy.py` à partir du code de pointe de la branche 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)
L'image `docker` est actuellement cassée sur `macOS` en raison d'une incompatibilité avec [vpnkit](https://github.com/moby/vpnkit/issues/469).
## Using HomeBrew
Les formules mises à jour pour `HomeBrew` sont maintenues dans la branche `develop` sous le répertoire `helper/homebrew`.
- `stable` formulae installe le paquet depuis la branche `master`.
- `develop` formulae installe le paquet depuis la branche `develop`.
### Version stable avec 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
# Démarrer proxy.py
## Depuis la ligne de commande lorsqu'il est installé via PIP
Lorsque `proxy.py` est installé via `pip`,
un exécutable nommé `proxy` est placé dans votre `$PATH`.
### Lancer
Tapez simplement `proxy` dans la ligne de commande pour démarrer avec la configuration par défaut.```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
Éléments à remarquer dans les logs ci-dessus :
Loaded plugin
proxy.py chargera proxy.http.proxy.HttpProxyPlugin par défauthttp(s) à l'instance proxy.pyStarted N threadless workers
proxy.py démarrera autant de processus workers qu'il y a de cœurs CPU sur la machine--num-workers pour personnaliser le nombre de processus workersStarted N acceptors
proxy.py démarrera autant de processus accepteurs qu'il y a de cœurs CPU sur la machine--num-acceptors pour personnaliser le nombre de processus accepteursTous les logs ci-dessus sont des logs de niveau INFO, --log-level par défaut pour proxy.py
Démarrons proxy.py avec le niveau de log 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
Vous pouvez utiliser une seule lettre pour personnaliser le niveau de journalisation. Exemple :
- `d = DEBUG`
- `i = INFO`
- `w = WARNING`
- `e = ERROR`
- `c = CRITICAL`
Comme nous pouvons le voir dans les journaux ci-dessus, avant le démarrage :
- `proxy.py` a essayé de définir la limite de fichiers ouverts `ulimit` sur le système
- La valeur par défaut pour `--open-file-limit` utilisée est `1024`
- Le drapeau `--open-file-limit` est sans effet (no-op) sur les systèmes d'exploitation `Windows`
Voir [flags](#flags) pour la liste complète des options de configuration disponibles.
## Depuis la ligne de commande en utilisant la source du dépôt
Si vous essayez d'exécuter `proxy.py` à partir du code source,
il n'y a pas de fichier binaire nommé `proxy` dans le code source.
Pour démarrer `proxy.py` à partir du code source, suivez ces instructions :
- Clonez le dépôt ```console
❯ git clone https://github.com/abhinavsingh/proxy.py.git
❯ cd proxy.py
Installer les dépendances ```console ❯ make lib-dep
- Générer `proxy/common/_scm_version.py`
NOTE : *L'étape suivante n'est pas nécessaire pour les installations modifiables.*
Ce fichier écrit la version détectée SCM dans le fichier `proxy/common/_scm_version.py`. ```console
❯ ./write-scm-version.sh
proxy.py ```console
❯ python -m proxy
Voir le Guide du développeur de plugins et contributeur
si vous prévoyez de travailler avec le code source de proxy.py.
Par défaut, le binaire docker est démarré avec les indicateurs de réseau IPv4 :
--hostname 0.0.0.0 --port 8899
Vous pouvez remplacer les indicateurs depuis la ligne de commande lors du démarrage du conteneur Docker. Par exemple, pour vérifier la version de proxy.py dans le conteneur Docker, exécutez :
❯ docker run -it \
-p 8899:8899 \
--rm abhinavsingh/proxy.py:latest \
-v
https
Ajoutez la prise en charge des liens courts dans vos navigateurs/applications préférés.
Démarrez proxy.py comme suit :```console
❯ proxy
--plugins proxy.plugin.ShortLinkPlugin
Now you can speed up your daily browsing experience by visiting your
favorite website using single character domain names :). This works
across all browsers.
Following short links are enabled by default:
| Lien court | URL de destination |
| :--------: | :--------------: |
| 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
Modifies POST request body before sending request to upstream server.
Start `proxy.py` as:```console
❯ proxy \
--plugins proxy.plugin.ModifyPostDataPlugin
Par défaut, le plugin remplace le contenu du corps POST avec le contenu codé en dur b'{"key": "modified"}'
et impose Content-Type: application/json.
Vérifiez cela en utilisant `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" }
Note suite à la réponse ci-dessus :
1. Les données POST ont été modifiées `"data": "{\"key\": \"modified\"}"`.
Les données de la commande `curl` originale étaient `{"key": "value"}`.
2. Notre commande `curl` n'a ajouté aucun en-tête `Content-Type`,
mais notre plugin en a ajouté un `"Content-Type": "application/json"`.
On peut également vérifier cela en regardant le champ `json` dans la sortie ci-dessus : ```
"json": {
"key": "modified"
},
Content-Length pour correspondre à la longueur
du corps modifié.Réponses simulées pour votre API REST serveur. Utilisez pour tester et développer des applications côté client sans avoir besoin d'un serveur API REST amont réel.
Lancez proxy.py comme :```console
❯ proxy
--plugins proxy.plugin.ProposedRestApiPlugin
Vérifier la réponse de l'API mock en utilisant `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"}]}
Vérifiez cela en inspectant les logs de proxy.py :```console
... [redacted] ... - access_log:1210 - ::1:64792 - GET None:None/v1/users/ - None None - 0 byte
Le journal d'accès montre `None:None` comme serveur `ip:port`. `None` signifie simplement que la connexion au serveur n'a jamais été établie, car la réponse a été renvoyée par notre plugin.
Modifiez maintenant `ProposedRestApiPlugin` pour renvoyer des réponses simulées de l'API REST comme attendu par vos clients.
### RedirectToCustomServerPlugin
Redirige toutes les requêtes `http` entrantes vers un serveur web personnalisé.
Par défaut, il redirige les requêtes client vers le serveur web intégré,
également en cours d'exécution sur le port `8899`.
Démarrez `proxy.py` et activez le serveur web intégré :```console
❯ proxy \
--enable-web-server \
--plugins proxy.plugin.RedirectToCustomServerPlugin
Vérifiez avec `curl -v -x localhost:8899 http://google.com```` ... [redacted] ... < HTTP/1.1 404 NOT FOUND < Server: proxy.py v1.0.0 < Connection: Close <
La réponse `404` ci-dessus a été renvoyée par le serveur web `proxy.py`.
Vérifiez cela en inspectant les logs de `proxy.py`.
En plus du log de requête proxy, vous devez également voir un log de requête de serveur web http.```
... [redacted] ... - access_log:1241 - ::1:49525 - GET /
... [redacted] ... - access_log:1157 - ::1:49524 - GET localhost:8899/ - 404 NOT FOUND - 70 bytes
Supprime le trafic en inspectant l'hôte amont.
Par défaut, le plugin supprime le trafic pour facebook.com et www.facebok.com.
Lancez proxy.py comme :```console
❯ proxy
--plugins proxy.plugin.FilterByUpstreamHostPlugin
Vérifier en utilisant `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
Ci-dessus, 418 I'm a tea pot est envoyé par notre plugin. Vérifiez cela en inspectant les logs pour 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
Met en cache les réponses du serveur en amont.
Démarrez `proxy.py` comme suit :```console
❯ proxy \
--plugins proxy.plugin.CacheResponsesPlugin
Vous pouvez également utiliser l'option --cache-requests pour activer la mise en cache des paquets de demande pour inspection.
Vérifiez en utilisant 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"
}
Obtenez le chemin du fichier cache à partir des journaux 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
Vérifiez le contenu du fichier de cache `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
Le plugin `CacheResponsesPlugin` peut également mettre en cache automatiquement les réponses par `content-type`.
Pour essayer cela, vous devez être en mode [TLS Interception](#tls-interception) puis passer le drapeau `--cache-by-content-type`. Exemple :```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
Faites quelques requêtes au serveur proxy et vous verrez des données dans le répertoire ~/.proxy/cache.
Vous devriez voir 2 dossiers :
content: Contient les fichiers jpg, css, js, html, pdf etc. analysés par type de contenuresponses: Contient les réponses brutes telles que reçues (bien sûr déchiffrées en raison de l'interception)Modifie les réponses du serveur en amont.
Lancez proxy.py comme suit :```console
❯ proxy
--plugins proxy.plugin.ManInTheMiddlePlugin
Vérifiez en utilisant `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
Le corps de réponse Hello from man in the middle est envoyé par notre plugin.
Transfère les requêtes proxy entrantes vers un ensemble de serveurs proxy en amont.
Commençons par lancer 2 proxies en amont. Pour simuler des proxies en amont,
lancez proxy.py sur les ports 9000 et `9001````console
❯ proxy --port 9000
<!-- No content provided in the INPUT section. Please supply the Markdown text to translate. -->```console
❯ proxy --port 9001
Maintenant, lancez proxy.py avec ProxyPoolPlugin (sur le port par défaut 8899),
pointant vers nos proxies amont sur les ports 9000 et 9001.```console
❯ proxy
--plugins proxy.plugin.ProxyPoolPlugin
--proxy-pool localhost:9000
--proxy-pool localhost:9001
Effectuez une requête curl via le proxy `8899` :
`curl -v -x localhost:8899 http://httpbin.org/get`
Vérifiez que le proxy `8899` transmet les requêtes aux proxies amont en consultant les journaux respectifs.
Si un proxy amont nécessite des identifiants, passez-les en arguments. Exemple :
`--proxy-pool user:[email protected]:port`
### FilterByClientIpPlugin
Rejetez le trafic provenant d'adresses IP spécifiques. Par défaut, ce plugin bloque le trafic en provenance de `127.0.0.1` et `::1`.
Lancez `proxy.py` comme suit :```console
❯ proxy \
--plugins proxy.plugin.FilterByClientIpPlugin
Envoyez une requête en utilisant 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 <
Modifiez le plugin selon vos goûts, par ex. n'autoriser que des adresses IP spécifiques.
### ModifyChunkResponsePlugin
Ce plugin démontre comment modifier des réponses chunked. Pour ce faire, ce plugin utilise le noyau de `proxy.py` pour analyser la réponse chunked. Ensuite, nous reconstruisons la réponse en utilisant des morceaux personnalisés codés en dur, ignorant les morceaux originaux reçus du serveur amont.
Lancez `proxy.py` comme :```console
❯ proxy \
--plugins proxy.plugin.ModifyChunkResponsePlugin
Vérifiez en utilisant curl -v -x localhost:8899 http://httpbin.org/stream/5:```console
... [redacted] ...
modify
chunk
response
plugin
Modifiez `ModifyChunkResponsePlugin` à votre goût. Par exemple, au lieu d'envoyer des morceaux codés en dur, analysez et modifiez les morceaux `JSON` originaux reçus du serveur en amont.
### ModifyRequestHeaderPlugin
Ce plugin montre comment modifier les en-têtes de requêtes HTTPS sortantes sous mode d'interception TLS.
Lancez `proxy.py` comme suit :```console
❯ proxy \
--plugins proxy.plugin.ModifyRequestHeaderPlugin \
... [TLS interception flags] ...
Vérifiez en utilisant 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
Ce plugin utilise `Cloudflare` qui héberge `DNS-over-HTTPS` [API](https://developers.cloudflare.com/1.1.1.1/encrypted-dns/dns-over-https/make-api-requests/dns-json) (json).
`DoH` exige un client compatible HTTP2. Malheureusement, `proxy.py` ne le fournit pas encore, donc nous utilisons une dépendance. Installez-la :```console
❯ pip install "httpx[http2]"
Maintenant, lancez proxy.py comme suit :```console
❯ proxy
--plugins proxy.plugin.CloudflareDnsResolverPlugin
Par défaut, `CloudflareDnsResolverPlugin` s'exécute en mode `security` et fournit une protection contre les logiciels malveillants.
Utilisez `--cloudflare-dns-mode family` pour également activer la protection contre le contenu pour adultes.
### CustomDnsResolverPlugin
Ce plugin montre comment utiliser une implémentation personnalisée de résolution DNS avec `proxy.py`.
Ce plugin exemple utilise actuellement le mécanisme de résolution intégré de Python. Personnalisez le code à votre goût. Par exemple, interrogez votre serveur DNS personnalisé, implémentez `DoH` ou d'autres mécanismes.
Démarrez `proxy.py` comme suit :```console
❯ proxy \
--plugins proxy.plugin.CustomDnsResolverPlugin
HttpProxyBasePlugin.resolve_dns callback can also be used to configure network interface which must be used as the source_address for connection to the upstream server.
See this thread for more details.
PS: There is no plugin named, but CustomDnsResolverPlugin can be easily customized according to your needs.
Tente de résoudre le nom du programme (application) pour les requêtes proxy provenant de la machine locale. Si identifié, l'IP du client dans les journaux d'accès est remplacée par le nom du programme.
Démarrez proxy.py comme suit :
python3 -m proxy \
--plugins proxy.plugin.ProgramNamePlugin
``````console
❯ proxy \
--plugins proxy.plugin.ProgramNamePlugin
Faites une requête en utilisant curl:```console
❯ curl -v -x localhost:8899 https://httpbin.org/get
Vous devez voir des lignes de log comme celles-ci :```console
... [redacted] ... - [I] server.access_log:419 - curl:58096 - CONNECT httpbin.org:443 - 6010 bytes - 1824.62ms
Remarque : utilisez curl à la place de ::1 ou 127.0.0.1 comme IP client.
Si
ProgramNamePlugin ne fonctionne pas de manière fiable sur votre système d'exploitation, veuillez contribuer en envoyant une pull request et/ou en ouvrant une issue. Merci !!!
Démontre le routage intégré du serveur Web via un plugin.
Démarrez proxy.py comme suit :```console
❯ proxy --enable-web-server
--plugins proxy.plugin.WebServerPlugin
Vérifiez en utilisant `curl -v localhost:8899/http-route-example`, devrait retourner :```console
HTTP route response
Étend le serveur web intégré pour ajouter des capacités de proxy inverse.
Démarrez proxy.py comme :```console
❯ proxy --enable-reverse-proxy
--plugins proxy.plugin.ReverseProxyPlugin
Avec la configuration par défaut, le plugin `ReverseProxyPlugin` est équivalent à la configuration `Nginx` suivante :```console
location /get {
proxy_pass http://httpbin.org/get;
}
Vérifiez en utilisant 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"
}
#### Réécrire l'en-tête Host
Avec l'exemple ci-dessus, vous pouvez parfois voir :```console
>
* Empty reply from server
* Closing connection
curl: (52) Empty reply from server
Cela se produit parce que notre plugin de proxy inverse par défaut ReverseProxyPlugin est configuré avec un serveur amont http et un serveur amont https. Et, par défaut, ReverseProxyPlugin conserve l'en-tête hôte d'origine. Bien que cela fonctionne avec les amonts https, cela ne fonctionne pas de manière fiable avec les amonts http. Pour contourner ce problème, utilisez les indicateurs --rewrite-host-header.
Exemple :```console
❯ proxy --enable-reverse-proxy
--plugins proxy.plugin.ReverseProxyPlugin
--rewrite-host-header
Cela garantira que le champ d'en-tête `Host` soit défini à `httpbin.org` et fonctionne à la fois avec les proxies amont `http` et `https`.
> NOTE : L'utilisation de `--rewrite-host-header` ou non dépend de votre cas d'utilisation.
## Ordre des plugins
Lors de l'utilisation de plusieurs plugins, selon leur fonctionnalité,
il peut être judicieux de considérer l'ordre dans lequel les plugins sont passés
en ligne de commande.
Les plugins sont appelés dans le même ordre que celui dans lequel ils sont passés. Par exemple,
disons que nous utilisons à la fois `FilterByUpstreamHostPlugin` et
`RedirectToCustomServerPlugin`. L'idée est de rejeter toutes les requêtes `http`
entrantes pour `facebook.com` et `www.facebook.com` et de rediriger les autres
requêtes `http` vers notre serveur web intégré.
Ainsi, dans ce scénario, il est important d'utiliser
`FilterByUpstreamHostPlugin` avant `RedirectToCustomServerPlugin`.
Si nous activons `RedirectToCustomServerPlugin` avant `FilterByUpstreamHostPlugin`,
les requêtes `facebook` seront également redirigées vers le serveur web intégré,
au lieu d'être rejetées.
# Chiffrement de bout en bout
Par défaut, `proxy.py` utilise le protocole `http` pour la communication avec les clients comme `curl`, `navigateur`. Pour activer le chiffrement de bout en bout avec `tls` / `https`, générez d'abord des certificats. **Clonez** le dépôt et exécutez :```console
make https-certificates
Démarrez proxy.py comme suit :```console
❯ proxy
--cert-file https-cert.pem
--key-file https-key.pem
Vérifiez en utilisant `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 vous souhaitez éviter de passer l'indicateur --proxy-cacert, envisagez également de signer les certificats SSL générés. Exemple :
Tout d'abord, générez des certificats CA :```console make ca-certificates
Ensuite, signez le certificat SSL :```console
make sign-https-certificates
Redémarrez maintenant le serveur avec l'option --cert-file https-signed-cert.pem. Notez que vous devez également approuver le fichier ca-cert.pem généré dans votre trousseau système.
Par défaut, proxy.py ne déchiffrera pas le trafic https entre le client et le serveur.
Pour activer l'interception TLS, générez d'abord les certificats racine de l'Autorité de Certification :```console
❯ make ca-certificates
Activons également `CacheResponsePlugin` pour pouvoir vérifier la réponse déchiffrée du serveur. Lancez `proxy.py` comme suit :```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
Fournissez également le chemin explicite du bundle CA nécessaire pour la validation des certificats homologues. Voir l'option
--ca-file.
Vérifiez l'interception TLS en utilisant `curl````console ❯ curl -v -x localhost:8899 --cacert ca-cert.pem https://httpbin.org/get
### Communauté et support
- **Discussions GitHub :** Pour des questions générales, des idées ou un support communautaire.
- **Issues :** Signalez des bogues ou demandez des fonctionnalités via le gestionnaire d’incidents du dépôt.
- **Recommandations :** Veuillez d’abord consulter la section FAQ et utiliser la fonction de recherche pour vérifier si votre question a déjà reçu une réponse avant d’ouvrir un nouveau ticket.
Pour plus de détails, consultez notre [Guide de contribution](https://github.com/abhinavsingh/proxy.py/blob/HEAD/CONTRIBUTING.md).
---```console
* issuer: C=US; ST=CA; L=SanFrancisco; O=proxy.py; OU=CA; CN=Proxy PY CA; [email protected]
* SSL certificate verify ok.
> 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 ligne issuer confirme que la réponse a été interceptée.
Vérifiez également le contenu du fichier de réponse mis en cache. Obtenez le chemin vers le fichier de cache
depuis les logs 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" }
Voilà !!! Si vous supprimez les flags CA, les données chiffrées se trouveront dans le fichier cache au lieu du texte en clair.
Utilisez maintenant les flags CA avec d'autres [exemples de plugins](#plugin-examples) pour les voir fonctionner avec le trafic `https`.
## Interception TLS non sécurisée
Pour intercepter le trafic TLS d'un serveur utilisant un certificat auto-signé, ajoutez le flag `--insecure-tls-interception` pour désactiver la validation obligatoire du certificat TLS.
REMARQUE : Ce flag désactive la vérification du certificat pour tous les serveurs.
## Interception TLS avec Docker
Notes importantes concernant l'interception TLS avec un conteneur Docker :
- Depuis `v2.2.0`, le conteneur Docker `proxy.py` est également livré avec `openssl`. Cela permet à `proxy.py`
de générer des certificats à la volée pour l'interception TLS.
- Pour des raisons de sécurité, le conteneur Docker `proxy.py` n'est pas livré avec
les certificats CA.
Voici comment démarrer un conteneur Docker `proxy.py`
avec l'interception TLS :
1. Générez les certificats CA sur l'ordinateur hôte ```console
❯ make ca-certificates
-v /tmp/ca-certificates:/tmp/ca-certificates flag monte notre répertoire de certificats CA dans l'environnement du conteneur
--plugins proxy.plugin.CacheResponsesPlugin active CacheResponsesPlugin afin que nous puissions inspecter le trafic intercepté--ca-* flags activent l'interception TLS.curl. Vous pouvez omettre le flag --cacert si le certificat CA est déjà approuvé par le système. ```console
❯ curl -v issuer dans les en-têtes de réponse. ```console
cat le dump de la réponse : ```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 est une alternative directe à ngrok et frpgrout est fourni avec 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
## Authentification Grout
Grout prend en charge l'authentification pour protéger vos fichiers, dossiers et services contre tout
accès non autorisé. Utilisez le paramètre `--basic-auth` pour imposer l'authentification. Exemple :```console
grout /path/to/folder --basic-auth user:pass
grout https://localhost:8080 --basic-auth u:p
Par défaut, Grout permet l'accès à tous les chemins sur les services. Utilisez le drapeau --path pour restreindre
l'accès à seulement certains chemins sur votre service web. Exemple:```console
grout https://localhost:8080 --path /worker/
grout https://localhost:8080 --path /webhook/ --path /callback/
## Domaines Wildcard de Grout
Par défaut, le client Grout sert le trafic entrant sur un sous-domaine dédié.
Cependant, certains services (par exemple Kubernetes) peuvent vouloir servir le trafic sur des sous-domaines ad hoc.
Démarrer un client Grout dédié pour chaque sous-domaine ad hoc peut ne pas être une solution pratique.
Pour de tels scénarios, Grout prend en charge les domaines wildcard. Voici comment configurer votre propre
domaine wildcard pour une utilisation avec les clients Grout.
1. Choisissez un domaine, par exemple `custom.example.com`
2. Votre service souhaite servir le trafic pour `custom.example.com` et `*.custom.example.com`
3. Si vous prévoyez d'utiliser `https://`, vous devez configurer un équilibreur de charge :
- Configurez un équilibreur de charge HTTPS (LB)
- Configurez le LB avec un certificat généré pour `custom.example.com` et `*.custom.example.com`
- Dirigez le trafic vers les adresses IP publiques du service Grout
4. Contactez l'équipe Grout à [email protected] pour mettre sur liste blanche `custom.example.com`. L'équipe Grout s'assurera
que vous possédez vraiment le domaine et que vous avez configuré un certificat SSL valide comme décrit ci-dessus
Démarrez Grout avec le drapeau `--wildcard`. Exemple :```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
Disponible uniquement avec
--wildcard
En plus de la route par défaut, vous pouvez également fournir des routes supplémentaires qui prennent le pas lorsque le champ host correspond. Exemple :```console
grout https://localhost:8080 custom.example.com
--wildcard
--tunnel-route-url stream.example.com=http://localhost:7001
Vous pouvez fournir plusieurs routes personnalisées en répétant ce drapeau.
## Grout Client Plugin
`GroutClientBasePlugin` vous permet de router dynamiquement le trafic vers différents upstreams. Ci-dessous se trouve une implémentation simple avec une description de la façon de l'utiliser.```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
Voir grout_client.py pour plus d'informations. Pour essayer, commencez par passer --plugin proxy.plugin.grout_client.GroutClientPlugin au démarrage du client grout.
❯ docker run --rm -it
--entrypoint grout
-v ~/.proxy:/root/.proxy
abhinavsingh/proxy.py:latest
http://host.docker.internal:29876
Ci-dessus :
- Nous avons changé `--entrypoint` en `grout`
- Nous avons remplacé `localhost` par `host.docker.internal`, afin que `grout` puisse router le trafic vers le port `29876` tournant sur la machine hôte
- *(Optionnel)* Monter le dossier `~/.proxy` de la machine hôte, afin que les identifiants `grout` puissent persister lors des redémarrages du conteneur
## Comment fonctionne Grout
- L'infrastructure `grout` a 2 composants : client et serveur
- Le client `grout` a 2 composants : un client léger et un client lourd
- Le client léger `grout` fait partie de l'open source `proxy.py` (licence BSD 3-Clause)
- Le client lourd et les serveurs `grout` sont hébergés sur [jaxl.io](https://jaxl.io) et sont une propriété intellectuelle de [Jaxl Innovations Private Limited](https://jaxl.com)
- Le serveur `grout` a 3 composants : un serveur d'enregistrement, un serveur proxy inverse et un serveur de tunnel
## `grout` auto-hébergé
- Le client lourd et les serveurs `grout` peuvent également être hébergés sur vos infrastructures GCP, AWS, Cloud
- Avec une version auto-hébergée, votre trafic circule à travers le réseau que vous contrôlez et auquel vous faites confiance
- Les développeurs `grout` de [jaxl.io](https://jaxl.io) fournissent des images GCP, AWS, Docker pour les solutions auto-hébergées
- Veuillez envoyer un e-mail à [[email protected]](mailto:[email protected]) pour commencer.
# Proxy via tunnel SSH
**Ceci est un travail en cours et peut ne pas fonctionner comme documenté**
Nécessite `paramiko` pour fonctionner. Installez les dépendances avec `pip install "proxy.py[tunnel]"`
## Proxy des requêtes distantes localement
|
+------------+ | +----------+
| LOCAL | | | REMOTE |
| HOST | <== SSH ==== :8900 == | PROXY |
+------------+ | +----------+
:8899 proxy.py |
|
FIREWALL
(allow tcp/22)
### Quoi
Proxy des requêtes HTTP(s) effectuées sur un serveur proxy `distant` via le serveur `proxy.py` tournant sur `localhost`.
### Comment
- Le port `distant` demandé est transféré via la connexion SSH.
- `proxy.py` tournant sur `localhost` gère et répond aux requêtes proxy `distantes`.
### Prérequis
1. `localhost` DOIT avoir un accès SSH au serveur `distant`
2. Le serveur `distant` DOIT être configuré pour proxy les requêtes HTTP(s) via le numéro de port transféré, par ex. `:8900`.
- Les ports `distant` et `localhost` PEUVENT être identiques, par ex. `:8899`.
- `:8900` est choisi dans l'art ascii à des fins de différenciation.
### Essayez-le
Démarrez `proxy.py` comme suit :```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...
Faire une requête proxy HTTP sur le serveur remote et vérifier que la réponse contient l'adresse IP publique de localhost comme origine :```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"
}
De plus, vérifiez que les logs de `proxy.py` sur `localhost` contiennent l'IP `remote` comme IP client.```console
access_log:328 - remote:52067 - GET httpbin.org:80
|
+------------+ | +----------+
| LOCAL | | | REMOTE |
| HOST | === SSH =====> | SERVER |
+------------+ | +----------+
| :8899 proxy.py
|
FIREWALL
(allow tcp/22)
Non planifié.
Si vous avez un cas d'utilisation valide, veuillez ouvrir un ticket. Vous êtes toujours les bienvenus pour envoyer des contributions via des pull-requests pour ajouter cette fonctionnalité :)
Pour faire un proxy de requêtes locales à distance, utilisez Proxy Pool Plugin.
Démarrez proxy.py en mode intégré avec la configuration par défaut en utilisant la méthode proxy.main. Exemple:```python
import proxy
if name == 'main': proxy.main()
Personnalisez les indicateurs de démarrage en les passant comme kwargs :```python
import ipaddress
import proxy
if __name__ == '__main__':
proxy.main(
hostname=ipaddress.IPv6Address('::1'),
port=8899
)
Note that:
main is equivalent to starting proxy.py from command line.main does not accept any args (only kwargs).main will automatically consume any available sys.argv as args.main will block until proxy.py shuts down.Démarrez proxy.py en mode intégré non bloquant avec la configuration par défaut en utilisant le gestionnaire de contexte Proxy : Exemple :```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()
Notez que :
1. `Proxy` est similaire à `main`, sauf que `Proxy` ne bloquera pas.
2. En interne, `Proxy` est un gestionnaire de contexte qui démarrera `proxy.py` lorsqu'il est appelé et l'arrêtera une fois la portée terminée.
3. Contrairement à `main`, les indicateurs de démarrage avec `Proxy` peuvent également être personnalisés en utilisant `args` et `kwargs`. Par ex. `Proxy(['--port', '8899'])` ou en passant des indicateurs comme kwargs, par ex. `Proxy(port=8899)`.
4. Contrairement à `main`, `Proxy` n'inspectera pas `sys.argv`.
## Port éphémère
Utilisez `--port=0` pour lier `proxy.py` sur un port aléatoire alloué par le noyau.
En mode embarqué, vous pouvez accéder à ce port. Exemple :```python
import proxy
if __name__ == '__main__':
with proxy.Proxy(port=0) as p:
print(p.flags.port)
proxy.sleep_loop()
flags.port vous donnera accès au port aléatoire alloué par le noyau.
Les utilisateurs peuvent utiliser le flag --plugins plusieurs fois pour charger plusieurs plugins.
Voir Impossible de charger les plugins si vous rencontrez des problèmes.
En mode embarqué, vous avez quelques options supplémentaires. Exemple :
bytes à la méthode proxy.main ou au gestionnaire de contexte proxy.Proxy.type de la classe du plugin. Cela est particulièrement utile si vous prévoyez de définir des plugins à l'exécution.Exemple, charger un seul plugin en utilisant le flag --plugins :```python
import proxy
if name == 'main': proxy.main(plugins=['proxy.plugin.CacheResponsesPlugin'])
Pour simplifier, vous pouvez également passer la liste de plugins comme argument nommé à `proxy.main` ou au constructeur `Proxy`. Exemple :```python
import proxy
from proxy.plugin import FilterByUpstreamHostPlugin
if __name__ == '__main__':
proxy.main(plugins=[
b'proxy.plugin.CacheResponsesPlugin',
FilterByUpstreamHostPlugin,
])
proxy.TestCasePour configurer et nettoyer proxy.py pour vos classes de test Python unittest, utilisez simplement proxy.TestCase au lieu de unittest.TestCase.
Exemple:```python
import proxy
class TestProxyPyEmbedded(proxy.TestCase):
def test_my_application_with_proxy(self) -> None:
self.assertTrue(True)
Notez que :
1. `proxy.TestCase` surcharge la méthode `unittest.TestCase.run()` pour configurer et arrêter `proxy.py`.
2. Le serveur `proxy.py` écoutera sur un port aléatoire disponible sur le système.
Ce port aléatoire est accessible via `self.PROXY.flags.port` dans vos cas de test.
3. Seuls un accepteur et un travailleur sont démarrés par défaut (`--num-workers 1 --num-acceptors 1`) pour un démarrage et un arrêt plus rapides.
4. Plus important encore, `proxy.TestCase` garantit également que le serveur `proxy.py`
est opérationnel avant de procéder à l'exécution des tests. Par défaut,
`proxy.TestCase` attendra `10 secondes` que le serveur `proxy.py` démarre,
en cas d'échec, une exception `TimeoutError` sera levée.
## Surcharger les indicateurs de démarrage
Pour surcharger les indicateurs de démarrage par défaut, définissez une variable `PROXY_PY_STARTUP_FLAGS` dans votre classe de test.
Exemple :```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] pour un exemple complet.
[test_embed.py] : https://github.com/abhinavsingh/proxy.py/blob/develop/tests/testing/test_embed.py
unittest.TestCaseSi pour une raison quelconque vous ne pouvez pas utiliser directement proxy.TestCase,
alors il suffit de redéfinir unittest.TestCase.run vous-même pour configurer et démonter proxy.py.
Exemple :```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)
ou simplement configurer / démonter `proxy.py` dans
`setUpClass` et `teardownClass` méthodes de classe.
# Utilitaires
## TCP Sockets
### new_socket_connection
Tente de créer une connexion IPv4, puis IPv6 et
finalement une connexion double pile vers l'adresse fournie.```python
>>> conn = new_socket_connection(('httpbin.org', 80))
>>> ...[ use connection ]...
>>> conn.close()
socket_connection est un décorateur pratique + gestionnaire de contexte
autour de new_socket_connection qui garantit que conn.close est implicite.
En tant que gestionnaire de contexte :```python
with socket_connection(('httpbin.org', 80)) as conn: ... [ use connection ] ...
En tant que decorator:```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
### Utilisation de l'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
Voir pki.py et test_pki.py pour des exemples d'utilisation.
Utilisez le module proxy.common.pki pour :
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
## Documentation interne
### Read The Doc
- Visitez [proxypy.readthedocs.io](https://proxypy.readthedocs.io/)
- Construire localement avec :
`make lib-doc`
### pydoc
Le code est bien documenté. Obtenez le code source et exécutez :
`pydoc3 proxy`
### pyreverse
Générez des diagrammes UML de hiérarchie de classes pour une analyse approfondie :
`make lib-pyreverse`
# Exécuter le Tableau de Bord
Le Tableau de Bord est actuellement en développement et n'est pas encore inclus dans les paquets `pip`.
Pour exécuter le Tableau de Bord, vous devez récupérer le code source.
Le Tableau de Bord est écrit en Typescript et SCSS, alors construisons-le d'abord en utilisant :```console
❯ make dashboard
Construisez également le Chrome DevTools intégré si vous prévoyez de l'utiliser :```console
❯ make devtools
Maintenant lancez `proxy.py` avec le plugin dashboard et en écrasant le répertoire racine pour le serveur statique :```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
Actuellement, activer le tableau de bord activera également tous les plugins du tableau de bord.
Visiter le tableau de bord :```console ❯ open http://localhost:8899/dashboard/
## Inspecter le trafic
***Ceci est un travail en cours et peut ne pas fonctionner comme décrit***
Attendez que la console de développement Chrome intégrée se charge. Actuellement, les détails de tout le trafic circulant via `proxy.py` sont poussés vers l'onglet « Inspecter le trafic ». Cependant, les charges utiles reçues ne sont pas encore intégrées à la console de développement intégrée.
La fonctionnalité actuelle peut être vérifiée en ouvrant la console de développement du tableau de bord et en inspectant la connexion WebSocket que le tableau de bord a établie avec le serveur `proxy.py`.
[](https://github.com/abhinavsingh/proxy.py)
# Protocole Chrome DevTools
Pour les scénarios où vous souhaitez un accès direct au point de terminaison WebSocket du protocole Chrome DevTools, démarrez `proxy.py` comme :```console
❯ proxy --enable-devtools --enable-events
Maintenant, pointez votre instance CDT vers ws://localhost:8899/devtools.
proxy.py avec le flag --enable-metrics pour activer les métriques internes via un endpoint Prometheusprometheus.yaml pour scraper depuis l'endpoint /metrics par ex. http://localhost:8899/metrics--metrics-path--enable-metrics active en interne aussi --enable-events et le plugin serveur webVoici quelques stratégies pour utiliser proxy.py dans vos projets privés/de production/d'entreprise.
Vous DEVEZ
éviter de forkerle repository "juste" pour mettre votre code de plugin dans le répertoireproxy/plugin. Le fork est un workflow recommandé pour les contributeurs du projet, PAS pour les utilisateurs du projet.
--plugin, --plugins ou les kwargs plugin.proxy.py.Il est fortement recommandé d'utiliser proxy.py via requirements.txt ou des configurations de gestion de dépendances similaires. Cela vous permettra de bénéficier des mises à jour régulières de performance, des corrections de bugs, des correctifs de sécurité et des autres améliorations dans l'écosystème proxy.py. Exemple :
Utilisez l'option --pre pour dépendre de la dernière pre-release
❯ pip install proxy.py --pre
Les pre-releases sont similaires à une dépendance sur le code de la branche develop, à ceci près que les pre-releases peuvent ne pas pointer vers HEAD. Cela peut se produire car les pre-releases ne sont PAS mises à disposition sur PyPi après chaque fusion de PR.
Utilisez TestPyPi avec l'option --pre pour dépendre du code de la branche develop
❯ pip install -i https://test.pypi.org/simple/ proxy.py --pre
Une pre-release est mise à disposition sur TestPyPi après chaque fusion de PR.
Utilisez le code de la dernière version stable
Si vous déployez des conteneurs, construisez simplement votre image à partir des images de base du conteneur proxy.py.
Utilisez GHCR pour construire à partir du code de la branche develop :
FROM ghcr.io/abhinavsingh/proxy.py:latest as base
PS : J'utilise GHCR latest pour plusieurs projets de niveau production
Utilisez DockerHub pour construire à partir du code de la dernière version stable :
FROM abhinavsingh/proxy.py:latest as base
PS : À mon avis, la stratégie basée sur les conteneurs est la meilleure approche et la seule stratégie que j'utilise moi-même.
Hé, mais vous ne cessez d'apporter des modifications cassantes dans la branche develop.
Je vous entends. Et donc, pour vos applications de niveau production, vous DEVEZ intégrer le CI/CD de votre application avec proxy.py. Vous devez vous assurer que votre application se construit et réussit ses tests pour chaque fusion de PR dans le dépôt amont proxy.py.
Si votre dépôt d'application est public, dans certains scénarios, les auteurs de PR peuvent envoyer des PR de correctifs pour tous les dépendants afin de maintenir la rétrocompatibilité et un CI/CD vert.
L'intégration CI/CD garantit que votre application continue de se construire avec le dernier code de proxy.py. Selon où vous hébergez votre code, utilisez la stratégie listée ci-dessous :
GitHub
À déterminer
Google Cloud Build
À déterminer
AWS
À déterminer
Azure
À déterminer
Autres
À déterminer
À un certain stade, nous déprécierons la ségrégation de la branche
masteret maintiendrons simplement une branchedevelop. Car les dépendants peuvent assurer la stabilité via les intégrations CI/CD. Actuellement, il est difficile pour un projet de niveau production de dépendre aveuglément de la branchedevelop.
La branche master contient le dernier code stable et est disponible via le dépôt PyPi et les conteneurs Docker via les registres docker.io et ghcr.io.
Les problèmes signalés pour les versions stable sont considérés avec la plus haute priorité. Cependant, actuellement nous ne backportons pas les correctifs dans les versions plus anciennes. Exemple, si vous avez signalé un problème dans v2.3.1, mais que la branche master actuelle contient maintenant v2.4.0rc1. Alors, le correctif atterrira dans v2.4.0rc2.
La branche develop contient les changements de pointe
La branche de développement est maintenue stable (la plupart du temps). Mais, si vous voulez une fiabilité à 100% et servir des utilisateurs dans un , utilisez TOUJOURS la version stable.
Une pull request vX.Y.ZrcN est créée une fois par mois qui fusionne develop → master. Trouvez ci-dessous comment le code circule d'une pull request à la prochaine version stable.
La version de développement est déployée de develop → test.pypi.org après chaque fusion de pull request
La version alpha est déployée de develop → pypi.org avant la fusion de la pull request vX.Y.Z.rcN de develop → master. Il peut y avoir plusieurs versions alpha avant la fusion de la pull request rc
La version bêta est déployée de master → pypi.org. Les versions bêta sont faites en préparation des versions rc et peuvent être ignorées si inutile
La version candidate (release candidate) est déployée de master → pypi.org. Les release candidates sont toujours mises à disposition avant la version stable finale
v1.xproxy.py créait de nouveaux threads pour gérer les requêtes des clients.
v2.0+proxy.py a ajouté la prise en charge de l'exécution sans thread (threadless) des requêtes client en utilisant asyncio.
v2.4.0+L'exécution sans thread a été activée par défaut pour Python 3.8+ sur les environnements mac et linux.
proxy.py l'exécution sans thread a été signalée comme sûre sur ces environnements par nos utilisateurs. Si vous rencontrez des problèmes, revenez au mode threadé en utilisant le flag --threaded.
Pour windows et Python < 3.8, vous pouvez toujours essayer le mode sans thread en démarrant proxy.py avec le flag --threadless.
Si le mode sans thread fonctionne pour vous, envisagez d'envoyer une PR en modifiant la méthode _env_threadless_compliant dans le fichier proxy/common/constants.py.
L'implémentation sans thread originale utilisait le mode d'exécution remote. Cela est également représenté sous Architecture de haut niveau en art ASCII.
En mode d'exécution remote, les accepteurs délèguent le traitement des connexions client entrantes à un processus worker distant. Par défaut, les accepteurs délèguent les connexions de manière round-robin. Le worker traitant la requête peut ou non s'exécuter sur le même cœur CPU que l'accepteur. Cette architecture passe bien à l'échelle pour un débit élevé, mais entraîne le lancement de deux processus par cœur CPU.
Exemple, s'il y a N-CPU sur la machine, par défaut, N processus accepteurs et N workers sont démarrés. Vous pouvez ajuster le nombre de processus à l'aide des flags --num-acceptors et --num-workers. Vous voudrez peut-être plus de workers que d'accepteurs ou vice versa selon votre cas d'utilisation.
Dans v2.4.x, le mode d'exécution local a été ajouté, principalement pour réduire le nombre de processus lancés par défaut. Ce modèle convient bien aux cas d'utilisation quotidiens d'un seul utilisateur et aux scénarios de test pour développeurs. En mode d'exécution local, les accepteurs délèguent les connexions client à un thread compagnon, au lieu d'un processus distant. Le mode d'exécution local assure l'affinité CPU, contrairement au mode remote où l'accepteur et le worker peuvent s'exécuter sur des cœurs CPU différents.
--local-executor 1 a été défini par défaut dans la série v2.4.x. En mode d'exécution local, le flag --num-workers n'a aucun effet, car aucun worker distant n'est démarré.
Pour utiliser le mode d'exécution remote, utilisez le flag --local-executor 0. Utilisez ensuite --num-workers pour ajuster le nombre de processus workers.
proxy.py est strictement typé et utilise les annotations typing de Python. Exemple :```python
my_strings : List[str] = [] #############^^^^^^^^^#####
Par conséquent, une version de Python qui comprend les annotations de typage est requise.
Assurez-vous d'utiliser `Python 3.6+`.
Vérifiez la version avant d'exécuter `proxy.py` :
`❯ python --version`
Toutes les annotations `typing` peuvent être remplacées par des annotations `comment-only`. Exemple :```python
>>> my_strings = [] # List[str]
>>> ################^^^^^^^^^^^
Cela permettra à proxy.py de fonctionner sur Python pre-3.6, même sur 2.7.
Cependant, comme toutes les futures versions de Python prendront en charge les annotations typing,
cela n'a pas été pris en compte.
Assurez-vous que les modules de plugins sont découvrables en les ajoutant à PYTHONPATH. Exemple :
`PYTHONPATH=/path/to/my/app proxy --plugins my_app.proxyPlugin````console ...[redacted]... - Loaded plugin proxy.HttpProxyPlugin ...[redacted]... - Loaded plugin my_app.proxyPlugin
OU, passez simplement un chemin absolu en paramètre, par ex.
`proxy --plugins /path/to/my/app/my_app.proxyPlugin`
Voici un exemple rapide :
- Contenu du dossier `/tmp/plug````console
╰─ ls -1 /tmp/plug ─╯
my_plugin.py
MyPlugin personnalisée```console
╰─ cat /tmp/plug/my_plugin.py ─╯
from proxy.http.proxy import HttpProxyBasePluginclass MyPlugin(HttpProxyBasePlugin): pass
Ceci est un plugin vide pour démontrer l'utilisation de plugins externes. Vous devez implémenter les méthodes nécessaires pour que vos plugins fonctionnent avec du trafic réel
- Lancez `proxy.py` avec `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
Assurez-vous que proxy.py écoute sur la bonne interface réseau.
Essayez les indicateurs suivants :
--hostname ::--hostname 0.0.0.0Il s'agit probablement d'un problème d'intégration du navigateur avec le trousseau système.
Vérifiez d'abord que l'authentification de base fonctionne avec curl
curl -v -x username:password@localhost:8899 https://httpbin.org/get
Consultez ce fil pour plus de détails.
C'est un problème de compatibilité avec vpnkit.
Voir moby/vpnkit épuise les ressources Docker et Connexion refusée : le proxy n'a pas pu se connecter pour plus de contexte.
Un modèle fluentd.conf de démarrage est disponible.
Copiez ce fichier de configuration sous le nom proxy.py.conf dans
/etc/google-fluentd/config.d/
Mettez à jour le champ path avec le chemin du fichier de log utilisé avec l'indicateur --log-file.
Par défaut, le chemin /tmp/proxy.log est surveillé.
Rechargez google-fluentd :
sudo service google-fluentd restart
Désormais, les logs de proxy.py peuvent être consultés via le
visualiseur de logs GCE.
ValueError: filedescriptor out of range in selectproxy.py est conçu pour gérer des milliers de connexions par seconde
sans fuite de sockets.
--open-file-limit pour personnaliser ulimit -n.--backlog pour une concurrence plus élevée.Si rien ne fonctionne, ouvrez un problème
avec les requêtes par seconde envoyées et la sortie du script de débogage suivant :```console
❯ ./helper/monitor_open_files.sh
## None:None dans les journaux d'accès
Parfois, vous pouvez voir `None:None` dans les journaux d'accès. Cela signifie simplement qu'une connexion au serveur en amont n'a jamais été établie, c'est-à-dire `upstream_host=None`, `upstream_port=None`.
Il peut y avoir plusieurs raisons pour l'absence de connexion en amont, quelques-unes évidentes sont :
1. Le client a établi une connexion mais n'a jamais terminé la requête.
2. Un plugin a retourné une réponse prématurément, évitant la connexion au serveur en amont.
## OSError lors de l'encapsulation du client pour l'interception TLS
Avec l'interception TLS activée, vous pouvez occasionnellement voir les exceptions suivantes :```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
Certains clients peuvent lever l'exception TLSV1_ALERT_UNKNOWN_CA s'ils ne peuvent pas vérifier le certificat du serveur car il est signé par une autorité de certification émettrice inconnue. Ce qui est le cas lorsque nous effectuons une interception TLS. Cela peut être dû à diverses raisons, par exemple le certificate pinning, etc. Une autre exception que vous pourriez rencontrer est 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
À l'avenir, nous pourrions prendre en charge la fourniture du contenu HTTPS original pour de tels clients tout en continuant à effectuer l'interception TLS en arrière-plan. Cela gardera les clients satisfaits sans affecter notre capacité à intercepter TLS. Malheureusement, cette fonctionnalité n'est pas encore disponible.
Un autre exemple avec l'exception `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` est conçu avec la performance à l'esprit. Par défaut, `proxy.py`
essaiera d'utiliser tous les cœurs CPU disponibles pour accepter de nouvelles
connexions client. Ceci est réalisé en démarrant `AcceptorPool` qui écoute
sur le port serveur configuré. Ensuite, `AcceptorPool` démarre des processus
`Acceptor` (`--num-acceptors`) pour accepter les connexions client entrantes.
Parallèlement, si `--threadless` est activé, `ThreadlessPool` est configuré
et démarre des processus `Threadless` (`--num-workers`) pour gérer les
connexions client entrantes.
Chaque processus `Acceptor` délègue la connexion client acceptée
à un processus threadless via la classe `Work`. Actuellement, `HttpProtocolHandler`
est la classe de travail par défaut.
`HttpProtocolHandler` suppose simplement que les clients entrants suivront
la spécification HTTP. Les implémentations spécifiques de proxy HTTP et de serveur HTTP
sont écrites comme plugins de `HttpProtocolHandler`.
Consultez la documentation de `HttpProtocolHandlerPlugin` pour les hooks de cycle de vie disponibles.
Utilisez `HttpProtocolHandlerPlugin` pour ajouter de nouvelles fonctionnalités aux clients http(s). Exemple,
Voir `HttpWebServerPlugin`.
## Tout est un plugin
Dans `proxy.py`, tout est un plugin.
- Nous avons activé les plugins `proxy server` en utilisant le drapeau `--plugins`.
Le serveur proxy `HttpProxyPlugin` est un plugin de `HttpProtocolHandler`.
De plus, le serveur proxy autorise les plugins via la spécification `HttpProxyBasePlugin`.
- Tous les [exemples de plugins](#plugin-examples) du serveur proxy implémentaient
`HttpProxyBasePlugin`. Consultez la documentation de `HttpProxyBasePlugin` pour les hooks
de cycle de vie disponibles. Utilisez `HttpProxyBasePlugin` pour modifier le comportement du protocole proxy http(s)
entre le client et le serveur amont. Exemple,
[FilterByUpstreamHostPlugin](#filterbyupstreamhostplugin).
- Nous avons également activé le `serveur web` intégré en utilisant `--enable-web-server`.
Le serveur web `HttpWebServerPlugin` est un plugin de `HttpProtocolHandler`
et implémente la spécification `HttpProtocolHandlerPlugin`.
- Il existe également un drapeau `--disable-http-proxy`. Il désactive le serveur proxy intégré.
Utilisez ce drapeau avec le drapeau `--enable-web-server` pour exécuter `proxy.py` comme un serveur
http(s) programmable.
## Gérer les états pour vos plugins sans état
Les instances de classes de plugin sont créées par requête. Le plus important,
les instances de plugin sont créées dans le contexte du cœur CPU où la requête
a été reçue.
Pour cette raison, les variables globales dans vos plugins peuvent ne pas fonctionner
comme prévu. Votre code de plugin doit par conception être **sans état**.
Pour gérer les états globaux, vous avez plusieurs options :
1) Utiliser les [structures de données multiprocessing sûres](https://python.readthedocs.io/en/latest/library/multiprocessing.html#sharing-state-between-processes) de Python.
2) Utiliser le [mécanisme d'événement](https://github.com/abhinavsingh/proxy.py/blob/develop/tutorial/eventing.ipynb) intégré de `proxy.py`.
## Passer un contexte de traitement entre les plugins
Parfois, un plugin peut avoir besoin de passer un contexte supplémentaire à d'autres plugins
après lui dans la chaîne de traitement. Par exemple, ce contexte supplémentaire
peut également être enregistré dans les journaux d'accès.
Pour passer un contexte de traitement, utilisez la méthode `on_access_log` du plugin.
Voyez comment le plugin [Program Name](https://github.com/abhinavsingh/proxy.py/blob/develop/proxy/plugin/program_name.py)
modifie la clé `client_ip` par défaut dans le contexte et la met à jour avec le nom du programme détecté.
En conséquence, lorsque nous activons le [Plugin Program Name](#programnameplugin),
nous voyons le nom du programme client local au lieu de l'adresse IP dans les journaux d'accès.
## Guide de développement
### Configurer l'environnement local
Les contributeurs doivent démarrer `proxy.py` à partir des sources pour vérifier et développer
de nouvelles fonctionnalités / corrections.
Voir [Exécuter proxy.py en ligne de commande en utilisant les sources du dépôt](#from-command-line-using-repo-source)
pour plus de détails.
[](https://github.com/abhinavsingh/proxy.py/issues/642) Sur `macOS`
vous devez installer `Python` en utilisant `pyenv`, car `Python` installé via `homebrew` a tendance à
être problématique. Voir le fil de discussion lié pour plus de détails.
### Configurer les hooks Git
Le hook pre-commit garantit que les tests sont réussis.
1. `cd /path/to/proxy.py`
2. `ln -s $(PWD)/git-pre-commit .git/hooks/pre-commit`
Le hook pre-push garantit que le lint et les tests sont réussis.
1. `cd /path/to/proxy.py`
2. `ln -s $(PWD)/git-pre-push .git/hooks/pre-push`
### Envoyer une pull request
Chaque pull request est testée à l'aide de GitHub actions.
Voir le [workflow GitHub](https://github.com/abhinavsingh/proxy.py/tree/develop/.github/workflows)
pour la liste des tests.
# Projets utilisant Proxy.Py
Quelques projets populaires utilisant `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)
Pour la liste complète, voir [utilisé par](https://github.com/abhinavsingh/proxy.py/network/dependents?package_id=UGFja2FnZS01MjQ0MDY5Ng%3D%3D)
# Benchmarks
Voir le répertoire [Benchmark](https://github.com/abhinavsingh/proxy.py/tree/develop/benchmark) sur comment exécuter des comparaisons de performances avec d'autres serveurs web OSS.
Pour exécuter un benchmark autonome pour `proxy.py`, utilisez la commande suivante depuis la racine du dépôt :```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 ...] 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 selectConsultez Threads vs Threadless et Mode d'exécution Threadless Remote vs Local pour contrôler le nombre de cœurs CPU utilisés.
Voir Benchmark pour plus de détails et pour savoir comment exécuter des benchmarks localement.
Léger
~5-20 Mo de RAM
~25 MoProgrammable
--plugins proxy.plugin.ProxyPoolPlugin--enable-web-server --plugins proxy.plugin.WebServerPlugin--enable-reverse-proxy --plugins proxy.plugin.ReverseProxyPluginPeut écouter sur plusieurs adresses et ports
--hostnames pour fournir des adresses supplémentaires--ports pour fournir des ports supplémentaires--port pour remplacer le port par défaut 8899Tableau de bord en temps réel
--enable-dashboardhttp://localhost:8899/dashboardproxy.py en cours d'exécutiontypescriptSécurisé
proxy.pyPrivé
Homme-du-milieu
Protocoles http pris en charge pour les requêtes proxy
http(s)
http1http1.1 avec pipelinehttp2websocketsPrise en charge du Protocole HAProxy
--enable-proxy-protocolPrise en charge du serveur de fichiers statiques
--enable-static-server et --static-server-dirOptimisé pour les téléchargements et téléversements de fichiers volumineux
--client-recvbuf-size, --server-recvbuf-size, --max-sendbuf-sizePrise en charge IPv4 et IPv6
--hostnamePrise en charge des sockets de domaine Unix
--unix-socket-pathPrise en charge de l'authentification de base
--basic-authPrise en charge de PAC (Proxy Auto-configuration)
--pac-file et --pac-file-url-pathStarted server on ::1:8899
proxy.py écoute sur IPv6 ::1, ce qui équivaut à IPv4 127.0.0.1proxy.py depuis un hôte externe, utilisez --hostname :: ou --hostname 0.0.0.0 ou liez à toute autre interface disponible sur votre machine.proxy.py vue par les serveurs en amont.Port 8899
--port pour personnaliser le port TCP par défaut.Comme d'habitude, utilisez simplement :
❯ pip install proxy.py
La version stable est déployée de master → pypi.org