Zurück zu den Updates
New releaseJul 26, 2026

pingap v0.1.3.6

Ein Reverse-Proxy wie nginx, basierend auf pingora, einfach und effizient.

Teilen

pingap

Bevor die Version von pingap stabil ist, werden keine Pull Requests akzeptiert. Wenn Sie Fragen haben, erstellen Sie bitte zuerst ein neues Issue.

Pingap Logo

Überblick

Pingap ist ein leistungsstarker Reverse-Proxy, der auf Cloudflare Pingora basiert. Er vereinfacht das Betriebsmanagement durch dynamisches, unterbrechungsfreies Hot-Reloading der Konfiguration über prägnante TOML-Dateien und eine intuitive Weboberfläche.

Seine Kernstärke liegt in einem leistungsfähigen Plugin-System mit über zwanzig integrierten Funktionen für Authentifizierung (JWT, Key Auth), Sicherheit (CSRF, IP/Referer/UA-Beschränkungen), Verkehrssteuerung (Rate Limiting, Caching), Inhaltsänderung (Weiterleitungen, Inhaltsersetzung) und Beobachtbarkeit (Request ID). Damit ist Pingap nicht nur ein Proxy, sondern ein flexibles und erweiterbares Anwendungs-Gateway, das mühelos komplexe Szenarien vom API-Schutz bis hin zu modernen Webanwendungsbereitstellungen bewältigt.

中文说明 | Dokumentation · 中文文档 | Beispiele | 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"]

Hauptfunktionen

  • 🚀 Hohe Leistung & Zuverlässigkeit

    • In Rust entwickelt für Speichersicherheit und Spitzenleistung.
    • Basierend auf Cloudflare Pingora, einer praxiserprobten asynchronen Netzwerkbibliothek.
    • Unterstützt HTTP/1.1, HTTP/2 und gRPC-Web-Proxy.
  • 🔧 Dynamisch & benutzerfreundlich

    • Unterbrechungsfreie Konfigurationsänderungen mit Hot-Reloading.
    • Einfache, lesbare TOML-Konfigurationsdateien.
    • Voll ausgestattete Weboberfläche für intuitive Echtzeitverwaltung.
    • Unterstützt sowohl Dateien als auch etcd als Konfigurations-Backends.
    • Unterstützt Konfigurationsverlauf, der mit einem Klick auf eine frühere Version wiederhergestellt werden kann.
  • 🧩 Leistungsstarke Erweiterbarkeit

    • Ein umfangreiches Plugin-System für gängige Gateway-Aufgaben.
    • Erweitertes Routing mit Host-, Pfad- und Regex-Abgleich.
    • Integrierte Service-Discovery über statische Listen, DNS oder Docker-Labels.
    • Automatisiertes HTTPS mit Let's Encrypt (unterstützt sowohl HTTP-01- als auch DNS-01-Challenges).
  • 📊 Moderne Beobachtbarkeit

    • Native Prometheus-Metriken für Monitoring (Pull- & Push-Modi).
    • Integrierte OpenTelemetry-Unterstützung für verteiltes Tracing.
    • Hochgradig anpassbare Zugriffsprotokolle mit über 30 Variablen.
    • Detaillierte Leistungsmetriken, einschließlich Upstream-Verbindungszeit, Verarbeitungszeit und mehr.

🚀 Erste Schritte

Der einfachste Weg, mit Pingap zu starten, ist die Verwendung von Docker Compose.

  1. Erstellen Sie eine docker-compose.yml-Datei:
# docker-compose.yml
version: '3.8'

