공용 네트워크 서비스
Fly.io에는 공용 및 사설 네트워크 서비스가 있어요. 공용 네트워크 서비스는 앱을 더 넓은 공용 인터넷에 연결하고, 사설 네트워크 서비스는 앱이 Fly.io 사설 네트워크 안의 다른 앱과 통신할 수 있게 해줘요.
출처: 문서
본문
Anycast IP 주소
IPv6 주소와 공유 IPv4 Anycast 주소는 무료예요. 전용 IPv4 주소는 월별로 청구돼요.
이 페이지에서 설명하는 Anycast IP 주소는 Machine 내부에서 이루어지는 아웃바운드 연결에는 사용되지 않아요. 자세한 내용은 Egress IP 주소를 참조하세요.
Anycast에 대해
우리는 BGP를 통해 모든 데이터센터에서 전역 IP 블록을 광고해요. 이를 Anycast라고 해요. Anycast는 클라이언트를 IP 블록을 광고하는 "가장 가까운" 서버에 연결하는 핵심 인터넷 라우팅 메커니즘이에요. Wikipedia에서 모든 것을 읽을 수 있어요.
IPv6
fly.toml에서 공용 서비스를 실행하도록 구성된 새 Fly App은 처음 배포될 때 전용 Anycast IPv6 주소를 자동으로 받아요.
fly machine명령이나 Machines API를 사용해 Machine 구성에 공용 서비스를 가진 앱을 만든다면, 전용 IPv6 주소를 얻기 위해fly ips allocate-v6을 실행해야 해요.
공유 IPv4
전용 IPv6 주소와 함께, 앱은 fly.toml에서 다음 프로토콜과 포트 중 하나 이상을 처리하도록 구성되면 첫 배포 시 공유 Anycast IPv4 주소를 자동으로 받아요:
- 80 포트의 HTTP, 또는
- 443 포트의 TLS & HTTP
여기에는 기본적으로 이 프로토콜과 포트만 처리하는 단순화된 [http_service] 섹션으로 구성된 앱도 포함돼요.
포트를 지정할 때 TLS 핸들러를 사용하면 80과 443이 아닌 TCP 포트에도 공유 IPv4 주소를 사용할 수 있어요.
자체 IP에 대한 명시적 필요가 없다면 공유 IPv4 주소가 권장돼요. 공유 IPv4 주소는 많은 앱과 조직에 걸쳐 공유돼요. 라우팅은 앱의 도메인에 기반해요.
공용 IPv4 주소가 없는 앱에 공유 IPv4를 할당하려면 다음을 실행하세요:
fly ips allocate-v4 --shared
fly machine명령이나 Machines API를 사용해 Machine 구성에 공용 서비스를 가진 앱을 만든다면, 공유 IPv4 주소를 얻기 위해fly ips allocate-v4 --shared을 실행해야 해요.
전용 IPv4
전용 IPv4 주소는 월별로 청구돼요.
자체 IP에 대한 명시적 필요가 없다면 공유 IPv4 주소가 권장돼요. 전용 IPv4 주소를 사용할 이유 중 일부는:
- 앱이 TLS를 사용하지 않는 비 HTTP 프로토콜을 사용해요.
- 앱이 UDP로 무언가를 해야 해요(공유 IPv4나 전용 IPv6에서는 UDP를 지원하지 않아요).
- 앱이 원시 TCP를 받아들이고 TLS 종료를 직접 처리하고 싶어요.
- 외부 연결을 위해 TLS를 통해 인터넷에 노출된 Fly Postgres가 있어요.
전용 IPv4 Anycast 주소 할당은 선택(opt-in)이에요. 앱에 전용 IPv4 주소를 수동으로 할당하려면 다음을 실행하세요:
fly ips allocate-v4
전용 IPv4 주소를 할당한 후, 공유 IPv4 주소를 해제하세요:
fly ips release <ip address to release>
전용 IPv4에서 공유 IPv4로 전환
다음 단계를 통해 사용자 지정 도메인이 있는 앱을 전용 IPv4 주소에서 무료 공유 IPv4로 다운타임 없이 전환할 수 있어야 해요.
flyctl ips allocate-v4 --shared로 공유 IPv4 주소를 추가하세요..fly.dev로의 CNAME을 사용하지 않는다면 공유 IPv4를 A 레코드로 추가하세요.- 공유 IP를 통해 앱이 작동하는지 확인하세요:
curl -Iv http://<your-hostname> --resolve <your-hostname>:80:<new-shared-ipv4>. 301 리다이렉트 응답을 받아야 해요. - 사용자 지정 도메인을 사용하고 이 앱에 대한 SSL 인증서가 아직 없다면 하나를 만드세요. HTTP 연결에도 사용자 지정 도메인을 통한 라우팅에는 인증서가 필요해요.
- DNS 캐시가 지워질 때까지 기다리세요. 5분이면 충분할 가능성이 높지만, 이는 매우 다양해요. 이는 DNS 레코드의 TTL과 우리의
<your-app>.fly.dev레코드 중 더 큰 값에 의해 결정돼요. fly ips release <ipv4-address-to-release>로 앱에서 전용 IPv4를 제거하세요.fly ips list로 앱의 IP 주소를 볼 수 있어요.- A 레코드로 수동 설정했다면 DNS에서 원하지 않는 IPv4 주소를 제거하세요.
사용자 지정 도메인이 없다면(앱이 .fly.dev 주소로 접근된다면), DNS 레코드를 직접 변경할 필요도 없고, 자체 SSL 인증서를 추가할 필요도 없어요.
연결 핸들러
핸들러는 TCP 연결을 앱이 처리할 수 있는 무언가로 변환해요. 핸들러를 사용해 외부 연결을 받아들이는 각 포트에 대해 인바운드 TCP 연결에 적용할 미들웨어를 지정할 수 있어요.
TCP 통과
핸들러를 지정하지 않으면 TCP를 앱으로 그대로 전달해요. 예를 들어 TLS 종료를 직접 처리하고 싶을 때 유용해요.
연결 핸들러 구성
fly.toml 파일의 services.ports 섹션에서 handlers 설정 항목을 설정하세요.
유효한 핸들러 문자열:
"http": TCP 연결을 HTTP로 변환"tls": TLS 연결을 암호화되지 않은 TCP로 변환"pg_tls": PostgreSQL 연결에 대한 TLS 처리"proxy_proto": TCP 연결을 PROXY 프로토콜로 감싸기
또한 기본적으로 443 포트에 TLS(및 HTTP) 핸들러가 있는 [http_service] 섹션에 대해 TLS 옵션을 구성할 수 있어요.
HTTP 핸들러
많은 앱은 HTTP 지원이 제한적이에요. http 핸들러는 HTTP 연결을 정규화하고 HTTP 1.1 요청을 애플리케이션 프로세스로 보내요. 이는 대략 nginx 및 기타 리버스 프록시가 작동하는 방식이며, 앱이 추가 복잡성 없이 (HTTP/2 같은) 현대 HTTP 프로토콜을 전역적으로 받아들일 수 있게 해줘요.
앱이 HTTP/2(gRPC 같은)가 필요하다면, h2_backend를 활성화해 HTTP/2를 통해 직접 통신하세요. 앱이 h2c(TLS 없는 HTTP/2)를 말하는지 확인하세요. 그렇지 않으면 작동하지 않아요.
HTTP 핸들러는 요청에 여러 표준 HTTP 헤더와 몇 가지 Fly.io 고유 헤더를 추가해요:
| Header | Description |
|---|---|
Fly-Client-IP |
Fly.io가 연결을 받아들인 IP 주소 |
X-Forwarded-For |
요청이 통과한 프록시 서버의 쉼표로 구분된 목록. MDN에 이 헤더에 대한 전체 문서가 있어요 |
X-Forwarded-Proto |
원래 클라이언트 프로토콜, http 또는 https |
X-Forwarded-SSL |
클라이언트가 SSL로 연결했는지, on 또는 off |
X-Forwarded-Port |
원래 연결 포트, 헤더는 클라이언트가 설정할 수 있음 |
Fly-Forwarded-Port |
원래 연결 포트, 항상 Fly.io가 설정 |
Fly-Region |
원래 들어오는 연결의 지역 |
Fly-Preferred-Instance-Unavailable |
프록시가 라우팅하지 못한 선호 인스턴스의 ID |
연결하고 싶은 지역에 대한 선호도를 HTTP 요청에 설정할 수 있어요. 단일 지역 또는 선호도 순서대로 여러 지역을 지정할 수 있어요:
Fly-Prefer-Region: iad
또는 여러 선호도로(지역을 순서대로 시도):
Fly-Prefer-Region: iad,ord,us,na
특정 Machine 인스턴스에 대한 선호도를 설정할 수 있어요:
Fly-Prefer-Instance-Id: instance-number
특정 Machine 인스턴스로 라우팅을 강제할 수 있어요:
Fly-Force-Instance-Id: instance-number
fly.toml의 구성 예시:
[[services]]
...
[[services.ports]]
handlers = ["http"]
port = 80
force_https = true # optional
[http_service]
...
[http_service.http_options]
h2_backend = true
TLS 핸들러
tls 핸들러는 Fly.io가 관리하는 애플리케이션 인증서로 TLS를 종료한 다음, 앱 프로세스로 일반 텍스트 연결을 전달해요. TCP 서비스를 실행하고 TLS를 Fly Proxy로 오프로드하는 데 유용해요.
성능을 위해 Fly Proxy는 클라이언트가 연결하는 호스트에서 TLS를 종료한 다음, 가장 가까운 사용 가능한 Machine으로 연결을 전달해요.
fly.toml의 구성 예시:
[[services]]
...
[[services.ports]]
handlers = ["tls"]
port = 443
tls_options = { "alpn" = ["mqtt"], "versions" = ["TLSv1.2", "TLSv1.3"] }
[http_service]
...
[http_service.tls_options]
alpn = ["h2", "http/1.1"]
versions = ["TLSv1.2", "TLSv1.3"]
default_self_signed = false
Postgres TLS 핸들러
pg_tls 핸들러는 Postgres 연결을 관리해, 프록시를 통해 Postgres 데이터베이스를 안전하게 노출할 수 있게 해줘요. 표준 TLS 종료가 Postgres에 왜 작동하지 않는지에 대한 @glebarez의 흥미로운 메모: https://github.com/glebarez/pgssl#readme
기본 Fly Postgres 앱 fly.toml의 예시 구성:
[[services]]
...
[[services.ports]]
port = 5433
handlers = ["pg_tls"]
PROXY 프로토콜 핸들러
proxy_proto 핸들러는 원래 연결(cl라이언트 IP와 포트, 서버 IP와 포트)에 대한 정보를 (클라이언트 관점에서) 추가해요. 대부분의 앱은 사전 빌드된 라이브러리를 사용하거나 PROXY 프로토콜을 직접 구현해 PROXY 프로토콜을 받아들이는 추가 로직이 필요해요.
Fly.io는 proxy_proto 핸들러로 기본적으로 PROXY 프로토콜 버전 1(사람이 읽을 수 있는 헤더 형식)을 지원해요. fly.toml 파일의 services.ports.proxy_proto_options 섹션에서 proxy_proto 핸들러를 버전 2(이진 헤더 형식)를 사용하도록 구성할 수 있어요.
fly.toml의 구성 예시:
[[services.ports]]
handlers = ["proxy_proto"]
port = 5000
proxy_proto_options = { version = "v2" }
HTTP에서 HTTPS로의 리다이렉트
force_https 구성 옵션은 HTTP를 HTTPS로 자동 리다이렉트해요. 활성화되면 모든 HTTP 요청은 301 상태 코드의 리다이렉트 응답을 반환해요. 이 옵션은 HTTP 핸들러에서만 설정할 수 있어요. 다른 핸들러에 설정하면 배포가 실패해요.
아웃바운드 IP 주소
Fly Machines는 Fly Proxy를 거치지 않고 더 넓은 인터넷에 요청을 하는 IPv6 주소를 가지고 있어요.
기본적으로 우리는 정적 IP나 지역별 IP 범위를 제공하지 않으며, 방화벽을 우회하기 위해 아웃바운드 IP를 사용하는 것을 권장하지 않아요. Machine의 아웃바운드 IP는 예고 없이 바뀔 수 있어요. 일상적인 일은 아니지만, 어떤 이유로든 Machine이 이동하면(한 지역의 서버 간 Fly Machines 로드 밸런싱 같은) 그렇게 될 거예요.
정적 아웃바운드 IP가 필요하다면 Machine별로 할당할 수 있어요. fly machine egress-ip allocate <machine-id>로 Machine에 할당할 수 있어요. 이는 IPv4와 IPv6 주소를 모두 Machine에 할당해요. 전용 IPv4 주소처럼 이들은 월별로 청구돼요.
또한 fly machine egress-ip list 명령으로 Machine에 할당된 모든 IP를 볼 수 있고, fly machine egress-ip release <egress-ip>으로 IP를 해제할 수 있어요.
Machine의 아웃바운드 IP 찾기
Machine의 아웃바운드 IPv6 주소는 FLY_PUBLIC_IP 환경 변수에서 사용할 수 있어요. fly ssh console -s로 원하는 Machine에서 대화형 셸을 얻으세요.
echo $FLY_PUBLIC_IP
2605:4c40:92:520a:0:8c93:3d8a:1
또한 IP를 알려주는 외부 서비스를 호출할 수도 있어요. 예를 들어:
curl text.ipv6.wtfismyip.com
2605:4c40:92:520a:0:8c93:3d8a:1
또는
dig +short txt o-o.myaddr.l.google.com @ns1.google.com
"2605:4c40:92:520a:0:8c93:3d8a:1"
그래서 이 Machine의 아웃바운드 IPv6 주소는 2605:4c40:92:520a:0:8c93:3d8a:1이에요.
dig나 curl을 사용하려면 Machine에 소프트웨어를 설치해야 할 수 있어요. Debian에서 dig는 dnsutils 패키지에 속해요.
기본 거부(Default-Deny) 보안 정책
Fly.io 앱에 대한 모든 요청은 에지 서버로 라우팅되고, 우리는 메모리 안전 Rust 프록시로 트래픽을 지시해요. 프록시는 모든 포트와 모든 Anycast 주소에서 수신하므로 포트가 더 넓은 인터넷에서 '열려' 있는 것처럼 보여요. 하지만 services로 노출하지 않는 한 앱의 어떤 것도 노출되지 않아요. 기본적으로 잠겨 있어요.
관련 자료
- App Service에 연결하기 Services를 통해 Fly App 프로세스를 공개 또는 비공개로 노출하는 방법.
- fly‑replay를 사용한 동적 요청 라우팅 Fly 고유 헤더로 지역, 앱 또는 Machine 간에 요청을 라우팅하는 방법.
- WireGuard로 사설 네트워크 연결하기 WireGuard 터널로 Fly.io와 사설 인프라 사이의 안전한 접근 설정.
- 사설 네트워킹 공용 인터넷을 거치지 않고 Fly.io 사설 네트워크에서 서비스가 안전하게 통신하는 방법.