# Rayfish: Iroh 기반 P2P VPN

> Clean Markdown view of GeekNews topic #31175. Use the original source for factual precision when an external source URL is present.

## Metadata

- GeekNews HTML: [https://news.hada.io/topic?id=31175](https://news.hada.io/topic?id=31175)
- GeekNews Markdown: [https://news.hada.io/topic/31175.md](https://news.hada.io/topic/31175.md)
- Type: GN+
- Author: [neo](https://news.hada.io/@neo)
- Published: 2026-07-06T18:05:12+09:00
- Updated: 2026-07-06T18:05:12+09:00
- Original source: [rayfish.xyz](https://rayfish.xyz/blog/01-introducing-rayfish)
- Points: 1
- Comments: 1

## Topic Body

- 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`을 덮어쓸 수 있음

  ```bash
  ray up --hostname dario
  ray create --name prod
  ray invite prod --hostname web
  ray join &lt;code&gt;
  ```

- ## 기기별 방화벽
  - 각 기기는 자기 방화벽을 가지고, 무엇을 누구에게서 받을지 스스로 결정함
  - 조정자는 네트워크별 권장 방화벽 규칙을 게시할 수 있음
  - 각 호스트는 규칙을 받아들이거나 자동 설치를 선택할 수 있음
  - 모두가 반드시 따라야 하는 중앙 정책 서버 없이 **공유 기본값**을 제공하는 방식임
- ## 플릿 프로비저닝
  - 여러 대의 기기는 선언형 파일로 네트워크와 방화벽 규칙을 정의하고 적용할 수 있음
  - 명세는 `networks:` 맵이며, 각 네트워크 아래에 호스트별 허용 피어와 포트를 적음

  ```yaml
  networks:
    prod:
      web:
        allows:
          "*": "tcp:443"
      db:
        allows:
          web: "tcp:5432"
    game:
      "*":
        allows:
          "*": "tcp:6969"
  ```

  ```bash
  ray apply deploy.yaml --dry-run
  ray apply deploy.yaml --invite-missing
  ```

  - 플릿에는 박스마다 코드를 발급하지 않고 **재사용 키**를 만들 수 있음

  ```bash
  ray invite prod --reusable
  ray join &lt;key&gt; --hostname web01 --auto-accept-firewall
  ```

  - 키를 폐기하면 새 가입만 막히고 이미 들어온 서버는 방해하지 않음
  - `ray apply`는 멱등적으로 동작해 명세 파일이 플릿의 기준 상태로 남음
- ## 1:1 연결과 파일 전송
  - 네트워크를 따로 만들 필요가 없을 때는 `ray connect`로 연락처 ID 기반 1:1 연결을 만들 수 있음

  ```bash
  ray contact id
  ray connect &lt;their-contact-id&gt;
  ray connections approve &lt;id&gt;
  ```

  - 승인되면 사설 2피어 네트워크가 자동으로 만들어짐
  - Magic DNS, 방화벽, 메시 기능은 동일하게 동작하며 `ray status`에는 `[direct]`로 표시됨
  - 연락처 ID는 회전할 수 있고, 이미 만들어진 연결은 계속 작동함
  - 멤버 간에는 인증되고 암호화된 경로가 이미 있으므로 별도 서비스 없이 파일을 보낼 수 있음

  ```bash
  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가 설치되지 않은 외부인은 네트워크에 접근할 수 없고, 외부인을 위한 게이트웨이는 없음

### 실제 구성 예시
- ## 두 부서가 데이터베이스를 공유하는 경우
  - `payments`와 `analytics`를 별도 네트워크로 두면 두 부서는 서로를 볼 수 없음
  - 데이터베이스 박스만 두 네트워크에 모두 가입함
  - 각 네트워크에서 필요한 포트만 열도록 권장 방화벽을 설정함

  ```yaml
  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 없이 이름으로 접속할 수 있음

  ```bash
  ray create --name mc
  ray invite mc
  ```

  - 클라이언트는 `mc-host.mc.ray:25565`를 대상으로 접속함
- ## 모두가 포트를 여는 닫힌 그룹
  - 모든 멤버가 TCP 6969를 열어야 하는 경우 관리자가 한 번 규칙을 제안할 수 있음

  ```bash
  ray firewall suggest mc --subject '*' --allow '*:tcp:6969'
  ```

  - 각 멤버는 제안된 규칙을 검토하고 수락하거나 거부함

  ```bash
  ray firewall pending mc
  ray firewall accept mc
  ```

  - 방화벽 제안은 강제 규칙이 아니며, 멤버가 원하지 않으면 거부할 수 있음

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

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

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

### 시작 방법
- 설치는 한 줄 명령으로 시작함

```bash
curl -fsSL https://rayfish.xyz/install.sh | sh
```

- 첫 네트워크 생성과 초대 절차는 [문서](https://rayfish.xyz/docs/01-introduction)에서 이어서 안내함

## Comments



### Comment 61329

- Author: neo
- Created: 2026-07-06T18:05:13+09:00
- Points: 1

###### [Lobste.rs 의견들](https://lobste.rs/s/4behtu/rayfish_p2p_vpn_built_on_top_iroh) 
- 동시에 둘 이상의 네트워크를 다루는 걸 Rayfish가 처음부터 전제로 삼는다는 점이 정말 좋음  
  Tailscale에서는 이게 [우선순위가 아닌 것 같아서](https://github.com/tailscale/tailscale/issues/183) 꽤 큰 장점이 될 수 있음  
  고빈도 거래 회사에서 분사했다는 대목은 예상 밖이었고, Tailscale이 속도에서 이긴다는 이유로 “WireGuard 데이터 평면이 커널에서 돈다”는 말은 틀렸음. Tailscale은 **커널 WireGuard**를 쓰지 않는데도 사람들이 계속 그렇게 착각함  
  “아이디어, 제품, 문장은 내 것”이라고 했지만 저장소에 `CLAUDE.md`가 있는 건 아쉬움. 다만 기여 요약을 보면 clod는 1,017++ / 383-- 줄이고 작성자는 104,786++ / 47,064-- 줄이라 대부분의 코드는 AI로 대충 만든 건 아닌 듯함. 그래도 작업량의 1/100 때문에 저장소에 그런 흔적을 남길 이유가 있었는지는 모르겠음
  - AI 보조를 받았더라도 크게 신경 쓰지 않음. 중요한 건 **실사용성**이고, 진짜 탈중앙화된 Tailscale 대안이라면 엄청날 것 같음  
    지금까지 Iroh는 귀엽지만 별로 쓸모없는 방식으로 쓰이는 걸 주로 봤는데, 이게 바로 그 앱일 수도 있음
  - Iroh 기반이라 **QUIC**이 있고, 그래서 메시 VPN에서 드디어 양자내성 암호화를 쓸 수 있을지도 모름  
    이것도 Tailscale에서는 [우선순위가 아닌 것 같음](https://github.com/tailscale/tailscale/issues/14370)

- 제품 자체는 진짜 멋져 보이고, 내 Tailscale 메시를 바꾸지 못하게 막는 유일한 건 **Android 클라이언트 부재**임  
  다만 글은 적어도 일부가 AI로 작성된 것처럼 읽혀서 조금 거슬렸음
  - 이건 봤는지 궁금함: https://github.com/rayfish/rayfish/blob/9e142411008f70228fccf9eb109af6a5d058c4e6/android/app/src/main/java/xyz/rayfish/android/RayfishVpnService.kt  
    그리고 nightly 태그에 디버그 APK 빌드도 배포하는 것 같음: https://github.com/rayfish/rayfish/releases/download/nightly/rayfish-android.apk  
    나도 이 글을 5분 전에 봐서 실제로 동작하는지는 저 링크 이상으로는 모름

- Yggdrasil과의 비교가 빈약하고 사실관계도 틀렸음. Yggdrasil 테스트넷이 전역 네트워크로 운영되긴 하지만, 그건 Yggdrasil의 위상 구조에서 편의상 나온 결과일 뿐임  
  서로 분리된 두 키 집합 사이의 어떤 연결도 동적으로 받아들일 수 있고, 분리된 Yggdrasil 네트워크 두 개와 큰 네트워크 하나의 차이는 서로 메시지를 주고받고 있느냐뿐임. **누구나 비공개 Yggdrasil 네트워크**를 만들 수 있음  
  키는 암호학적으로 추측 불가능하지만, 그게 숨겨진 서비스까지 의미한다고 보진 않음. 도메인 이름은 임의적이지만 많은 사람이 전역 DNS로 Yggdrasil 주소 공간을 가리키기도 함  
  “친구 셋과 게임 서버용 네트워크만 원한다면 Yggdrasil은 조립할 게 많다”는 관점이라면, 세 친구와 게임 서버의 표준에 가까운 [tinc](https://en.wikipedia.org/wiki/Tinc_(protocol))와 비교가 없는 게 오히려 놀라움
  - 공개 ID 자체는 추측 불가능할 수 있지만, 공유한 로그나 버그 리포트에 **공개 ID**가 나타날 수도 있음. 그래서 승인 프롬프트가 있는 비공개 네트워크가 그 문제를 다룸  
    별도의 비공개 네트워크를 만들고 사람을 받아들이는 개념이 없고, 초대 코드, 친숙한 DNS 이름, 네트워크별 방화벽, 누군가 들어오려 할 때의 승인 프롬프트 같은 편의 기능도 없다는 설명이 그 부분임. 네트워크 엔지니어라면 문제가 아닐 수 있음  
    Yggdrasil과의 비교에서 빠진 또 다른 점은 Rayfish가 Iroh의 **NAT 홀 펀칭**을 활용해서, 어느 쪽도 공개적으로 접근 가능하지 않아도 두 피어가 통신할 수 있다는 점임
