보이지 않는 다리 — Cloudflare Tunnel로 우리집 블로그 외부 노출하기

작성자

카테고리:

This post is written in Korean. Most browsers (Chrome, Edge) can translate it automatically — look for a translate icon in the address bar, or right-click the page and choose “Translate to English.”

셀프호스팅 구축기 9편. 도메인 산 다음, 우리집 컴퓨터까지 트래픽을 어떻게 끌어오나.

← 이전 편: 8편 — 24시간 안에 봇이 온다 (보안 P0)
→ 다음 편: 10편 — 블로그에 뭘 쓰면 안 되나 (개인정보 검열)

TL;DR (한 화면 요약)

  • 문제: 우리집 미니PC에 WordPress를 띄웠는데, 산 도메인(sticknstone.org)을 외부에서 어떻게 연결하나
  • 옛 방식: 공유기 포트 열기 → 공인 IP DNS 등록 → SSL 갱신. 5가지 골치
  • 새 방식: Cloudflare Tunnel — 미니PC가 Cloudflare에 outbound로 다리를 미리 놓는다. 공유기 구멍 X, IP 노출 X
  • 도구: cloudflared 데몬을 Docker로 가동. 5분
  • 공짜 보너스: WAF·DDoS·CDN·SSL·트래픽 통계 전부 무료
  • 비용: 0원 (도메인 갱신비 연 $10 별도)

1. 풀고 싶은 문제

블로그(WordPress)는 우리집 미니PC에 띄워뒀다. 도메인(sticknstone.org)도 샀다. 그런데 이 둘이 어떻게 만나야 하나?

평범한 길 (포트포워딩) 5가지 골치

골치 왜
공유기 구멍 443번 포트 외부에 열면 평생 봇 공격
공유 IP 통신사가 매번 바꿈. 자동 갱신 스크립트 필요
우리집 위치 노출 IP만 알면 대략적 동네 추정 가능
SSL 갱신 매 90일마다 Let’s Encrypt 직접
트래픽 폭주 DDoS 맞으면 우리집 인터넷 마비

2. 다른 길: 다리를 놓는다

발상의 전환: 외부에서 우리집으로 들어오는 연결을 받지 말자. 대신 우리집에서 외부 어딘가로 나가는 연결을 미리 만들어두자.

포트포워딩과 Cloudflare Tunnel의 요청 경로 비교 위: 옛 방식. 방문자가 공유기의 열린 포트 443을 거쳐 미니PC 공개 IP로 바로 들어오며, 해커도 같은 포트를 공격할 수 있다. 아래: 새 방식. 방문자는 Cloudflare 서울 DC로 가고, Cloudflare는 미니PC가 먼저 열어둔 outbound 채널로 요청을 cloudflared에 넘긴다. 해커는 Cloudflare에서 차단된다. 옛 방식 — 포트포워딩 방문자 공유기 포트 443 오픈 미니PC 공개 IP WordPress 외부에서 들어오는 연결 열림 노출 해커 공격 새 방식 — Cloudflare Tunnel 방문자 Cloudflare 서울 DC 미니PC cloudflared WordPress 미리 열린 outbound 채널 (미니PC가 먼저 연결) 해커 차단
그림 1. 포트포워딩(위)과 Cloudflare Tunnel(아래)의 요청 경로 — 터널 방식은 공유기 포트를 열지 않는다

핵심: 미니PC가 먼저 손을 뻗는다. 외부 → 우리집 흐름이 아니라, 우리집 → Cloudflare로 outbound 연결을 늘 열어둔다. 방문자 요청은 Cloudflare가 이 채널로 미니PC에 던진다.

호텔 비유

호텔 손님(미니PC)이 친구를 만나고 싶을 때.

  • 평범한 길: 호텔 입구에 자기 방 번호를 크게 써붙임. 친구는 그 번호로 들어옴. 동시에 도둑도 옴.
  • 다리의 길: 호텔 프론트데스크(Cloudflare)에 미리 메모를 남긴다. 내 친구 찾는 사람 있으면 객실로 연결해달라고. 친구는 이름만 대고, 프론트데스크가 안내한다. 방 번호는 외부 노출 X. 의심스러운 사람은 1차로 거른다.

3. 트래픽 흐름 — 방문자가 도메인 칠 때

