Flycast로 사설(private) 앱 실행하기
이 블루프린트에서는 Flycast가 무엇인지, 언제 왜 사용해야 하는지, 그리고 Flycast를 통해 연결할 수 있는 작은 사설 HTTP 서비스를 어떻게 배포하는지 알려드릴게요. 공개 앱과 완전 사설 앱 사이의 중간 지점이 필요한 상황에서 Flycast가 어떤 도움이 되는지 함께 살펴보아요.
출처: 문서
본문
개요
여러분의 애플리케이션이 공개되고 전 세계와 공유되도록 만들어진 경우가 많습니다. 하지만 때로는 더 신중해야 할 때가 있죠. Fly.io에 앱을 배포하면 조직을 위한 사설 네트워크를 얻습니다. 이를 통해 다른 대륙에 있는 앱도 마치 같은 방에 있는 것처럼 서로 통신할 수 있습니다.
때로는 완전 공개 앱과 완전 사설 앱 사이의 중간 지점이 필요합니다. Flycast 주소는 사설 네트워크 안에 있는 사설이면서 전역적인 IPv6 주소이며, Fly Proxy를 통과합니다. 그래서 공개 앱에서 무료로 얻는 모든 로드 관리와 Machine 깨우기 기능을 그대로 누릴 수 있습니다.
이 블루프린트는 Flycast가 무엇인지, 언제 왜 사용하려고 하는지 다루고, Flycast를 통해 연결할 수 있는 작은 사설 HTTP 서비스를 배포하는 방법을 보여줍니다.
Flycast란 무엇인가요?
시작하기 전에 Flycast와 언제 사용하고 싶을지 이야기해 보겠습니다. 일반적으로 모든 종류의 Fly App을 공개 앱(public app)과 사설 앱(private app)이라는 두 가지 범주로 나눌 수 있습니다.
공개 앱은 사용자에게 공개 인터넷으로 노출시키는 것입니다. 보통 사용자가 어떤 일을 할 수 있게 하면서도 경계를 벗어나지 못하도록 접근 제한이 있는 강화된(hardened) 앱입니다. 대부분 브라우저가 상호 작용하도록 HTTP로 수신 대기하는 프로그램입니다. 사용자는 플랫폼 라우터를 통해 .fly.dev 도메인이나 다른 설정한 도메인으로 공개 앱에 연결합니다.
사설 앱은 데이터베이스 서버나 워커 큐 같은 내부적인 것입니다. 백그라운드에서 실행되며 일을 처리하는 데 도움이 되지만, 의도적으로 공개 인터넷에 노출되지 않도록 설계된 것들입니다. Postgres나 Valkey 서버를 모두에게 노출하고 싶지는 않겠죠?
하지만 완전 사설 앱에서는 모든 연결이 .internal 주소를 통해 Machines에 직접 연결되므로, 연결을 유지하려면 24/7 계속 실행하고 있어야 합니다. 데이터베이스 엔진처럼 항상 실행되길 원하는 서비스에는 괜찮지만, 관리자 패널(admin panel)은 어떨까요? 관리자 패널을 메인 앱과 분리해서 사용자가 실수로라도 접근할 수 없게 하면서도, 사용하지 않을 때는 꺼지길 원할 것입니다.
Flycast는 바로 이 중간 범주의 앱을 위해 존재합니다. Flycast를 사용하면 앱이 조직의 사설 네트워크에서만 보이고, 트래픽은 프록시를 통과하므로 필요할 때 켜고 필요 없을 때 끌 수 있습니다. 이를 통해 관리 패널을 물리적으로 분리해서 사용자가 접근할 수 없게 만들 수 있습니다.
Flycast로 앱에 연결하려면 appname.flycast에 연결하면 됩니다.
보안 참고 사항
미리 말씀드리자면, 일반적으로 Flycast나 NAT 같은 네트워크 접근 장벽을 보안 계층으로 간주하는 것은 좋지 않은 생각입니다. 기껏해야 공격자가 사설 애플리케이션에 접근하기 더 어렵게 만드는 난독화(obfuscation) 계층일 뿐입니다. Flycast는 사설 애플리케이션의 인증을 대체하지 않습니다. Flycast를 사용해도 요청이 누구에게서 오는지는 알 수 없고, 사설 네트워크 안의 무언가 또는 누군가에게서 온다는 것만 알 수 있습니다.
Flycast를 기본으로 사용하는 가장 큰 플랫폼 기능 중 하나는 Managed Postgres입니다. Flycast 주소가 사설 네트워크에 국한되더라도 Managed Postgres는 여전히 데이터베이스의 사용자 이름과 비밀번호를 구성합니다.
목표
조직의 사설 네트워크 안에서만 접근할 수 있는 작은 HTTP 서비스를 배포해 Flycast를 선보이겠습니다. 전형적인 예는 내부 관리자 패널입니다. 여러분과 앱이 접근해야 하지만 공개 인터넷에 노출되어서는 안 되는 서비스죠. Flycast를 사용하면 아무도 이용하지 않을 때 플랫폼이 서비스를 꺼서, 유휴 관리자 패널을 계속 실행하기 위해 비용을 지불하지 않아도 됩니다.
이 워크스루에서는 공개 nginxdemos/hello 이미지를 사설 HTTP 서비스의 예시로 사용합니다. 이 이미지는 HTTP 요청에 서버의 호스트 이름과 주소로 응답하는 작은 컨테이너라서, 트래픽이 Flycast를 통해 올바른 Machine에 도달하는지 쉽게 확인할 수 있습니다.
사전 요구사항
시작하려면 다음을 해야 합니다:
컴퓨터에서 Flycast 앱과 상호 작용하고 싶다면 WireGuard로 사설 네트워크에 접속해야 합니다.
단계
컴퓨터에 flycast-demo라는 새 폴더를 만들고 그 안에서 터미널을 엽니다. 이 워크스루에는 소스 코드가 필요 없습니다. --flycast 플래그로 공개 Docker 이미지에서 직접 앱을 실행할 텐데, 이 플래그는 Fly Launch가 공개 주소 대신 사설 IPv6 주소를 할당하도록 지시합니다. 또한 --no-deploy를 전달해 첫 배포 전에 한 가지 설정을 조정합니다:
fly launch --image nginxdemos/hello --flycast --internal-port 80 --no-deploy
앱에 선택한 이름이 Flycast를 통해 접근하는 호스트 이름(<appname>.flycast)이 됩니다. fly launch가 설정을 조정할지 묻으면 기본값을 수락해도 됩니다.
--internal-port 80 플래그는 Fly Launch에 앱이 80번 포트에서 수신 대기한다는 것(nginxdemos/hello 이미지의 기본값)을 알려줍니다. Fly Launch의 기본값은 8080이므로, 이 플래그가 없으면 Fly Proxy가 앱에 접근할 수 없습니다. 다음 단계에서 fly.toml에 직접 internal_port = 80을 설정할 수도 있습니다. 플래그는 파일을 두 번 편집하지 않도록 하는 바로 가기일 뿐입니다.
생성된 fly.toml을 편집기에서 열고 [http_service] 블록을 찾아 force_https를 false로 변경하세요:
[http_service]
internal_port = 80
force_https = false
Fly Launch는 기본적으로 force_https를 활성화해서 프록시가 HTTP에서 HTTPS로 301 리다이렉트를 반환하게 합니다. 공개 앱에는 좋은 기본값이지만, Flycast 주소에는 공개 TLS 인증서가 없으므로 리다이렉트가 사설 네트워크 안의 일반 HTTP 요청을 그냥 깨뜨리게 됩니다.
이제 앱을 배포하세요:
fly deploy
배포가 끝나면 fly ips list로 앱에 연결된 IP 주소 목록을 볼 수 있습니다:
$ fly ips list
VERSION\tIP \tTYPE \tREGION\tCREATED AT
v6 \tfdaa:3:9018:0:1::7\tprivate\tglobal\t23h12m ago
Fly.io 공개, 사설, 공유, 전용 IP 주소에 대해 자세히 알아보세요.
이 앱에는 사설 Flycast IPv6 주소 하나만 있습니다. 공개 IP 주소가 있다면 다음과 같이 보일 것입니다:
$ fly ips list -a recipeficator
VERSION\tIP \tTYPE \tREGION\tCREATED AT
v6 \t2a09:8280:1::37:7312:0\tpublic (dedicated)\tglobal\tMay 30 2024 13:51
v4 \t66.241.124.113 \tpublic (shared) \t \tJan 1 0001 00:00
사설임을 확인했으니 이제 양방향 셸(two-way shell) Machine을 열어 Flycast를 갖고 놀아 보겠습니다. fly machine run으로 셸 Machine을 만들고, apt로 패키지 몇 개를 설치할 수 있게 충분한 메모리를 줍니다:
$ fly machine run --shell --vm-memory 1024 ubuntu
root@e784127b51e083:/#
우리가 고른 Ubuntu 이미지는 매우 최소 구성이라 ping, curl, dig 같은 몇 가지 도구를 설치해야 합니다:
# apt update && apt install -y curl iputils-ping dnsutils
앱 이름이 flycast-demo라고 가정해 보겠습니다. nslookup flycast-demo.flycast로 .flycast 주소를 조회해 봅시다:
# nslookup flycast-demo.flycast
Server:\t\tfdaa::3
Address:\tfdaa::3#53
Name:\tflycast-demo.flycast
Address: fdaa:3:9018:0:1::7
앞서 본 IP 주소와 일치합니다. 이제 ping을 보내면 어떤 일이 벌어지는지 확인해 봅시다:
# ping flycast-demo.flycast -c2
PING flycast-demo.flycast (fdaa:3:9018:0:1::7) 56 data bytes
64 bytes from fdaa:3:9018:0:1::7: icmp_seq=1 ttl=63 time=0.138 ms
64 bytes from fdaa:3:9018:0:1::7: icmp_seq=2 ttl=63 time=0.223 ms
--- flycast-demo.flycast ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1009ms
rtt min/avg/max/mdev = 0.138/0.180/0.223/0.042 ms
이제 curl로 앱에 요청을 보내 봅시다:
# curl http://flycast-demo.flycast
서버의 호스트 이름과 주소가 포함된 HTML 페이지를 받아야 합니다. 앱이 잠들 때까지 잠시 기다린 다음 time 명령을 실행해 첫 요청에 걸리는 시간을 확인하세요:
# time curl -o /dev/null -s http://flycast-demo.flycast
real\t0m1.539s
user\t0m0.004s
sys\t\t0m0.012s
플랫폼이 Machine을 깨우고 요청을 처리할 준비를 확인하는 데 몇 초가 걸렸습니다. 다음 요청은 훨씬 빠릅니다:
# time curl -o /dev/null -s http://flycast-demo.flycast
real\t0m0.018s
user\t0m0.003s
sys\t\t0m0.008s
그리고 잠시 기다리면 다시 잠들게 됩니다.
이게 다입니다! Flycast가 무엇인지, 왜 사용하고 싶은지 알아봤고, 사설 HTTP 서비스를 배포해서 그 기능을 확인했습니다. 이 패턴은 관리자 패널, 내부 API, 대시보드 등 공개 인터넷에서 유지하고 싶지 않은 모든 내부 앱에 동일하게 적용됩니다.