[홈서버 3편] 포트 포워딩 없이 HTTPS 열기 - Cloudflare Tunnel의 마법 🔒
포트 포워딩 없이 HTTPS 열기 - Cloudflare Tunnel의 마법 🔒
문제: localhost에서 벗어나고 싶다
지난 편에서 우리는 http://localhost:8080에서 Spring Boot를 성공적으로 실행했습니다.
하지만 문제가 있죠:
❌ http://192.168.0.61:8080 ← 로컬 네트워크에서만 접속 가능❌ HTTP (보안 취약)❌ 외부 인터넷에서 접속 불가목표:
✅ https://api.yourdomain.com ← 전 세계 어디서나 접속✅ HTTPS (SSL 암호화)✅ 포트 포워딩 없이!이걸 어떻게 할까요?
전통적인 방법: 포트 포워딩의 지옥 🔥
옛날 방식 (2010년대)
-
공유기 설정 페이지 접속 (192.168.0.1)
- 공유기 비밀번호 찾기 (보통 잊어버림)
- DMZ 또는 포트 포워딩 설정
- 8080 → 192.168.0.61:8080 매핑
-
공인 IP 확인
curl ifconfig.me→ 123.456.789.12- 하지만! 유동 IP라서 재부팅하면 바뀜 😱
-
DDNS 설정 (공인 IP 변경 추적)
- No-IP, DuckDNS 등 가입
- 스크립트로 IP 업데이트
-
SSL 인증서 발급
- Let’s Encrypt 설치
- certbot 설정
- 90일마다 갱신
-
보안 설정
- 방화벽 규칙
- fail2ban 설치 (무차별 대입 공격 방어)
- 포트 변경 (8080 → 20443?)
소요 시간: 반나절 이상 😫
문제점
- 🔴 복잡함: 5단계나 되는 설정
- 🔴 보안 위험: 홈 네트워크 포트 개방
- 🔴 유지보수: 인증서 갱신, IP 변경 추적
- 🔴 공유기 의존: 공유기 지원 필요
- 🔴 DDoS 취약: 공인 IP 노출
현대적인 방법: Cloudflare Tunnel ✨
Cloudflare Tunnel이란?
Cloudflare가 제공하는 무료 터널 서비스입니다.
┌─────────────────────────────────────────────┐│ 사용자 (전 세계 어디든) ││ https://api.yourdomain.com │└─────────────────────────────────────────────┘ ↓ HTTPS┌─────────────────────────────────────────────┐│ Cloudflare Edge Network ││ - SSL 인증서 자동 발급 ││ - DDoS 보호 ││ - CDN 캐싱 │└─────────────────────────────────────────────┘ ↓ 암호화된 터널┌─────────────────────────────────────────────┐│ 맥미니 (192.168.0.61, 로컬 네트워크) ││ cloudflared (Outbound 연결만) ││ http://localhost:8080 │└─────────────────────────────────────────────┘핵심 원리
-
맥미니에서 Cloudflare로 연결 (Outbound)
- 방화벽 통과 가능 (나가는 연결이니까!)
- 포트 개방 불필요
-
Cloudflare가 중간에서 HTTPS 처리
- SSL 인증서 자동 발급
- 사용자 요청을 터널로 전달
-
터널을 통해 맥미니로 전달
- 암호화된 연결
- localhost:8080으로 프록시
장점
- ✅ 무료! (개인 사용)
- ✅ 포트 포워딩 불필요
- ✅ 자동 HTTPS (인증서 관리 없음)
- ✅ DDoS 보호 (Cloudflare가 처리)
- ✅ 공인 IP 불필요
- ✅ 5분이면 설정 완료
너무 좋은데요? 🤩
Cloudflare 계정 & 도메인 준비
필요한 것
-
Cloudflare 계정 (무료 가입)
-
도메인 (Cloudflare에 등록된)
- 저는
log8.kr사용 중 - 도메인 구매: Namecheap, GoDaddy 등
- Cloudflare에 네임서버 변경
- 저는
⚠️ 도메인이 없다면?
- DuckDNS 같은 무료 DDNS는 Cloudflare Tunnel과 호환 안 됨
- 도메인 구매 추천 (연 ₩10,000~₩15,000)
cloudflared 설치
Homebrew로 설치
맥미니에 접속 후:
brew install cloudflare/cloudflare/cloudflared설치 진행…
==> Downloading https://github.com/cloudflare/cloudflared/releases/...==> Installing cloudflared🍺 /opt/homebrew/Cellar/cloudflared/2024.11.0: 5 files, 50MB설치 확인
cloudflared --version출력:
cloudflared version 2024.11.0 (built 2024-11-15-1234)완료! ✅
Cloudflare 로그인
터미널에서 로그인
cloudflared tunnel login명령어 실행 시:
Please open the following URL in a browser:https://dash.cloudflare.com/argotunnel?callback=https://...자동으로 브라우저가 열립니다! (안 열리면 URL 복사해서 열기)
브라우저에서
- Cloudflare 로그인
- 도메인 선택 (
log8.kr) - Authorize 클릭
터미널 확인
You have successfully logged in.If you wish to copy your credentials to a server, they have been saved to:/Users/sweetheart/.cloudflared/cert.pem인증 완료! 🎉
터널 생성
터널 생성 명령어
cloudflared tunnel create mac-mini-umc출력:
Tunnel credentials written to /Users/sweetheart/.cloudflared/c8020eea-444c-41eb-85c8-302e025fe1cd.jsonCreated tunnel mac-mini-umc with id c8020eea-444c-41eb-85c8-302e025fe1cd터널 ID: c8020eea-444c-41eb-85c8-302e025fe1cd (저장해두세요!)
터널 목록 확인
cloudflared tunnel list출력:
ID NAME CREATEDc8020eea-444c-41eb-85c8-302e025fe1cd mac-mini-umc 2025-01-17T14:30:00Z완벽! ✅
설정 파일 작성
시스템 레벨 디렉토리 생성
나중에 서비스로 실행할 거라서 /etc에 설정 파일을 둡니다.
sudo mkdir -p /etc/cloudflaredcredentials 파일 복사
sudo cp ~/.cloudflared/c8020eea-444c-41eb-85c8-302e025fe1cd.json \ /etc/cloudflared/config.yml 생성
sudo nano /etc/cloudflared/config.yml내용 입력:
tunnel: mac-mini-umccredentials-file: /etc/cloudflared/c8020eea-444c-41eb-85c8-302e025fe1cd.json
ingress: - hostname: spring-swagger-api.log8.kr service: http://localhost:8080 - service: http_status:404저장: Ctrl + O → Enter → Ctrl + X
설정 파일 설명
tunnel: 터널 이름credentials-file: 인증 정보 파일 경로ingress: 라우팅 규칙spring-swagger-api.log8.kr→localhost:8080연결- 나머지는 404 반환
DNS 라우팅 설정
CNAME 레코드 자동 생성
cloudflared tunnel route dns mac-mini-umc spring-swagger-api.log8.kr출력:
Added CNAME spring-swagger-api.log8.kr which will route to this tunnel.Cloudflare 대시보드 확인
https://dash.cloudflare.com → 도메인 선택 → DNS
새 레코드 확인:
| Type | Name | Content | Proxy status |
|---|---|---|---|
| CNAME | spring-swagger-api | c8020eea-444c-41eb-85c8-302e025fe1cd.cfargotunnel.com | Proxied 🟠 |
Proxied (오렌지 구름) 상태여야 합니다! ✅
터널 테스트 실행
포그라운드 모드로 실행
cloudflared tunnel --config /etc/cloudflared/config.yml run mac-mini-umc출력:
2025-01-17T14:35:00Z INF Starting tunnel tunnelID=c8020eea-444c-41eb-85c8-302e025fe1cd2025-01-17T14:35:01Z INF Connection 0 registered2025-01-17T14:35:01Z INF Connection 1 registered2025-01-17T14:35:01Z INF Connection 2 registered2025-01-17T14:35:01Z INF Connection 3 registered4개의 연결이 생성되었네요! (로드 밸런싱)
새 터미널에서 테스트
Windows PC에서:
curl https://spring-swagger-api.log8.kr/actuator/health응답:
{ "status": "UP"}HTTPS로 접속됩니다! 🎉🎉🎉
브라우저 테스트
Chrome에서:
https://spring-swagger-api.log8.kr/swagger-ui.htmlSwagger UI가 보입니다! 🌐✨
인증서 확인 (자물쇠 아이콘 클릭):
발급자: Cloudflare Inc유효 기간: 2025-01-17 ~ 2025-04-17SSL 인증서 자동 발급! 🔒
자동 시작 설정 (macOS LaunchDaemon)
터미널 끄면 터널도 종료되니까, 백그라운드 서비스로 등록해야겠죠?
plist 파일 생성
sudo nano /Library/LaunchDaemons/com.cloudflare.cloudflared.plist전체 내용 입력:
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"><plist version="1.0"><dict> <key>Label</key> <string>com.cloudflare.cloudflared</string> <key>ProgramArguments</key> <array> <string>/opt/homebrew/bin/cloudflared</string> <string>--config</string> <string>/etc/cloudflared/config.yml</string> <string>tunnel</string> <string>run</string> <string>mac-mini-umc</string> </array> <key>RunAtLoad</key> <true/> <key>KeepAlive</key> <true/> <key>StandardOutPath</key> <string>/var/log/cloudflared.out.log</string> <key>StandardErrorPath</key> <string>/var/log/cloudflared.err.log</string></dict></plist>⚠️ 중요! ProgramArguments가 완전해야 합니다:
/opt/homebrew/bin/cloudflared--config/etc/cloudflared/config.ymltunnelrunmac-mini-umc
이 중 하나라도 빠지면 Status 1 에러! (제가 겪은 삽질… 😭)
권한 설정
sudo chown root:wheel /Library/LaunchDaemons/com.cloudflare.cloudflared.plistsudo chmod 644 /Library/LaunchDaemons/com.cloudflare.cloudflared.plist서비스 로드 및 시작
sudo launchctl load /Library/LaunchDaemons/com.cloudflare.cloudflared.plist상태 확인
sudo launchctl list | grep cloudflare출력:
- 0 com.cloudflare.cloudflaredStatus: 0 (성공!) ✅
만약 Status가 1이면? → 다음 섹션으로!
🔧 삽질 기록: Status 1 에러와의 전쟁
새벽 2시의 악몽
서비스를 시작했는데…
sudo launchctl list | grep cloudflare출력:
- 1 com.cloudflare.cloudflaredStatus: 1 (실패!) ❌
로그를 확인했습니다:
sudo tail /var/log/cloudflared.err.log…아무것도 없음. 😱
첫 번째 시도: 수동 실행
혹시 명령어가 틀렸나?
/opt/homebrew/bin/cloudflared --config /etc/cloudflared/config.yml tunnel run mac-mini-umc이건 잘 됨! 그럼 plist 파일 문제?
두 번째 시도: plist 파일 확인
cat /Library/LaunchDaemons/com.cloudflare.cloudflared.plist발견!
<key>ProgramArguments</key><array> <string>/opt/homebrew/bin/cloudflared</string></array>헐… tunnel run mac-mini-umc 부분이 없었어요! 😭
즉, cloudflared만 실행되고 끝난 거죠.
세 번째 시도: 완전한 ProgramArguments
<key>ProgramArguments</key><array> <string>/opt/homebrew/bin/cloudflared</string> <string>--config</string> <string>/etc/cloudflared/config.yml</string> <string>tunnel</string> <string>run</string> <string>mac-mini-umc</string></array>각 인자를 별도 <string> 태그로!
재시작
sudo launchctl unload /Library/LaunchDaemons/com.cloudflare.cloudflared.plistsudo launchctl load /Library/LaunchDaemons/com.cloudflare.cloudflared.plist상태 확인
sudo launchctl list | grep cloudflare출력:
73421 0 com.cloudflare.cloudflaredPID 출현! Status 0! 🎉🎉🎉
로그 확인
sudo tail -f /var/log/cloudflared.out.log2025-01-17T18:45:23Z INF Starting tunnel tunnelID=c8020eea...2025-01-17T18:45:24Z INF Connection 0 registered2025-01-17T18:45:24Z INF Connection 1 registered...드디어 성공! 😭✨
새벽 2시에 해결했습니다… (그날 밤 3시간 삽질)
최종 테스트
외부 접속
스마트폰 (LTE, Wi-Fi 끄고):
https://spring-swagger-api.log8.kr/swagger-ui.html접속됩니다! 📱✅
HTTPS 확인
curl -I https://spring-swagger-api.log8.kr출력:
HTTP/2 200date: Thu, 17 Jan 2025 10:00:00 GMTcontent-type: text/htmlserver: cloudflarecf-ray: 85e3f2a1b8c4d5e6-ICNHTTP/2 + Cloudflare! 🚀
응답 시간 측정
time curl https://spring-swagger-api.log8.kr/actuator/health출력:
{"status":"UP"}real 0m0.234s234ms - Cloudflare 경유치고 빠른 편이네요!
보안 체크리스트 🔒
✅ 완료된 보안 설정
- HTTPS 암호화 (TLS 1.3)
- 포트 개방 없음 (Outbound만)
- 공인 IP 숨김 (Cloudflare가 앞단)
- DDoS 보호 (Cloudflare가 처리)
- 자동 인증서 갱신
🔐 추가 보안 옵션 (선택)
Cloudflare Access Policy
API를 공개하고 싶지 않다면 인증 추가 가능:
- Cloudflare Zero Trust → Access → Applications
- Add an application → Self-hosted
- Policy 설정:
- 이메일 인증
- Google OAuth
- GitHub OAuth
접속 시 로그인 페이지가 나타남!
Rate Limiting
DDoS 방지:
- Cloudflare Dashboard → Security → WAF
- Rate Limiting Rules 추가
- 예: 1분에 100 요청 제한
비용 총정리 💰
Cloudflare Tunnel
┌────────────────────────────────────┐│ Cloudflare Tunnel (개인 사용) ││ 월 비용: ₩0 (무료!) │└────────────────────────────────────┘무료 플랜 제한:
- 무제한 터널
- 무제한 트래픽
- 무제한 도메인
⚠️ 유료 전환 조건:
- 월 방문자 100만 명 초과
- 엔터프라이즈 기능 필요 (Zero Trust 고급 기능)
개인 프로젝트는 평생 무료! 🎉
전체 비용 (vs AWS)
┌────────────────────────────────────────────┐│ AWS ALB + ACM (HTTPS) ││ 월 ₩20,000 + ₩35,000 = ₩55,000 │└────────────────────────────────────────────┘
┌────────────────────────────────────────────┐│ 맥미니 + Cloudflare Tunnel ││ 전기세 ₩1,300 + ₩0 = ₩1,300 │└────────────────────────────────────────────┘
💰 월 절감액: ₩53,700💰 연 절감액: ₩644,400 (64만 원!)성능 비교
응답 시간
| 항목 | 지연 시간 |
|---|---|
| localhost | 2ms |
| 로컬 네트워크 | 5ms |
| Cloudflare Tunnel | 230ms |
| AWS Seoul | 180ms |
Cloudflare가 약간 느리지만, 토이 프로젝트에는 충분합니다!
트래픽 제한
- AWS: 데이터 전송 비용 (GB당 ₩130)
- Cloudflare: 무제한 ✨
다음 편 예고
이제 외부에서 HTTPS로 접속 가능해졌습니다! 🌐🔒
하지만 배포는 여전히 수동:
cd ~/projects/umc-9th-springboot-sweetheartgit pulldocker compose up --build -d이걸 자동화하고 싶어요!
다음 편에서는:
- 🚀 git push만으로 자동 배포
- 🤖 GitHub Actions CI/CD
- 🏠 Self-Hosted Runner (SSH 타임아웃 해결)
- ✅ 테스트 → 빌드 → 배포 자동화
4편: git push만으로 자동 배포 - Self-Hosted Runner 🚀 (Coming Soon)
마치며
포트 포워딩 없이 HTTPS를 5분 만에 구현했습니다!
Cloudflare Tunnel은 정말 마법 같아요. AWS ELB/ALB 없이도 프로덕션 수준의 HTTPS를 무료로 쓸 수 있다니! 🤩
plist 파일 삽질은 아팠지만, 그 덕분에 macOS LaunchDaemon을 제대로 이해하게 되었네요. 😅
다음 편도 기대해주세요!
댓글로 여러분의 경험을 공유해주세요! 💬
이전 글 / 다음 글← 이전: 맥미니 개봉부터 첫 배포까지 🖥️ | 다음: git push만으로 자동 배포 - Self-Hosted Runner 🚀 →---
시리즈 목차
- AWS 요금 폭탄 💸에서 맥미니 홈서버로 탈출하기
- 맥미니 개봉부터 첫 배포까지 🖥️
- 포트 포워딩 없이 HTTPS 열기 - Cloudflare Tunnel 🔒 ← 현재
- git push만으로 자동 배포 - Self-Hosted Runner 🚀
- 삽질 기록 - 트러블슈팅 모음집 🔧
- 맥미니 홈서버 1개월 후기 & 최종 정산 💰
Tags: #Cloudflare #Tunnel #HTTPS #SSL #홈서버 #네트워크 #DNS #보안
💬 댓글