1P by GN⁺ | ★ favorite | 댓글 1개
  • Rayfish는 서버·계정 없이 사용자 기기 사이에 P2P 메시 VPN을 만드는 첫 릴리스로, 네트워크 상태를 멤버들이 보관하는 서명된 기록으로 유지함
  • 중앙 제어 평면을 없애 회사 계정, 운영자, 항상 켜져 있어야 하는 조정 서버 없이도 가입 이후 네트워크가 계속 동작함
  • Iroh v1이 암호화된 QUIC 연결, NAT 통과, 홀 펀칭, 직접 경로가 없을 때의 릴레이 폴백을 맡아 출시 기반이 됨
  • 현재는 여러 격리 네트워크 동시 가입, 초대 코드·승인 기반 가입, Magic DNS, 기기별 방화벽, 선언형 플릿 프로비저닝, 1:1 연결, 파일 전송을 제공함
  • Tailscale보다 성숙도와 처리량에서 불리할 수 있고 SDK도 아니지만, 중앙 당사자 없는 사설 네트워크가 필요한 경우에 초점을 맞춤

Rayfish가 해결하려는 문제

  • Rayfish는 기기들 사이에 사설 네트워크를 만드는 P2P 메시 VPN
  • 중간 서버나 계속 운영을 믿어야 하는 회사 없이 동작함
  • 사용자는 키를 받고, 기기들은 그 키로 서로를 찾으며, 만들어진 네트워크는 그 안의 사람들에게 속함

중앙 제어 평면을 없앤 설계

  • 많은 현대 VPN은 회사가 운영하는 제어 평면에 의존함
    • 회사가 네트워크 멤버와 정책을 결정함
    • 기기들이 통신하는 동안에도 회사가 흐름 안에 남아 있음
    • 회사가 중단되거나 가격을 올리거나 고객 관계를 끊으면 사설 네트워크가 완전히 사용자 소유로 남기 어려움
  • Rayfish는 계정과 중앙 운영자를 제거함
    • 네트워크 상태는 멤버 누구나 다른 멤버에게 전달할 수 있는 서명된 기록
    • Rayfish 제작자가 사라져도 기존 네트워크는 계속 동작함

한 기기에서 여러 네트워크를 다루는 방식

  • Rayfish는 사용자가 하나의 평평한 네트워크만 쓰지 않는다는 전제에서 출발함
  • 한 기기가 친구용, 사이드 프로젝트용, 업무용 네트워크에 동시에 속할 수 있음
  • 구현은 하나의 프로세스와 하나의 가상 인터페이스 뒤에서 동작함
  • 각 네트워크는 서로 격리되며, 사용자는 가입한 모든 네트워크의 정식 멤버가 됨

Iroh v1이 가능하게 한 출시

  • Rayfish는 전송 계층의 어려운 부분을 Iroh에 맡김
    • 피어 간 암호화된 QUIC 연결
    • NAT 통과
    • 홀 펀칭
    • 직접 경로가 없을 때의 릴레이 폴백
  • Iroh v1은 빌드 도중 전송 계층이 흔들리지 않을 안정성을 제공해 이번 릴리스를 가능하게 함
  • 다음 과제는 초기 도구를 프로덕션에서 부담 없이 실행할 수 있는 도구로 다듬는 것임

Field Technologies에서 나온 스핀오프

  • Rayfish는 고빈도 거래 회사 Field Technologies에서 분리된 프로젝트임
  • 내부에서 분산 시스템을 다루며 기기 탐색, 공유 상태 합의, 빠르고 사적인 통신을 여러 차례 구축한 경험이 바탕이 됨
  • 이런 내부 인프라는 주로 다른 회사의 제어 평면에 의존하지 않기 위해 만들어졌음
  • Rayfish는 4년 넘게 이어진 아이디어였지만, 중앙 운영자가 없다는 특성 때문에 명확한 과금 지점이 없어 제품화가 늦어짐
  • 향후 플릿 관리나 감사 같은 기업형 문제로 확장할 수 있지만, 그런 기능은 아직 존재하지 않음

