
pingap v0.1.3.6
Un proxy inverse comme nginx, construit sur pingora, simple et efficace.
pingap
Avant que la version de pingap ne soit stable, aucune pull request ne sera acceptée. Si vous avez des questions, veuillez d'abord créer un nouveau ticket (issue).

Présentation
Pingap est un reverse proxy haute performance propulsé par Cloudflare Pingora. Il simplifie la gestion opérationnelle en permettant un rechargement dynamique de la configuration sans interruption, via des fichiers TOML concis et une interface d'administration web intuitive.
Sa force principale réside dans un puissant système de plugins, offrant plus de vingt fonctionnalités prêtes à l'emploi pour l'Authentification (JWT, Key Auth), la Sécurité (CSRF, Restrictions IP/Référent/UA), le Contrôle du Trafic (Limitation de Débit, Mise en Cache), la Modification de Contenu (Redirections, Substitution de Contenu) et l'Observabilité (ID de Requête). Cela fait de Pingap non seulement un proxy, mais aussi une passerelle applicative flexible et extensible, conçue pour gérer sans effort des scénarios complexes, de la protection d'API aux déploiements d'applications web modernes.
中文说明 | Documentation · 中文文档 | Exemples | Plugins | Crates
flowchart LR
internet("Internet") -- request --> pingap["Pingap"]
pingap -- proxy:pingap.io/api/* --> apiUpstream["10.1.1.1,10.1.1.2"]
pingap -- proxy:cdn.pingap.io --> cdnUpstream["10.1.2.1,10.1.2.2"]
pingap -- proxy:/* --> upstream["10.1.3.1,10.1.3.2"]
Fonctionnalités Clés
-
🚀 Haute Performance & Fiabilité
- Conçu en Rust pour la sécurité mémoire et des performances de premier ordre.
- Propulsé par Cloudflare Pingora, une bibliothèque réseau asynchrone éprouvée en conditions réelles.
- Prend en charge le proxy HTTP/1.1, HTTP/2 et gRPC-web.
-
🔧 Dynamique & Facile à Utiliser
- Modifications de configuration sans interruption grâce au rechargement à chaud.
- Fichiers de configuration TOML simples et lisibles.
- Interface web complète pour une gestion intuitive en temps réel.
- Prend en charge les fichiers et etcd comme backends de configuration.
- Prend en charge l'historique de configuration, permettant de restaurer une version antérieure en un clic.
-
🧩 Extensibilité Puissante
- Un riche système de plugins pour gérer les tâches courantes de passerelle.
- Routage avancé avec correspondance par hôte, chemin et expression régulière.
- Découverte de services intégrée via listes statiques, DNS ou étiquettes Docker.
- HTTPS automatisé avec Let's Encrypt (prise en charge des défis HTTP-01 et DNS-01).
-
📊 Observabilité Moderne
- Métriques Prometheus natives pour la surveillance (modes pull & push).
- Prise en charge intégrée d'OpenTelemetry pour le traçage distribué.
- Journaux d'accès hautement personnalisables avec plus de 30 variables.
- Métriques de performance détaillées, y compris le temps de connexion en amont, le temps de traitement, et plus encore.
🚀 Pour Commencer
Le moyen le plus simple de démarrer avec Pingap est d'utiliser Docker Compose.
- Créez un fichier
docker-compose.yml:
# docker-compose.yml
version: '3.8'
services:
pingap:
image: vicanso/pingap:latest # Pour la production, utilisez une version spécifique comme vicanso/pingap:0.12.1-full
container_name: pingap-instance
restart: always
ports:
- "80:80"
- "443:443"
volumes:
# Montez un répertoire local pour conserver toutes les configurations et données
- ./pingap_data:/opt/pingap
environment:
# Configurez à l'aide de variables d'environnement
- PINGAP_CONF=/opt/pingap/conf
- PINGAP_ADMIN_ADDR=0.0.0.0:80/pingap
- PINGAP_ADMIN_USER=pingap
- PINGAP_ADMIN_PASSWORD=<YourSecurePassword> # Changez ceci !
command:
# Démarrez pingap et activez le rechargement à chaud
- pingap
- --autoreload
- Créez un répertoire de données et exécutez :
mkdir pingap_data
docker-compose up -d
- Accédez à l'interface d'administration :
Votre instance Pingap est maintenant en cours d'exécution ! Vous pouvez accéder à l'interface d'administration web à l'adresse http://localhost/pingap avec les identifiants que vous avez définis.
Installer le binaire via curl
Pour Linux et macOS, vous pouvez installer le dernier binaire précompilé dans /usr/local/bin/pingap avec une seule commande :
curl -sSL https://raw.githubusercontent.com/vicanso/pingap/main/install.sh | sh
Variables d'environnement optionnelles :
PINGAP_FULL=1— installe la version-full(toutes les fonctionnalités optionnelles activées)PINGAP_LIBC=gnu— sur Linux, utilise la version glibc au lieu de la version statique musl par défautPINGAP_TLS=rustls— sur Linux, installe la version-rustls-full(backend TLS rustls, toutes les fonctionnalités optionnelles, sans OpenSSL) ; voir Backend TLS
# Version complète
curl -sSL https://raw.githubusercontent.com/vicanso/pingap/main/install.sh | PINGAP_FULL=1 sh
Cibles prises en charge : Linux x86_64/arm64, Darwin x86_64/arm64. Consultez la page des versions pour tous les fichiers disponibles.
Pour des instructions plus détaillées, y compris l'exécution à partir d'un binaire, consultez notre Documentation.
Démarrer un proxy sans fichier de configuration
Une seule commande suffit pour servir un domaine en https et le rediriger vers un backend :
# certificat demandé auprès de let's encrypt
pingap --domain=pingap.io --upstream=192.168.1.1:3000
# ou apportez votre propre certificat
pingap --domain=pingap.io --upstream=192.168.1.1:3000 --cert=/etc/ssl/pingap.io
Sans --cert, Pingap demande un certificat à Let's Encrypt via le défi HTTP-01, donc pingap.io doit résoudre vers cet hôte et le port 80 doit être accessible depuis Internet. Le certificat émis est conservé dans ~/.pingap/acme/<domains>.toml et réutilisé au redémarrage — l'émission est limitée en débit, ne le supprimez donc pas. Tout le reste provient toujours de la ligne de commande : modifier --upstream prend effet au prochain démarrage sans toucher au certificat.
--cert accepte le certificat lui-même ou le répertoire qui le contient — les dispositions courantes fullchain.pem / privkey.pem, cert.pem / key.pem et tls.crt / tls.key sont détectées automatiquement, utilisez --key pour tout autre cas. L'écouteur par défaut est 0.0.0.0:443 lorsqu'il y a un certificat et 0.0.0.0:80 lorsqu'il n'y a ni certificat ni domaine, et --addr le remplace. --upstream accepte une liste de backends séparés par des virgules, --domain une liste d'hôtes séparés par des virgules (omettez-le pour servir chaque hôte en http simple). Les requêtes pour un hôte qui n'est pas listé reçoivent une réponse 404.
La configuration est générée à chaque démarrage, elle ne peut donc pas être modifiée via l'interface d'administration : pour tout ce qui dépasse un serveur unique, utilisez --conf, qui ne peut pas être combiné avec ces options.
Configuration Dynamique
Pingap est conçu pour s'adapter aux changements de configuration sans interruption.
Rechargement à chaud (--autoreload) : Pour la plupart des changements — comme la mise à jour des upstreams, des locations ou des plugins — Pingap applique la nouvelle configuration en moins de 10 secondes sans redémarrage. C'est le mode recommandé pour les environnements conteneurisés.
Redémarrage gracieux (-a ou --autorestart) : Pour les changements fondamentaux (comme la modification des ports d'écoute du serveur), ce mode effectue un redémarrage complet sans interruption, garantissant qu'aucune requête n'est perdue.
La passation est pilotée par l'état de préparation plutôt que par un minuteur : le remplaçant est démarré avec -d -u, signale son retour via une socket unix à côté de la socket de mise à niveau dès qu'il est prêt à reprendre les écouteurs, et ce n'est qu'alors que le processus en cours s'envoie SIGQUIT. Si le remplaçant se termine, si son démon meurt, ou si basic.restart_ready_timeout (défaut 1m) expire en premier, le redémarrage est abandonné et le processus en cours continue de servir.
🔧 Développement
make dev
Si vous avez besoin d'une interface d'administration web, vous devez installer nodejs et compiler les ressources web.
# générer les ressources web d'administration
cd web
npm i
cd ..
make build-web
Backend TLS
La version par défaut termine TLS avec OpenSSL, compilé à partir des sources par la crate openssl. Pour compiler avec rustls à la place, ce qui supprime la compilation des sources OpenSSL (un compilateur C est toujours nécessaire : les fournisseurs cryptographiques de rustls, ring et aws-lc-rs, contiennent du C et de l'assembleur) :
cargo build --release --no-default-features --features tls-rustls
# avec les fonctionnalités optionnelles également
cargo build --release --no-default-features --features tls-rustls,full
La version rustls ignore les paramètres par serveur tls_min_version, tls_max_version, tls_cipher_list et tls_ciphersuites et journalise un avertissement lorsqu'ils sont définis : elle propose toujours TLS 1.2 et 1.3 avec les suites de chiffrement par défaut de rustls. Tout le reste, y compris les certificats SNI dynamiques, l'émission de CA auto-signés, ACME et l'option ca en amont, se comporte de la même manière. Une différence à connaître lors de la vérification des upstreams : rustls (webpki) rejette un certificat serveur portant CA:TRUE, qu'OpenSSL accepte, donc un backend utilisant un certificat auto-signé rapide openssl req -x509 nécessite une feuille appropriée signée par une CA (ou une feuille auto-signée sans l'indicateur CA) avant que l'option ca en amont puisse lui faire confiance. Le journal de démarrage indique avec quel backend le binaire a été compilé.
📝 Configuration
server "test" {
addr = "127.0.0.1:6118"
location "github-api" {
path = "/api"
proxy_set_headers = ["Host:api.github.com"]
rewrite = "^/api/(?<path>.+)$ /$1"
upstream "api" {
addrs = ["api.github.com:443"]
discovery = "dns"
sni = "api.github.com"
}
}
location "static" {
plugin "staticServe" {
category = "directory"
path = "~/Downloads"
step = "request"
}
}
}
[upstreams.api]
addrs = ["api.github.com:443"]
discovery = "dns"
sni = "api.github.com"
[plugins.staticServe]
category = "directory"
path = "~/Downloads"
step = "request"
[locations.github-api]
upstream = "api"
path = "/api"
proxy_set_headers = ["Host:api.github.com"]
rewrite = "^/api/(?<path>.+)$ /$1"
[locations.static]
plugins = ["staticServe"]
[servers.test]
addr = "127.0.0.1:6118"
locations = ["github-api", "static"]
Vous trouverez les instructions pertinentes ici : https://pingap.io/crates/config.
🔄 Étape de proxy
graph TD;
server["HTTP Server"];
locationA["Location A"];
locationB["Location B"];
locationPluginListA["Proxy Plugin List A"];
locationPluginListB["Proxy Plugin List B"];
upstreamA1["Upstream A1"];
upstreamA2["Upstream A2"];
upstreamB1["Upstream B1"];
upstreamB2["Upstream B2"];
locationResponsePluginListA["Response Plugin List A"];
locationResponsePluginListB["Response Plugin List B"];
start("New Request") --> server
server -- "host:HostA, Path:/api/*" --> locationA
server -- "Path:/rest/*"--> locationB
locationA -- "Exec Proxy Plugins" --> locationPluginListA
locationB -- "Exec Proxy Plugins" --> locationPluginListB
locationPluginListA -- "proxy pass: 10.0.0.1:8001" --> upstreamA1
locationPluginListA -- "proxy pass: 10.0.0.2:8001" --> upstreamA2
locationPluginListA -- "done" --> response
locationPluginListB -- "proxy pass: 10.0.0.1:8002" --> upstreamB1
locationPluginListB -- "proxy pass: 10.0.0.2:8002" --> upstreamB2
locationPluginListB -- "done" --> response
upstreamA1 -- "Exec Response Plugins" --> locationResponsePluginListA
upstreamA2 -- "Exec Response Plugins" --> locationResponsePluginListA
upstreamB1 -- "Exec Response Plugins" --> locationResponsePluginListB
upstreamB2 -- "Exec Response Plugins" --> locationResponsePluginListB
locationResponsePluginListA --> response
locationResponsePluginListB --> response
response["HTTP Response"] --> stop("Logging");
📊 Performance
CPU : M4 Pro, Thread : 1
Ping sans journal d'accès
wrk 'http://127.0.0.1:6118/ping' --latency
Running 10s test @ http://127.0.0.1:6118/ping
2 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 66.41us 23.67us 1.11ms 76.54%
Req/Sec 73.99k 2.88k 79.77k 68.81%
Latency Distribution
50% 67.00us
75% 80.00us
90% 91.00us
99% 116.00us
1487330 requests in 10.10s, 194.32MB read
Requests/sec: 147260.15
Transfer/sec: 19.24MB
📦 Version de Rust
Notre MSRV actuel est 1.96
📄 Licence
Ce projet est sous licence Apache License, Version 2.0.