A reverse proxy like nginx, built on pingora, simple and efficient.
Sentry and opentelemetry are optional, they are supported in the full-featured version.
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"]
- The service supports configuring multiple Locations, filtering locations by host and path, and matching and selecting them one by one according to the weight
- Supports regular expression configuration to rewrite path
- Support transparent proxy
- Support HTTP 1/2, including h2c
- Support static, dns and docker label service discovery
- Support grpc-web reverse proxy
- Configuration based on TOML format, the configuration is very simple, and can be saved to files or etcd
- Supports more than 10 Prometheus indicators, pull and push mode
- Opentelemetry supports w3c context trace and jaeger trace
- Frequently updated config: upstream, location and plugin, which adjustments take effect in 10 seconds, and other config is updated, program will be restarted gracefully without interruption
- Templated configuration of access logs, which supports more than 30 related attribute configurations, and various parameters and indicators can be specified as needed
- Web UI for config, simple and easy to use
- Support let's encrypt, just set the domain of http server
- TLS certificates of different domain names can be served in the same service port, and the matching certificate is automatically selected according to servername
- Supports push events: lets_encrypt, backend_status, diff_config, restart, etc.
- Many http plugins, such as cache service components, compression components with multiple compression algorithms, authentication components, limiting components, etc.
- Provides statistical data at different stages, such as upstream_connect_time, upstream_processing_time, compression_time, cache_lookup_time and cache_lock_time, etc.
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
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
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 run -it -d --restart=always \
-v $PWD/pingap:/opt/pingap \
-p 3018:3018 \
vicanso/pingap -c /opt/pingap/conf \
--autoreload \
--admin=pingap:[email protected]:3018
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
[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.
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
wrk 'http://127.0.0.1:6100/ping' --latency
Running 10s test @ http://127.0.0.1:6100/ping
2 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 59.87us 20.27us 1.00ms 81.00%
Req/Sec 82.12k 3.04k 85.77k 90.59%
Latency Distribution
50% 63.00us
75% 69.00us
90% 76.00us
99% 97.00us
1650275 requests in 10.10s, 215.61MB read
Requests/sec: 163396.17
Transfer/sec: 21.35MB
Our current MSRV is 1.74
This project is Licensed under Apache License, Version 2.0.