
ReproxyはシンプルなエッジHTTP(s)サーバー/リバースプロキシであり、さまざまなプロバイダー(docker、static、file、consul catalog)をサポートしています。1つ以上のプロバイダーが、要求されたサーバー、要求されたURL、宛先URL、およびヘルスチェックURLに関する情報を提供します。単一のバイナリまたはDockerコンテナとして配布されます。
サーバー(ホスト)はFQDN(例:s.example.com)、*(キャッチオール)、または正規表現で設定できます。完全一致が優先されるため、example.com と example\.(com|org) の2つのルールがある場合、example.com/some/url へのリクエストは前者に一致します。要求されたURLは正規表現にでき、例えば ^/api/(.*) のように、宛先URLには正規表現でマッチしたグループを含めることができます(例:http://d.example.com:8080/$1)。上記の例では、http://s.example.com/api/something?foo=bar は http://d.example.com:8080/something?foo=bar にプロキシされます。
便宜上、末尾に / が付き、正規表現グループがないリクエストは /(.*) に展開され、その場合の宛先は /$1 に展開されます。つまり、/api/ -> http://127.0.0.1/service は ^/api/(.*) -> http://127.0.0.1/service/$1 と解釈されます。
宛先URLではホスト置換がサポートされています。例えば、/files/${host} はマッチしたホスト名に置き換えられます。$host(中括弧なし)も使用できます。
HTTPとHTTPSの両方をサポートしています。HTTPSでは、静的証明書の他に、自動ACME(Let's Encrypt)証明書を使用できます。オプションのアセットサーバーを使用して静的ファイルを提供することもできます。Reproxyを起動するには、少なくとも1つのプロバイダーを定義する必要があります。残りのパラメーターは厳密にはオプションであり、妥当なデフォルト値があります。
例:
reproxy --static.enabled --static.rule="*,example.com/api/(.*),https://api.example.com/$1"reproxy --docker.enabled --docker.autodocker up -p 80:8080 umputun/reproxy --docker.enabled --docker.autodocker up -p 80:8080 -p 443:8443 umputun/reproxy --docker.enabled --docker.auto --ssl.type=auto --ssl.fqdn=example.comReproxyは、小さな自己完結型バイナリとDockerイメージとして配布されています。バイナリとイメージの両方が複数のアーキテクチャと複数のオペレーティングシステム(linux_x86_64、linux_arm64、linux_arm、macos_x86_64、macos_arm64、windows_x86_64、windows_armなど)をサポートしています。また、arm64とx86の両方のdebおよびrpmパッケージも提供しています。
brew install umputun/apps/reproxydocker pull umputun/reproxy または docker pull ghcr.io/umputun/reproxy。最新の安定版には :vX.Y.Z のDockerタグ(:latest エイリアス付き)が付いており、現在のmasterには :master タグが付いています。
プロキシルールはさまざまなプロバイダーによって提供されます。現在含まれているのは、file、docker、static、consul-catalog です。各プロバイダーは、プロキシリクエストと静的(アセット)の両方に対して複数のルーティングルールを定義できます。ユーザーは同時に複数のプロバイダーを設定できます。
各種プロバイダーの例については、examplesを参照してください。
これは、すべてのマッピングルールをコマンドライン(または環境変数)で直接定義する最もシンプルなプロバイダーです。複数のルールをサポートしています。各ルールは、カンマ区切りの3~7要素 server,sourceurl,destination[,ping-url[,forward-health-checks[,timeout[,throttle]]]] です。例:
*,^/api/(.*),https://api.example.com/$1 – /api プレフィックスを持つ任意のホスト/サーバーへのすべてのリクエストを https://api.example.com にプロキシします。example.com,/foo/bar,https://api.example.com/zzz,https://api.example.com/ping – example.com へのすべてのリクエストで、/foo/bar のURLを https://api.example.com/zzz にプロキシし、ヘルスチェックには https://api.example.com/ping を使用します。example.com,/foo/bar,https://api.example.com/zzz,https://api.example.com/ping,true – 上記と同じですが、/ping および /health リクエストもバックエンドに転送します。example.com,^/upload/(.*),https://api.example.com/$1,,,5m – ルートごとのリクエストタイムアウトを5分に設定します(4番目と5番目のフィールドは空欄で、ping-urlとforward-health-checksをスキップします)。4番目の要素は、ヘルスレポートに使用されるオプションのping URLを定義します。5番目の要素は、ヘルスチェックリクエストをバックエンドに転送することをオプションで有効にします(true、yes、1)。詳細はヘルスチェックセクションを参照してください。6番目の要素は、ルートごとのオプションのリクエストタイムアウト(Goの期間。例:5m、30s)です。0 または空の場合はグローバルな --timeout.write 設定を継承します。7番目の要素は、ルートごとのユーザーあたりのオプションの req/sec 制限です。0 または空の場合は --throttle.user を継承します。空の位置フィールドは許可されています(未使用の中間フィールドには ,, を使用できます)。
このプロバイダーは、ルーティングルールを含むyamlファイルを使用します。
reproxy --file.enabled --file.name=config.yml
config.yml の例:```yaml
default: # the same as * (catch-all) server
これは動的プロバイダーであり、ファイルの変更は自動的に適用されます。
**異なるドメイン上の複数の静的サイト**は、サーバー名をキーとして`assets: true`を使用することで提供できます。```yaml
site-en.example.com:
- { route: "/", dest: "/var/www/en", "assets": true }
site-ru.example.com:
- { route: "/", dest: "/var/www/ru", "assets": true }
重要: アセットルールの route フィールドはパスプレフィックス(例: /、/web/)でなければならず、正規表現ではありません。^/(.*) のような正規表現パターンは、静的アセットのマッチングがパスプレフィックス比較を使用するため、assets: true では機能しません。
Dockerプロバイダーは、追加設定なしで完全自動検出(--docker.auto)をサポートしています。デフォルトでは、http://<url>/<コンテナ名>/(.*) のようなすべてのリクエストを、指定されたコンテナの内部IPと公開ポートにリダイレクトします。アクティブ(実行中)なコンテナのみが検出されます。
このデフォルトはラベルで変更できます:
reproxy.server - 照合するサーバー(ホスト名)。カンマ区切りのサーバーリストも指定可能。reproxy.route - 送信元ルート(location)reproxy.dest - 宛先パス。注意:これは完全なURLではなく、コンテナのip:portに追加されるパスです。reproxy.port - 検出されたコンテナの宛先ポートreproxy.ping - 宛先コンテナのpingパス。reproxy.remote - カンマ区切りのサブネットまたはIPのリストでルートへのアクセスを制限reproxy.auth - カンマ区切りの user:bcrypt_hash ペア(htpasswd -nbB で生成)でルートにベーシック認証を要求reproxy.assets - アセットマッピングを web-root:location として設定(例: reproxy.assets=/web:/var/www)reproxy.keep-host - Hostヘッダーをそのまま維持(、、)するか、宛先ホストに置き換える(、、)注意:--docker.auto がない場合、宛先コンテナはreproxyの潜在的な宛先として考慮されるために、少なくとも1つの reproxy.* ラベルを持つ必要があります。
--docker.auto を使用すると、公開ポートを持つすべてのコンテナがルーティング先と見なされます。これを制限する方法は3つあります:
--docker.exclude で特定のコンテナを明示的に除外(例: --docker.exclude=c1 --docker.exclude=c2 ...)--docker.network で特定のDockerネットワークのみを許可reproxy.enabled=false または reproxy.enabled=no または reproxy.enabled=0 を設定reproxy.route が定義されていない場合、デフォルトのルートは ^/<コンテナ名>/(.*) です。すべてのプロキシ送信元が同じプレフィックスパターンを持つ必要がある場合(例: /api/(.*))、ユーザーはすべてのコンテナベースのルートに共通のプレフィックス(この場合は /api)を定義できます。これは --docker.prefix パラメーターで行えます。
Dockerプロバイダーは、同じコンテナ上で複数の異なるルートにマッチするように、reproxy.N.something ラベルの複数セットを定義することもできます。これは、単一のコンテナが複数のエンドポイント(例: 公開APIと管理API)を公開する場合などに便利です。上記のすべてのラベルは「N-index」で使用できます(例: reproxy.1.server、reproxy.1.port など)。Nは0から9の範囲です。
これは動的プロバイダーであり、コンテナのステータスに変更があると自動的に適用されます。
使用方法: reproxy --consul-catalog.enabled
Consul Catalogプロバイダーは、reproxy. プレフィックスを持つタグを持つサービスを取得するために、定期的に(デフォルトでは毎秒)Consul APIを呼び出します。チェック間隔は --consul-catalog.interval コマンドラインフラグで、Consulアドレスは --consul-catalog.address コマンドラインオプションで再定義できます。デフォルトのアドレスは http://127.0.0.1:8500 です。
例えば:``` reproxy --consul-catalog.enabled --consul-catalog.address=http://192.168.1.100:8500 --consul-catalog.interval=10s
デフォルトでは、プロバイダはすべてのサービスに対して以下の値を設定します:
- enabled `false`
- server `*`
- route `^/(.*)`
- dest `http://<SERVICE_ADDRESS_FROM_CONSUL>/$1`
- ping `http://<SERVICE_ADDRESS_FROM_CONSUL>/ping`
このデフォルトはタグで変更できます:
- `reproxy.server` - マッチするサーバー(ホスト名)。カンマ区切りのサーバーリストも指定可能。
- `reproxy.route` - ソースルート(場所)
- `reproxy.dest` - 宛先パス。注: これは完全なURLではなく、サービスのIP:ポートに追加されるパスです。
- `reproxy.port` - 検出されたサービスの宛先ポート
- `reproxy.remote` - カンマ区切りのサブネットまたはIPリストでルートへのアクセスを制限
- `reproxy.auth` - カンマ区切りの `user:bcrypt_hash` ペア(`htpasswd -nbB` で生成)でルートのベーシック認証を要求
- `reproxy.ping` - 宛先サービスのpingパス。
- `reproxy.forward-health-checks` - `/ping` および `/health` リクエストをバックエンドに転送(`true`, `yes`, `1`)。
- `reproxy.timeout` - ルートごとのリクエストタイムアウト(Goの期間指定、例: `5m`, `30s`)。`0` または未設定の場合はグローバル `--timeout.write` を継承。無効な値は警告とともに無視される。
- `reproxy.throttle` - ルートごとのユーザーあたりのリクエスト/秒制限。`0` または未設定の場合は `--throttle.user` を継承。無効または負の値は警告とともに無視される。
- `reproxy.enabled` - サービスを reproxy の宛先から有効化(`yes`, `true`, `1`)または無効化(その他の値)。
### Docker Compose 固有の詳細
ルールが Docker Compose 環境の一部として設定されている場合、正規表現グループを含む宛先は Compose の構文と競合します。つまり、Compose 環境で `https://api.example.com/$1` を使用しようとすると、構文エラーが発生します。標準的な解決策は、`$` 記号を `$$` に置き換えて「エスケープ」することです。例: `https://api.example.com/$$1`。この置換は Docker Compose でサポートされており、reproxy 自体とは関係ありません。別の方法として、reproxy レベルでサポートされている `@` を `$` の代わりに使用することもできます。例: `https://api.example.com/@1`_
## SSL サポート
SSL モード(デフォルトは none)は、`auto`(ACME/LE 証明書)、`static`(既存の証明書)、`none` のいずれかに設定できます。`auto` が有効な場合、検出されたすべてのサーバー名に対して SSL 証明書が自動的に発行されます。ユーザーは `--ssl.fqdn` 値を設定して上書きできます。`auto` および `static` SSL モードでは、Reproxy が自動的に `X-Forwarded-Proto` および `X-Forwarded-Port` ヘッダーを追加します。これらのヘッダーは、プロキシ背後にあるサービスがクライアントによって使用された元のプロトコル(http または https)とポート番号を知るために役立ちます。
ディスカバリプロバイダ(docker、file、consul)で ACME を使用する場合、reproxy の再起動を必要とせずに、新しく検出されたサーバーの SSL 証明書が自動的に取得されます。
### ACME チャレンジ
Reproxy は SSL 証明書検証のために2種類の ACME チャレンジをサポートしています:
1. **HTTP-01 チャレンジ**(デフォルト): 特定の HTTP URL でトークンを提供することによりドメインの所有権を検証します。ポート 80 がパブリックにアクセス可能である必要があります。
2. **DNS-01 チャレンジ**: DNS TXT レコードを作成してドメインの所有権を検証します。この方法:
- ポート 80 がアクセス可能である必要がない
- ワイルドカード証明書で動作する
- サポートされている DNS プロバイダの設定が必要
#### チャレンジの選択
Reproxy は設定に基づいて使用するチャレンジ方式を自動的に決定します:
- **HTTP-01**(デフォルト): DNS プロバイダが設定されていない場合に使用
- **DNS-01**: DNS プロバイダが設定されている場合に使用
チャレンジタイプを明示的に選択する必要はありません - DNS-01 チャレンジを使用したい場合は DNS プロバイダを設定するだけです。
#### 現在サポートされている DNS プロバイダ
Reproxy は現在以下の DNS プロバイダをサポートしています:
- **Cloudflare**: `--ssl.dns.type=cloudflare --ssl.dns.cloudflare.api-token=TOKEN`
- **Route53 (AWS)**: `--ssl.dns.type=route53 --ssl.dns.route53.region=REGION --ssl.dns.route53.hosted-zone-id=ID`
- **Gandi**: `--ssl.dns.type=gandi --ssl.dns.gandi.bearer-token=TOKEN`
- **DigitalOcean**: `--ssl.dns.type=digitalocean --ssl.dns.digitalocean.api-token=TOKEN`
- **Hetzner**: `--ssl.dns.type=hetzner --ssl.dns.hetzner.api-token=TOKEN`
- **Linode**: `--ssl.dns.type=linode --ssl.dns.linode.api-token=TOKEN`
- **GoDaddy**: `--ssl.dns.type=godaddy --ssl.dns.godaddy.api-token=TOKEN`
- **Namecheap**: `--ssl.dns.type=namecheap --ssl.dns.namecheap.api-key=KEY --ssl.dns.namecheap.user=USER`
- **Scaleway**: `--ssl.dns.type=scaleway --ssl.dns.scaleway.secret-key=KEY --ssl.dns.scaleway.organization-id=ID`
- **Porkbun**: `--ssl.dns.type=porkbun --ssl.dns.porkbun.api-key=KEY --ssl.dns.porkbun.api-secret-key=SECRET`
- **DNSimple**: `--ssl.dns.type=dnsimple --ssl.dns.dnsimple.api-access-token=TOKEN --ssl.dns.dnsimple.account-id=ID`
- **DuckDNS**: `--ssl.dns.type=duckdns --ssl.dns.duckdns.api-token=TOKEN`
Cloudflare を DNS プロバイダとして使用する例:```
export CLOUDFLARE_API_TOKEN=your_api_token
reproxy --ssl.type=auto [email protected] --ssl.fqdn=example.com
DNS-01チャレンジは特に以下の場合に便利です:
Reproxyは、--drop-headerパラメータ(繰り返し可能)を渡すことで、着信ヘッダーをサニタイズ(削除)できます。このパラメータは、サービス内部で設定された一部のヘッダーがエンドユーザーによって設定/偽装されるのを防ぐために役立ちます。例えば、認証を担当するサービスがX-Auth-UserとX-Auth-Tokenを設定する場合、着信リクエストからこれらのヘッダーを削除するために、--drop-header=X-Auth-User --drop-header=X-Auth-Tokenパラメータ、または環境変数DROP_HEADERS=X-Auth-User,X-Auth-Tokenを渡すのが適切でしょう。
逆の機能である、送信ヘッダーの設定もサポートされています。これは多くの場合に役立ちます。例えば、カスタムCORSルールやセキュリティ関連ヘッダーの強制などに使用できます。これは--headerパラメータ(繰り返し可能)または環境変数HEADERで行えます。例えば、docker composeでは次のように設定できます:```yaml
environment:
- HEADER=
X-Frame-Options:SAMEORIGIN,
X-XSS-Protection:1; mode=block;,
Content-Security-Policy:default-src 'self'; style-src 'self' 'unsafe-inline';
## ロギング
デフォルトではリクエストログは生成されません。これは `--logger.enabled` を設定することで有効にできます。ログ(自動ローテーション)は [Apache Combined Log Format](http://httpd.apache.org/docs/2.2/logs.html#combined) です。
ユーザーは `--logger.stdout` で標準出力ログを有効にすることもできます。これは上記のファイルログには影響しませんが、処理されたリクエストに関する最小限の情報を出力します。以下のようになります:```
2021/04/16 01:17:25.601 [INFO] GET - /echo/image.png - xxx.xxx.xxx.xxx - 200 (155400) - 371.661251ms
2021/04/16 01:18:18.959 [INFO] GET - /api/v1/params - xxx.xxx.xxx.xxx - 200 (74) - 1.217669m
ユーザーはアセットサーバーをオンにすることで(デフォルトではオフ)静的ファイルを提供できます。--assets.location が設定されている限り、assets.root 以下のプロキシされていないすべてのリクエストを静的ファイルのリクエストとして扱います。アセットサーバーはプロキシプロバイダーなしでも使用できます。このモードでは、reproxy は静的コンテンツの単純なウェブサーバーとして動作します。アセットサーバーは --assets.spa を使用した「SPAモード」もサポートしており、見つからないリクエストはすべて index.html に転送されます。
共通のアセットサーバーに加えて、複数のカスタムアセットサーバーがサポートされています。各プロバイダーはこのような静的ルールを定義する方法が異なり、一部のプロバイダーはまったくサポートしない場合もあります。たとえば、複数のアセットサーバーは静的プロバイダー(コマンドラインプロバイダー)、ファイルプロバイダー、さらにはDockerプロバイダーでも有用ですが、Consulカタログプロバイダーではほとんど意味がありません。
assets: または spa: の場合、ファイルサーバーとして扱われます。例: *,assets:/web,/var/www, は、/web/* へのすべてのリクエストを /var/www ディレクトリ上のファイルサーバーで提供します。assets: true または spa: true を設定します。注意: route フィールドはパスプレフィックス(例: /、/web/)である必要があり、正規表現パターンではありません。reproxy.assets=web-root:location、つまり reproxy.assets=/web:/var/www。SPAモードへの切り替えは reproxy.spa を yes または に設定することで行います。アセットサーバーは --assets.cache=<duration> パラメータでキャッシュ制御をサポートしています。0s の期間(デフォルト)はキャッシュ制御をオフにします。期間は、各々がオプションの小数と単位接尾辞を持つ10進数のシーケンスです。例: "300ms", "1.5h", "2h45m"。有効な時間単位は "ns", "us" (または "µs"), "ms", "s", "m", "h", "d" です。
キャッシュ期間を設定する方法は2つあります。
--assets.cache=48h のように簡単です。--assets.cache オプションのように見えます。例: --assets.cache=48h --assets.cache=text/html:24h --assets.cache=image/png:2h。環境変数の値はカンマ区切りにする必要があります。例: ASSETS_CACHE=48h,text/html:24h,image/png:2hカスタム404(見つからない)ページは --assets.not-found=<path> パラメータで設定できます。パスはアセットルートからの相対パスである必要があります。
純粋に静的コンテンツを提供することは、一般的なユースケースの1つです。通常、これはUIのみを提供する別のフロントエンドコンテナに使用されます。アセットサーバーを使用すると、そのようなコンテナはほとんど簡単に作成できます。これは reproxy.io を提供するコンテナの例です。```docker FROM node:22-alpine as build
WORKDIR /build COPY site/ /build COPY README.md /build/src/index.md
RUN yarn --frozen-lockfile RUN yarn build RUN ls -la /build/public
FROM ghcr.io/umputun/reproxy COPY --from=build /build/public /srv/site EXPOSE 8080 USER app ENTRYPOINT ["/srv/reproxy", "--assets.location=/srv/site"]
すべての必要なのは、静的アセットを適切な場所にコピーし、その場所を `"--assets.location` として reproxy のエントリポイントに渡すことだけです。
## SPAフレンドリーモード
一部のSPAアプリケーションは、静的アセットに対する404を特別な方法で処理するためにプロキシに依存しており、それを "/index.html" にリダイレクトします。これはnginxの `try_files $uri $uri/ …` ディレクティブに似ており、明らかにこの機能は現代のウェブアプリにとってある程度重要です。
このモードはデフォルトではオフになっており、`--assets.spa` を設定するか、`ASSETS_SPA=true` 環境変数を設定することで有効にできます。
## リダイレクト
デフォルトでは、reproxy は宛先をプロキシの場所として扱います。つまり、内部でHTTP呼び出しを行い、応答をクライアントに返します。しかし、宛先URLの先頭に `@code` を付けることで、この動作を恒久的(ステータスコード301)または一時的(ステータスコード302)なリダイレクトに変更できます。つまり、宛先を `@301 https://example.com/something` と設定すると、`Location: https://example.com/something` への恒久的なHTTPリダイレクトが発生します。
サポートされているコード:
- `@301`, `@perm` - 恒久的リダイレクト
- `@302`, `@temp`, `@tmp` - 一時的リダイレクト
## その他のオプション
- `--gzip` 応答のgzip圧縮を有効にします。
- `--max=N` リクエストの最大サイズを設定できます(デフォルト64k)。`0` に設定するとサイズチェックが無効になります。
- `--timeout.*` サーバーとプロキシトランスポートの両方のさまざまなタイムアウト。 [すべてのアプリケーションオプション](#all-application-options) の `timeout` セクションを参照してください。ゼロまたは負の値はタイムアウトがないことを意味します。
- `--insecure` 宛先ホストのSSL検証を無効にします。これは自己署名証明書に便利です。
## デフォルトポート
カスタムパラメータや環境変数を渡す必要をなくすために、デフォルトの `--listen` は動的であり、典型的なケースで合理的で役立つようにしようとします:
- ユーザーが `--listen` に何か設定した場合、以下のロジックは無視され、渡されたhost:portが直接使用されます。
- ユーザーが `--listen` に何も設定しておらず、reproxy がDockerコンテナの外で実行されている場合、HTTPモード(`ssl.type=none`)ではデフォルトは `127.0.0.1:80`、SSLモード(`ssl.type=auto` または `ssl.type=static`)では `127.0.0.1:443` です。
- ユーザーが `--listen` に何も設定しておらず、reproxy がDocker内で実行されている場合、HTTPモードではデフォルトは `0.0.0.0:8080`、SSLモードでは `0.0.0.0:8443` です。
もう一つのデフォルトは、同様の動的な方法で設定される `--ssl.http-port` です。Dockerコンテナ内で実行する場合は `8080` に、そうでない場合は `80` に設定されます。
## Ping、ヘルスチェック、フェイルオーバー
reproxy はこの目的のために2つのエンドポイントを提供します:
- `/ping` は `pong` で応答し、reproxy が起動して実行中であることを示します。
- `/health` は、すべての宛先サーバーが ping リクエストに `200` で応答した場合は `200 OK` ステータスを、いずれかのサーバーが200以外のコードで応答した場合は `417 Expectation Failed` を返します。また、合格/不合格のサービスの詳細を含むJSON本文も返します。
上記のエンドポイントに加えて、reproxy はオプションのライブヘルスチェックをサポートしています。この場合(有効な場合)、各宛先は定期的に ping 応答をチェックされ、失敗した宛先ルートは除外されます。同じプロバイダーまたは異なるプロバイダーから複数の同一の宛先を返すことが可能で、合格したものだけが選択されます。複数の一致が見つかり合格した場合、最終的なものは `lb-type` 戦略に従って選択されます(デフォルトはランダム選択)。
ライブヘルスチェックを有効にするには、ユーザーは `--health-check.enabled`(または環境変数 `HEALTH_CHECK_ENABLED=true`)を設定する必要があります。チェック間隔をカスタマイズするには `--health-check.interval=` を使用できます。
## 管理API
オプションで、`--mgmt.enabled` で有効にできます。`mgmt.listen`(アドレス:ポート)上に2つのエンドポイントを公開します:
- `GET /routes` - 発見されたすべてのルートのリスト
- `GET /metrics` - Prometheusメトリクス(`http_requests_total`、`response_status`、`http_response_time_seconds`)を返します
デフォルトでは、`http_response_time_seconds` はラベルとして生のリクエストパスを使用するため、動的なURL(例:`/api/users/123`、`/api/users/456`)では高いカーディナリティが発生する可能性があります。`--mgmt.low-cardinality` を使用すると、代わりにルートパターン(例:`^/api/users/(.*)`)に切り替わり、メトリクスのカーディナリティが大幅に削減されます。
_参照: [examples/metrics](https://github.com/umputun/reproxy/tree/master/examples/metrics)_
## エラーレポート
reproxy は、リクエストが提供されたルートやアセットのいずれにも一致しない場合、502 (Bad Gateway) エラーを返します。予期しない内部エラーが発生した場合は500を返します。デフォルトでは、reproxy は最も単純なテキスト版のエラー「Server error」をレンダリングします。`--error.enabled` を設定するとデフォルトのHTMLエラーメッセージが有効になり、`--error.template` を使用するとユーザーはエラーレンダリング用に任意のカスタムHTMLテンプレートファイルを設定できます。テンプレートには `{{.ErrCode}}` と `{{.ErrMessage}}` の2つの変数があります。例えば、このテンプレート `oh my! {{.ErrCode}} - {{.ErrMessage}}` は `oh my! 502 - Bad Gateway` とレンダリングされます。
## スロットリング
reproxy は、システム全体のアクティビティおよびユーザーごとに、システムレベルの最大req/秒の値を定義できます。0の値(デフォルト)は無制限として扱われます。
ユーザーアクティビティは、一致したルートと一致しなかったルートの両方に対して制限されます。一致しなかったルートはすべて「単一の宛先グループ」と見なされ、共通のリミッター(`rate*3`)を取得します。つまり、`--throttle.user=10` で10(req/秒)が定義されている場合、エンドユーザーは静的アセットまたは一致しなかったルートに対して最大30リクエスト/秒を実行できます。一致したルートの場合、このリミッターは宛先(ルート)ごとに維持されます。つまり、s1.example.com/api にプロキシされたリクエストは10r/sを許可し、s2.example.com にプロキシされたリクエストはさらに10r/sを許可します。
### ルートごとのタイムアウトとスロットル
個別のルートは、プロバイダー固有の `timeout` および `throttle` フィールドを介して、グローバルな `--timeout.write` および `--throttle.user` の設定を上書きできます。これは、アップロードやレポート生成など、グローバルな書き込みタイムアウトよりも高い期限が必要な長時間実行エンドポイントや、他のすべてのグローバルな上限を引き上げることなく、機密ルート(例:ログイン)のレート制限を厳しくする場合に便利です。
優先順位は「ゼロはグローバルを継承、正の値は上書き」です。`timeout: 0`(または `timeout` フィールドなし)のルートはグローバルな `--timeout.write` を維持します。`timeout: 5m` のルートは、一致したリクエストに対してのみそれを上書きします。同じルールが `throttle` にも適用されます。
ルートごとのタイムアウトは、一致したリクエストの接続の読み取りおよび書き込み期限を上書きするため、グローバルな `--timeout.write`(デフォルト30秒)を超えて延長できます。ルートごとのタイムアウトがないルートは、引き続きグローバル設定を尊重します。
**制限事項 — トランスポートレベルの応答ヘッダータイムアウト:** ルートごとの `timeout` は `--timeout.resp-header`(デフォルト5秒)を上書きしません。そのタイムアウトは共有の `http.Transport` に設定され、アップストリームが応答ヘッダーの送信を開始する前に適用されます。アップストリームが応答を開始するまでに `--timeout.resp-header` よりも時間がかかる場合(例:遅いレポートエンドポイント)、ルートごとの `timeout` に関係なく、その境界でリクエストは失敗します。そのようなルートをサポートするには、`--timeout.resp-header` を、低速応答ルートに必要な最大値にグローバルに引き上げてください。トランスポートレベルのタイムアウトのルートごとの上書きは、意図的にスコープ外です。
プロバイダー構文:
- **ファイルプロバイダー**(YAML): `timeout: 5m`、`throttle: 2`
- **静的プロバイダー**(CSV): 6番目と7番目の位置フィールド。例: `*,^/upload/(.*),http://up:8080/$1,,,5m,2`
- **Dockerプロバイダー**: `reproxy.timeout=5m`、`reproxy.throttle=2`(マルチルートコンテナの場合は `reproxy.<n>.timeout` / `reproxy.<n>.throttle`)
- **Consul Catalogプロバイダー**: `reproxy.timeout=5m`、`reproxy.throttle=2`
## アップストリーム接続制限
reproxy は、バックエンドサーバーに維持される接続数を制御するためのアップストリーム接続プール設定を構成できます:
- `--upstream.max-idle-conns` - すべてのアップストリームホストにわたるアイドル接続の最大数。デフォルト: 100。
- `--upstream.max-conns` - アップストリームホストあたりの最大接続数(0 = 無制限)。デフォルト: 0。
`--upstream.max-conns` を設定すると、各バックエンドへの同時接続数が制限されます。これは、アップストリームサーバーの容量が限られている場合や、接続の枯渇を防ぐのに役立ちます。
## Basic認証
reproxy は、2つのモードでBasic認証をサポートしています: グローバル(すべてのルート)とルートごと。
### グローバルBasic認証
グローバルBasic認証はすべてのルートを保護します。これは、開発中やテスト中にエンドポイントを保護するのに便利です。有効にするには、htpasswdファイルを `--basic-htpasswd=<ファイルの場所>` または環境変数 `BASIC_HTPASSWD=<ファイルの場所>` で設定します。
reproxy は、htpasswdファイルが以下の形式であることを期待します:```
username1:bcrypt(password1)
username2:bcrypt(password2)
...
これは htpasswd -nbB コマンドで生成できます。例: htpasswd -nbB test passwd
ルートごとの認証では、ルートごとに異なる認証情報を設定できます。ルートにルートごとの認証が設定されている場合、そのルートではグローバル認証はバイパスされます。ルートごとの認証はプロバイダ固有の設定で構成します:
auth フィールド。例: auth: "user1:$2y$..., user2:$2y$..."reproxy.auth ラベルreproxy.auth タグ形式は user:bcrypt_hash のペアをカンマで区切ったリストです (htpasswd と同じ形式)。同じルートに複数のユーザーを指定できます。
docker-compose の例:```yaml services: admin-api: labels: - "reproxy.route=^/admin/(.*)" - "reproxy.dest=/$1" - "reproxy.auth=admin:$$2y$$05$$hashedpassword"
注:docker-composeでは、`$` は `$$` のようにエスケープする必要があります。
## IPベースのアクセス制御
Reproxyは、カンマ区切りのサブネットまたはIPアドレスのリストを使用してルートへのアクセスを制限できます。これは、無制限のアクセスを許可する前の開発およびテストに役立ちます。また、内部サービスへのアクセスを制限するためにも使用できます。デフォルトでは、すべてのルートはすべてのクライアントに対して開かれています。
ルートへのアクセスを制限するには、ユーザーはルートに適切なキーを設定する必要があります。つまり、dockerとconsulの場合は `reproxy.remote`、ファイルプロバイダーの場合は `remote` です。値は、カンマ区切りのサブネットまたはIPアドレス、またはサブネットのリストである必要があります。例: `127.0.0.1, 192.168.1.0/24`。詳細については、[dockerプロバイダー](#docker-provider)セクションおよび[consulカタログプロバイダー](#consul-catalog-provider)セクションを参照してください。
デフォルトでは、reproxyはクライアントのリクエストからリモートアドレスをチェックします。ただし、背後に別のプロキシがある場合やdockerブリッジネットワークを使用している場合など、期待通りに動作しないことがあります。これは `--remote-lookup-headers` パラメーターで変更でき、ヘッダー `X-Real-IP` または `X-Forwarded-For`(この順序で)の値をチェックし、チェックに使用できるようにします。ヘッダーが設定されていない場合、チェックはクライアントのリモートアドレスに対して実行されます。これらのヘッダーはクライアントによって提供され、簡単に偽装できるため、このパラメーターは、reproxyがこれらのヘッダーを常に設定して上書きする信頼されたフロントエンドプロキシの背後で実行されている場合にのみ有効にする必要があります。
ヘッダーのチェックは偽装が可能なため、注意して使用する必要があります。`--remote-lookup-headers` が有効な場合、IP許可リストはこの信頼の前提に完全に依存します。許可されたアドレスを含む `X-Real-IP` または `X-Forwarded-For` を送信するクライアントは、制限を回避できる可能性があります。このオプションは、reproxyがこれらのヘッダーを制御する信頼されたプロキシの背後にあり、偽装されていないことが保証できる場合にのみ有効にしてください。
## プラグインサポート
reproxyのコア機能は、外部プラグインによって拡張できます。各プラグインは、[rpcサーバー](https://golang.org/pkg/net/rpc/)を実装した独立したプロセス/コンテナです。プラグインはreproxy conductorに登録され、ミドルウェアのチェーンに追加されます。各プラグインは、元のURL、ヘッダー、および一致するすべてのルート情報を含むリクエストを受け取り、ヘッダーとステータスコードで応答します。400以上のステータスコードはエラー応答として扱われ、プロキシエラーですぐにフローを終了します。プラグインが設定できるヘッダーには2つのタイプがあります。
- `HeadersIn` - 受信ヘッダー。これらはプロキシ先のURLに送信されます。
- `HeadersOut` - 送信ヘッダー。クライアントに返送されます。
デフォルトでは、プラグインによって設定されたヘッダーは元のヘッダーと混合されます。プラグインがすべてのヘッダーを制御する必要がある場合(たとえば、一部のヘッダーを削除する場合)、プラグインは `OverrideHeaders*` フィールドを設定して、コアのreproxyプロセスに混合ではなくすべてのヘッダーを上書きする必要があることを示すことができます。
- `OverrideHeadersIn` - プラグインがすべての受信ヘッダーを担当することを示します。
- `OverrideHeadersOut` - プラグインがすべての送信ヘッダーを担当することを示します。
開発プロセスを簡素化するために、すべてのビルディングブロックが提供されています。これには、登録、リスニング、ディスパッチ呼び出しを処理する `lib.Plugin` と、入力と出力を定義する `lib.Request` および `lib.Response` が含まれます。プラグインの作成者は、`func(req lib.Request, res *lib.HandlerResponse) (err error)` シグネチャを満たす具体的なハンドラーを実装する必要があります。各プラグインは、このような複数のハンドラーを含むことができます。
_詳細については、[examples/plugin](https://github.com/umputun/reproxy/tree/master/examples/plugin) を参照してください_
## コンテナのセキュリティ
デフォルトでは、reproxyコンテナは初期設定を簡素化し、Dockerソケットにアクセスするためにrootユーザーで実行されます。これは、Dockerプロバイダーが実行中のコンテナを検出できるようにするために必要です。ただし、そのような検出が不要な場合やDockerプロバイダーを使用していない場合は、権限の低いユーザーに変更することをお勧めします。これはdocker-composeレベルおよびdockerレベルで `user` オプションを使用して行うことができます。詳細については、以下のセクションを参照してください。
Docker内ルーティングを使用している場合でも、Dockerプロバイダーを無効にし、静的プロバイダーまたはファイルプロバイダーでルールを設定することが意味をなす場合があります。Compose内で実行されているすべてのコンテナは同じネットワークを共有し、ローカルDNSを介してアクセス可能です。ユーザーはDocker検出を避けるために次のようなルールを持つことができます: `- STATIC_RULES=*,/api/email/(.*),http://email-sender:8080/$$1`。このルールは、同じCompose内で定義された `email-sender` コンテナを想定しています。注意: 宛先サービスが別のComposeファイルで定義されている場合でも、Dockerネットワークを使用することで同じ結果を得ることができます。これにより、reproxyの設定を実際のサービスから分離したままにできます。
reproxyコンテナ内には、空の(scratch)イメージの上に構築されているため、reproxyバイナリ以外は何も含まれていません。
### 非rootユーザーでの実行
UID `1001`(グループ `1001` および `999` に所属)のユーザーがコンテナ内に事前に作成されており、非rootユーザーとしてreproxyを実行するために使用できます。```yaml
services:
reproxy:
user: 1001
image: umputun/reproxy:latest
# <...>
# see examples/ssl/docker-compose.yml for the full file example
Dockerプロバイダーを使用する場合は、このユーザーがホストシステム上のDockerソケットにアクセスするための権限を持っていることを確認する必要があります。これらの権限の設定方法は、ホストシステムの構成によって異なります。Dockerソケットの権限設定の詳細については、Dockerデーモンソケットの保護に関するDockerドキュメントを参照してください。
各オプションは、コマンドラインまたは環境変数のキー:値ペアの2つの形式で指定できます。一部のコマンドラインオプションには、-l localhost:8080のような短い形式があり、すべてに--listen=localhost:8080のような長い形式があります。各オプションの環境変数キー(名前)は、接尾辞としてリストされています(例:[$LISTEN])。
すべてのサイズオプションは単位接尾辞をサポートしています。例えば、キロバイトには10K(または10k)、メガバイトには16M(または16m)、ギガバイトには10G(または10g)です。接尾辞がない場合(1024など)はバイトを意味します。
一部のオプションは繰り返し指定可能で、その場合ユーザーはコマンドラインで複数回渡すか、環境変数ではカンマ区切りで渡すことができます。例えば--ssl.fqdnはそのようなオプションで、--ssl.fqdn=a1.example.com --ssl.fqdn=a2.example.comのように渡すか、環境変数としてSSL_ACME_FQDN=a1.example.com,a2.example.comのように渡すことができます。
複数の要素をサポートするすべてのオプションのリストは次のとおりです。
ssl.fqdn (SSL_ACME_FQDN)assets.cache (ASSETS_CACHE)docker.exclude (DOCKER_EXCLUDE)static.rule ($STATIC_RULES)header ($HEADER)drop-header ($DROP_HEADERS)-l, --listen= listen on host:port (default: 0.0.0.0:8080/8443 under docker, 127.0.0.1:80/443 without) [$LISTEN]
-m, --max= max request size (default: 64K) [$MAX_SIZE]
-g, --gzip enable gz compression [$GZIP]
-x, --header= outgoing proxy headers to add [$HEADER]
--drop-header= incoming headers to drop [$DROP_HEADERS]
--basic-htpasswd= htpasswd file for basic auth [$BASIC_HTPASSWD]
--lb-type=[random|failover|roundrobin] load balancer type (default: random) [$LB_TYPE]
--signature enable reproxy signature headers [$SIGNATURE]
--remote-lookup-headers enable remote lookup headers, trust only behind a trusted proxy [$REMOTE_LOOKUP_HEADERS]
--keep-host keep original Host header as default when proxying [$KEEP_HOST]
--insecure skip SSL verification on destination host [$INSECURE]
--dbg debug mode [$DEBUG]
ssl: --ssl.type=[none|static|auto] ssl (auto) support (default: none) [$SSL_TYPE] --ssl.cert= path to cert.pem file [$SSL_CERT] --ssl.key= path to key.pem file [$SSL_KEY] --ssl.acme-location= dir where certificates will be stored by autocert manager (default: ./var/acme) [$SSL_ACME_LOCATION] --ssl.acme-email= admin email for certificate notifications [$SSL_ACME_EMAIL] --ssl.http-port= http port for redirect to https and acme challenge test (default: 8080 under docker, 80 without) [$SSL_HTTP_PORT] --ssl.fqdn= FQDN(s) for ACME certificates [$SSL_ACME_FQDN]
assets: -a, --assets.location= assets location [$ASSETS_LOCATION] --assets.root= assets web root (default: /) [$ASSETS_ROOT] --assets.spa spa treatment for assets [$ASSETS_SPA] --assets.cache= cache duration for assets [$ASSETS_CACHE] --assets.not-found= path to file to serve on 404, relative to location [$ASSETS_NOT_FOUND]
logger: --logger.stdout enable stdout logging [$LOGGER_STDOUT] --logger.enabled enable access and error rotated logs [$LOGGER_ENABLED] --logger.file= location of access log (default: access.log) [$LOGGER_FILE] --logger.max-size= maximum size before it gets rotated (default: 100M) [$LOGGER_MAX_SIZE] --logger.max-backups= maximum number of old log files to retain (default: 10) [$LOGGER_MAX_BACKUPS]
docker: --docker.enabled enable docker provider [$DOCKER_ENABLED] --docker.host= docker host (default: unix:///var/run/docker.sock) [$DOCKER_HOST] --docker.network= docker network [$DOCKER_NETWORK] --docker.exclude= excluded containers [$DOCKER_EXCLUDE] --docker.auto enable automatic routing (without labels) [$DOCKER_AUTO] --docker.prefix= prefix for docker source routes [$DOCKER_PREFIX] --docker.api-version= docker API version (default: 1.24) [$DOCKER_API_VERSION]
consul-catalog: --consul-catalog.enabled enable consul catalog provider [$CONSUL_CATALOG_ENABLED] --consul-catalog.address= consul address (default: http://127.0.0.1:8500) [$CONSUL_CATALOG_ADDRESS] --consul-catalog.interval= consul catalog check interval (default: 1s) [$CONSUL_CATALOG_INTERVAL]
file: --file.enabled enable file provider [$FILE_ENABLED] --file.name= file name (default: reproxy.yml) [$FILE_NAME] --file.interval= file check interval (default: 3s) [$FILE_INTERVAL] --file.delay= reload only after the file has been unchanged for this long (default: 500ms) [$FILE_DELAY]
static: --static.enabled enable static provider [$STATIC_ENABLED] --static.rule= routing rules [$STATIC_RULES]
timeout: --timeout.read-header= read header server timeout (default: 5s) [$TIMEOUT_READ_HEADER] --timeout.write= write server timeout (default: 30s) [$TIMEOUT_WRITE] --timeout.idle= idle server timeout (default: 30s) [$TIMEOUT_IDLE] --timeout.dial= dial transport timeout (default: 30s) [$TIMEOUT_DIAL] --timeout.keep-alive= keep-alive transport timeout (default: 30s) [$TIMEOUT_KEEP_ALIVE] --timeout.resp-header= response header transport timeout (default: 5s) [$TIMEOUT_RESP_HEADER] --timeout.idle-conn= idle connection transport timeout (default: 90s) [$TIMEOUT_IDLE_CONN] --timeout.tls= TLS hanshake transport timeout (default: 10s) [$TIMEOUT_TLS] --timeout.continue= expect continue transport timeout (default: 1s) [$TIMEOUT_CONTINUE]
mgmt: --mgmt.enabled enable management API [$MGMT_ENABLED] --mgmt.listen= listen on host:port (default: 0.0.0.0:8081) [$MGMT_LISTEN] --mgmt.low-cardinality use route patterns instead of raw paths for metrics labels [$MGMT_LOW_CARDINALITY]
error: --error.enabled enable html errors reporting [$ERROR_ENABLED] --error.template= error message template file [$ERROR_TEMPLATE]
health-check: --health-check.enabled enable automatic health-check [$HEALTH_CHECK_ENABLED] --health-check.interval= automatic health-check interval (default: 300s) [$HEALTH_CHECK_INTERVAL]
throttle: --throttle.system= throttle overall activity' (default: 0) [$THROTTLE_SYSTEM] --throttle.user= limit req/sec per user and per proxy destination (default: 0) [$THROTTLE_USER]
upstream: --upstream.max-idle-conns= max idle connections total (default: 100) [$UPSTREAM_MAX_IDLE_CONNS] --upstream.max-conns= max connections per upstream host (0=unlimited) (default: 0) [$UPSTREAM_MAX_CONNS]
plugin: --plugin.enabled enable plugin support [$PLUGIN_ENABLED] --plugin.listen= registration listen on host:port (default: 127.0.0.1:8081) [$PLUGIN_LISTEN]
Help Options: -h, --help Show this help message
## ステータス
このプロジェクトは活発に開発中であり、`v1`がリリースされるまでは破壊的な変更が発生する可能性があります。ただし、正当な理由がない限り、変更を加えないよう最善を尽くしています。バージョン0.4.x時点で、reproxyは実際の使用に十分な品質と判断されており、多くの環境で本番運用されています。
example.com,^/login,https://api.example.com/login,,,,2 – ルートごとのユーザーあたりのスロットルを2 req/secに設定します(前の位置フィールドは空欄)。yestrue1nofalse0reproxy.forward-health-checks - /ping と /health リクエストをreproxy自身で処理せずにバックエンドに転送(yes、true、1)。バックエンドにアプリケーション固有の応答を持つ独自のヘルスチェックエンドポイントがある場合に便利。reproxy.timeout - ルートごとのリクエストタイムアウト(Goの時間形式、例: 5m、30s)。0 または未設定の場合はグローバルの --timeout.write を継承。無効な値は警告とともに無視される。reproxy.throttle - ルートごとのユーザーあたりのreq/sec制限。0 または未設定の場合は --throttle.user を継承。無効または負の値は警告とともに無視される。reproxy.enabled - コンテナをreproxyの宛先として有効(yes、true、1)または無効(no、false、0)にする。true