방문자가 도메인을 칠 때의 트래픽 흐름 방문자 브라우저가 sticknstone.org에 GET 요청을 보내면 Cloudflare 서울 DC가 WAF·DDoS 1차 필터를 거친 뒤 미리 열린 outbound 채널로 미니PC의 cloudflared에 넘긴다. cloudflared는 localhost:8090의 WordPress 컨테이너에 전달하고, HTML 응답은 같은 채널을 거꾸로 타고 Cloudflare로 돌아가 SSL 종단·CDN 캐시와 함께 방문자에게 전달된다. 방문자 브라우저 Cloudflare 서울 DC cloudflared (미니PC) WordPress 컨테이너 GET https://sticknstone.org WAF·DDoS 1차 필터 미리 열린 outbound 채널로 forward http://localhost:8090 HTML 응답 outbound 채널 회신 SSL 종단·CDN 캐시 + 응답 터널(outbound 채널) 구간 응답
그림 2. 방문자가 도메인을 칠 때 요청과 응답이 오가는 순서

4단계: 방문자 → Cloudflare(필터) → 다리 → 미니PC → 역순. 미니PC IP는 어디에도 안 등장.


4. 다리지기: cloudflared

이 outbound 채널을 우리집에서 유지하는 작은 데몬이 cloudflared — Cloudflare 공식 오픈소스.

왜 Docker로 띄우나

미니PC에 이미 Docker가 돌고 있다. 다른 컨테이너들과 같은 호텔에 묵는 게 자연스럽다.

미니PC의 Docker 구성 미니PC(Ubuntu 24.04)의 Docker 호스트 안에 cloudflared, wordpress-wordpress-1(:8090), wordpress-db-1(MariaDB), wordpress-redis-1(Object Cache), umami_umami-1(:3001), umami_db-1(Postgres)이 있다. 바깥의 Cloudflare 네트워크는 outbound 채널로 cloudflared와만 이어지고, network_mode host로 뜬 cloudflared가 WordPress와 Umami에 전달한다. 미니PC (Ubuntu 24.04) Docker 호스트 Cloudflare 네트워크 cloudflared network_mode: host wordpress-wordpress-1 :8090 umami_umami-1 :3001 wordpress-db-1 MariaDB wordpress-redis-1 Object Cache umami_db-1 Postgres outbound 채널
그림 3. 미니PC 안 Docker 구성 — cloudflared만 host 네트워크로 떠서 WordPress와 Umami에 닿는다

cloudflared만 network_mode: host로 띄워서 호스트의 localhost:8090(WP)와 localhost:3001(Umami)에 접근하게 한다.

설치 5분 가이드

폴더 + 설정 파일:

/home/user/cloudflared/
├── .env                # TUNNEL_TOKEN=eyJh... (Cloudflare 대시보드에서 받은 토큰)
└── docker-compose.yml

docker-compose.yml:

services:
  cloudflared:
    image: cloudflare/cloudflared:latest
    container_name: cloudflared
    restart: unless-stopped
    network_mode: host
    command: tunnel --no-autoupdate run --token ${TUNNEL_TOKEN}
    env_file: .env

가동 + 로그 검증:

cd /home/user/cloudflared
sudo docker compose up -d
sudo docker logs cloudflared --tail 20

성공 로그에 다음 4줄이 보인다 (Cloudflare 서울 데이터센터 4곳 동시 연결):

Registered tunnel connection ... location=icn06 protocol=quic
Registered tunnel connection ... location=icn01 protocol=quic
Registered tunnel connection ... location=icn05 protocol=quic
Registered tunnel connection ... location=icn06 protocol=quic

미니PC는 4중 백업 채널로 Cloudflare에 연결된다. 한 채널이 죽어도 나머지 3개가 살아있다.


5. 토큰은 위험하다 — 어디 두나

cloudflared가 Cloudflare에 자기를 증명할 때 쓰는 토큰. 발급 시 한 번 보여주고 끝.

토큰 다루기 원칙

  • .env 파일에 평문 저장. 권한 chmod 600 (소유자만 읽기·쓰기)
  • 채팅·노트·git 커밋에 절대 평문 X
  • 토큰 노출 의심 시 즉시 Cloudflare 대시보드에서 revoke + 재발급

정확한 명령

sudo chown user:user /home/user/cloudflared/.env
sudo chmod 600 /home/user/cloudflared/.env

