LAN에서 HTTPS 부재를 보완하기 위한 SSH 터널 사용

발행: (2026년 6월 7일 PM 12:58 GMT+9)
13 분 소요
원문: Dev.to

출처: Dev.to

여러 대의 머신에서 로컬 모델/앱을 오래 운영해 왔다면, 백엔드 LLM API든 프론트엔드 사이트든, 혹은 다른 어떤 것을 넣었든 모두가 일반 HTTP로 제공되고 있다는 것을 눈치챘을 겁니다. 대부분은 기본적으로 HTTP 전용이며 TLS 옵션은 어디에도 보이지 않습니다. 한 대의 머신에서는 모두 루프백이기 때문에 보통은 괜찮지만, 몇 대의 컴퓨터에 걸쳐 앱을 배포하면(우리 중 일부가 하는 방식), 모든 프롬프트와 응답이 LAN을 통해 평문으로 전송됩니다.

자신의 LAN에서 평문 전송이 큰 문제일까요? 솔직히… 위험도가 낮다고 생각하는 사람도 많습니다. 하지만 손님이 오거나, 다른 사람의 휴대폰, 혹은 무작위 IoT 기기가 같은 네트워크를 공유하게 되면, 프롬프트와 모델 응답이 그대로 노출되는 상황은 생각보다 더 위험할 수 있습니다.

그래서 저는 이 문제를 어떻게 해결했는지 정리해 보았습니다. 가장 직접적인 해결책(인증서)은 로컬 네트워크에서는 번거로워서 많은 사람들이 포기하기 때문입니다. 이 방법은 특히 macOS처럼 launchd를 통해 자동 실행을 보장할 수 있는 환경에서 훨씬 간단합니다.


왜 TLS만 쓰지 않을까

정답은 모든 서비스에 TLS를 적용하고 HTTPS를 전부 사용하도록 하는 것입니다. 물론 가능합니다. 하지만 가정용 네트워크에 섞여 있는 여러 대의 머신을 생각해 보세요.

  • 자체 CA를 만들고 각 호스트마다 인증서를 서명합니다(코드가 인증서를 바로 거부하는 경우를 제외하고).
  • 그 CA를 모든 클라이언트에 설치하고 신뢰하도록 합니다. 모든 브라우저, OS 신뢰 저장소, 그리고 (이게 가장 귀찮은 부분) 자체 신뢰 저장소를 사용하고 시스템 저장소를 무시하는 모든 앱에도 적용해야 합니다. 파이썬·노드 앱 중 상당수가 그렇게 동작합니다.
  • 많은 로컬 LLM 앱은 TLS 옵션을 제공하지 않으므로, nginx나 Caddy 같은 프록시를 앞에 두어 TLS를 적용해야 합니다. 이는 각 머신에 또 다른 구성 요소를 추가하는 것이죠(Caddy 설정이 이 방식을 선택하게 만든 결정적인 이유였습니다).
  • 그 후 머신이 새로 합류하거나 인증서가 만료되면, 다시 CA를 배포해야 합니다.

물론 이 과정이 로켓 과학은 아니지만, 번거롭고 한 번 설정했다고 끝나는 일이 거의 없습니다. 특히 macOS, Windows, Linux, 그리고 휴대폰을 동시에 관리한다면 더욱 그렇습니다. 제가 알기로는 최소 한 대 이상의 플랫폼에서는 반드시 손질이 필요한 부분이 존재합니다.


먼저 고려해야 할 중요한 점들

시작하기 전에 말씀드리자면, 저 역시 아직 완벽하게 구현하지 못했고 현재도 문제점을 해결 중입니다. 따라서 이 방법을 완벽한 솔루션이라고 과대평가하고 싶지는 않습니다. 앞으로 에지 케이스를 찾아서 정리할 예정이지만, 때때로 수동 개입이 필요할 수 있다는 점을 염두에 두세요. 이 방법은 로컬 TLS의 복잡함을 우회하기 위한 저렴하고 쉬운 대안일 뿐입니다.

또 한 가지: 해당 머신에 SSH가 아직 활성화되지 않았다면, 이 전체 과정은 SSH를 켜는 것에 의존합니다. 이는 보안적인 고려사항이 필요합니다. LAN 전체에서 접근 가능한 완전한 로그인 서비스를 제공하게 되는 것이니까요. 아래에 제시된 authorized_keys 제한은 해당 터널 키만 제한할 뿐, 다른 키나 비밀번호 로그인은 그대로 정상 쉘 접근을 허용합니다. 즉, 키 제한은 키 자체를 보호할 뿐 머신 전체를 보호하지는 못합니다.

과도하게 설정할 필요는 없지만, 최소한 누가 접근할 수 있는지 제한하는 것을 고려하세요(예: 실제로 연결이 필요한 머신만 방화벽으로 허용하고, 해당 머신에 고정 IP를 할당). 그리고 OS를 최신 상태로 유지하세요. sshd는 오래된 표적이며 과거에 심각한 버그가 있었으니, 최신 버전을 유지하는 것이 가장 큰 방어입니다.


