23 releases (5 breaking)

new 0.6.2 Jul 26, 2024
0.5.6 May 29, 2024
0.1.2 Mar 29, 2024

#214 in HTTP server

Download history 65/week @ 2024-04-04 102/week @ 2024-04-11 277/week @ 2024-04-18 452/week @ 2024-04-25 703/week @ 2024-05-02 108/week @ 2024-05-09 338/week @ 2024-05-16 501/week @ 2024-05-23 72/week @ 2024-05-30 8/week @ 2024-06-06 5/week @ 2024-06-13 17/week @ 2024-07-04 2/week @ 2024-07-11 104/week @ 2024-07-18

123 downloads per month

Apache-2.0

590KB
15K SLoC

pingap

Pingap Logo

What is Pingap

A reverse proxy like nginx, built on pingora, simple and efficient.

中文说明

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:pingap.io --> upstream["10.1.3.1,10.1.3.2"]

Feature

  • Server supports multiple locations, select the location by host and path
  • Using regular expression rewriting path
  • HTTP 1/2 end to end proxy, including h2c
  • TOML base configuration, file or etcd storage
  • Uptream and location changes are effective about 10s, and other configurations are effective after graceful restart
  • Template for http access log, supports more than 30 attributes
  • Admin Web UI configuration which is easy to use
  • Genrate TLS certificates from let's encrypt
  • Server supports multiple tls certificates for different domains
  • Notification events: lets_encrypt, backend_status, diff_config, restart, etc.
  • Http proxy plugins: compression, static serve, limit, stats, mock, etc.
  • Statistics at different stages: upstream_connect_time, upstream_processing_time, compression_time, cache_lookup_time and cache_lock_time

Start

Loads all configurations from /opt/pingap/conf or file /opt/pingap/pingap.toml and run in the background. Log appends to /opt/pingap/pingap.log.

RUST_LOG=INFO pingap -c=/opt/pingap/conf -d --log=/opt/pingap/pingap.log

Graceful restart

Validate the configurations, send quit signal to pingap, then start a new process to handle all requests.

RUST_LOG=INFO pingap -c=/opt/pingap/conf -t \
  && pkill -SIGQUIT pingap \
  && RUST_LOG=INFO pingap -c=/opt/pingap/conf -d -u --log=/opt/pingap/pingap.log

Auto restart

Watch the configurations, if one of them changes, graceful restart pingap. autoreload means if only the upstream and location configurations are updated, they will take effect about 10s without restarting.

RUST_LOG=INFO pingap -c=/opt/pingap/conf \
  && -a -d --autoreload --log=/opt/pingap/pingap.log

Docker

cGluZ2FwOjEyMzEyMw== is base64("pingap:123123")

docker run -it -d --restart=always \
  -v $PWD/pingap:/opt/pingap \
  -p 3018:3018 \
  vicanso/pingap -c /opt/pingap/conf \
  --autoreload \
  --admin=cGluZ2FwOjEyMzEyMw==@0.0.0.0:3018

Dev

make dev

If you need a web admin, you should install nodejs and build web asssets.

# generate admin web asset
cd web
yarn install
cd ..
make build-web

Config

[upstreams.charts]
addrs = ["127.0.0.1:5000"]

[locations.lo]
upstream = "charts"
path = "/"

[servers.test]
addr = "0.0.0.0:6188"
locations = ["lo"]

All toml configurations are as follows pingap.toml.

Proxy step

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: M2, Thread: 1

Ping no accces log:

wrk 'http://127.0.0.1:6188/ping' --latency

Running 10s test @ http://127.0.0.1:6188/ping
  2 threads and 10 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    67.10us   67.52us   4.63ms   99.53%
    Req/Sec    74.82k     2.57k   85.56k    92.57%
  Latency Distribution
     50%   69.00us
     75%   76.00us
     90%   83.00us
     99%  105.00us
  1504165 requests in 10.10s, 196.52MB read
Requests/sec: 148928.76
Transfer/sec:     19.46MB

Rust version

Our current MSRV is 1.74

License

This project is Licensed under Apache License, Version 2.0.

Dependencies

~94–130MB
~2.5M SLoC