6. 공짜로 따라오는 것

Cloudflare 무료 플랜으로 이 다리만 놓아도 따라오는 보너스:

보너스 설명 평소 가격대
WAF (웹 방화벽) SQL injection·XSS 알려진 공격 자동 차단 월 $20~
DDoS 보호 트래픽 폭주 자동 흡수, 무제한 월 $200~
CDN 정적 파일 전 세계 캐싱. 외국 방문자도 빠르게 월 $10~
SSL 자동 Let’s Encrypt 갱신 신경 0 월 $5~
트래픽 통계 Cloudflare 대시보드에서 그래프로 (분석 도구)

총합 비용: 0원. 도메인 갱신비 연 $10만.


7. 함정 — 우리가 실제로 만난 것

함정 1. Operating System 선택 헷갈림

Cloudflare 대시보드의 cloudflared 설치 명령 화면에서 OS를 골라야 한다. 처음에는 자기 윈도우 PC가 OS인 줄 알고 Windows를 골랐다. 틀렸다. cloudflared가 설치되는 곳은 미니PC(Ubuntu)지 내 윈도우가 아니다. Docker를 골랐어야 한다.

함정 2. 토큰을 LLM 채팅에 그대로 붙여넣음

복사한 토큰을 LLM 채팅에 보내면 그 채팅 내용은 외부 서버에 저장된다. 토큰은 카드 비밀번호급 민감 정보. 작업 끝나면 즉시 Cloudflare 대시보드에서 토큰 회수 권장.

함정 3. cloudflared가 어떻게 다른 서비스에 forward하나

cloudflared 컨테이너만 띄우면 Cloudflare와 연결은 되지만, 들어온 요청을 어디로 보낼지는 별도 설정이다. Public Hostname 설정이라고 한다. 다음 편(10편)에서 다룬다.


8. 검증

가동 직후 Cloudflare 대시보드의 Tunnel 페이지 하단 Connection Status를 본다.

Before:  No connection detected yet
After:   Connected (체크)

이 한 줄이 바뀌면 다리가 놓인 것이다.


FAQ

Q. Tailscale Funnel과 무엇이 다른가?
둘 다 NAT 우회 + 미니PC IP 비공개라는 점은 같다. Cloudflare Tunnel은 WAF·DDoS·CDN·자기 도메인 사용까지 무료로 묶어준다. Tailscale Funnel은 전용 도메인 강제 + 보호막 없음. 블로그용은 Cloudflare가 우위.

Q. 미니PC가 꺼지면 어떻게 되나?
다리가 끊긴다. 방문자는 Cloudflare에서 521(Web server is down) 에러를 본다. 미니PC가 다시 켜지면 cloudflared가 자동으로 다리를 재연결한다 (Docker restart: unless-stopped).

Q. Cloudflare가 트래픽을 보나? 개인정보 우려?
Cloudflare는 SSL을 자기가 종단한다 = 평문 트래픽을 본다. 신뢰 모델은 Cloudflare는 내 편이라는 가정. 신뢰 못 하면 적합 X (대안: 자체 reverse proxy + Let’s Encrypt + dynamic DNS).

Q. 무료 플랜 한계는?
대역폭 무제한, 사이트 수 무제한, Tunnel 수 무제한. 단 Cloudflare Workers·R2 같은 부가 서비스에 별도 한도. 블로그 1개 운영엔 무료 플랜이 평생 충분.

Q. 도메인이 .org가 아니어도 되나?
무관. .com / .net / .io / .dev 모두 동일하게 작동. 단 도메인이 Cloudflare DNS를 쓰는 게 가장 쉬움 (자동 DNS 등록).


다음 편 예고

10편에서는 Public Hostname을 설정해 sticknstone.org → WordPress로 매핑하고, 글에 무엇을 쓰면 안 되는지(개인정보 검열)를 다룬다.


한 줄 정리

집에 있는 컴퓨터에 블로그를 띄우려면 공유기에 구멍 뚫고 IP 노출하는 옛 방식 대신, 컴퓨터에서 Cloudflare로 outbound 채널을 미리 열어두는 Cloudflare Tunnel 방식이 깔끔하다. 그 채널을 유지하는 작은 데몬이 cloudflared. Docker로 띄우면 5분.


참고

코멘트

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다