Relayium

Relayium CLI로 서버 간 전송(데몬 다이렉트)

마지막 업데이트: 2026-08-05

두 기기가 모두 내 것이고 서로의 주소를 알고 있다면, SSH는 불필요한 마찰이고 랑데부는 순전한 오버헤드입니다. 데몬 다이렉트는 정확히 이를 위해 만들어졌습니다. 한쪽 서버는 대기하고, 다른 쪽은 인증서 고정 TLS 1.3 연결로 그곳에 곧바로 푸시합니다. 릴레이도 SSH도 페어링 코드도 없습니다. 신뢰는 공개 키 방식이며 한 번만 설정하면 됩니다.

이 가이드는 리스너 시작하기, 리스너로의 푸시, 처음 접촉했을 때 새로운 푸시하는 쪽 승인하기, 자동화하기, 그리고 리스너를 systemd 서비스로 실행하는 방법을 다룹니다.

시작하기 전에

아래는 모두 relayium CLI이므로, 설치하지 않았다면 먼저 설치하세요. macOS나 Linux에서는 명령어 하나로 사전 빌드된 바이너리가 PATH에 등록됩니다:

curl -fsSL https://relayium.com/install.sh | sh

리스너 시작하기(받는 쪽)

필요한 것

  • 직접 관리하는 두 대의 기기, 그리고 보내는 쪽에서 닿을 수 있는 받는 쪽 주소. 호스트명이든 생 IP든 됩니다.
  • 양쪽 모두의 relayium. 데몬 다이렉트는 네이티브 프로토콜만 쓰므로, 설치 누락을 구해 줄 tar 대체 방식이 여기에는 없습니다.
  • 보내는 쪽에 열린 리스너 포트 — 바꾸지 않았다면 9031/TCP — 호스트 방화벽과 클라우드 보안 그룹 양쪽에서.
  • 첫 푸시 때 승인 프롬프트에 답할 수 있도록 받는 쪽의 터미널. 터미널이 없다면 대신 보내는 쪽을 미리 승인하세요(아래 참고).

받는 쪽 서버에서 serve는 푸시를 대기하고 이를 어떤 디렉터리에 기록합니다. 기본적으로 계속 실행되며, --once를 추가하면 한 번의 전송만 받고 종료합니다. 미리 공유해야 할 것은 아무것도 없습니다. 미리 복사해 둘 핑거프린트도 없습니다:

  1. 푸시가 도착할 디렉터리를 만듭니다.

    mkdir -p ~/inbox
  2. 리스너의 포트를 보내는 쪽에만 엽니다. 203.0.113.7 은 보내는 쪽 자신의 주소——공인 IP, 두 서버가 같은 네트워크에 있다면 사설 IP——로 바꾸고, 클라우드 보안 그룹도 인터넷 전체가 아니라 같은 출발지로 좁히세요.

    sudo ufw allow from 203.0.113.7 to any port 9031 proto tcp
  3. 첫 푸시의 승인 프롬프트에 답할 사람이 있도록 터미널에서 리스너를 시작합니다. --once 를 붙이면 한 번 받고 종료하고, --port 로 9031을 벗어날 수 있습니다.

    relayium serve --dir ~/inbox

리스너가 떠 있을 때 보이는 것

serve는 바인딩한 주소, 파일을 쓰는 디렉터리, 그리고 이 호스트 자신의 지문을 알려 줍니다. 승인된 피어가 아직 없으면 새 피어마다 물어보겠다는 안내도 함께 나옵니다.

relayium serve --dir ~/inbox
no authorized peers yet — you'll be asked to approve each new peer on its first push.
relayium serve: listening on [::]:9031, receiving into /home/you/inbox (fingerprint 5c1d9f04…)

리스너로 푸시하기(보내는 쪽)

보내는 쪽 서버에서 받는 쪽의 relayium:// 주소로 푸시하세요. 첫 연결에서 받는 쪽의 핑거프린트가 고정되고, 이후 모든 연결은 이를 검증합니다. 핑거프린트가 바뀌면 조용히 받아들여지는 대신 거부됩니다. 그래서 키가 바뀌었거나 중간자 공격이 있으면 신뢰되는 대신 발견됩니다. 첫 푸시에서는 받는 쪽이 승인할 때까지 보내는 쪽이 잠시 대기합니다(다음 단계).

  1. 보내는 서버에서 푸시를 실행합니다. 맨 처음 연결에서는 받는 쪽이 승인할 때까지 바로 여기서 멈춥니다.

    relayium push ./build.tar.zst relayium://receiver.example.com
  2. 받는 쪽에서 프롬프트에 답합니다 — 바로 다음 절의 내용입니다. 그 뒤로 푸시는 스스로 끝나고, 이후의 푸시는 다시는 여기서 멈추지 않습니다.

  3. 리스너가 9031이 아니라면 주소 뒤에 포트를 덧붙입니다.

    relayium push ./build.tar.zst relayium://receiver.example.com:9040

