터널로 게이트웨이 노출
Cloudflare, Tailscale, ngrok, Pinggy, OpenVPN 또는 커스텀 명령을 사용하여 게이트웨이를 인터넷에서 접근 가능하게 만드는 방법을 설명합니다.
기본적으로 Revka 게이트웨이는 127.0.0.1에 바인딩되어 실행 중인 머신에서만 접근할 수 있습니다. 웹훅을 수신하거나, 인터넷을 통해 기기를 페어링하거나, 다른 네트워크에서 대시보드에 접근하려면 퍼블릭 인그레스가 필요합니다. Revka에는 외부 터널 도구(Cloudflare, Tailscale, ngrok, Pinggy, OpenVPN, 또는 직접 지정한 명령)를 래핑하는 내장 터널 레이어가 포함되어 있으며, 데몬과 함께 시작 및 종료됩니다.
이 가이드에서는 게이트웨이를 외부에서 접근할 수 있는 두 가지 방법(allow_public_bind를 통한 신뢰할 수 있는 LAN 접근과 퍼블릭 인터넷을 위한 터널)을 설명하고, 각 프로바이더 설정 방법을 안내합니다. 게이트웨이 서버 자체에 대한 내용은 대시보드 실행과 revka 게이트웨이, 데몬 & 서비스를 참조하세요.
외부 접근을 위한 두 가지 방법
섹션 제목: “외부 접근을 위한 두 가지 방법”게이트웨이는 자체적으로 퍼블릭 인터넷에 노출되지 않습니다. [gateway]와 [tunnel]에서 다음 두 가지 노출 방식 중 하나를 선택합니다.
- 직접 퍼블릭 바인딩 — 리스너를 루프백이 아닌 주소(
0.0.0.0,[::], 또는 LAN IP)에 바인딩합니다. 신뢰할 수 있는 LAN 환경이나 Docker 내부처럼 네트워크 경계가 방화벽으로 보호되는 경우에 사용합니다.allow_public_bind로 제어합니다. - 터널 — 게이트웨이는
127.0.0.1에 유지하고, 터널 프로바이더가 인터넷 facing URL을 게이트웨이로 포워딩합니다. 리스너 자체가 루프백에 유지되므로 Revka를 퍼블릭 인터넷에 노출하는 권장 방법입니다.
두 방법을 함께 사용할 수 있지만, 터널은 localhost로도 충분히 포워딩되므로 대부분의 경우 두 방법을 동시에 사용할 필요는 없습니다.
바인드 주소와 allow_public_bind
섹션 제목: “바인드 주소와 allow_public_bind”리슨 주소는 [gateway].host에서 가져옵니다. 루프백(127.0.0.1, localhost, ::1) 이외의 모든 주소는 퍼블릭 바인딩으로 처리됩니다.
[gateway]host = "127.0.0.1" # default — localhost onlyport = 42617allow_public_bind = false # guard against accidental exposure| 키 | 타입 | 기본값 | 의미 |
|---|---|---|---|
host | string | "127.0.0.1" | 바인드 주소. 0.0.0.0 = 모든 IPv4 인터페이스, [::] = 모든 IPv6 인터페이스. 환경 변수: REVKA_GATEWAY_HOST |
port | int | 42617 | 리슨 포트. 환경 변수: REVKA_GATEWAY_PORT |
allow_public_bind | bool | false | 루프백이 아닌 바인딩을 명시적으로 허용. 환경 변수: REVKA_ALLOW_PUBLIC_BIND |
CLI에서 실행 시마다 호스트와 포트를 재정의할 수 있습니다.
revka daemon --host 127.0.0.1 # localhost only (default)revka daemon --host 0.0.0.0 # all interfaces, LAN accessrevka daemon --port 9090 # override the gateway port터널 설정이나 allow_public_bind = true 없이 퍼블릭 주소에서 게이트웨이를 시작하면 Revka는 시작 시 경고 로그를 출력하며 세 가지 안전한 옵션을 안내합니다. 127.0.0.1을 유지하거나, 터널을 구성하거나, allow_public_bind = true를 설정하여 노출을 명시적으로 허용하고 경고를 숨기는 방법입니다. 터널을 구성하면 경고가 자동으로 사라집니다.
[tunnel] 섹션
섹션 제목: “[tunnel] 섹션”터널은 외부 도구를 래핑합니다. Revka는 바이너리(또는 Pinggy의 경우 SSH 세션)를 실행하고, 출력에서 퍼블릭 URL을 감시하며 출력 후, 데몬이 종료될 때 깔끔하게 종료합니다. tunnel.provider로 프로바이더를 선택하고 해당 프로바이더의 하위 섹션을 설정합니다.
[tunnel]provider = "cloudflare" # none | cloudflare | tailscale | ngrok | openvpn | pinggy | custom
[tunnel.cloudflare]token = "eyJhIjoiMTI..."| 필드 | 타입 | 기본값 | 의미 |
|---|---|---|---|
tunnel.provider | string | "none" | 시작할 프로바이더. 빈 문자열은 "none"과 동일합니다. |
프로바이더 값은 대소문자를 구분하지 않으므로 "CloudFlare"와 같은 기존 PascalCase 설정도 동작합니다. 단, 새 설정에서는 소문자 형식을 사용하세요. provider가 "none" 이외의 값이면 해당 하위 섹션이 존재하고 필수 필드가 설정되어 있어야 합니다. 그렇지 않으면 데몬이 tunnel.provider = "ngrok" but [tunnel.ngrok] section is missing과 같은 오류와 함께 시작을 거부합니다.
일반적인 프로바이더(Cloudflare, Tailscale, ngrok, Custom)는 revka onboard 5단계에서 대화형으로 설정할 수 있습니다. OpenVPN과 Pinggy는 config.toml을 직접 편집하여 설정합니다.
프로바이더
섹션 제목: “프로바이더”cloudflared 바이너리와 Cloudflare Zero Trust 터널 토큰을 래핑합니다. 시작 시 Revka는 로컬 포트에 대해 cloudflared tunnel --no-autoupdate run을 실행하고 stderr에서 퍼블릭 URL을 읽습니다(최대 30초 대기).
[tunnel]provider = "cloudflare"
[tunnel.cloudflare]token = "eyJhIjoiMTI..." # required — from the Zero Trust dashboard| 필드 | 타입 | 필수 여부 | 의미 |
|---|---|---|---|
token | string | 필수 | Zero Trust 대시보드에서 발급한 Cloudflare 터널 토큰 |
cloudflared가 설치되어 있고 PATH에 등록되어 있어야 합니다. cloudflared는 URL을 stdout이 아닌 stderr로 출력합니다.
tailscale CLI를 래핑합니다. 기본 모드는 tailscale serve로, 테일넷의 기기에만 게이트웨이를 노출합니다. funnel = true로 설정하면 tailscale funnel을 사용하여 퍼블릭 인터넷에 공개합니다. 호스트명을 생략하면 tailscale status --json에서 자동으로 감지합니다.
[tunnel]provider = "tailscale"
[tunnel.tailscale]funnel = false # false = serve (tailnet only); true = funnel (public)hostname = "" # auto-detected if empty| 필드 | 타입 | 기본값 | 의미 |
|---|---|---|---|
funnel | bool | false | false = 테일넷 전용 serve, true = 퍼블릭 funnel |
hostname | string | 자동 감지 | 테일넷 호스트명; 비어 있으면 tailscale status에서 감지 |
tailscale이 설치되어 있고 인증(tailscale up)이 완료되어야 합니다. Funnel 모드는 계정에서 Tailscale Funnel이 활성화되어 있어야 합니다. [tunnel.tailscale] 섹션은 선택 사항이며, 생략하면 위의 기본값이 사용됩니다.
ngrok CLI를 래핑합니다. Revka는 ngrok config add-authtoken으로 인증 토큰을 등록하고, 터널을 시작한 뒤 ngrok의 logfmt 출력에서 퍼블릭 URL을 파싱합니다(15초 대기).
[tunnel]provider = "ngrok"
[tunnel.ngrok]auth_token = "2abc..." # requireddomain = "my-custom.ngrok.app" # optional, paid plan| 필드 | 타입 | 필수 여부 | 의미 |
|---|---|---|---|
auth_token | string | 필수 | ngrok 인증 토큰 |
domain | string | 선택 | 예약된 커스텀 도메인(유료 ngrok 플랜 필요) |
ngrok이 설치되어 있어야 합니다. 무료 플랜에서는 재시작마다 변경되는 자동 생성된 *.ngrok-free.app 주소가 사용됩니다. 안정적인 URL을 원하면 도메인을 예약하세요.
시스템 ssh 명령을 통한 SSH 역방향 포트 포워딩을 사용합니다. 별도의 바이너리 설치가 필요 없습니다. 무료 플랜은 free.pinggy.io에 연결하며, Pro 토큰을 제공하면 pro.pinggy.io로 전환됩니다. Revka는 SSH 출력에서 *.pinggy.link URL을 추출합니다(15초 대기).
[tunnel]provider = "pinggy"
[tunnel.pinggy]token = "your-pro-token" # optional — omit for the free tierregion = "us" # optional regional prefix, e.g. "us", "eu"| 필드 | 타입 | 필수 여부 | 의미 |
|---|---|---|---|
token | string | 선택 | Pinggy Pro 토큰; 무료 플랜을 사용하려면 생략 |
region | string | 선택 | 지역 엔드포인트 프리픽스 |
ssh만 있으면 됩니다. 세션은 포트 443으로 연결되어 대부분의 방화벽을 통과하며, 첫 연결 시 호스트 키를 자동으로 수락합니다(StrictHostKeyChecking=accept-new). 무료 플랜의 터널은 임시적입니다.
.ovpn 클라이언트 프로파일에 대해 openvpn 바이너리를 래핑합니다. Revka는 OpenVPN의 Initialization Sequence Completed 마커를 기다린 후, advertise_address에 설정한 주소를 퍼블릭 URL로 보고합니다. HTTP 터널과 달리 OpenVPN은 호스트명을 자동 감지하지 않습니다.
[tunnel]provider = "openvpn"
[tunnel.openvpn]config_file = "/etc/openvpn/client.ovpn" # requiredauth_file = "/etc/openvpn/auth.txt" # optional, for --auth-user-passadvertise_address = "10.8.0.2:42617" # optional, reported as the public URLconnect_timeout_secs = 30 # default 30extra_args = ["--verb", "3"] # optional extra openvpn flags| 필드 | 타입 | 필수 여부 | 의미 |
|---|---|---|---|
config_file | string | 필수 | .ovpn 클라이언트 프로파일 경로 |
auth_file | string | 선택 | --auth-user-pass용 자격증명 파일 |
advertise_address | string | 선택 | 퍼블릭 URL로 보고할 주소; 생략 시 로컬 게이트웨이 주소로 대체 |
connect_timeout_secs | int | 선택 (30) | 연결 대기 시간 |
extra_args | array | 선택 | openvpn에 전달할 추가 플래그 |
openvpn이 설치되어 있어야 하며, 일반적으로 tun/tap 디바이스 생성을 위해 root/관리자 권한이 필요합니다.
직접 터널을 가져올 수 있습니다. Revka는 임의의 명령을 실행하면서 {host}와 {port} 플레이스홀더를 치환하고, 선택적으로 stdout에서 퍼블릭 URL을 추출합니다. URL을 찾지 못하면 http://{host}:{port}로 대체합니다.
[tunnel]provider = "custom"
[tunnel.custom]start_command = "bore local {port} --to bore.pub" # requiredhealth_url = "https://bore.pub/health" # optional liveness probeurl_pattern = "bore.pub" # optional URL-extraction hint다른 예시:
start_command = "ssh -R 80:localhost:{port} serveo.net"start_command = "frp -c /etc/frp/frpc.ini"| 필드 | 타입 | 필수 여부 | 의미 |
|---|---|---|---|
start_command | string | 필수 | 실행할 명령; {host}와 {port}가 치환됨 |
health_url | string | 선택 | 헬스 체크에 폴링할 HTTP URL (5초 타임아웃) |
url_pattern | string | 선택 | stdout에서 퍼블릭 URL 줄을 찾는 데 사용하는 부분 문자열 |
명령은 공백으로 분리되며 셸 확장은 지원하지 않습니다. URL 추출은 url_pattern과 일치하는 줄에서 http:// 또는 https://를 찾습니다. health_url이 설정되지 않은 경우 헬스 체크는 프로세스 활성 여부 확인으로 대체됩니다.
기본값입니다. 터널이 시작되지 않으며, 게이트웨이는 http://{host}:{port}에서만 접근 가능합니다. 다른 방법으로 게이트웨이를 노출하거나 로컬에서만 사용하는 경우에 이 값을 설정하거나 [tunnel]을 생략하세요.
[tunnel]provider = "none" # or omit the [tunnel] section entirely터널 설정하기
섹션 제목: “터널 설정하기”-
프로바이더의 도구를 설치합니다. Cloudflare는
cloudflared, Tailscale은tailscale, ngrok은ngrok, OpenVPN은openvpn이 필요합니다. Pinggy와 Custom(SSH 기반 명령 사용 시)은ssh만 있으면 됩니다. -
[tunnel]섹션을 추가합니다. 위의 예시를 참고하여~/.revka/config.toml에 프로바이더와 자격증명을 설정합니다. -
게이트웨이를 localhost에 유지합니다.
[gateway].host = "127.0.0.1"을 그대로 두세요. 터널이 로컬 포트로 포워딩하므로allow_public_bind를 설정할 필요가 없습니다. -
데몬을 시작합니다. Revka가 게이트웨이와 함께 터널을 실행하고 퍼블릭 URL을 출력합니다.
Terminal window revka daemon# 🔗 Starting cloudflare tunnel...# 🌐 Public URL: https://your-tunnel.example.com -
퍼블릭 URL로 페어링합니다. 출력된 URL을 열고 페어링을 완료합니다. 6자리 코드는 원격 브라우저가 아닌 터미널에 표시됩니다. 원격 페어링 플로우에 대한 자세한 내용은 대시보드 실행을 참조하세요.
확인 및 트러블슈팅
섹션 제목: “확인 및 트러블슈팅”먼저 게이트웨이가 로컬에서 응답하는지 확인하세요. 헬스 엔드포인트는 인증이 필요 없고 민감한 정보를 노출하지 않습니다.
curl http://127.0.0.1:42617/health# {"status":"ok","paired":true,"require_pairing":true,...}그런 다음 터널 URL을 통해 동일한 경로에 접근해 보세요. 로컬 확인은 성공하지만 터널이 동작하지 않는 경우:
- 데몬이 섹션 누락 오류와 함께 종료됩니다.
provider가 설정되어 있지만 해당[tunnel.<provider>]하위 섹션이나token/auth_token/config_file과 같은 필수 필드가 없는 경우입니다. 해당 내용을 추가하세요. - 퍼블릭 URL이 출력되지 않습니다. 프로바이더 도구가
PATH에 없거나 타임아웃(Cloudflare 30초, ngrok/Pinggy 15초) 내에 URL을 출력하지 않은 경우입니다. 도구를 직접 실행하여 동작을 확인한 후 데몬 로그를 확인하세요. - 다른 머신에서 게이트웨이에 접근할 수 없다는 대시보드 메시지가 나타납니다. 터널 없이 루프백에 바인딩된 상태입니다.
[tunnel]섹션을 추가하거나, 신뢰할 수 있는 LAN 환경이라면allow_public_bind = true를 설정하세요.
revka doctor를 실행하여 구조화된 진단 정보를 확인하세요. LAN 바인딩, 리버스 프록시, Raspberry Pi 등 네트워크 배포에 대한 자세한 내용은 네트워크 배포, Raspberry Pi & 프록시를 참조하세요.