
경량 에지 HTTP(S) 서버 및 리버스 프록시로, 자동 SSL, Docker/Consul 디스커버리, 경로별 인증, 속도 제한, 상태 확인 기반 장애 조치를 제공합니다.
<div align="center">
<img class="logo" src="https://raw.githubusercontent.com/umputun/reproxy/master/site/logo-bg.svg" width="355px" height="142px" alt="Reproxy | Simple Reverse Proxy"/>
</div>
Reproxy는 다양한 프로바이더(docker, static, file, consul catalog)를 지원하는 간단한 엣지 HTTP(s) 서버 / 리버스 프록시입니다. 하나 이상의 프로바이더가 요청된 서버, 요청된 URL, 대상 URL, 헬스 체크 URL에 대한 정보를 제공합니다. 단일 바이너리 또는 docker 컨테이너로 배포됩니다.
- <a href="https://letsencrypt.org/" rel="nofollow noopener noreferrer" target="_blank">Let's Encrypt</a>를 이용한 자동 SSL 종료
- 사용자 제공 SSL 인증서 지원
- 간단하지만 유연한 프록시 규칙
- 정적, 명령줄 프록시 규칙 프로바이더
- 동적, 파일 기반 프록시 규칙 프로바이더
- 자동 검색 기능을 갖춘 Docker 프로바이더
- 서비스 태그로 검색하는 Consul Catalog 프로바이더
- 다중 (가상) 호스트 지원
- 선택적 트래픽 압축
- 선택적 IP 기반 접근 제어
- 라우트별 기본 인증
- 사용자 정의 크기 제한 및 타임아웃
- 단일 바이너리 배포
- Docker 컨테이너 배포
- 선택적 "SPA 친화적" 모드를 갖춘 내장 정적 자산 서버
- 리다이렉트 규칙 지원
- 전체 활동 및 사용자 활동에 대한 선택적 제한기
- 실시간 헬스 체크 및 장애 조치/로드 밸런싱
- 라우트 정보와 prometheus 메트릭을 제공하는 관리 서버
- RPC를 통한 플러그인 지원으로 사용자 정의 기능 구현
- Apache Log Format과 간소화된 stdout 리포트를 모두 지원하는 선택적 로깅
---
<div align="center">
[](https://github.com/umputun/reproxy/actions/workflows/ci.yml) [](https://coveralls.io/github/umputun/reproxy?branch=master) [](https://goreportcard.com/report/github.com/umputun/reproxy) [](https://hub.docker.com/r/umputun/reproxy)
</div>
서버(호스트)는 FQDN, 즉 `s.example.com`, `*`(모두 포괄) 또는 정규식으로 설정할 수 있습니다. 정확한 일치가 우선하므로, 서버가 `example.com`과 `example\.(com|org)`인 두 규칙이 있는 경우 `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를 시작하려면 최소 하나의 프로바이더가 정의되어야 합니다. 나머지 매개변수는 엄격히 선택 사항이며 합리적인 기본값을 가집니다.
예시:
- 정적 프로바이더 사용: `reproxy --static.enabled --static.rule="*,example.com/api/(.*),https://api.example.com/$1"`
- 자동 docker 검색 사용: `reproxy --docker.enabled --docker.auto`
- docker 컨테이너로 실행: `docker up -p 80:8080 umputun/reproxy --docker.enabled --docker.auto`
- 자동 SSL 사용: `docker up -p 80:8080 -p 443:8443 umputun/reproxy --docker.enabled --docker.auto --ssl.type=auto --ssl.fqdn=example.com`
## 설치
Reproxy는 작은 자체 포함 바이너리와 도커 이미지로 배포됩니다. 바이너리와 이미지 모두 여러 아키텍처와 여러 운영 체제를 지원하며, linux_x86_64, linux_arm64, linux_arm, macos_x86_64, macos_arm64, windows_x86_64, windows_arm을 포함합니다. 또한 arm64와 x86용 deb 및 rpm 패키지도 제공합니다.
- 바이너리 배포판의 경우 [릴리스 섹션](https://github.com/umputun/reproxy/releases)에서 적절한 파일을 다운로드하세요
- Homebrew 사용자의 경우: `brew install umputun/apps/reproxy`
- 도커 컨테이너는 [Docker Hub](https://hub.docker.com/r/umputun/reproxy)와 [Github Container Registry](https://github.com/users/umputun/packages/container/reproxy/versions)에서 사용할 수 있습니다. 예: `docker pull umputun/reproxy` 또는 `docker pull ghcr.io/umputun/reproxy`.
최신 안정 버전은 `:vX.Y.Z` 도커 태그(`:latest` 별칭 포함)를 가지며, 현재 master는 `:master` 태그를 가집니다.
## 프로바이더
다양한 프로바이더가 프록시 규칙을 제공합니다. 현재 포함된 것 - `file`, `docker`, `static`, `consul-catalog`. 각 프로바이더는 프록시 요청과 정적(에셋) 모두에 대해 여러 라우팅 규칙을 정의할 수 있습니다. 사용자는 동시에 여러 프로바이더를 설정할 수 있습니다.
_다양한 프로바이더의 예시는 [examples](https://github.com/umputun/reproxy/tree/master/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를 건너뜀).
- `example.com,^/login,https://api.example.com/login,,,,2` - 사용자당 라우트별 스로틀 2 req/sec(앞의 위치 필드는 비워둠).
4번째 요소는 헬스 보고에 사용되는 선택적 ping url을 정의합니다. 5번째 요소는 선택적으로 헬스 체크 요청을 백엔드로 전달하는 것을 활성화합니다(`true`, `yes`, `1`). 자세한 내용은 [헬스 체크](#ping-and-health-checks) 섹션을 참조하세요. 6번째 요소는 선택적 라우트별 요청 타임아웃(Go duration, 예: `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
- { route: "^/api/svc1/(.*)", dest: "http://127.0.0.1:8080/blah1/$1" }
- {
route: "/api/svc3/xyz",
dest: "http://127.0.0.3:8080/blah3/xyz",
ping: "http://127.0.0.3:8080/ping",
remote: "192.168.1.0/24, 127.0.0.1", # optional, restrict access to the route
forward-health-checks: true # optional, forward /ping and /health to backend
}
- {
route: "^/admin/(.*)",
dest: "http://127.0.0.4:8080/$1",
auth: "admin:$2y$05$..." # optional, per-route basic auth (htpasswd bcrypt format)
}
- {
route: "^/upload/(.*)",
dest: "http://127.0.0.5:8080/$1",
timeout: 5m # optional, per-route request timeout (Go duration). 0 or omitted inherits --timeout.write
}
- {
route: "^/login",
dest: "http://127.0.0.6:8080/login",
throttle: 2 # optional, per-route req/sec per user. 0 or omitted inherits --throttle.user
}
srv.example.com:
- { route: "^/api/svc2/(.*)", dest: "http://127.0.0.2:8080/blah2/$1/abc" }
- { route: "/web/", dest: "/var/www", "assets": true }
"*.files.example.com":
- { route: "^/files/(.*)", dest: "http://123.123.200.200:8080/$host/$1" }
```
동적 프로바이더이므로 파일 변경 사항이 자동으로 적용됩니다.
**서로 다른 도메인의 여러 정적 사이트**는 서버 이름을 키로 사용하고 `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 provider
Docker provider는 추가 구성 없이 완전 자동 검색(`--docker.auto` 사용)을 지원합니다. 기본적으로 `http://<url>/<container name>/(.*)`와 같은 모든 요청을 해당 컨테이너의 내부 IP와 노출된 포트로 리다이렉트합니다. 활성(실행 중) 컨테이너만 감지됩니다.
이 기본값은 레이블로 변경할 수 있습니다:
- `reproxy.server` - 매칭할 서버(호스트명). 쉼표로 구분된 서버 목록도 가능합니다.
- `reproxy.route` - 소스 라우트 (위치)
- `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` - 호스트 헤더를 그대로 유지(`yes`, `true`, `1`)하거나 대상 호스트로 교체(`no`, `false`, `0`)
- `reproxy.forward-health-checks` - reproxy가 처리하는 대신 `/ping` 및 `/health` 요청을 백엔드로 전달(`yes`, `true`, `1`). 백엔드에 애플리케이션별 응답을 가진 자체 헬스 체크 엔드포인트가 있을 때 유용합니다.
- `reproxy.timeout` - Go duration 형식의 라우트별 요청 타임아웃(예: `5m`, `30s`). `0`이거나 설정하지 않으면 전역 `--timeout.write`를 상속합니다. 잘못된 값은 경고와 함께 무시됩니다.
- `reproxy.throttle` - 사용자당 라우트별 초당 요청 제한. `0`이거나 설정하지 않으면 `--throttle.user`를 상속합니다. 잘못된 값이나 음수 값은 경고와 함께 무시됩니다.
- `reproxy.enabled` - 컨테이너를 reproxy 대상에서 활성화(`yes`, `true`, `1`) 또는 비활성화(`no`, `false`, `0`)
참고: `--docker.auto` 없이는 대상 컨테이너가 잠재적 대상으로 간주되려면 최소 하나의 `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`가 정의되지 않은 경우 기본 라우트는 `^/<container_name>/(.*)`입니다. 모든 프록시 소스가 동일한 접두사 패턴을 가져야 하는 경우, 예를 들어 `/api/(.*)`라면 사용자는 모든 컨테이너 기반 라우트에 대해 공통 접두사(이 경우 `/api`)를 정의할 수 있습니다. 이는 `--docker.prefix` 파라미터로 수행할 수 있습니다.
Docker provider는 또한 동일한 컨테이너에서 여러 개의 서로 다른 라우트를 매칭하기 위해 여러 세트의 `reproxy.N.something` 레이블을 정의할 수 있습니다. 이는 일부 경우 단일 컨테이너가 여러 엔드포인트를 노출할 수 있기 때문에 유용합니다. 예를 들어 공용 API와 일부 관리자 API가 있습니다. 위의 모든 레이블은 "N-index"와 함께 사용할 수 있습니다. 즉, `reproxy.1.server`, `reproxy.1.port` 등입니다. N은 0에서 9 범위여야 합니다.
이것은 동적 provider이며 컨테이너 상태의 모든 변경이 자동으로 적용됩니다.
### Consul Catalog provider
사용법: `reproxy --consul-catalog.enabled`
Consul Catalog provider는 `reproxy.` 접두사가 있는 태그를 가진 서비스를 얻기 위해 주기적으로(기본적으로 매초) Consul API를 호출합니다. 사용자는 `--consul-catalog.interval` 명령줄 플래그로 체크 간격을 재정의할 수 있으며, `--consul-catalog.address` 명령줄 옵션으로 consul 주소도 재정의할 수 있습니다. 기본 주소는 `http://127.0.0.1:8500`입니다.
예를 들어:
```
reproxy --consul-catalog.enabled --consul-catalog.address=http://192.168.1.100:8500 --consul-catalog.interval=10s
```
기본적으로 provider는 모든 서비스에 대해 값을 설정합니다:
- enabled `false`
- server `*`
- route `^/(.*)`
- dest `http://<SERVICE_ADDRESS_FROM_CONSUL>/$1`
- ping `http://<SERVICE_ADDRESS_FROM_CONSUL>/ping`
이 기본값은 태그로 변경할 수 있습니다:
- `reproxy.server` - 일치시킬 서버(호스트명). 쉼표로 구분된 서버 목록일 수도 있습니다.
- `reproxy.route` - 소스 라우트 (location)
- `reproxy.dest` - 대상 경로. 참고: 전체 URL이 아니라 서비스의 ip:port에 추가될 경로일 뿐입니다
- `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 duration 형식의 라우트별 요청 타임아웃 (예: `5m`, `30s`). `0`이거나 설정하지 않으면 전역 `--timeout.write`를 상속합니다. 잘못된 값은 경고와 함께 무시됩니다.
- `reproxy.throttle` - 사용자당 라우트별 초당 요청 제한. `0`이거나 설정하지 않으면 `--throttle.user`를 상속합니다. 잘못된 값이나 음수 값은 경고와 함께 무시됩니다.
- `reproxy.enabled` - reproxy 대상에서 서비스를 활성화(`yes`, `true`, `1`) 또는 비활성화(`다른 모든 값`).
### 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)과 포트 번호를 알 수 있게 해줍니다.
검색 provider(docker, file, consul)와 함께 ACME를 사용하는 경우, 새로 검색된 서버에 대한 SSL 인증서가 reproxy를 재시작할 필요 없이 자동으로 획득됩니다.
### ACME 챌린지
Reproxy는 SSL 인증서 검증을 위해 두 가지 유형의 ACME 챌린지를 지원합니다:
1. **HTTP-01 챌린지** (기본값): 특정 HTTP URL에서 토큰을 제공하여 도메인 소유권을 검증합니다. 포트 80이 공개적으로 접근 가능해야 합니다.
2. **DNS-01 챌린지**: DNS TXT 레코드를 생성하여 도메인 소유권을 검증합니다. 이 방법은:
- 포트 80에 접근할 수 있어야 하지 않습니다
- 와일드카드 인증서와 함께 작동합니다
- 지원되는 DNS provider 구성이 필요합니다
#### 챌린지 선택
Reproxy는 구성에 따라 사용할 챌린지 방법을 자동으로 결정합니다:
- **HTTP-01** (기본값): DNS provider가 구성되지 않은 경우 사용됩니다
- **DNS-01**: DNS provider가 구성된 경우 사용됩니다
챌린지 유형을 명시적으로 선택할 필요는 없습니다. DNS-01 챌린지를 사용하려면 DNS provider를 구성하기만 하면 됩니다.
DNS 전파 확인은 기본적으로 2분 후에 타임아웃됩니다. 챌린지 레코드를 느리게 게시하는 영역의 경우 `--ssl.dns.propagation-timeout=5m`으로 이 시간을 늘리세요. `--ssl.dns.ttl` 옵션은 레코드 TTL을 제어하며 전파 타임아웃을 변경하지 않습니다.
#### 현재 지원되는 DNS Provider
Reproxy는 현재 다음 DNS provider에 대한 지원을 포함합니다:
- **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`
DNS 공급자로 Cloudflare를 사용하는 예시:
```
export CLOUDFLARE_API_TOKEN=your_api_token
reproxy --ssl.type=auto [email protected] --ssl.fqdn=example.com
```
DNS-01 챌린지는 특히 다음과 같은 경우에 유용합니다:
- 서버가 포트 80을 공개적으로 노출하지 않은 경우
- 와일드카드 인증서(예: *.example.com)가 필요한 경우
- 제한적인 방화벽 뒤에 있는 경우
## 헤더
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`으로 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 서버
사용자는 정적 파일을 제공하기 위해 assets 서버를 켤 수 있습니다(기본값은 꺼짐). `--assets.location`이 설정되어 있는 한, `assets.root` 아래의 모든 프록시되지 않은 요청을 정적 파일에 대한 요청으로 처리합니다. assets 서버는 프록시 제공자 없이도 사용할 수 있으며, 이 모드에서 reproxy는 정적 콘텐츠를 위한 단순 웹 서버 역할을 합니다. assets 서버는 또한 `--assets.spa`를 사용하는 "spa 모드"를 지원하며, 이 모드에서는 찾을 수 없는 모든 요청이 `index.html`로 전달됩니다.
일반적인 assets 서버 외에도 여러 개의 사용자 정의 assets 서버가 지원됩니다. 각 제공자는 이러한 정적 규칙을 정의하는 방식이 다르며, 일부 제공자는 이를 전혀 지원하지 않을 수 있습니다. 예를 들어, 여러 asset 서버는 static(명령줄 제공자), file 제공자, 그리고 docker 제공자에서도 유용하지만, consul catalog 제공자에서는 거의 의미가 없습니다.
1. static 제공자 - 소스 요소에 `assets:` 또는 `spa:` 접두사가 붙으면 파일 서버로 처리됩니다. 예를 들어 `*,assets:/web,/var/www,`는 `/web/*` 요청을 `/var/www` 디렉터리 위의 파일 서버로 제공합니다.
2. file 제공자 - 선택적 필드 `assets: true` 또는 `spa: true`를 설정합니다. 참고: `route` 필드는 정규식 패턴이 아닌 경로 접두사(예: `/`, `/web/`)여야 합니다.
3. docker 제공자 - `reproxy.assets=web-root:location`, 즉 `reproxy.assets=/web:/var/www`입니다. spa 모드로 전환하려면 `reproxy.spa`를 `yes` 또는 `true`로 설정합니다.
### 캐싱
Assets 서버는 `--assets.cache=<duration>` 매개변수로 캐싱 제어를 지원합니다. `0s` 기간(기본값)은 캐싱 제어를 끕니다. 기간은 선택적 소수와 단위 접미사가 붙은 일련의 십진수로, 예를 들어 "300ms", "1.5h" 또는 "2h45m"과 같습니다. 유효한 시간 단위는 "ns", "us"(또는 "µs"), "ms", "s", "m", "h" 및 "d"입니다.
캐시 기간을 설정하는 방법에는 두 가지가 있습니다:
1. 모든 정적 자산에 대한 단일 값. 이는 `--assets.cache=48h`처럼 간단합니다.
2. 서로 다른 mime 유형에 대한 사용자 정의 기간. 이는 기본값과 mime:duration 쌍의 두 부분을 포함해야 합니다. 명령줄에서는 여러 개의 `--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>` 매개변수로 설정할 수 있습니다. 경로는 assets 루트에 상대적이어야 합니다.
## reproxy를 기본 이미지로 사용하기
순수하게 정적 콘텐츠를 제공하는 것은 인기 있는 사용 사례 중 하나입니다. 일반적으로 이는 UI만 제공하는 별도의 프론트엔드 컨테이너에 사용됩니다. assets 서버를 사용하면 이러한 컨테이너를 거의 간단하게 만들 수 있습니다. 다음은 [reproxy.io](http://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"]
```
필요한 것은 정적 자산을 어딘가의 위치로 복사하고 이 위치를 reproxy 엔트리포인트에 `"--assets.location`으로 전달하는 것뿐입니다.
## 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(또는 deflate) 압축을 활성화합니다. 결정은 최종 헤더를 기준으로 응답마다 이루어집니다:
- `--gzip-exclude`와 일치하는 미디어 타입은 그대로 전송됩니다. 값은 정확한 타입(`image/png`) 또는 접두사(`audio/*`)의 쉼표로 구분된 목록입니다. 기본값은 오디오, 비디오, 압축 이미지(jpeg, png, gif, webp, avif), woff 폰트 및 일반적인 아카이브를 건너뜁니다. 사용자 지정 목록은 기본값을 대체하며, 빈 값(`--gzip-exclude=`)은 제외를 끕니다.
- 부분 응답(`206`, 또는 `Content-Range`가 있는 모든 응답)은 절대 압축되지 않으므로 `Range` 요청이 계속 작동합니다.
- reproxy는 이미 `Content-Encoding`을 가진 응답을 재압축하지 않습니다. 클라이언트의 `Accept-Encoding`은 업스트림으로 전달되므로, 자체적으로 압축하는 업스트림은 자신의 응답에 대해 결정하며, 제외 목록은 reproxy가 수행하는 압축에만 적용됩니다.
- 압축된 응답은 `Accept-Ranges`와 원래의 `Content-Length`를 제거하며, 강력한 `ETag`는 원본과 바이트가 다르기 때문에 약한 `ETag`(`W/"..."`)가 됩니다.
- `--max=N` 요청의 최대 크기를 설정할 수 있습니다(기본값 64k). `0`으로 설정하면 크기 검사가 비활성화됩니다.
- `--timeout.*` 서버와 프록시 전송 모두에 대한 다양한 타임아웃입니다. [모든 애플리케이션 옵션](#all-application-options)의 `timeout` 섹션을 참조하세요. 0 또는 음수 값은 타임아웃이 없음을 의미합니다.
- `--insecure` 대상 호스트에 대한 SSL 검증을 비활성화합니다. 이는 자체 서명 인증서에 유용합니다.
## 기본 포트
사용자 지정 파라미터/환경 변수를 전달할 필요를 없애기 위해, 기본 `--listen`은 동적이며 일반적인 경우에 합리적이고 유용하도록 시도합니다:
- 사용자가 `--listen`에 무엇이든 설정하면 아래의 모든 로직이 무시되고 전달된 host:port가 직접 사용됩니다.
- 사용자가 `--listen`에 아무것도 설정하지 않았고 reproxy가 도커 컨테이너 외부에서 실행되는 경우, 기본값은 http 모드(`ssl.type=none`)에서 `127.0.0.1:80`이고 ssl 모드(`ssl.type=auto` 또는 `ssl.type=static`)에서 `127.0.0.1:443`입니다.
- 사용자가 `--listen`에 아무것도 설정하지 않았고 reproxy가 도커 내부에서 실행되는 경우, 기본값은 http 모드에서 `0.0.0.0:8080`이고 ssl 모드에서 `0.0.0.0:8443`입니다.
비슷한 동적 방식으로 설정되는 또 다른 기본값은 `--ssl.http-port`입니다. 도커 컨테이너 내부에서 실행할 때는 `8080`으로 설정되고 그렇지 않으면 `80`으로 설정됩니다.
## 핑, 상태 확인 및 장애 조치
reproxy는 이 목적을 위해 두 개의 엔드포인트를 제공합니다:
- `/ping`은 `pong`으로 응답하며 reproxy가 실행 중임을 나타냅니다
- `/health`는 모든 대상 서버가 핑 요청에 `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)_
## 오류 보고
---
[Read more](https://github.com/umputun/reproxy)