푸시가 성공했을 때 보이는 것

첫 접촉에서 보내는 쪽이 리스너의 지문을 배워 고정한 뒤 전송합니다. 받는 쪽은 푸시한 기기의 지문을 기록하고 파일 수와 바이트 수를 보고합니다.

# on the SENDER, first contact
learned receiver.example.com:9031 5c1d9f04… (added to known_hosts)
  build.tar.zst (48213004 bytes)

# on the RECEIVER
authorized 74318e3b… (added to /home/you/.config/relayium/authorized_fingerprints)
received 1 file(s), 48213004 bytes from 74318e3b…

첫 푸시 시 보내는 쪽 승인하기(받는 쪽)

새 기기가 리스너로 처음 푸시하면, serve는(터미널에서) 그 출처와 핑거프린트를 보여주고 승인할지 물어봅니다. SSH의 첫 연결 프롬프트와 비슷하지만, 받는 쪽에서 이루어진다는 점이 다릅니다:

# 받는 쪽에서, 새 보내는 쪽이 푸시할 때:
Incoming push from 203.0.113.7:54021
  fingerprint: 74318e3b…
Accept and remember this peer? [y/N] y

자동화하기(또는 터미널 없이 실행하기)

승인된 핑거프린트는 기억되므로 이후의 푸시에는 확인이 필요 없습니다. 따라서 relayium push는 cron, 배포 스크립트, CI에 곧바로 연결되어 암호화되고 무결성이 검증되며 재개 가능한 서버 간 동기화를 제공합니다. serve가 터미널 없이 실행될 때(systemd 서비스, 파이프 등)는 프롬프트를 띄울 수 없으므로 알 수 없는 푸시하는 쪽을 거부합니다. 대신 미리 승인해 두세요. 핑거프린트는 푸시하는 쪽에서 relayium id로 얻거나, serve 로그의 “rejected unauthorized peer …” 줄에서 복사한 뒤 다음을 실행하세요:

# 받는 쪽에서: 프롬프트 없이 보내는 쪽을 미리 승인
relayium authorize 74318e3b...

systemd에서 리스너 실행하기

항상 켜져 있는 수신함을 만들려면 serve를 systemd 서비스로 실행하세요. --config-dir을 /etc/relayium 같은 고정된 위치로 지정해 재시작 간에도 신원이 안정적으로 유지되게 하고, 살아 있게 하는 것은 systemd에 맡기세요:

# /etc/systemd/system/relayium-serve.service
[Unit]
Description=Relayium daemon-direct listener
After=network-online.target

[Service]
ExecStart=/usr/local/bin/relayium serve --dir /srv/inbox --config-dir /etc/relayium
Restart=always
User=relayium

[Install]
WantedBy=multi-user.target

푸시가 통하지 않을 때

먼저 볼 것은 도달성과 신뢰, 이 두 가지입니다. 보내는 쪽에서 ss -tinp 를 돌리면 리스너에 닿기는 했는지 알 수 있고, 받는 쪽의 relayium authorize 는 거부당한 보내는 쪽에 없는 신뢰를 부여합니다. 다만 푸시가 실패하는 방식이 이 둘뿐인 것은 아닙니다. 받는 쪽 디스크가 꽉 찼거나, 받는 디렉터리에 실행 사용자가 쓸 수 없거나, 전송된 파일이 무결성 검사를 통과하지 못하는 경우도 각각 자기 오류를 냅니다. 그러니 아래 네 가지 중 하나라고 단정하지 말고 눈앞의 오류를 읽으세요.

증상, 확인, 해결

푸시가 그대로 멈춰 있다가 연결 오류로 실패합니다.
# 보내는 쪽에서, 푸시가 도는 동안 — 몇 초 간격으로 두 번 실행
ss -tinp dst :9031
# ESTAB    리스너에 닿았다는 뜻일 뿐, 진행 여부는 말해 주지 않음
# SYN-SENT 그 포트에서 아무도 응답하지 않음