현재 제공 기능

  • 점대점 구조

    • Rayfish는 허브 앤드 스포크가 아니라 점대점 구조임
    • 모든 멤버가 다른 모든 멤버와 직접 연결됨
    • 멤버십은 서버에 묻는 값이 아니라 각 멤버가 들고 다니는 서명된 기록임
    • 네트워크를 만든 조정자는 새 멤버를 받아들일 때만 필요하고, 가입 이후에는 중앙의 누군가 없이 네트워크가 동작함
  • 닫힌 네트워크와 가입 방식

    • 네트워크는 기본적으로 닫힌 상태
    • 조정자는 두 가지 방식으로 새 멤버를 들일 수 있음
      • 1회용 초대 코드
      • 가입 요청에 대한 실시간 승인
    • 공개 네트워크가 필요하면 ray create --open으로 게이트를 열 수 있고, 이 경우 room id만으로 가입할 수 있음
    • 가입한 멤버는 안정적인 IP와 친숙한 Magic DNS 이름으로 접근 가능함
    • 기본 호스트명은 ray up --hostname dario처럼 설정할 수 있고, 네트워크별로 --hostname을 덮어쓸 수 있음
    ray up --hostname dario
    ray create --name prod
    ray invite prod --hostname web
    ray join <code>
    
  • 기기별 방화벽

    • 각 기기는 자기 방화벽을 가지고, 무엇을 누구에게서 받을지 스스로 결정함
    • 조정자는 네트워크별 권장 방화벽 규칙을 게시할 수 있음
    • 각 호스트는 규칙을 받아들이거나 자동 설치를 선택할 수 있음
    • 모두가 반드시 따라야 하는 중앙 정책 서버 없이 공유 기본값을 제공하는 방식임
  • 플릿 프로비저닝

    • 여러 대의 기기는 선언형 파일로 네트워크와 방화벽 규칙을 정의하고 적용할 수 있음
    • 명세는 networks: 맵이며, 각 네트워크 아래에 호스트별 허용 피어와 포트를 적음
    networks:
      prod:
        web:
          allows:
            "*": "tcp:443"
        db:
          allows:
            web: "tcp:5432"
      game:
        "*":
          allows:
            "*": "tcp:6969"
    
    ray apply deploy.yaml --dry-run
    ray apply deploy.yaml --invite-missing
    
    • 플릿에는 박스마다 코드를 발급하지 않고 재사용 키를 만들 수 있음
    ray invite prod --reusable
    ray join <key> --hostname web01 --auto-accept-firewall
    
    • 키를 폐기하면 새 가입만 막히고 이미 들어온 서버는 방해하지 않음
    • ray apply는 멱등적으로 동작해 명세 파일이 플릿의 기준 상태로 남음
  • 1:1 연결과 파일 전송

    • 네트워크를 따로 만들 필요가 없을 때는 ray connect로 연락처 ID 기반 1:1 연결을 만들 수 있음
    ray contact id
    ray connect <their-contact-id>
    ray connections approve <id>
    
    • 승인되면 사설 2피어 네트워크가 자동으로 만들어짐
    • Magic DNS, 방화벽, 메시 기능은 동일하게 동작하며 ray status에는 [direct]로 표시됨
    • 연락처 ID는 회전할 수 있고, 이미 만들어진 연결은 계속 작동함
    • 멤버 간에는 인증되고 암호화된 경로가 이미 있으므로 별도 서비스 없이 파일을 보낼 수 있음
    ray send ./build.tar.gz web01
    ray files accept 1
    

Tailscale과의 차이

  • Tailscale과 Rayfish는 모두 안정적인 IP, Magic DNS, NAT 통과, P2P 데이터 평면을 제공함
  • 가장 큰 차이는 제어 위치
    • Tailscale은 Tailscale 조정 서버나 self-hosted Headscale 같은 제어 평면을 사용함
    • Rayfish는 중앙 제어 평면 없이, 네트워크 상태를 P2P로 전달되는 서명된 기록으로 둠
  • 데이터 평면도 다름
    • Tailscale은 커널에서 동작하는 WireGuard를 사용함
    • Rayfish는 사용자 공간의 Iroh/QUIC 데이터그램을 사용함
  • 속도는 보통 Tailscale이 유리함
    • WireGuard가 커널에서 동작해 빠른 링크에서 대용량 전송 시 차이가 뚜렷할 수 있음
    • Rayfish는 중앙 당사자가 없는 구조와 약간의 원시 처리량을 맞바꾸는 형태임
  • Rayfish는 계정이나 SSO가 아니라 디스크의 키쌍을 정체성으로 사용함
  • Rayfish는 젊고 최소 기능 중심이며, Tailscale은 성숙하고 기능 폭이 넓음

Yggdrasil과의 차이

  • Yggdrasil은 중앙 권한이 없는 종단 간 암호화 IPv6 네트워크를 제공함
  • 사용자가 직접 다뤄야 하는 마지막 단계에서 차이가 남
    • Yggdrasil은 하나의 전역 네트워크와 IPv6 주소를 제공함
    • Rayfish는 사용자가 만들고 멤버를 들이는 별도 사설 네트워크를 제공함
  • Rayfish는 초대 코드, 친숙한 DNS 이름, 네트워크별 방화벽, 가입 승인 프롬프트 같은 편의 기능을 포함함
  • Yggdrasil은 네트워크 지식이 있는 엔지니어에게 적합하고, Rayfish는 몇 명이 쓰는 사설 네트워크를 쉽게 만들려는 사용자까지 겨냥함

