미니 PC에 Docker + Cloudflare Tunnel로 셀프 호스팅하기
집에 있는 미니 PC 한 대로 여러 웹 서비스를 안전하게 공개하는 법. 포트 개방 없이 Cloudflare Tunnel 로 HTTPS 를 붙이고 Docker Compose 로 굴립니다.
핵심 요약
미니 PC 에서 Docker Compose 로 서비스를 띄우고, Cloudflare Tunnel(cloudflared)로 포트 개방 없이 도메인·HTTPS 를 붙인다. 공유기 설정도, 고정 IP 도, 인증서 갱신도 필요 없다.
목차
클라우드 요금은 작은 프로젝트에 은근히 부담입니다. 저는 이 블로그를 포함한 몇 개 서비스를 집에 있는 미니 PC 한 대에 올려서 굴립니다. 방법을 공유합니다.
왜 미니 PC인가
- 늘 켜져 있고, 전기값은 월 몇천 원
- 도커만 있으면 배포 환경이 클라우드와 똑같음
- 트래픽이 커지면 그때 옮기면 됨
문제는 딱 하나, "집 네트워크를 어떻게 안전하게 바깥에 노출하냐"입니다.
포트를 열지 마세요
전통적으로는 공유기 포트포워딩 + DDNS + 인증서 갱신을 합니다. 번거롭고, 홈 네트워크를 그대로 인터넷에 여는 셈이라 위험하죠.
대신 Cloudflare Tunnel 을 씁니다. 미니 PC 에서 cloudflared 가 Cloudflare 로 바깥으로 연결을 열고, 트래픽은 그 터널로 들어옵니다. 바깥에서 열어둔 인바운드 포트가 0 이에요.
사용자 → Cloudflare(HTTPS) → 터널 → 미니 PC 의 컨테이너
- 공인 IP·포트포워딩 불필요
- HTTPS 인증서는 Cloudflare 가 자동 처리
- 유동 IP 여도 상관없음
Docker Compose 로 서비스 묶기
각 서비스는 컨테이너로 띄웁니다. Next.js 앱이라면 output: "standalone" 으로 빌드해 가벼운 이미지를 만들고요.
services:
blog:
build:
context: .
dockerfile: apps/blog/Dockerfile
container_name: why-next-blog
restart: unless-stopped
networks: [api]
networks:
api:
external: true # cloudflared 와 같은 네트워크
핵심은 cloudflared 와 같은 도커 네트워크에 두는 겁니다. 그래야 터널이 컨테이너 이름으로 서비스를 찾아가요.
도메인 붙이기
Cloudflare 대시보드(또는 터널 설정)에서 Public Hostname 을 하나 추가합니다.
blog.example.com → http://why-next-blog:3001
이게 끝입니다. docker compose up -d --build 하면 몇 분 뒤 도메인으로 사이트가 열려요.
정리
- 미니 PC + Docker = 저렴하고 클라우드와 동일한 배포
- Cloudflare Tunnel 로 포트 개방 없이 HTTPS·도메인
- cloudflared 와 같은 네트워크에 컨테이너 배치
- Public Hostname 으로
도메인 → 컨테이너:포트매핑
작은 서비스라면 이 조합만으로 충분히 오래 버팁니다. 저도 이렇게 여러 앱을 굴리며 만든 것들을 늘려가고 있어요.
자주 묻는 질문
집 IP 가 유동인데 괜찮나요?
괜찮습니다. Cloudflare Tunnel 은 미니 PC 가 Cloudflare 로 바깥 연결을 여는 방식이라, 공인 IP·포트포워딩·DDNS 가 전혀 필요 없습니다.
비용이 드나요?
Cloudflare Tunnel 자체는 무료입니다. 도메인 비용만 있으면 시작할 수 있습니다.
관련 글
- 💻 개발
한 버킷에 주인이 둘이면, 마지막으로 apply한 쪽이 이긴다
S3 lifecycle 규칙 하나를 추가했더니 terraform apply가 실패했다. 원인은 같은 버킷의 lifecycle 설정을 두 리소스가 각자 소유한 구조. S3 lifecycle은 규칙 단위가 아니라 문서 단위라, 마지막 승자가 상대 규칙을 조용히 지운다.
- 💻 개발
안 받고 있던 할인 - Spot과 Graviton은 왜 싼가
AWS 청구서가 두 달 연속 예산을 넘겼다. 줄일 리소스를 찾다가 진짜 레버는 '얼마나 쓰느냐'가 아니라 '어떻게 사느냐'였음을 알았다. Spot과 Graviton이 왜 싼지, 그리고 낭비처럼 보이지만 끄면 안 되는 비용(RDS Proxy)까지 - 청구서의 각 숫자에 담긴 '왜'에 대한 이야기.
- 💻 개발
테스트는 초록인데, 알림은 한 번도 발송된 적이 없었다
큐에 잡을 넣는 코드가 첫날부터 항상 실패하고 있었다. 에러는 삼켜졌고, 테스트는 목(mock) 덕분에 초록이었다. 콜론 한 글자가 기능 세 개를 조용히 죽인 이야기.