services:
  pingap:
    image: vicanso/pingap:latest # Für die Produktion eine bestimmte Version verwenden, z. B. vicanso/pingap:0.12.1-full
    container_name: pingap-instance
    restart: always
    ports:
      - "80:80"
      - "443:443"
    volumes:
      # Ein lokales Verzeichnis einhängen, um alle Konfigurationen und Daten zu speichern
      - ./pingap_data:/opt/pingap
    environment:
      # Konfiguration über Umgebungsvariablen
      - PINGAP_CONF=/opt/pingap/conf
      - PINGAP_ADMIN_ADDR=0.0.0.0:80/pingap
      - PINGAP_ADMIN_USER=pingap
      - PINGAP_ADMIN_PASSWORD=<YourSecurePassword> # Ändern Sie dies!
    command:
      # Pingap starten und Hot-Reloading aktivieren
      - pingap
      - --autoreload
  1. Erstellen Sie ein Datenverzeichnis und führen Sie es aus:
mkdir pingap_data
docker-compose up -d
  1. Zugriff auf die Admin-Oberfläche:

Ihre Pingap-Instanz läuft jetzt! Sie können auf die Weboberfläche unter http://localhost/pingap mit den von Ihnen festgelegten Anmeldedaten zugreifen.

Binärdatei per curl installieren

Für Linux und macOS können Sie die neueste vorgefertigte Binärdatei mit einem Befehl in /usr/local/bin/pingap installieren:

curl -sSL https://raw.githubusercontent.com/vicanso/pingap/main/install.sh | sh

Optionale Umgebungsvariablen:

  • PINGAP_FULL=1 — installiert den -full-Build (alle optionalen Funktionen aktiviert)
  • PINGAP_LIBC=gnu — unter Linux den glibc-Build anstelle des standardmäßigen statischen musl-Builds verwenden
  • PINGAP_TLS=rustls — unter Linux den -rustls-full-Build installieren (rustls-TLS-Backend, alle optionalen Funktionen, kein OpenSSL); siehe TLS-Backend
# Voll ausgestatteter Build
curl -sSL https://raw.githubusercontent.com/vicanso/pingap/main/install.sh | PINGAP_FULL=1 sh

Unterstützte Ziele: Linux x86_64/arm64, Darwin x86_64/arm64. Alle verfügbaren Assets finden Sie auf der Releases-Seite.

Für detailliertere Anweisungen, einschließlich der Ausführung über eine Binärdatei, lesen Sie unsere Dokumentation.

Einen Proxy ohne Konfigurationsdatei starten

Ein einziger Befehl genügt, um eine Domain über HTTPS zu bedienen und an ein Backend weiterzuleiten:

# Zertifikat von Let's Encrypt angefordert
pingap --domain=pingap.io --upstream=192.168.1.1:3000

# oder eigenes Zertifikat mitbringen
pingap --domain=pingap.io --upstream=192.168.1.1:3000 --cert=/etc/ssl/pingap.io

Ohne --cert fordert Pingap ein Zertifikat von Let's Encrypt über die HTTP-01-Challenge an, daher muss pingap.io auf diesen Host auflösen und Port 80 vom Internet aus erreichbar sein. Das ausgestellte Zertifikat wird in ~/.pingap/acme/<domains>.toml gespeichert und beim Neustart wiederverwendet — die Ausstellung ist ratenbegrenzt, daher nicht löschen. Alles andere kommt weiterhin von der Befehlszeile: Eine Änderung von --upstream wird beim nächsten Start wirksam, ohne das Zertifikat zu berühren.

--cert akzeptiert das Zertifikat selbst oder das Verzeichnis, das es enthält — die gängigen Layouts fullchain.pem / privkey.pem, cert.pem / key.pem und tls.crt / tls.key werden automatisch erkannt, für alles andere --key verwenden. Der Listener lautet standardmäßig auf 0.0.0.0:443, wenn ein Zertifikat vorhanden ist, und auf 0.0.0.0:80, wenn weder ein Zertifikat noch eine Domain vorhanden ist; --addr überschreibt dies. --upstream akzeptiert eine durch Kommas getrennte Liste von Backends, --domain eine durch Kommas getrennte Liste von Hosts (weglassen, um jeden Host über einfaches HTTP zu bedienen). Anfragen für einen Host, der nicht aufgeführt ist, werden mit 404 beantwortet.