만들 수 있는 것과 만들 수 없는 것

  • Rayfish는 라이브러리가 아니라 완성된 도구
  • 애플리케이션 안에 SDK처럼 임베드할 수 없음
  • Rayfish가 설치된 기기끼리 사적으로 통신해야 하는 용도에 맞음
    • 친구들이 이름으로 접속하는 P2P 게임 서버
    • 공개 인터넷에 닿지 않는 내부 API
    • 백업 대상
    • 네트워크 멤버 간 채팅이나 통화 앱
    • 서로 보지 않아야 하는 두 팀이 공유하는 데이터베이스
  • 애플리케이션은 name.network.ray로 피어에 접근할 수 있음
  • Rayfish가 설치되지 않은 외부인은 네트워크에 접근할 수 없고, 외부인을 위한 게이트웨이는 없음

실제 구성 예시

  • 두 부서가 데이터베이스를 공유하는 경우

    • paymentsanalytics를 별도 네트워크로 두면 두 부서는 서로를 볼 수 없음
    • 데이터베이스 박스만 두 네트워크에 모두 가입함
    • 각 네트워크에서 필요한 포트만 열도록 권장 방화벽을 설정함
    networks:
      payments:
        db:
          allows:
            "*": "tcp:8123,tcp:9000"
      analytics:
        db:
          allows:
            "*": "tcp:8123,tcp:9000"
    
    • 각 팀은 db.payments.ray 또는 db.analytics.ray로 접근함
    • 두 네트워크는 서로 존재를 알지 못하며, 중앙 ACL 감사 없이 네트워크 분리와 공유 호스트로 접근 제어가 구성됨
  • 친구용 Minecraft 서버

    • 닫힌 네트워크를 만들고 친구들을 초대하면 IP 주소, 포트 포워딩, 동적 DNS 없이 이름으로 접속할 수 있음
    ray create --name mc
    ray invite mc
    
    • 클라이언트는 mc-host.mc.ray:25565를 대상으로 접속함
  • 모두가 포트를 여는 닫힌 그룹

    • 모든 멤버가 TCP 6969를 열어야 하는 경우 관리자가 한 번 규칙을 제안할 수 있음
    ray firewall suggest mc --subject '*' --allow '*:tcp:6969'
    
    • 각 멤버는 제안된 규칙을 검토하고 수락하거나 거부함
    ray firewall pending mc
    ray firewall accept mc
    
    • 방화벽 제안은 강제 규칙이 아니며, 멤버가 원하지 않으면 거부할 수 있음

보안과 주소 처리

  • IP 주소는 서버가 할당하지 않고 각 피어의 암호학적 정체성에서 파생됨
  • 주소 충돌은 거의 없지만, 충돌이 나면 조정자가 두 번째 피어를 다음 빈 슬롯에 배치함
  • 모든 피어는 중앙 할당자 없이 같은 주소 배정에 결정적으로 수렴함
  • Rayfish는 중앙 ACL 대신 두 가지로 보안을 구성함
    • 같은 네트워크를 공유한 피어끼리만 통신 가능한 분할
    • 각 기기의 네트워크별 방화벽
  • proddev를 격리하려면 두 네트워크로 만들면 됨
  • 여러 네트워크에 속한 호스트는 각 네트워크에서 자기 방화벽을 들고 있음

서버와 포트 개방 필요 여부

  • 별도 제어 서버를 호스팅할 필요가 없음
  • 네트워크를 만든 조정자는 모든 멤버가 가입한 뒤에는 오프라인이어도 됨
  • Iroh가 NAT 통과와 홀 펀칭을 처리하고, 직접 경로가 불가능하면 암호화된 릴레이 폴백을 사용함
  • 라우터를 제어하고 특정 박스에 보장된 직접 경로를 원하면 Rayfish의 고정 UDP 포트를 포워딩할 수 있지만 선택 사항임

앞으로의 계획과 맞지 않는 경우

  • 현재 데스크톱과 서버에서는 명령줄 도구로 제공됨
  • 다음 작업은 사용자가 실제로 들고 다니는 기기로 확장하는 것임
    • Android 클라이언트
    • iOS 클라이언트
    • 제대로 된 데스크톱 앱
  • 동시에 프로덕션에서 부담 없이 쓸 수 있도록 기존 기능을 단단하게 만드는 작업을 진행함
  • 이미 Tailscale, 회사 VPN, 직접 구성한 WireGuard 메시가 잘 동작한다면 Rayfish로 바꿀 이유는 크지 않음
  • Rayfish는 더 젊고 기능이 적으며, 기존 도구들이 더 매끄럽게 제공하는 기능도 많음
  • Rayfish가 제거하는 것은 하나임
    • 계정
    • 네트워크를 중단할 수 있는 회사
    • 계속 켜져 있어야 하는 제어 서버
    • 다른 사람이 운영하는 정책 데이터베이스

