글로벌 테크 허브시장 · 기술 · 실전 정보
개발2026.09.28

공유기 포트포워딩 없이 집 서버로 웹사이트 열기: Cloudflare Tunnel 실사용기

집에 있는 PC 한 대에 Hyper-V로 우분투 가상머신을 올리고, 그 안에서 워드프레스와 몇 개의 웹 서비스를 돌리고 있습니다. 처음 부딪힌 문제는 단순했습니다. 밖에서 이 서버에 어떻게 들어오게 하느냐였습니다.

보통은 공유기에서 80/443 포트를 열고, 유동 IP 대응용 DDNS를 붙이는 방법을 떠올립니다. 저도 처음엔 그렇게 하려다 그만뒀습니다. 이유는 세 가지였습니다.

  • 통신사 공유기 위에 개인 공유기가 한 겹 더 있어서, 포트포워딩을 두 번 해야 했습니다.
  • 집 공인 IP가 그대로 DNS에 노출됩니다. 서버를 한 번이라도 운영해 봤다면 로그에 찍히는 스캐너 트래픽이 어느 정도인지 아실 겁니다.
  • 가정용 회선은 80번 포트를 막는 경우가 있고, 인증서 갱신도 따로 챙겨야 합니다.

그래서 선택한 게 Cloudflare Tunnel입니다. 한 문장으로 말하면, 서버가 Cloudflare 쪽으로 먼저 연결을 걸어두고, 방문자 요청은 그 연결을 거꾸로 타고 들어오는 방식입니다. 서버는 바깥으로 나가는 연결만 하기 때문에 공유기 설정을 전혀 건드리지 않아도 됩니다.

실제로 구성한 모습

제 구성은 이렇습니다. 가상머신 안에서 docker compose로 MariaDB, 워드프레스, nginx를 띄우고, nginx가 80번 포트에서 도메인별로 요청을 나눕니다. 그리고 같은 가상머신에 cloudflared를 systemd 서비스로 설치했습니다.

구성요소 역할 외부 노출
cloudflared (systemd) Cloudflare와 아웃바운드 연결 유지 없음 (나가는 연결만)
nginx (docker) 도메인별로 요청 분기 localhost:80만
WordPress + MariaDB (docker) 실제 사이트 없음 (내부 네트워크)

터널 설정 파일의 핵심은 ingress 규칙 몇 줄입니다.

tunnel: <터널 ID>
credentials-file: /etc/cloudflared/<터널 ID>.json
ingress:
  - hostname: example.com
    service: http://localhost:80
  - hostname: www.example.com
    service: http://localhost:80
  - service: http_status:404

마지막 줄의 http_status:404는 꼭 넣어야 합니다. 어떤 hostname에도 안 걸린 요청을 처리할 기본 규칙이 없으면 cloudflared가 설정 검증에서 실패합니다.

DNS는 도메인을 <터널 ID>.cfargotunnel.com으로 가리키는 CNAME 하나면 됩니다. 프록시(주황색 구름)를 켜두면 HTTPS 인증서도 Cloudflare가 알아서 붙여줍니다. 서버 쪽 nginx는 평문 HTTP만 받아도 됩니다.

해보고 나서 알게 된 것들

1. 워드프레스 리다이렉트 루프는 미리 막아두자

이 구성에서 가장 흔하게 걸린다는 문제라 설치할 때 미리 설정해뒀습니다. 방문자는 HTTPS로 들어오는데, 터널을 지나 nginx에 닿을 때는 HTTP입니다. 워드프레스는 사이트 주소가 https로 설정돼 있는데 요청이 http로 들어오니 계속 https로 보내고, 그게 또 http로 도착하는 루프가 생깁니다. nginx에서 X-Forwarded-Proto 헤더를 넘겨주고, wp-config.php에서 그 헤더가 https면 $_SERVER['HTTPS']='on'으로 맞춰주면 해결됩니다.

2. 서브도메인 하나를 막으면 다른 서비스까지 멈출 수 있다

한동안 와일드카드 서브도메인을 한꺼번에 403으로 막아둔 적이 있습니다. nginx는 더 구체적인 server_name을 우선하기 때문에, 전용 서버 블록이 있는 서브도메인은 영향을 받지 않았습니다. 정작 문제는 다른 데서 터졌습니다. nginx 설정에 적어둔 upstream 컨테이너 하나가 꺼져 있었는데, 그것 때문에 reload 자체가 실패했습니다. nginx는 설정을 읽을 때 upstream 이름을 해석하는데, 컨테이너가 없으면 이름을 못 찾습니다. 그 뒤로는 reload 전에 docker ps로 전체 컨테이너 상태부터 확인합니다.

3. 이메일 주소가 멋대로 바뀌어 보인다

문의 페이지에 이메일 링크를 넣었는데, 실제 페이지 소스를 보면 __cf_email__이라는 이상한 코드로 바뀌어 있었습니다. Cloudflare의 “Email Address Obfuscation” 기능이 스팸 수집을 막으려고 자동으로 이메일을 가리는 겁니다. 사람이 브라우저로 보면 자바스크립트가 다시 풀어주니 정상으로 보이지만, 원본 HTML에서는 이메일이 사라집니다. 워드프레스 쪽에서 아무리 고쳐도 소용없고, Cloudflare 대시보드의 Scrape Shield 메뉴에서 꺼야 합니다.

4. 예전에 만든 터널이 남아 있을 수 있다

Cloudflare 계정을 열어보니 제가 기억하지 못하는 터널이 두 개 더 있었습니다. 둘 다 연결이 끊긴 상태였고, DNS에는 그 터널을 가리키는 레코드가 남아 있었습니다. 쓰지 않는 터널과 DNS 레코드는 정리해두는 게 좋습니다. 나중에 무엇이 살아 있는 건지 헷갈립니다.

누구에게 맞는 방법인가

한 달 넘게 운영해 보니 장단점이 분명합니다.

포트포워딩 + DDNS Cloudflare Tunnel
공유기 설정 필요 (이중 공유기면 두 번) 불필요
집 IP 노출 노출됨 숨겨짐
HTTPS 인증서 직접 발급·갱신 자동
의존성 없음 Cloudflare에 의존
비HTTP 서비스 (게임서버 등) 자유로움 제약 있음

웹사이트나 관리용 대시보드처럼 HTTP로 여는 서비스라면 터널이 훨씬 편하고 안전합니다. 반대로 UDP를 쓰는 게임 서버를 열어야 하거나 Cloudflare에 트래픽을 맡기기 싫다면 전통적인 방식이 낫습니다. 저는 SSH 같은 관리 접속은 아예 외부에 열지 않고, 집 안 내부망에서만 접속하게 해뒀습니다. 이렇게 역할을 나누면 바깥에서 공격받을 수 있는 면이 거의 남지 않습니다.

터널 설정 자체는 공식 문서(Cloudflare Tunnel 문서)를 따라가면 30분이면 끝납니다. 시간이 드는 건 위에 적은 것처럼 그 뒤에 하나씩 드러나는 작은 문제들입니다.