العودة إلى التحديثات
New releaseJul 26, 2026

pingap v0.1.3.6

وكيل عكسي مثل nginx، مبني على pingora، بسيط وفعّال.

مشاركة

pingap

قبل أن يستقر إصدار pingap، لن يتم قبول أي طلبات سحب (pull requests). إذا كانت لديك أي أسئلة، يرجى إنشاء issue جديد أولاً.

Pingap Logo

نظرة عامة

Pingap هو وكيل عكسي (reverse proxy) عالي الأداء مبني على Cloudflare Pingora. يبسّط إدارة التشغيل من خلال تمكين إعادة التحميل الديناميكي للتكوين دون أي توقف للخدمة، وذلك عبر ملفات TOML موجزة وواجهة إدارة ويب بديهية.

تكمن قوته الأساسية في نظام إضافات (plugins) قوي، يقدم أكثر من عشرين ميزة جاهزة للاستخدام في مجالات المصادقة (JWT، Key Auth)، والأمان (CSRF، تقييد IP/Referer/UA)، والتحكم في حركة المرور (تحديد المعدل، التخزين المؤقت)، وتعديل المحتوى (إعادة التوجيه، استبدال المحتوى)، والمراقبة (Request ID). هذا يجعل Pingap ليس مجرد وكيل، بل بوابة تطبيقات مرنة وقابلة للتوسع، مصممة للتعامل بسهولة مع السيناريوهات المعقدة بدءًا من حماية واجهات API وصولاً إلى نشر تطبيقات الويب الحديثة.

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

الميزات الرئيسية

  • 🚀 أداء عالٍ وموثوقية

    • مبني بلغة Rust لضمان أمان الذاكرة وأداء من الطراز الأول.
    • مدعوم من Cloudflare Pingora، وهي مكتبة شبكات غير متزامنة مجرّبة في المعارك.
    • يدعم بروكسي HTTP/1.1 وHTTP/2 وgRPC-web.
  • 🔧 ديناميكي وسهل الاستخدام

    • تغييرات التكوين دون أي توقف للخدمة مع إعادة التحميل الساخن.
    • ملفات تكوين TOML بسيطة وسهلة القراءة.
    • واجهة ويب كاملة الميزات لإدارة بديهية وفي الوقت الفعلي.
    • يدعم كلاً من الملفات و etcd كخلفيات للتكوين.
    • يدعم تسجيل سجل التكوين، مع إمكانية الاستعادة إلى الإصدار السابق بنقرة واحدة.
  • 🧩 قابلية توسع قوية

    • نظام إضافات غني للتعامل مع مهام البوابة الشائعة.
    • توجيه متقدم مع مطابقة المضيف والمسار والتعبيرات النمطية.
    • اكتشاف خدمات مدمج عبر قوائم ثابتة أو DNS أو Docker labels.
    • HTTPS تلقائي مع Let's Encrypt (يدعم تحديات HTTP-01 وDNS-01).
  • 📊 مراقبة حديثة

    • مقاييس Prometheus أصلية للمراقبة (أوضاع السحب والدفع).
    • دعم OpenTelemetry مدمج للتتبع الموزع.
    • سجلات وصول قابلة للتخصيص بدرجة عالية مع أكثر من 30 متغيراً.
    • مقاييس أداء مفصلة، بما في ذلك وقت اتصال المنبع (upstream)، ووقت المعالجة، والمزيد.

🚀 البدء

أسهل طريقة للبدء مع Pingap هي باستخدام Docker Compose.

  1. أنشئ ملف docker-compose.yml:
# docker-compose.yml
version: '3.8'