시작 방법

  • 설치는 한 줄 명령으로 시작함
curl -fsSL https://rayfish.xyz/install.sh | sh
  • 첫 네트워크 생성과 초대 절차는 문서에서 이어서 안내함

댓글과 토론

Lobste.rs 의견들
  • 동시에 둘 이상의 네트워크를 다루는 걸 Rayfish가 처음부터 전제로 삼는다는 점이 정말 좋음
    Tailscale에서는 이게 우선순위가 아닌 것 같아서 꽤 큰 장점이 될 수 있음
    고빈도 거래 회사에서 분사했다는 대목은 예상 밖이었고, Tailscale이 속도에서 이긴다는 이유로 “WireGuard 데이터 평면이 커널에서 돈다”는 말은 틀렸음. Tailscale은 커널 WireGuard를 쓰지 않는데도 사람들이 계속 그렇게 착각함
    “아이디어, 제품, 문장은 내 것”이라고 했지만 저장소에 CLAUDE.md가 있는 건 아쉬움. 다만 기여 요약을 보면 clod는 1,017++ / 383-- 줄이고 작성자는 104,786++ / 47,064-- 줄이라 대부분의 코드는 AI로 대충 만든 건 아닌 듯함. 그래도 작업량의 1/100 때문에 저장소에 그런 흔적을 남길 이유가 있었는지는 모르겠음

    • AI 보조를 받았더라도 크게 신경 쓰지 않음. 중요한 건 실사용성이고, 진짜 탈중앙화된 Tailscale 대안이라면 엄청날 것 같음
      지금까지 Iroh는 귀엽지만 별로 쓸모없는 방식으로 쓰이는 걸 주로 봤는데, 이게 바로 그 앱일 수도 있음
    • Iroh 기반이라 QUIC이 있고, 그래서 메시 VPN에서 드디어 양자내성 암호화를 쓸 수 있을지도 모름
      이것도 Tailscale에서는 우선순위가 아닌 것 같음
  • 제품 자체는 진짜 멋져 보이고, 내 Tailscale 메시를 바꾸지 못하게 막는 유일한 건 Android 클라이언트 부재
    다만 글은 적어도 일부가 AI로 작성된 것처럼 읽혀서 조금 거슬렸음

  • Yggdrasil과의 비교가 빈약하고 사실관계도 틀렸음. Yggdrasil 테스트넷이 전역 네트워크로 운영되긴 하지만, 그건 Yggdrasil의 위상 구조에서 편의상 나온 결과일 뿐임
    서로 분리된 두 키 집합 사이의 어떤 연결도 동적으로 받아들일 수 있고, 분리된 Yggdrasil 네트워크 두 개와 큰 네트워크 하나의 차이는 서로 메시지를 주고받고 있느냐뿐임. 누구나 비공개 Yggdrasil 네트워크를 만들 수 있음
    키는 암호학적으로 추측 불가능하지만, 그게 숨겨진 서비스까지 의미한다고 보진 않음. 도메인 이름은 임의적이지만 많은 사람이 전역 DNS로 Yggdrasil 주소 공간을 가리키기도 함
    “친구 셋과 게임 서버용 네트워크만 원한다면 Yggdrasil은 조립할 게 많다”는 관점이라면, 세 친구와 게임 서버의 표준에 가까운 tinc와 비교가 없는 게 오히려 놀라움

    • 공개 ID 자체는 추측 불가능할 수 있지만, 공유한 로그나 버그 리포트에 공개 ID가 나타날 수도 있음. 그래서 승인 프롬프트가 있는 비공개 네트워크가 그 문제를 다룸
      별도의 비공개 네트워크를 만들고 사람을 받아들이는 개념이 없고, 초대 코드, 친숙한 DNS 이름, 네트워크별 방화벽, 누군가 들어오려 할 때의 승인 프롬프트 같은 편의 기능도 없다는 설명이 그 부분임. 네트워크 엔지니어라면 문제가 아닐 수 있음
      Yggdrasil과의 비교에서 빠진 또 다른 점은 Rayfish가 Iroh의 NAT 홀 펀칭을 활용해서, 어느 쪽도 공개적으로 접근 가능하지 않아도 두 피어가 통신할 수 있다는 점임