Cloudflare Tunnel로 로컬 서버를 안전하게 공개하기
로컬에서 개발 중인 웹 서버를 외부에 공개해야 할 때 어떤 방법을 쓰시나요? ngrok같은 터널링 도구를 많이 사용하는데, 무료 플랜에서는 임시 URL이 매번 바뀌고 커스텀 도메인도 쓸 수 없어서 불편할 때가 있습니다.
Cloudflare Tunnel은 Cloudflare에서 제공하는 무료 터널링 서비스입니다. 내 컴퓨터에서 Cloudflare 네트워크까지 암호화된 아웃바운드 터널을 만들어주기 때문에 방화벽 포트를 열거나 공유기 설정을 건드릴 필요가 없어요. 게다가 자기 소유의 도메인을 연결할 수 있고, Cloudflare의 DDoS 보호와 WAF까지 자동으로 적용됩니다.
이번 글에서는 Cloudflare Tunnel의 동작 원리부터 cloudflared CLI 설치, 빠른 터널과 영구 터널 설정, 그리고 시스템 서비스로 등록하는 방법까지 살펴보겠습니다.
Cloudflare Tunnel이란?
Cloudflare Tunnel은 내 서버와 Cloudflare 엣지 네트워크 사이에 암호화된 터널을 만들어주는 서비스입니다. 핵심은 아웃바운드 연결만 사용한다는 점이에요.
일반적으로 외부에서 로컬 서버에 접속하려면 방화벽에서 특정 포트를 열어야 합니다. 포트 포워딩을 설정하거나, 클라우드 서버에 배포하거나, 아니면 ngrok 같은 도구로 터널을 뚫거나요. 이 방법들은 각각 보안 위험이 있거나, 번거롭거나, 제약이 많습니다.
Cloudflare Tunnel은 접근 방식이 다릅니다. 내 서버에서 Cloudflare 방향으로 나가는 연결만 맺고, 외부에서 들어오는 연결은 Cloudflare가 대신 받아서 터널을 통해 전달합니다. 서버 쪽에서 인바운드 포트를 전혀 열지 않아도 되니까 보안이 훨씬 강화되죠.
그러면 실제로 트래픽이 어떻게 흘러가는지 정리해보겠습니다.
- 내 서버에서
cloudflared라는 데몬이 Cloudflare 엣지까지 아웃바운드 터널을 생성합니다. - 사용자가
my-app.example.com같은 도메인으로 접속하면 Cloudflare가 요청을 받습니다. - Cloudflare가 해당 요청을 터널을 통해 내 서버로 전달합니다.
- 서버가 응답하면 같은 터널을 거쳐 사용자에게 돌아갑니다.
이 과정에서 사용자는 내 서버의 실제 IP 주소를 알 수 없고, 서버는 외부에 어떤 포트도 노출하지 않습니다.
cloudflared 설치
Cloudflare Tunnel을 사용하려면 cloudflared라는 CLI 도구를 설치해야 합니다.
이 도구가 터널을 생성하고 관리하는 역할을 합니다.
macOS에서는 Homebrew로 간단하게 설치할 수 있어요.
brew install cloudflared
Linux에서는 배포판에 따라 패키지 매니저로 설치합니다.
# Debian/Ubuntu
curl -L --output cloudflared.deb https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb
sudo dpkg -i cloudflared.deb
# RHEL/CentOS
curl -L --output cloudflared.rpm https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-x86_64.rpm
sudo rpm -i cloudflared.rpm
Windows에서는 GitHub 릴리스 페이지에서 .msi 파일을 다운로드하거나, winget을 사용할 수 있습니다.
winget install --id Cloudflare.cloudflared
설치가 완료되면 버전을 확인해봅시다.
cloudflared --version
cloudflared version 2025.2.1 (built 2025-02-10-1015 UTC)
빠른 터널 (Quick Tunnel)
가장 간편한 사용법은 계정 없이 바로 쓸 수 있는 빠른 터널입니다. 로컬에서 8080 포트로 웹 서버가 실행 중이라면 이렇게 한 줄만 입력하면 됩니다.
cloudflared tunnel --url http://localhost:8080
2025-02-15T10:30:00Z INF Requesting new quick Tunnel on trycloudflare.com...
2025-02-15T10:30:01Z INF +--------------------------------------------------------------------------------------------+
2025-02-15T10:30:01Z INF | Your quick Tunnel has been created! Visit it at (it may take some time to be reachable): |
2025-02-15T10:30:01Z INF | https://random-words-here.trycloudflare.com |
2025-02-15T10:30:01Z INF +--------------------------------------------------------------------------------------------+
https://random-words-here.trycloudflare.com 같은 임시 URL이 생성되고, 이 주소로 외부에서 내 로컬 서버에 접속할 수 있습니다.
Cloudflare 계정도 필요 없고 인증 토큰 설정도 없어서 정말 빠르게 시작할 수 있어요.
다만 빠른 터널에는 몇 가지 제한이 있습니다.
URL이 매번 바뀌고, 커스텀 도메인을 연결할 수 없고, cloudflared 프로세스를 종료하면 터널도 사라집니다.
데모나 임시 테스트 용도로는 충분하지만, 지속적으로 사용하려면 영구 터널을 설정하는 게 좋습니다.
Cloudflare 로그인
영구 터널을 만들려면 먼저 Cloudflare 계정에 로그인해야 합니다.
cloudflared tunnel login
이 명령어를 실행하면 브라우저가 열리면서 Cloudflare 로그인 페이지로 이동합니다. 로그인하고 터널에 사용할 도메인을 선택하면 인증서가 자동으로 다운로드됩니다.
Please open the following URL and log in with your Cloudflare account:
https://dash.cloudflare.com/argotunnel?aud=&callback=https%3A%2F...
You have successfully logged in.
If you wish to copy your credentials to a server, they have been saved to:
/Users/dale/.cloudflared/cert.pem
인증서는 ~/.cloudflared/cert.pem에 저장되며, 이후 터널 생성과 관리에 사용됩니다.
이 인증서는 한 번만 발급받으면 되고, 여러 터널에서 공유할 수 있습니다.
영구 터널 만들기
이제 본격적으로 영구 터널을 만들어봅시다. 터널 이름은 자유롭게 지을 수 있습니다.
cloudflared tunnel create my-tunnel
Tunnel credentials written to /Users/dale/.cloudflared/a1b2c3d4-5678-90ab-cdef-1234567890ab.json
Created tunnel my-tunnel with id a1b2c3d4-5678-90ab-cdef-1234567890ab
터널이 생성되면 고유한 UUID가 부여되고, 해당 터널의 자격 증명 파일이 ~/.cloudflared/ 디렉토리에 JSON 형식으로 저장됩니다.
이 파일은 터널을 실행할 때 인증에 사용되므로 안전하게 보관해야 합니다.
생성된 터널 목록은 다음 명령어로 확인할 수 있어요.
cloudflared tunnel list
ID NAME CREATED CONNECTIONS
a1b2c3d4-5678-90ab-cdef-1234567890ab my-tunnel 2025-02-15T10:45:00Z
DNS 레코드 연결
터널을 만들었으면 도메인의 DNS 레코드를 터널에 연결해야 합니다. 이렇게 하면 해당 도메인으로 들어오는 요청이 터널을 통해 내 서버로 전달됩니다.
cloudflared tunnel route dns my-tunnel my-app.example.com
INF Added CNAME my-app.example.com which will route to this tunnel tunnelID=a1b2c3d4-5678-90ab-cdef-1234567890ab
이 명령어는 Cloudflare DNS에 CNAME 레코드를 자동으로 추가합니다.
my-app.example.com이 터널의 UUID를 가리키는 a1b2c3d4-5678-90ab-cdef-1234567890ab.cfargotunnel.com으로 연결되는 거예요.
서브도메인뿐 아니라 루트 도메인(example.com)도 연결할 수 있고, 하나의 터널에 여러 도메인을 연결하는 것도 가능합니다.
설정 파일 작성
터널을 실행할 때마다 옵션을 일일이 지정하는 건 번거롭습니다. 설정 파일을 만들어두면 편리하게 관리할 수 있어요.
~/.cloudflared/config.yml 파일을 다음과 같이 작성합니다.
tunnel: a1b2c3d4-5678-90ab-cdef-1234567890ab
credentials-file: /Users/dale/.cloudflared/a1b2c3d4-5678-90ab-cdef-1234567890ab.json
ingress:
- hostname: my-app.example.com
service: http://localhost:8080
- service: http_status:404
tunnel에는 터널 UUID를, credentials-file에는 터널 자격 증명 파일 경로를 지정합니다.
ingress 섹션이 핵심인데요, 어떤 호스트명으로 들어오는 요청을 어디로 보낼지 라우팅 규칙을 정의합니다.
마지막 규칙은 반드시 hostname 없이 기본 응답을 지정해야 합니다.
여기서는 매칭되지 않는 요청에 404를 반환하도록 설정했어요.
여러 서비스를 하나의 터널로 묶는 것도 가능합니다.
tunnel: a1b2c3d4-5678-90ab-cdef-1234567890ab
credentials-file: /Users/dale/.cloudflared/a1b2c3d4-5678-90ab-cdef-1234567890ab.json
ingress:
- hostname: app.example.com
service: http://localhost:3000
- hostname: api.example.com
service: http://localhost:8080
- hostname: grafana.example.com
service: http://localhost:3001
- service: http_status:404
이런 식으로 하나의 터널로 여러 서브도메인을 각각 다른 로컬 서비스에 연결할 수 있습니다.
터널 실행
설정 파일을 작성했으면 터널을 실행합니다.
cloudflared tunnel run my-tunnel
2025-02-15T11:00:00Z INF Starting tunnel tunnelID=a1b2c3d4-5678-90ab-cdef-1234567890ab
2025-02-15T11:00:00Z INF Version 2025.2.1
2025-02-15T11:00:00Z INF ICMP proxy will use 192.168.1.100 as source for IPv4
2025-02-15T11:00:01Z INF Connection registered connIndex=0 connection=abc123 location=NRT
2025-02-15T11:00:01Z INF Connection registered connIndex=1 connection=def456 location=KIX
2025-02-15T11:00:02Z INF Connection registered connIndex=2 connection=ghi789 location=NRT
2025-02-15T11:00:02Z INF Connection registered connIndex=3 connection=jkl012 location=KIX
로그를 보면 Cloudflare 엣지 로케이션(NRT는 도쿄, KIX는 오사카)에 4개의 연결이 생성된 걸 확인할 수 있습니다.
기본적으로 cloudflared는 가장 가까운 두 곳의 데이터 센터에 각각 2개씩 총 4개의 연결을 유지해서 안정성을 높입니다.
이제 브라우저에서 https://my-app.example.com으로 접속하면 로컬의 8080 포트로 실행 중인 서버에 연결됩니다.
SSL 인증서도 Cloudflare가 자동으로 처리해주기 때문에 별도로 설정할 게 없어요.
시스템 서비스로 등록
터미널을 닫으면 터널도 같이 종료되겠죠. 서버를 재시작해도 터널이 자동으로 실행되게 하려면 시스템 서비스로 등록하는 게 좋습니다.
Linux에서는 다음 명령어로 systemd 서비스를 설치할 수 있어요.
sudo cloudflared service install
이 명령어는 ~/.cloudflared/config.yml 파일을 /etc/cloudflared/config.yml로 복사하고, systemd 유닛 파일을 생성합니다.
서비스가 설치되면 다음과 같이 관리할 수 있습니다.
# 서비스 시작
sudo systemctl start cloudflared
# 서비스 상태 확인
sudo systemctl status cloudflared
# 부팅 시 자동 시작 설정
sudo systemctl enable cloudflared
macOS에서는 launchd 서비스로 등록됩니다.
sudo cloudflared service install
# 서비스 시작
sudo launchctl start com.cloudflare.cloudflared
# 서비스 상태 확인
sudo launchctl list | grep cloudflare
서비스를 제거하고 싶을 때는 uninstall 명령어를 사용합니다.
sudo cloudflared service uninstall
ngrok과 비교
ngrok도 로컬 서버를 외부에 공개하는 대표적인 도구인데요, Cloudflare Tunnel과는 성격이 좀 다릅니다.
ngrok은 빠른 시작에 최적화되어 있어요. 명령어 하나로 즉시 터널이 열리고 공개 URL을 받을 수 있습니다. 웹훅 테스트나 짧은 데모에는 ngrok이 더 간편합니다. 다만 무료 플랜에서는 URL이 매번 바뀌고, 커스텀 도메인을 사용하려면 유료 플랜이 필요합니다.
Cloudflare Tunnel은 무료로 커스텀 도메인을 연결할 수 있고, DDoS 방어와 WAF가 기본 제공됩니다. 시스템 서비스로 등록하면 서버 재시작 후에도 자동으로 터널이 복구되어서 상시 운영에 적합합니다. 단, 초기 설정이 ngrok보다는 단계가 많고, Cloudflare에 도메인이 등록되어 있어야 합니다.
정리하면 일시적인 테스트에는 ngrok이, 도메인을 연결한 지속적인 서비스 운영에는 Cloudflare Tunnel이 적합합니다. 물론 Cloudflare Tunnel의 빠른 터널 기능을 쓰면 ngrok처럼 간편하게 임시 URL을 받을 수도 있으니 상황에 맞게 선택하면 됩니다.
마치며
Cloudflare Tunnel은 로컬 서버를 외부에 안전하게 공개할 수 있는 강력한 도구입니다. 인바운드 포트를 열지 않아도 되니 보안 측면에서 큰 장점이 있고, 무료로 커스텀 도메인과 SSL까지 제공되는 점이 매력적입니다.
빠른 터널로 간단히 시작해보고, 지속적으로 사용할 서비스가 있다면 영구 터널과 시스템 서비스 등록까지 진행해보세요. 홈 서버나 NAS를 외부에서 접속하거나, 개발 중인 웹 서비스를 안정적으로 공유하는 데 유용하게 쓸 수 있을 거예요.
좀 더 깊이 알고 싶다면 Cloudflare Tunnel 공식 문서를 참고해보세요. 여러 기기를 하나의 사설 네트워크로 연결하는 데 관심이 있다면 Tailscale 활용법도 함께 살펴보시면 좋겠습니다.
This work is licensed under
CC BY 4.0