SYN-SENT는 패킷이 대기 중인 소켓까지 닿지 못했다는 뜻입니다. 받는 쪽에서 ss -tlnp | grep 9031 로 serve가 떠 있는지 확인하고, 호스트 방화벽과 클라우드 보안 그룹에서 9031/TCP를 보내는 쪽에 여세요. ESTAB은 닿았다는 것만 증명합니다. established 소켓도 놀고 있거나 멈춰 있을 수 있습니다. 그러니 움직이는지 멈췄는지 가리려면 이 확인을 몇 초 간격으로 두 번 실행해, -i 가 그 소켓에 대해 출력하는 bytes_acked 카운터를 비교하세요. 여기에는 릴레이 경로가 없으므로, 닿지 않는 리스너는 느린 것이 아니라 완전한 실패입니다.

serve 로그에 “rejected unauthorized peer …”가 찍히고 푸시가 실패합니다.
# 보내는 쪽에서
relayium id
# 74318e3b…

# 받는 쪽에서
relayium authorize 74318e3b…

serve에게 물어볼 터미널이 없었기 때문입니다 — systemd 유닛이나 파이프 — 그래서 알 수 없는 지문은 신뢰 대신 거부됩니다. 미리 승인하세요. 거부 줄에 있는 지문은 보내는 쪽의 relayium id 가 출력하는 것과 똑같고, authorize는 몇 번 실행해도 같습니다.

“fingerprint mismatch for receiver.example.com:9031”.
grep receiver.example.com ~/.config/relayium/known_hosts

리스너가 첫 접촉 때 고정한 것과 다른 키를 제시했습니다. 일부러 그 키를 교체했다면 해당 known_hosts 줄을 지우고 다시 푸시하세요. 그렇지 않다면 그 줄은 그대로 두고, 키가 왜 바뀌었는지 알아내기 전에는 아무것도 보내지 마세요.

systemd 유닛이 시작하자마자 권한 오류로 죽습니다.
systemctl status relayium-serve
# secure: /etc/relayium/id.key has insecure permissions 0644; run: chmod 600 /etc/relayium/id.key
ls -l /etc/relayium/id.key

relayium은 소유자 외의 누구라도 읽을 수 있는 개인 키를 읽어들이길 거부합니다. ssh와 같은 규칙입니다. 오류가 알려 준 경로에 chmod 600을 적용하고, 그 파일의 소유자가 서비스 사용자인지 확인한 뒤 유닛을 재시작하세요.

자주 묻는 질문

데몬 다이렉트는 SSH를 통한 push와 어떻게 다른가요?

SSH를 통한 push는 전송을 SSH 연결 터널로 통과시키며 원격에 SSH 계정이 필요합니다. 데몬 다이렉트는 SSH도 계정도 필요 없습니다. 두 서버는 인증서 고정 TLS를 통해 인증서 핑거프린트로 서로를 인증하며, 두 기기가 모두 내 것일 때 더 가볍습니다.

핑거프린트를 손으로 일일이 복사해서 옮겨야 하나요?

아니요. 터미널에서는 serve가 각 새 푸시하는 쪽의 첫 푸시 시 주소와 핑거프린트를 보여주며 승인할지 물어보고, 이를 기억합니다. 그래서 이후의 푸시는 조용히 진행됩니다. relayium id나 relayium authorize가 필요한 경우는 systemd 서비스처럼 프롬프트에 답할 사람이 없는 비대화형 설정뿐입니다.

신원 및 신뢰 파일은 어디에 있나요?

기본적으로 ~/.config/relayium/에 있습니다(--config-dir로 재정의 가능). id.key / id.crt는 이 호스트의 영구적인 신원이고, known_hosts는 푸시했던 리스너들의 핑거프린트를 담고 있으며, authorized_fingerprints는 리스너 쪽의 푸시하는 쪽 허용 목록입니다.

핑거프린트가 바뀌면 어떻게 되나요?

푸시가 거부되고 경고가 표시됩니다. 리스너의 키는 첫 사용 시 known_hosts에 고정되므로, 이후의 변화(키를 재발급한 호스트든 중간자 공격이든)는 조용히 받아들여지는 대신 거부됩니다. known_hosts의 해당 줄은 의도적으로 키를 교체했을 때만 삭제하세요.

릴레이 폴백이 있나요?

없습니다. 데몬 다이렉트는 도달 가능한 리스너 주소를 전제로 합니다. 연결할 수 없으면 실패합니다. 어떤 것도 Relayium을 통해 프록시되지 않습니다. 그것이 이 모드의 요점입니다.

내 서버 두 대를 연결해 직접 전송을 해보세요. 릴레이도, SSH도, 페어링 코드도 필요 없습니다.

CLI 받기

계속 읽기