Cloudflare Tunnel을 통해 홈랩 노출하기
Source: Dev.to
저는 자체 호스팅을 좋아합니다. 저는 직접 서버에서 블로그, 대시보드, 그리고 다양한 실험을 운영합니다. 하지만 제가 싫어하는 것은 포트 포워딩, ISP NAT, 동적 IP, 그리고 라우터를 전체 인터넷에 노출시키는 일입니다.
다행히도 Cloudflare는 Cloudflare Tunnel이라는 해결책을 제공합니다. 이 서비스를 사용하면 라우터에서 단 하나의 인바운드 포트도 열지 않고 서비스를 공개할 수 있습니다. 이 글은 제가 실제 운영 환경에서 이를 어떻게 사용하는지에 대한 내용입니다.
“전통적인” 셀프‑호스팅의 문제점
클래식한 접근 방식은 다음과 같습니다:
flowchart LR
Internet --> Router
Router --> Server
즉:
- 라우터에서 포트 열기
- 방화벽 설정을 신뢰하기
- IP가 변하지 않기를 기대하기
- 소프트 DDoS 대상이 되기
홈랩이나 개인 서버에 이 방식은 재앙을 부르는 레시피이며, 확장 가능한 솔루션이 아닙니다.
Cloudflare Tunnel 접근 방식
Cloudflare Tunnel을 사용하면 흐름이 바뀝니다. 인터넷이 내 네트워크로 들어오는 대신, 내 서버가 외부로 연결합니다.
flowchart LR
User --> Cloudflare
Cloudflare --> Tunnel
Tunnel --> Server
이제 내 서버는 Cloudflare에만 아웃바운드 연결을 하고, Cloudflare가 공개 엣지 역할을 합니다. 이는 훨씬 더 안전합니다: 열려 있는 포트가 없고 공용 IP도 필요 없으며, 전체 위험 카테고리를 제거합니다.
What Actually Runs on My Server?
내 서버에서는 cloudflared 라는 작은 데몬을 실행합니다.
flowchart TB
cloudflared --> CloudflareEdge
CloudflareEdge --> LocalService1
CloudflareEdge --> LocalService2
cloudflared는 다음을 수행합니다:
- Cloudflare에 암호화된 터널을 엽니다
- 내 계정 자격 증명을 사용해 인증합니다
- 트래픽을 내부적으로
localhost로 라우팅합니다
따라서 내 애플리케이션은 공개 인터넷에 직접 접속하지 않습니다.
cloudflared 설치
Linux에서는 cloudflared를 설치하는 데 약 1분 정도 걸립니다:
curl -fsSL https://pkg.cloudflare.com/install.sh | sudo bash
sudo apt install cloudflared
간단한 확인:
cloudflared --version
참고: 대부분의 경우 공식 웹사이트에서 바이너리를 다운로드하여 수동으로 설치하는 것이 더 좋습니다. 이렇게 하면 업데이트를 직접 제어할 수 있습니다.
내 서버 인증하기
서버를 인증하려면 다음을 실행합니다:
cloudflared tunnel login
브라우저 창이 열리며 Cloudflare 계정에 로그인하고, 도메인을 선택한 뒤 연결을 승인하라는 메시지가 표시됩니다. 자격 증명은 향후 터널을 위해 ~/.cloudflared/cert.pem에 로컬로 저장됩니다.
Creating the Tunnel
Create a tunnel with:
cloudflared tunnel create
Cloudflare는 터널에 대한 UUID와 구성 파일을 다운로드할 수 있는 URL을 반환합니다. 해당 파일을 ~/.cloudflared/.json으로 저장합니다. 이 파일은 서버의 신원(identity)입니다.
내 터널 구성 (예시)
구성 파일의 간소화된 버전:
tunnel:
credentials-file: ~/.cloudflared/.json
ingress:
- hostname: blog.example.com
service: http://localhost:8080
- hostname: dashboard.example.com
service: http://localhost:8081
- service: http_status:404
이 설정은 하나의 터널을 생성하여 여러 호스트명을 서버의 서로 다른 서비스로 라우팅하며, 안전한 폴백(http_status:404)을 제공합니다.
트래픽이 엔드‑투‑엔드로 흐르는 방식
전체 그림:
flowchart LR
User --> DNS
DNS --> Cloudflare
Cloudflare --> Tunnel
Tunnel --> ReverseProxy
ReverseProxy --> App
개념적으로:
sequenceDiagram
participant User
participant Cloudflare
participant Tunnel
participant Server
User->>Cloudflare: HTTPS request
Cloudflare->>Tunnel: Forward request
Tunnel->>Server: Local HTTP
Server-->>Tunnel: Response
Tunnel-->>Cloudflare: Encrypted response
Cloudflare-->>User: HTTPS response
외부에서는 일반 HTTPS 연결처럼 동작하지만, 트래픽은 엔드‑투‑엔드로 암호화되고 서버에서는 localhost 트래픽으로 보입니다.
DNS: 수동 레코드 필요 없음
Cloudflare Tunnel은 필요한 DNS 레코드를 자동으로 생성합니다. 도메인을 Cloudflare의 엣지로 가리키는 CNAME을 추가합니다. 실행하세요:
cloudflared tunnel route dns
…그리고 끝입니다! 나머지는 Cloudflare가 처리합니다.
터널을 영구적으로 실행하기
먼저 터널을 테스트합니다:
cloudflared tunnel run
작동하면 시스템 서비스로 설치합니다:
sudo cloudflared service install
sudo systemctl enable cloudflared
sudo systemctl start cloudflared
이제 부팅 시 시작되고, 실패 시 재시작되며, 비‑루트 사용자로 실행됩니다.
인증 추가
프라이빗(관리자 패널, 대시보드) 등 모든 경우에, Cloudflare Access 정책을 추가하여 요청이 터널에 도달하기 전에 인증을 요구합니다. 이를 통해 권한이 있는 사용자만 해당 서비스에 접근할 수 있습니다.
Cloudflare Access
다음과 같은 기능을 제공합니다:
- 서비스에 접근하기 전에 로그인을 요구합니다
- 이메일 또는 신원 제공자를 기준으로 제한합니다
- VPN 없이 내부 도구를 보호합니다
따라서 외부에서는 내 대시보드가 공개된 것처럼 보이지만, 실제로는 인증 뒤에 잠겨 있습니다.
My Production Setup
This is the layout I actually recommend:
flowchart LR
User --> Cloudflare
Cloudflare --> Tunnel
Tunnel --> ReverseProxy
ReverseProxy --> Blog
ReverseProxy --> Dashboard
ReverseProxy --> Admin
Why this works so well?
Cloudflare handles edge security, while my reverse proxy handles routing. The apps stay internal and “dumb,” and there are zero inbound ports.
내가 저지른 흔한 실수들 (당신은 하지 않도록)
- 리버스 프록시를 거치지 않고 앱을 직접 노출하기
- 404 인그레스 규칙을 잊어버리기
- Access 없이 관리자 패널 실행하기
localhost대신 불필요하게 서비스를0.0.0.0에 바인딩하기
대략적인 원칙:
공개용이 아니라면localhost에 두세요. 공개용이라면 Cloudflare Access를 사용하세요.
최종 생각
Cloudflare Tunnel은 강력한 도구이지만 만능 해결책은 아닙니다. 퍼즐의 한 조각에 불과합니다. Cloudflare Access와 같은 다른 보안 조치와 결합하여 서버를 안전하게 유지하세요.
다음과 같은 서비스에는 사용하지 마세요:
- 지연에 민감한 서비스
- 게임 서버
- 전체 네트워크 접근(이 경우 저는 WireGuard를 사용합니다)
하지만 HTTP(S) 애플리케이션에 대해서는 기본으로 사용합니다. 개인 서버와 홈랩에서는 오늘날 실행할 수 있는 가장 깔끔한 설정 중 하나입니다.