Retour aux mises à jour
New releaseAug 1, 2026

pingap v0.13.8

Un reverse proxy comme nginx, construit sur pingora, simple et efficace.

Partager

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).

Pingap Logo

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.

  1. 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
  1. Créez un répertoire de données et exécutez :
mkdir pingap_data
docker-compose up -d
  1. 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éfaut
  • PINGAP_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.

Catégories