휴대폰 안에 리눅스 환경을 만들었다고 해도, 그 안에서 돌아가는 웹사이트나 API를 외부에서 접속할 수 없다면 서버로서 의미가 없습니다. 문제는 이 폰이 가정용 모바일/와이파이 네트워크 뒤에 있어서 고정 공인 IP도, 포트포워딩도 쓸 수 없다는 점이었습니다. 이번 글은 이 문제를 Cloudflare Tunnel과 Caddy 조합으로 해결한 과정입니다.

Cloudflare Tunnel: 포트를 열지 않고 밖으로 나가는 통로

Cloudflare Tunnel(cloudflared)은 서버 쪽에서 Cloudflare로 나가는 아웃바운드 연결만 유지하면, 외부 요청이 그 터널을 통해 들어오는 구조입니다. 방화벽에서 인바운드 포트를 하나도 열 필요가 없다는 게 핵심입니다. 도메인(blog.mhub.uk 등)을 Cloudflare에 연결해두고, cloudflared가 로컬에서 실행 중인 서비스로 트래픽을 넘겨주도록 설정했습니다.

외부 노출 과정

Caddy: 여러 서비스를 하나의 도메인 체계로 묶기

이 폰 위에서는 블로그(Hugo 정적 사이트), 블로그 글쓰기용 관리자 페이지, 그 외 여러 소규모 API가 동시에 돌아갑니다. Caddy는 이 여러 서비스를 리버스 프록시로 묶어주는 역할을 합니다. Caddyfile 하나에 도메인/경로별로 어느 로컬 포트로 넘길지만 적어두면, HTTPS 인증서 발급·갱신까지 자동으로 처리해줍니다. 별도로 certbot을 돌리거나 인증서 갱신을 신경 쓸 필요가 없었던 점이 특히 편했습니다.

설치 과정에서 겪은 일

Caddy 역시 apt-get으로 설치를 시도했다가 모바일 네트워크에서 응답 없이 멈추는 문제를 겪었고, 결국 GitHub Releases에서 바이너리(또는 .deb)를 직접 받아 설치했습니다. 이 폰 위의 소프트웨어 설치 상당수가 결국 같은 패턴— 공식 저장소 대신 릴리스 바이너리 직접 다운로드 — 으로 해결됐습니다.

지금의 구조

정리하면 “요청 → Cloudflare → cloudflared 터널 → Caddy → 각 로컬 서비스"라는 흐름입니다. 터널 프로세스가 죽으면 외부에서는 그 무엇도 보이지 않는다는 점이 오히려 마음에 들었습니다 — 포트를 열어두는 방식보다 실패 시 안전한 방향(그냥 안 보임)으로 닫히기 때문입니다.

핵심 요약

다음 글에서는 이 구조 위에 실제로 올린 첫 서비스, Hugo 블로그 이야기를 이어가겠습니다.

🤖 이 포스팅은 AI의 도움을 받아 작성되었습니다.