
nginx のようなリバースプロキシ、pingora 上に構築、シンプルで効率的。
# Pingap
[Cloudflare Pingora](https://github.com/cloudflare/pingora) 上に構築されたリバースプロキシ兼アプリケーションゲートウェイです。TOML ファイル、またはバイナリに組み込まれた Web 管理画面から設定でき、再起動なしで変更を反映し、30 以上のプラグインを備えています。
[中文说明](https://github.com/vicanso/pingap/blob/main/README_zh.md) | [ドキュメント](https://pingap.io/) · [中文ドキュメント](https://pingap.io/zh/) | [サンプル](https://github.com/vicanso/pingap/blob/main/examples/README.md) | [プラグイン](https://github.com/vicanso/pingap/blob/main/pingap-plugin/README.md) | [Crates](https://github.com/vicanso/pingap/blob/main/docs/README.md) | [アップグレード](https://pingap.io/guide/upgrading)

## 際立った特徴
- **バイナリに組み込まれた Web 管理画面。** すべての設定にフォームがあります。変更は保存前に `pingap -t` と同じ方法で検証され、以前のバージョンを保持して復元でき、読み取り専用アカウントと API トークンも用意されています。ホームページには直近 15 分間のトラフィック(レート、ステータス、レイテンシ、各アップストリーム)が Prometheus なしでグラフ表示されます。
- **ダウンタイムなしの変更。** アップストリーム、ロケーション、プラグイン、証明書は実行中のプロセス内で置き換えられます(`--autoreload`)。新しいリスナーが必要なものは、ソケットを引き継ぐ再起動で適用され(`--autorestart`、Linux のデーモン向け)、後継プロセスが起動しなかった場合は実行中のプロセスがサービスを継続します。
- **30 以上のプラグイン**を、ロケーションごとに、列挙した順序で適用します。認証(JWT、OIDC、キー、ベーシック、HMAC、フォワード認証)、アクセス制御(IP、リファラー、ユーザーエージェント、ブロックパス)、トラフィック(レート制限と帯域制限、キャッシュ、ミラーリング、トラフィックスプリッティング)、コンテンツ(圧縮、ボディ置換、リダイレクト、静的ファイル、画像最適化)、運用(メンテナンスモード、ヘルスエンドポイント、エラーページ)。[すべてのプラグイン](https://github.com/vicanso/pingap/blob/main/pingap-plugin/README.md)
- **cron ジョブ不要の証明書。** Let's Encrypt またはその他の ACME CA を HTTP-01 または DNS-01(Alibaba Cloud、Cloudflare、Tencent Cloud、Huawei Cloud)で利用でき、RSA と ECDSA の併用、OCSP ステープリング、クライアントおよびアップストリームに対する相互 TLS をサポートします。
- **実行前に検証される設定。** `-t` は起動時と同じものをすべて構築し、`--strict` は未知のキーを拒否し、`--diff` は変更が何をもたらすかを表示します。TOML、HCL、KDL をファイルまたは etcd で利用でき、シークレットは環境変数またはファイルから取得します。
- **監視を前提とした設計。** Prometheus メトリクス(プルとプッシュ)、OpenTelemetry トレース、30 以上のフィールドを持つテキストまたは JSON 形式のアクセスログ、クライアントの JA4 TLS フィンガープリント。
- リバースプロキシとしてのその他の機能も備えています。HTTP/1.1、HTTP/2、WebSocket、gRPC-web。ホスト、パス、正規表現によるルーティング。ラウンドロビン、最小接続数、コンシステントハッシュ、スティッキーセッションと、ヘルスチェック、リトライ、サーキットブレーカー。DNS(A/AAAA、SRV)または Docker ラベルからのバックエンド。リスナー側およびアップストリーム側の PROXY プロトコル。OpenSSL または rustls。
メトリクス、トレーシング、画像最適化は `-full` ビルドに含まれます。
## 🚀 はじめに
### Docker Compose
```yaml
# docker-compose.yml
services:
pingap:
image: vicanso/pingap:latest # for production, pin a release: vicanso/pingap:<version>-full
container_name: pingap-instance
restart: always
ports:
- "80:80"
- "443:443"
volumes:
# everything Pingap keeps: configuration, certificates, cache
- ./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> # change this
command:
- pingap
- --autoreload
```
```bash
mkdir pingap_data
docker compose up -d
```
管理画面は http://localhost/pingap にあります。イメージには `latest`、`full`、`rustls-full` のタグが付与され、リリース版には `<version>`、`<version>-full`、`<version>-rustls-full` が付与されます。それぞれにシェルを持たない `-distroless` 版もあり、その場合は上記と同様に `command` を `pingap` で始める必要があります。
### バイナリ
```bash
curl -sSL https://raw.githubusercontent.com/vicanso/pingap/main/install.sh | sh
```
Linux と macOS(x86_64 および arm64)では、最新リリースを `/usr/local/bin/pingap` にインストールします。`sh` の前に置く変数によって、インストールされる内容が決まります:
| 変数 | 効果 |
| --- | --- |
| `PINGAP_FULL=1` | すべてのオプション機能を含む `-full` ビルド |
| `PINGAP_TLS=rustls` | Linux:OpenSSL を含まない `-rustls-full` ビルド([TLS バックエンド](#tls-backend)を参照) |
| `PINGAP_LIBC=gnu` | Linux:静的 musl 版の代わりに glibc ビルド |
| `PINGAP_SERVICE=1` | systemd を使用する Linux:`pingap` サービスと `/etc/pingap/conf` 内のスターター設定も含む。有効化や起動は行われない |
| `PINGAP_VERSION=0.15.0` | 最新版の代わりにそのリリース |
すべてのアセットは[リリースページ](https://github.com/vicanso/pingap/releases)にあります。
### コマンド1つ、設定ファイル不要
```bash
# the certificate comes from Let's Encrypt
pingap --domain=pingap.io --upstream=192.168.1.1:3000
# or bring your own
pingap --domain=pingap.io --upstream=192.168.1.1:3000 --cert=/etc/ssl/pingap.io
```
- `--cert` を指定しない場合、証明書は HTTP-01 によって発行されます。ドメインがこのホストに解決され、ポート 80 に到達可能である必要があります。証明書は `~/.pingap/acme/<domains>.toml` に保存され、次回起動時に再び使用されます。削除しないでください。発行にはレート制限があります。
- `--cert` は証明書またはその証明書が置かれているディレクトリです(`fullchain.pem` / `privkey.pem`、`cert.pem` / `key.pem`、`tls.crt` / `tls.key` が検出されます。それ以外の名前は `--key` で指定します)。`--upstream` と `--domain` はカンマ区切りのリストを受け取り、`--addr` はリッスンするアドレスを指定します。
- 設定は起動のたびに新しく作成されるため、管理者は編集できません。複数のサーバーを使用する場合は `--conf` を使用してください。これらのフラグとは併用できません。
## 📝 設定
```toml
[upstreams.api]
addrs = ["api.github.com:443"]
discovery = "dns"
sni = "api.github.com"
[plugins.staticServe]
category = "directory"
path = "~/Downloads"
[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"]
```
HCL または KDL でも同様に記述できます。すべてのキーは[設定リファレンス](https://pingap.io/crates/config)で説明されています。
| | |
| --- | --- |
| `--autoreload` | 再起動なしで変更が適用されます。ファイルからは10秒以内、etcd からは即座に反映されます。再起動が必要なものは報告され、再起動を待ちます。コンテナ向けのモード |
| `-a`, `--autorestart` | 上記に加え、リロードでは変更できないもの(例えばリッスンアドレス)についてもリクエストを落とさずに再起動します。Linux 上のデーモン(`-d`)向け。それ以外の環境ではリロードし、待機中のものを報告します |
| `-t` | 起動時と同様にすべての upstream、location、プラグイン、証明書、サーバーを構築し、何もバインドしません |
| `--strict` | Pingap が認識しないキー、またはこのビルドに機能がないキーを、通常は警告とするところをエラーにします。CI での `-t` 向け |
| `--diff <other>` | `<other>` が設定の代わりになった場合に何が変わるかを出力します。認証情報はチェックサムとして表示されます |
| `$ENV:NAME`, `$FILE:/path` | 値全体として、設定の読み込み時に変数またはファイルの内容で置き換えられます |
## 🔄 リクエストの処理方法

1. **サーバー**が接続を受け付け、ホストとパスが最もよく一致する **location** を選択します。どれにも一致しないリクエストには `404` が返されます。
2. location の **プラグイン**はリストされた順に、それぞれのステップ(受信時または応答時)で実行されます。プラグインはリクエスト自体に応答できます(キャッシュヒット、認証失敗、リダイレクト、静的ファイルなど)。その場合 upstream は呼び出されません。
3. そうでなければ、location の **upstream** が正常なバックエンドを選択し、リクエストが転送されます。`max_retries` を指定すると、接続できない場合は別のバックエンドで試行されます。`fallback_upstream` を指定すると、upstream が受け付けられないリクエストは2番目の upstream に送られます。
4. レスポンスはレスポンスプラグインを通ってクライアントに返され、リクエストは**ログに記録**されます(アクセスログ、メトリクス、トレース)。
## 📊 パフォーマンス
M4 Pro の1スレッドで `/ping` に対して毎秒約147,000リクエスト、99パーセンタイルは116µs(`wrk`、10接続、アクセスログなし)。
<details>
<summary>実行結果</summary>
```
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
```
</details>
## 🔧 開発
```bash
make dev # needs bacon: cargo install bacon
make build-web # after a change under web/, needs Node.js
make fmt && make lint && make test
```
`make dev` は `full` フィーチャーでビルドし、`~/tmp/pingap` の設定で `--autoreload` を付けて Pingap を実行し、`127.0.0.1:3018` で管理画面を提供し(`pingap` / `123123`)、ソースが変更されると再ビルドします。管理画面は `dist/` からバイナリに埋め込まれ、`make build-web` がそれを生成します。サポートされる最小の Rust バージョンは 1.96 です。
### TLS バックエンド
デフォルトのビルドでは、ソースからコンパイルされた OpenSSL を使用します。rustls を使用する場合:
```bash
cargo build --release --no-default-features --features tls-rustls,full
```
rustls ビルドは常に TLS 1.2 と 1.3 を rustls 独自の暗号スイートで提供するため、設定チェック時にサーバーごとの `tls_min_version`、`tls_max_version`、`tls_cipher_list`、`tls_ciphersuites` は拒否されます。それ以外の動作は同じです。相違点は [certificate crate](https://pingap.io/crates/certificate) に記載されています。`pingap --version` を実行すると、バイナリがどのバックエンドを使用しているかが表示されます。
## 🤝 コントリビューション
プルリクエストを歓迎します。
- 新機能の場合は、コードを書く前に議論できるよう、まず issue を作成してください。
- 誤字やコメントの書式の修正のみを目的としたプルリクエストは作成しないでください。これらはまとめて修正されます。
- プッシュする前に `make fmt`、`make lint`、`make test` を実行してください。CI はすべてのプルリクエストで同じチェックを実行します。
- コントリビューションは [Contributor License Agreement](https://github.com/vicanso/pingap/blob/main/CLA.md) の下で行われ、プルリクエストテンプレートのチェックボックスにチェックを入れることで同意したものとみなされます。作業の著作権はあなたに帰属し、プロジェクトのライセンスの下でプロジェクトにライセンスされます。
## 📄 ライセンス
[Apache License, Version 2.0](https://github.com/vicanso/pingap/blob/main/LICENSE)。