Die Konfiguration wird bei jedem Start generiert und kann daher nicht über die Admin-Oberfläche bearbeitet werden: Für alles über einen einzelnen Server hinaus --conf verwenden, das nicht mit diesen Flags kombiniert werden kann.

Dynamische Konfiguration

Pingap ist darauf ausgelegt, sich ohne Ausfallzeiten an Konfigurationsänderungen anzupassen.

Hot Reload (--autoreload): Für die meisten Änderungen — wie das Aktualisieren von Upstreams, Locations oder Plugins — wendet Pingap die neue Konfiguration innerhalb von 10 Sekunden ohne Neustart an. Dies ist der empfohlene Modus für Container-Umgebungen.

Graceful Restart (-a oder --autorestart): Für grundlegende Änderungen (wie das Ändern von Server-Listen-Ports) führt dieser Modus einen vollständigen, unterbrechungsfreien Neustart durch, sodass keine Anfragen verworfen werden.

Die Übergabe erfolgt readiness-gesteuert und nicht zeitgesteuert: Der Ersatz wird mit -d -u gestartet, meldet sich über einen Unix-Socket neben dem Upgrade-Socket zurück, sobald er bereit ist, die Listener zu übernehmen, und erst dann sendet sich der laufende Prozess selbst SIGQUIT. Wenn der Ersatz beendet wird, sein Daemon stirbt oder basic.restart_ready_timeout (Standard 1m) zuerst abläuft, wird der Neustart abgebrochen und der laufende Prozess bedient weiterhin.

🔧 Entwicklung

make dev

Wenn Sie eine Weboberfläche benötigen, sollten Sie nodejs installieren und die Web-Assets erstellen.

# Admin-Web-Asset generieren
cd web
npm i 
cd ..
make build-web

TLS-Backend

Der Standard-Build beendet TLS mit OpenSSL, das von der openssl-Crate aus dem Quellcode kompiliert wird. Um stattdessen mit rustls zu bauen, das den OpenSSL-Quellcode-Build weglässt (ein C-Compiler wird weiterhin benötigt: Die Krypto-Provider von rustls, ring und aws-lc-rs, enthalten C und Assembly):

cargo build --release --no-default-features --features tls-rustls
# auch mit den optionalen Funktionen
cargo build --release --no-default-features --features tls-rustls,full

Der rustls-Build ignoriert die pro-Server-Einstellungen tls_min_version, tls_max_version, tls_cipher_list und tls_ciphersuites und protokolliert eine Warnung, wenn sie gesetzt sind: Er bietet immer TLS 1.2 und 1.3 mit den Standard-Cipher-Suites von rustls an. Alles andere, einschließlich dynamischer SNI-Zertifikate, Ausstellung selbstsignierter CAs, ACME und der Upstream-ca-Option, verhält sich gleich. Ein Unterschied bei der Verifizierung von Upstreams: rustls (webpki) lehnt ein Serverzertifikat mit CA:TRUE ab, das OpenSSL akzeptiert. Ein Backend, das ein schnelles selbstsigniertes Zertifikat von openssl req -x509 verwendet, benötigt daher ein ordnungsgemäßes Blatt, das von einer CA signiert ist (oder ein selbstsigniertes Blatt ohne das CA-Flag), bevor die Upstream-ca-Option ihm vertrauen kann. Das Startprotokoll meldet, mit welchem Backend eine Binärdatei erstellt wurde.

📝 Konfiguration

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"]

Die entsprechenden Anweisungen finden Sie hier: https://pingap.io/crates/config.

🔄 Proxy-Schritt

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");

📊 Leistung

CPU: M4 Pro, Thread: 1

Ping ohne Zugriffsprotokoll

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

📦 Rust-Version

Unsere aktuelle MSRV ist 1.96

📄 Lizenz

Dieses Projekt ist unter der Apache License, Version 2.0 lizenziert.

Kategorien