services:
  pingap:
    image: vicanso/pingap:latest # للإنتاج، استخدم إصداراً محدداً مثل vicanso/pingap:0.12.1-full
    container_name: pingap-instance
    restart: always
    ports:
      - "80:80"
      - "443:443"
    volumes:
      # قم بتركيب دليل محلي لحفظ جميع التكوينات والبيانات
      - ./pingap_data:/opt/pingap
    environment:
      # قم بالتكوين باستخدام متغيرات البيئة
      - PINGAP_CONF=/opt/pingap/conf
      - PINGAP_ADMIN_ADDR=0.0.0.0:80/pingap
      - PINGAP_ADMIN_USER=pingap
      - PINGAP_ADMIN_PASSWORD=<YourSecurePassword> # غيّر هذا!
    command:
      # ابدأ pingap وفعّل إعادة التحميل الساخن
      - pingap
      - --autoreload
  1. أنشئ دليل البيانات وشغّل:
mkdir pingap_data
docker-compose up -d
  1. الوصول إلى واجهة الإدارة:

مثيل Pingap الخاص بك يعمل الآن! يمكنك الوصول إلى واجهة الإدارة على http://localhost/pingap باستخدام بيانات الاعتماد التي قمت بتعيينها.

تثبيت الثنائي عبر curl

بالنسبة لنظامي Linux وmacOS، يمكنك تثبيت أحدث ثنائي مُجمّع مسبقاً إلى /usr/local/bin/pingap بأمر واحد:

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

متغيرات البيئة الاختيارية:

  • PINGAP_FULL=1 — تثبيت إصدار -full (جميع الميزات الاختيارية مفعّلة)
  • PINGAP_LIBC=gnu — على Linux، استخدم إصدار glibc بدلاً من إصدار musl الثابت الافتراضي
  • PINGAP_TLS=rustls — على Linux، قم بتثبيت إصدار -rustls-full (خلفية TLS من rustls، جميع الميزات الاختيارية، بدون OpenSSL)؛ راجع خلفية TLS
# إصدار كامل الميزات
curl -sSL https://raw.githubusercontent.com/vicanso/pingap/main/install.sh | PINGAP_FULL=1 sh

الأنظمة المدعومة: Linux x86_64/arm64، Darwin x86_64/arm64. راجع صفحة الإصدارات لجميع الأصول المتاحة.

للحصول على تعليمات أكثر تفصيلاً، بما في ذلك التشغيل من ثنائي، راجع Documentation.

بدء وكيل بدون ملف تكوين

أمر واحد يكفي لخدمة نطاق عبر https وإعادة توجيهه إلى خلفية:

# شهادة مطلوبة من let's encrypt
pingap --domain=pingap.io --upstream=192.168.1.1:3000

# أو استخدم شهادتك الخاصة
pingap --domain=pingap.io --upstream=192.168.1.1:3000 --cert=/etc/ssl/pingap.io

بدون --cert، يطلب Pingap شهادة من Let's Encrypt عبر تحدي HTTP-01، لذا يجب أن يحل pingap.io إلى هذا المضيف ويجب أن يكون المنفذ 80 قابلاً للوصول من الإنترنت. يتم الاحتفاظ بالشهادة الصادرة في ~/.pingap/acme/<domains>.toml وإعادة استخدامها عند إعادة التشغيل — إصدار الشهادات محدود المعدل، لذا لا تحذفها. كل شيء آخر يأتي من سطر الأوامر: تغيير --upstream يسري في التشغيل التالي دون لمس الشهادة.

يقبل --cert الشهادة نفسها أو الدليل الذي يحتويها — يتم اكتشاف التخطيطات الشائعة fullchain.pem / privkey.pem، cert.pem / key.pem و tls.crt / tls.key تلقائياً، استخدم --key لأي شيء آخر. يكون المستمع افتراضياً على 0.0.0.0:443 عند وجود شهادة و 0.0.0.0:80 عند عدم وجود شهادة ولا نطاق، و --addr يتجاوز ذلك. يأخذ --upstream قائمة مفصولة بفواصل من الخلفيات، و --domain قائمة مفصولة بفواصل من المضيفات (احذفه لخدمة كل مضيف عبر http عادي). يتم الرد على الطلبات لمضيف غير مدرج برمز 404.

