실습 로그 / Proxmox 홈랩

홈랩 4단계 · 도메인·HTTPS로 외부 공개

Tailscale 사설망에서만 보이던 포트폴리오 사이트를 도메인(ihaewon.com)으로 외부에 공개한다. 공유기 포트는 열지 않고 Cloudflare Tunnel로 연결하며, HTTPS를 적용한다.

진행 과정은 실습 내용을 AI와 함께 정리했고, 배운 점은 그걸 보고 제가 이해한 대로 직접 썼습니다. 배운 점 바로가기 ↓

구축네트워크보안

목표

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 : 설정 파일 문법 검사 → OK
  • service 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에 두고 컨테이너에 연결
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 쳐보면 다 나오는 걸 막아

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 은 터널 비밀번호라 공유 금지
  • 설정파일 (/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)
          • 나 대신 저 이름에게 물어보라는 뜻
    • 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 (리눅스 프로그램 관리자) 한테 명령하는 도구
  • Cloudflare 단점

    • Cloudflare가 멈추면 사이트도 같이 멈춤 (의존성)