터널을 한눈에

설정의 핵심은 다음과 같습니다. SSH 로컬 포트 포워딩을 사용하면 자신의 머신에 127.0.0.1:5050 같은 포트를 열 수 있고, 그 포트로 들어오는 모든 트래픽은 암호화된 SSH 연결을 통해 원격 머신으로 전달되어 그 머신의 루프백 서비스와 통신하게 됩니다.

즉, 클라이언트 머신에서 실행 중인 앱은 “같은 컴퓨터의 로컬 HTTP 서비스와 통신한다”고 생각하지만, 실제로는 네트워크 상 다른 박스로 연결된 암호화된 파이프를 통해 데이터를 주고받는 것입니다. SSH가 두 머신 사이의 전송을 암호화하고, 앱은 평소와 같이 localhost에 요청을 보냅니다.


인증

가능하면 인증키를 사용하고, 사용자 이름·비밀번호를 여기저기 넣는 일은 피하세요.

일반 SSH 키는 로그인 후 사용자가 할 수 있는 모든 작업을 허용합니다. 포워딩에만 필요한 권한보다 훨씬 많기 때문에 제한을 두는 것이 좋습니다. 대상 머신의 authorized_keys에 키를 넣을 때 다음과 같이 제한 옵션을 앞에 붙입니다:

restrict,port-forwarding,permitopen="127.0.0.1:5050" ssh-ed25519 AAAA...

대략적인 동작은 다음과 같습니다.

  • restrict : 모든 권한을 차단합니다(쉘, PTY, 에이전트, X11 포워딩 등 전부 비활성).
  • port-forwarding : 포워딩만 허용하도록 다시 켭니다.
  • permitopen : 지정한 루프백 포트만 열 수 있도록 제한합니다.

이렇게 하면 키가 유출되더라도 가장 나쁠 경우 지정한 루프백 포트에만 포워딩을 열 수 있습니다.

제 설정에서는 각 연결마다 전용 ed25519 키를 만들고, 패스프레이즈를 설정한 뒤 OS 키체인이 자동으로 패스프레이즈를 제공하도록 했습니다. 전원 장애가 발생하면 자동화가 중단될 수 있기 때문입니다.

참고: permitopen은 로컬(-L) 포워딩만 제한하고 원격(-R) 포워딩은 제한하지 않습니다. port-forwarding 옵션이 두 종류 모두를 조용히 활성화하기 때문입니다. 기본값인 GatewayPorts no 상태에서는 원격 포워딩이 서버 자체 루프백에만 바인딩되므로 실제로 악용되기 어렵습니다. 더 강력히 제한하고 싶다면 permitlisten 옵션을 사용해 -R 쪽도 제한할 수 있습니다.


예시 설정

아래는 시작점을 잡기 위한 일반적인 설정 예시입니다.

클라이언트(터널을 여는 머신)에서 해야 할 일

  1. 대상 머신에 SSH 서버가 실행 중인지 확인
    macOS에서는 SharingRemote Login을 켭니다. 다른 OS도 각각 토글이 있습니다. 예를 들어 Linux Mint에서는 기본으로 설치되지 않아 직접 설치해야 했습니다. 여기서 한 번 수동으로 ssh 접속을 해두면 대상 머신의 호스트 키가 known_hosts에 저장됩니다. 이 과정을 건너뛰면 자동 터널링 중 “이 호스트를 신뢰하시겠습니까?” 라는 프롬프트에 스크립트가 응답하지 못해 멈출 수 있습니다.

  2. 전용 키 생성

    ssh-keygen -t ed25519 -f ~/.ssh/my_tunnel

    그리고 패스프레이즈를 설정합니다.

  3. 대상 머신에 공개키 설치
    앞서 만든 restrict,port-forwarding,permitopen=... 옵션을 키 앞에 붙여 authorized_keys에 추가합니다. 여기서 permitopen에 지정하는 포트는 포워딩하려는 포트와 일치해야 합니다.

  4. 수동으로 터널이 동작하는지 확인

    ssh -i ~/.ssh/my_tunnel -N -L 5050:127.0.0.1:5050 your-user@target-host

    이 명령은 패스프레이즈 입력을 요구하고, 이후 아무 출력도 없이 대기합니다(-N은 명령 실행 없이 포워딩만 수행). 다른 터미널에서 다음과 같이 테스트합니다:

    curl http://127.0.0.1:5050/v1/models

    HTTP 응답이 돌아오면 터널이 정상 동작하는 것입니다.

    만약 curl이 계속 대기하거나 거부된다면, 대상 머신의 sshd가 포워딩을 허용하고 있는지 확인하세요. AllowTcpForwarding 기본값은 yes이지만, 보안 강화된 시스템에서는 no로 설정될 수 있습니다. 이 경우 포워딩이 조용히 거부되어 원인을 찾기 어려울 수 있습니다.

  5. 수동 테스트가 성공하면 자동화
    이제 터널을 영구적으로 실행하도록 설정하면 됩니다.


0 조회
Back to Blog

관련 글

더 보기 »