يتم إنشاء التكوين في كل تشغيل، لذا لا يمكن تعديله عبر واجهة الإدارة: لأي شيء يتجاوز خادماً واحداً استخدم --conf، والذي لا يمكن دمجه مع هذه العلامات.

التكوين الديناميكي

صُمم Pingap للتكيف مع تغييرات التكوين دون توقف.

إعادة التحميل الساخن (--autoreload): لمعظم التغييرات — مثل تحديث المنبع (upstreams) أو المواقع أو الإضافات — يطبق Pingap التكوين الجديد خلال 10 ثوانٍ دون إعادة تشغيل. هذا هو الوضع الموصى به لبيئات الحاويات.

إعادة التشغيل اللطيفة (-a أو --autorestart): للتغييرات الأساسية (مثل تعديل منافذ استماع الخادم)، يقوم هذا الوضع بإعادة تشغيل كاملة دون أي توقف، مما يضمن عدم فقدان أي طلبات.

عملية التسليم مدفوعة بالجاهزية وليس بالتوقيت: يتم بدء الاستبدال بـ -d -u، ويُبلغ عبر مقبس unix بجوار مقبس الترقية لحظة جاهزيته لتولي المستمعين، وعندها فقط يرسل العملية الجارية لنفسها SIGQUIT. إذا خرج الاستبدال، أو ماتت عمليته الخفية، أو انقضى basic.restart_ready_timeout (الافتراضي 1 دقيقة) أولاً، يتم التخلي عن إعادة التشغيل وتستمر العملية الجارية في الخدمة.

🔧 التطوير

make dev

إذا كنت بحاجة إلى واجهة إدارة ويب، يجب تثبيت nodejs وبناء أصول الويب.

# توليد أصل إدارة الويب
cd web
npm i 
cd ..
make build-web

خلفية TLS

الإصدار الافتراضي ينهي TLS باستخدام OpenSSL، المُجمّع من المصدر بواسطة crate openssl. للبناء باستخدام rustls بدلاً من ذلك، والذي يلغي بناء مصدر OpenSSL (لا يزال هناك حاجة إلى مترجم C: موفرو التشفير في rustls، ring و aws-lc-rs، يحتويان على C و assembly):

cargo build --release --no-default-features --features tls-rustls
# مع الميزات الاختيارية أيضاً
cargo build --release --no-default-features --features tls-rustls,full

يتجاهل إصدار rustls إعدادات tls_min_version و tls_max_version و tls_cipher_list و tls_ciphersuites الخاصة بكل خادم ويسجل تحذيراً عند تعيينها: فهو يقدم دائماً TLS 1.2 و 1.3 مع مجموعات التشفير الافتراضية في rustls. كل شيء آخر، بما في ذلك شهادات SNI الديناميكية، وإصدار CA ذاتي التوقيع، وACME وخيار ca للمنبع، يتصرف بنفس الطريقة. هناك فرق واحد يجب معرفته عند التحقق من المنبع: rustls (webpki) يرفض شهادة خادم تحمل CA:TRUE، والتي يقبلها OpenSSL، لذا فإن الخلفية التي تستخدم شهادة ذاتية التوقيع سريعة openssl req -x509 تحتاج إلى ورقة (leaf) مناسبة موقعة من CA (أو ورقة ذاتية التوقيع بدون علامة CA) قبل أن يثق بها خيار ca للمنبع. يسجل سجل بدء التشغيل الخلفية التي تم بناء الثنائي بها.

📝 التكوين

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

يمكنك العثور على التعليمات ذات الصلة هنا: https://pingap.io/crates/config.

🔄 خطوة الوكيل

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

📊 الأداء

CPU: M4 Pro, Thread: 1

Ping بدون سجل وصول

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

إصدار MSRV الحالي لدينا هو 1.96

📄 الترخيص

هذا المشروع مرخص بموجب Apache License, Version 2.0.

الفئات