목표
Tailscale 사설망에서만 보이던 포트폴리오 사이트를 도메인(ihaewon.com)으로 외부에 공개한다. 공유기 포트는 열지 않고 Cloudflare Tunnel로 연결하며, HTTPS를 적용한다.
구성
방문자 → https://ihaewon.com → Cloudflare(HTTPS·DNS) ⇄ 터널 ⇄ cloudflared(portfolio VM) → localhost:80 → Nginx 컨테이너
- VM이 Cloudflare 쪽으로 먼저 연결을 열어두는 방식(아웃바운드)이라 집 공유기에 들어오는 포트를 열 필요가 없음
- HTTPS 인증서는 Cloudflare가 자동 관리
A. 도메인 구매
- Cloudflare Registrar에서
ihaewon.com구매 ($10.46/년, 원가 판매)- 자동 갱신 ON → 갱신 놓치면 남이 가져갈 수 있고 이력서 링크가 깨짐
- 등록자 정보는 영어 주소로 입력. WHOIS 정보는 Cloudflare가 기본으로 가려줌
- Cloudflare에서 사면 DNS도 자동으로 Cloudflare에 연결됨
B. cloudflared 설치 (portfolio VM)
sudo mkdir -p --mode=0755 /usr/share/keyrings
curl -fsSL https://pkg.cloudflare.com/cloudflare-main.gpg | sudo tee /usr/share/keyrings/cloudflare-main.gpg >/dev/null
echo 'deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] https://pkg.cloudflare.com/cloudflared any main' | sudo tee /etc/apt/sources.list.d/cloudflared.list
sudo apt-get update && sudo apt-get install -y cloudflared
- 서명키 → 저장소 추가 → 설치 순서. 서명키는 진짜 Cloudflare 패키지인지 확인하는 용도
docker ps로 사이트 컨테이너가 80번 포트로 열려 있는 것 확인
C. 터널 생성과 도메인 연결
cloudflared tunnel login
cloudflared tunnel create portfolio
login: 브라우저에서 ihaewon.com 승인 → VM에 인증서(cert.pem) 저장create: 터널 생성 + 터널 인증 파일(.json) 생성. .json은 터널 비밀번호라 외부 공유 금지
설정 파일 /etc/cloudflared/config.yml
tunnel: <터널 ID>
credentials-file: /etc/cloudflared/<터널 ID>.json
ingress:
- hostname: ihaewon.com
service: http://localhost:80
- hostname: www.ihaewon.com
service: http://localhost:80
- service: http_status:404
- ingress : 들어온 주소별로 어디로 보낼지 정하는 규칙. 위에서부터 순서대로 확인
- 마지막 줄 : 위에 없는 주소는 404로 거절 (필수)
cloudflared tunnel route dns portfolio ihaewon.com
cloudflared tunnel route dns portfolio www.ihaewon.com
sudo cloudflared --config /etc/cloudflared/config.yml tunnel ingress validate
sudo cloudflared service install
systemctl status cloudflared --no-pager
route dns: Cloudflare DNS에 도메인 → 터널 CNAME 레코드 자동 생성ingress validate: 설정 파일 문법 검사 → OKservice install: systemd 서비스로 등록 → VM 재부팅 시 터널 자동 실행active (running)확인
D. 검증
- 근로처 컴퓨터(Tailscale 없음, 외부 네트워크)에서
https://ihaewon.com접속 성공
트러블슈팅
하위 페이지가 http로 넘어감
- 증상: 메인은 https로 열리는데,
https://ihaewon.com/projects처럼 끝에/가 없는 주소로 들어가면http://ihaewon.com/projects/로 돌려보냄 → 자물쇠 사라짐 (10.26) - 확인
- 사이트 안 링크는 전부 끝에
/가 붙어 있어서 메뉴로 이동할 땐 안 생김. 주소를 직접 치거나/없이 공유한 링크에서만 생김 - VM에서
curl -sI http://localhost/projects→Location: http://...
- 사이트 안 링크는 전부 끝에
- 원인: Nginx는
/projects를 폴더로 보고/projects/로 주소를 고쳐 돌려보냄. Nginx는 Cloudflare Tunnel 안쪽에서 http로만 요청을 받기 때문에, 돌려보내는 주소도http://로 만듦 - 해결
- Nginx 설정에
absolute_redirect off;추가 →http://없이 경로(/projects/)만 돌려보내서 브라우저가 https 유지. 설정 파일은 저장소infra/nginx/site.conf에 두고 컨테이너에 연결
- Nginx 설정에
docker rm -f site
docker run -d --name site -p 80:80 -v ~/portfolio-site/public:/usr/share/nginx/html:ro -v ~/portfolio-site/infra/nginx/site.conf:/etc/nginx/conf.d/default.conf:ro --restart unless-stopped nginx
docker exec site nginx -t
curl -sI http://localhost/projects | grep -i location # Location: /projects/
- Cloudflare SSL/TLS → Edge Certificates → Always Use HTTPS 켜기 →
http://로 들어와도 https로 넘어감 - 재발 방지: 프록시 뒤에 서버를 둘 땐 서버가 만드는 리다이렉트 주소가 http인지 확인. 배포 후 메인만 보지 말고
/없는 하위 주소도 열어보기
남은 작업
- Hugo
baseURL을https://ihaewon.com/으로 변경 - 휴대폰 LTE로 접속 확인
- BIOS 정전 후 자동 부팅 설정 (사이트가 집 미니PC에서 돌아가므로)
배운 점
직접 작성A. 도메인 구매
- 도메인 : 숫자 IP 대신 쓰는 사람이 읽는 주소 (ihaewon.com)
- 필요한 이유 : Tailscale 주소 (100.x.x.x) 는 내 기기에서만 열리기 때문에 외부용 주소가 필요
- Cloudflare 에서 구매
- 원가 판매 (년에 10달러) + DNS가 자동으로 Cloudflare에 연결
- 자동갱신 ON
- 갱신 놓치면 ihaewon.com 도메인을 다른 사람이 가져감
- WHOIS : 도메인 주인 정보를 누구나 조회하는 명부
- Cloudflare가 기본적으로 가려줌
- 가려주지 않으면 사이트를 본 아무나 우리 집 주소 및 전화번호를 알 수 있음
- whois ihaewon.com 쳐보면 다 나오는 걸 막아
- Cloudflare가 기본적으로 가려줌
B. cloudflared 설치
sudo mkdir -p --mode=0755 /usr/share/keyrings
curl -fsSL https://pkg.cloudflare.com/cloudflare-main.gpg | sudo tee /usr/share/keyrings/cloudflare-main.gpg >/dev/null
echo 'deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] https://pkg.cloudflare.com/cloudflared any main' | sudo tee /etc/apt/sources.list.d/cloudflared.list
sudo apt-get update && sudo apt-get install -y cloudflared
- cloudflared : VM에 까는 터널 프로그램
- 순서 : 서명키 받기 → 저장소 추가 → 설치
- 서명키 : 진짜 cloudflare 패키지인지 확인하는 키
- 1단계 proxmox 저장소 설정이랑 같은 원리
- docker ps 로 사이트 컨테이너가 80번에 떠있는지 확인 → 터널이 연결할 대상
C. 터널 생성과 도메인 연결
-
VM이 먼저 cloudflare로 연결을 열어둠 (아웃바운드) → 방문자 요청이 그 연결을 타고 들어옴 → 공유기 포트 안 열어도 됨
- 포트포워딩 : 공유기 문을 열어 밖에서 들어오게 하는 것 (집 IP 노출 및 공격위험성 농후)
-
흐름 : 방문자 → Cloudflare(HTTPS) → 터널 → cloudflared → localhost:80 → nginx 컨테이너
- VM의 cloudflared가 먼저 Cloudflare 서버로 연결을 걺.
- 안에서 밖으로 나가는 거라 공유기가 막지 않음.
- 이 연결을 끊지 않고 열어두는 것이 터널
- 터널 : 안에서 밖으로 전화를 걸어두고 그 통화로 대화
- 방문자가 ihaewon.com 에 접속하면 DNS가 Cloudflare로 가라고 안내.
- 방문자는 집이 아니라 Cloudflare에 도착함
- Cloudflare 은 열려있는 터널로 보냄.
- DNS : 인터넷 전화번호부
- 사람들은 도메인을 기억, 컴퓨터는 104.21.x.x 같은 숫자 (IP) 로만 찾아가고 그것을 연결시켜줌
- cloudflared가 받아서 같은 VM안에 있는 Nginx(localhost:80)으로 넘기고 응답은 터널 타고 다시 돌아감
cloudflared tunnel login cloudflared tunnel create portfolio- login : 브라우저에서 ihaewon.com 승인 → VM에 인증서 (cert.pem) 저장
- create: 터널 생성 + 인증파일 (.json) 생성. .json 은 터널 비밀번호라 공유 금지
- VM의 cloudflared가 먼저 Cloudflare 서버로 연결을 걺.
-
설정파일 (/etc/cloudflared/config.yml)
tunnel: <터널 ID> credentials-file: /etc/cloudflared/<터널 ID>.json ingress: - hostname: ihaewon.com service: http://localhost:80 - hostname: www.ihaewon.com service: http://localhost:80 - service: http_status:404- 터널 ID는 create 할 때 나온 긴 문자열 (보안상 적지 않음)
- ingress : 들어온 주소별로 어떻게 보낼지 정하는 규칙
- service : http_status : 404 —> 위에 없는 주소는 404로 거절
cloudflared tunnel route dns portfolio ihaewon.com cloudflared tunnel route dns portfolio www.ihaewon.com sudo cloudflared --config /etc/cloudflared/config.yml tunnel ingress validate sudo cloudflared service install systemctl status cloudflared --no-pager- route dns : 도메인 → 터널로 가는 CNAME 기록을 자동으로 만듦 (터널을 가리키는 CNAME 기록을 두 개 만듦.)
- DNS 기록 종류
- A : 이름 → IP (ihaewon.com —> 104.21.x.x)
- CNAME : 이름 → 다른 이름 (별명) (ihaewon.com → 터널ID.cfargotunnel.com)
- 나 대신 저 이름에게 물어보라는 뜻
- DNS 기록 종류
- ingress validate : 설정 파일 문법 검사
- service install : systemd에 등록 —> VM 재부팅해도 터널 자동 실행 (3단계 --restart랑 같은 목적)
- HTTPS 인증서는 Cloudflare가 자동 관리 —> 1단계 proxmox 웹 UI 처럼 경고가 뜨지 않음
- 외부에 열린 건 사이트 하나 뿐. SSH, proxmox 는 여전히 Tailscale로
- systemctl status cloudflared --no-pager : cloudflared 서비스가 잘 돌아가고 있는지 확인
- --no-pager : 결과를 한 번에 쭉 출력하고 끝내기
- 이걸 붙이지 않으면 결과가 길 때 페이지 넘기는 화면이 떠서 q를 눌러야 빠져나옴
- status : 상태 보기
- systemctl : systemd (리눅스 프로그램 관리자) 한테 명령하는 도구
- --no-pager : 결과를 한 번에 쭉 출력하고 끝내기
-
Cloudflare 단점
- Cloudflare가 멈추면 사이트도 같이 멈춤 (의존성)