Listener(리스너)
요청(request)을 수락(accept)하려면 config/listeners
API 섹션(section)에 리스너 객체(listener object)를 추가하십시오. 객체의 이름은 다음과 같을 수 있습니다.
- 고유(unique) IP 소켓:
127.0.0.1:80
,[::1]:8080
- 포트의 모든 호스트 IP와 일치하는 와일드카드:
*:80
Linux: 추상(Abstract) UNIX 소켓 및 포트 제한 사항
Linux 기반 시스템에서 추상(abstract) UNIX 소켓도 사용할 수 있습니다: unix:@abstract_socke
t
.
또한 와일드카드 Listener는 Linux 커널에 의해 부과된 규칙으로 인해 동일한 포트의 다른 Listener와 겹칠 수 없습니다. 예를 들어 *:8080
은 127.0.0.1:8080
과 충돌합니다. 특히, 이것은 *:8080
을 먼저 삭제하지 않고는 즉시 127.0.0.1:8080
으로(또는 그 반대로) 대체될 수 없음을 의미합니다.
Unit은 수신한 요청을 Listener가 참조하는 대상으로 전달합니다. 여러 Listener를 하나의 대상에 연결하거나 단일 Listener를 사용하여 여러 대상 간에 hot-swap할 수 있습니다.
사용 가능한 Listener 옵션:
Option | Description |
pass | listener가 들어오는 요청을 전달하는 대상입니다. 가능한 대안: – 애플리케이션: applications/qwk2mart – PHP Target 또는 Python Target: applications/myapp/section – 라우트: route/route66, routes – 업스트림: upstreams/rr-lb 값(value)은 변수(variable)에 보간됩니다. 보간 후 구성 엔터티와 일치하지 않으면 404 “Not Found” 상태 코드가 반환(Return)됩니다. |
tls | 객체(Object); SSL/TLS 설정을 정의합니다. |
forwarded | 객체(Object); 클라이언트 IP 주소 및 프로토콜 교체(replacement)를 구성합니다. |
여기에서 local listener는 port 8300에서 요청을 수락하고 uri
변수로 식별되는 blogs
앱 대상으로 전달합니다. 포트 8400의 와일드카드 수신기는 모든 호스트 IP의 요청을 main
route로 릴레이합니다.
{
"127.0.0.1:8300": {
"pass": "applications/blogs$uri"
},
"*:8400": {
"pass": "routes/main"
}
}
또한 pass
값(value)은 퍼센트(percent)로 인코딩될 수 있습니다. 예를 들어 엔티티 이름(entity names)에서 슬래시(slashes)를 이스케이프(escape)할 수 있습니다.
{
"listeners": {
"*:80": {
"pass": "routes/slashes%2Fin%2Froute%2Fname"
}
},
"routes": {
"slashes/in/route/name": []
}
}
SSL/TLS 구성(Configuration)
tls
객체는 다음 옵션을 제공합니다.
Option | Description |
certificate (required) | 문자열 또는 문자열 배열(array of strings) listener를 통한 secure communicaiton을 가능하게 하는 이전에 업로드된 하나 이상의 인증서 번들(certificate bundles)을 나타냅니다. |
conf_commands | Object; listener에 대해 설정할 SSL 구성 명령을 정의합니다. 이 옵션을 사용하려면 OpenSSL 1.0.2+에서 Unit을 빌드하고 실행해야 합니다. $ openssl version OpenSSL 1.1.1d 10 Sep 2019 |
session | Object; listener에 대한 TLS session cache 및 tickets을 구성합니다. |
이전에 업로드한 certificate bundle을 사용하려면 tls
객체의 certificate
옵션에서 이름을 지정합니다.
{
"listeners": {
"127.0.0.1:443": {
"pass": "applications/wsgi-app",
"tls": {
"certificate": "bundle"
}
}
}
}
여러 번들 구성(Configuring Multiple Bundles)
버전 1.23.0부터 Unit은 certificate
옵션 값에 대한 certificate bundle 이름 배열을 제공하여 listener에서 SNI(Server Name Indication) 구성을 지원합니다.
{
"*:443": {
"pass": "routes",
"tls": {
"certificate": [
"bundleA",
"bundleB",
"bundleC"
]
}
}
}
연결하는 클라이언트가 server name을 보내면 Unit은 일치하는 인증서 번들(certificate bundle)로 응답합니다. 이름(name)이 여러 번들과 일치하는 경우 정확한 일치가 와일드카드보다 우선합니다. 이것이 도움이 되지 않으면 먼저 나열된 것이 사용됩니다. 일치하는 항목이 없거나 서버 이름(server name)이 전송되지 않은 경우 Unit은 목록의 첫 번째 번들(first bundle)을 사용합니다.
listener에 대한 사용자 정의 OpenSSL 구성 명령(configuration commands)을 설정하려면 tls
에서 conf_commands
객체를 사용하십시오.
{
"tls": {
"certificate": "bundle",
"conf_commands": {
"ciphersuites": "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256",
"minprotocol": "TLSv1.3"
}
}
}
tls
의 session
객체는 listener의 세션 설정을 구성합니다.
Option | Description |
cache_size | 정수(integer); TLS session cache의 세션 수를 설정합니다. 기본값(default)은 0 (캐싱이 비활성화됨)입니다. |
timeout | 정수(integer); TLS session cache에 대한 세션 시간 초과(session timeout)를 설정합니다. 새 세션이 생성되면 해당 수명은 current time 및 timeout에서 파생됩니다. 캐시된 세션이 수명이 지난 후에 요청되면 재사용되지 않습니다. 기본값(default)은 300(5분)입니다. |
tickets | 부울(Boolean), 문자열 또는 문자열 배열 TLS session tickets을 구성합니다. 기본값(default)은 false입니다(티켓이 비활성화됨). |
{
"tls": {
"certificate": "bundle",
"session": {
"cache_size": 10240,
"timeout": 60,
"tickets": [
"k5qMHi7IMC7ktrPY3lZ+sL0Zm8oC0yz6re+y/zCj0H0/sGZ7yPBwGcb77i5vw6vCx8vsQDyuvmFb6PZbf03Auj/cs5IHDTYkKIcfbwz6zSU=",
"3Cy+xMFsCjAek3TvXQNmCyfXCnFNAcAOyH5xtEaxvrvyyCS8PJnjOiq2t4Rtf/Gq",
"8dUI0x3LRnxfN0miaYla46LFslJJiBDNdFiPJdqr37mYQVIzOWr+ROhyb1hpmg/QCM2qkIEWJfrJX3I+rwm0t0p4EGdEVOXQj7Z8vHFcbiA="
]
}
}
}
티켓(tickets
) 옵션은 다음과 같이 작동합니다.
– 부울 값(Boolean Value)은 세션 티켓(session tickets)을 활성화(enable)하거나 비활성화(disable)합니다. true이면 임의의 세션 티켓 키(random session ticket key)가 사용됩니다.
{
"session": {
"tickets": true
}
}
문자열(string)은 티켓(tickets)을 활성화(enables)하고 세션 티켓 키(session ticket key)를 명시적으로 설정합니다.
{
"session": {
"tickets": "IAMkP16P8OBuqsijSDGKTpmxrzfFNPP4EdRovXH2mqstXsodPC6MqIce5NlMzHLP"
}
}
이렇게 하면 키(key)가 개별 서버 간에 공유되는 시나리오에서 티켓(ticket)을 재사용(reuse)할 수 있습니다.
공유 키 순환(Shared Key Rotation)
여러 Unit 인스턴스가 서로 발행한 티켓을 인식해야 하는 경우(예: load balancer 뒤에서 실행할 때) session ticket key를 공유해야 합니다.
예를 들어 Unit*.example.com이라는 SSH 지원 서버 3대가 설치되어 있고 Unit이 설치되어 있고 동일한 *:443 listener가 구성(configured)되어 있다고 가정해 보겠습니다. 각 서버에서 초기 키(initial key) 3개로 구성된 단일 세트를 구성하려면 다음을 수행하십시오.
SERVERS="unit1.example.com
unit2.example.com
unit3.example.com"
KEY1=$(openssl rand -base64 48)
KEY2=$(openssl rand -base64 48)
KEY3=$(openssl rand -base64 48)
for SRV in $SERVERS; do
ssh root@$SRV \
curl -X PUT -d '["$KEY1", "$KEY2", "$KEY3"]' --unix-socket /path/to/control.unit.sock \
'http://localhost/config/listeners/*:443/tls/session/tickets/'
done
각 서버에 새 키(new key)를 추가하려면:
NEWKEY=$(openssl rand -base64 48)
for SRV in $SERVERS; do
ssh root@$SRV \
curl -X POST -d '\"$NEWKEY\"' --unix-socket /path/to/control.unit.sock \
'http://localhost/config/listeners/*:443/tls/session/tickets/'"
done
새 키(new key)를 추가한 후 가장 오래된 키(oldest key)를 삭제하려면:
for SRV in $SERVERS; do
ssh root@$SRV \
curl -X DELETE --unix-socket /path/to/control.unit.sock \
'http://localhost/config/listeners/*:443/tls/session/tickets/0'
done
이 scheme를 사용하면 개별 Unit 인스턴스 간에 세션 티켓 키(session ticket key)를 안전하게 공유할 수 있습니다.
Unit는 AES256(80-byte keys) 또는 AES128(48-byte keys)을 지원합니다. 바이트는 Base64로 인코딩되어야 합니다.
$ openssl rand -base64 48
LoYjFVxpUFFOj4TzGkr5MsSIRMjhuh8RCsVvtIJiQ12FGhn0nhvvQsEND1+OugQ7
$ openssl rand -base64 80
GQczhdXawyhTrWrtOXI7l3YYUY98PrFYzjGhBbiQsAWgaxm+mbkm4MmZZpDw0tkK
YTqYWxofDtDC4VBznbBwTJTCgYkJXknJc4Gk2zqD1YA=
– 위와 같은 문자열 배열(array of strings):
{
"session": {
"tickets": [
"IAMkP16P8OBuqsijSDGKTpmxrzfFNPP4EdRovXH2mqstXsodPC6MqIce5NlMzHLP",
"Ax4bv/JvMWoQG+BfH0feeM9Qb32wSaVVKOj1+1hmyU8ORMPHnf3Tio8gLkqm2ifC"
]
}
}
Unit은 이 key를 사용하여 세션 상태(session state)를 복구하려는 클라이언트가 제출한 티켓을 해독(decrypt)합니다. 마지막 키(last key)는 항상 새 세션 티켓(new session ticket)을 생성하고 이전에 생성된 티켓을 업데이트하는 데 사용됩니다.
Note
빈 배열(empty array)은ticket
을false
로 설정하는 것과 마찬가지로 session ticket을 효과적으로 비활성화(disable)합니다.
IP, 프로토콜 포워딩(Protocol Forwarding)
Unit은 forwarded
객체(object) 및 해당 옵션이 있는 X-Forwarded-*
헤더 필드를 활성화합니다.
Option | Description |
client_ip | String; 요청자(requestr)에서 예상하는 HTTP 헤더 필드의 이름을 지정합니다. 값(value)이 쉼표 또는 공백으로 구분된 IPv4 또는 IPv6 목록인 X-Forwarded-For 형식을 사용해야 합니다. |
protocol | String; 요청(request)에서 찾을 관련 HTTP 헤더 필드를 정의합니다. Unit은 필드 값 자체가 http , https 또는 on 인 X-Forwarded-Proto 표기법을 따를 것으로 예상합니다. |
source (required) | 문자열(String) 또는 문자열 배열(array of strings) 신뢰할 수 있는 주소에 대한 주소 기반 패턴(address-based patterns)을 정의합니다. 교체(replacement)는 요청의 source IP가 일치(match)하는 경우에만 발생합니다. 여기서 특별한 경우(special case)는 "unix" 문자열(string)입니다. 모든 UNIX domain socket과 일치합니다. |
recursive | 부울(Boolean); client_ip 필드가 순회되는(traversed) 방법을 제어합니다.기본값(default)은 false (재귀 없음)입니다. |
Note
source
외에forwarded object
는client_ip
,protocol
또는 둘 다를 지정(specify)해야 합니다.
Warning
버전 1.28.0 이전에는 Unit이 다음과 같이forwarded client_ip
객체를 제공했습니다.
client_ip (pre-1.28.0) | forwarded (post-1.28.0) |
header | client_ip |
source | source |
recursive | recursive |
N/A | protocol |
이 오래된 구문은 여전히 작동하지만 버전 1.30.0 이전은 아니지만 결국 사용되지 않습니다.
forwarded
가 설정되면 Unit은 요청의 직접적인 source IP가 source
option과 일치하는 경우에만 적절한 헤더 필드(header field)를 존중합니다. 서브넷(subnet)뿐만 아니라 모든 주소 기반 패턴(address-based pattern)을 사용할 수 있습니다.
{
"forwarded": {
"client_ip": "X-Forwarded-For",
"source": [
"198.51.100.1-198.51.100.254",
"!198.51.100.128/26",
"203.0.113.195"
]
}
}
Overwriting Protocol Scheme
프로토콜 옵션을 사용하면 지정된 헤더 필드를 기반으로 들어오는 요청의 프로토콜 체계를 덮어쓸 수 있습니다. 다음과 같은 전달 구성을 고려하십시오.
{
"forwarded": {
"protocol": "X-Forwarded-Proto",
"source": [
"192.0.2.0/24",
"198.51.100.0/24"
]
}
}
다음 헤더 필드와 함께 요청이 도착한다고 가정합니다.
X-Forwarded-For: 192.0.2.18
X-Forwarded-For: 203.0.113.195, 198.51.100.178
recursive
가 false
(default)로 설정된 경우 Unit은 client_ip
에 명명된 last filed의 가장 오른쪽 주소를 요청의 발신 IP로 선택합니다. 이 예에서는 192.0.2.0/24 또는 198.51.100.0/24의 요청에 대해 198.51.100.178로 설정됩니다.
recursive
가 true
로 설정되면 Unit은 모든 client_ip
필드를 역순(reverse)으로 검사합니다. 각각은 첫 번째 non-trusted address까지 오른쪽에서 왼쪽으로 순회(traversed)합니다. 발견되면 발신 IP로 선택됩니다. "recursive": true
가 있는 이전 예에서 클라이언트 IP는 203.0.113.195로 설정됩니다. 198.51.100.178도 신뢰할 수 있기 때문입니다. 이것은 여러 리버스 프록시 뒤에서 작업을 단순화합니다.