3부에서는 하나의 NAS에서 여러 서비스를 운영하기 위해 도메인을 각각 연결하고, Reverse Proxy를 이용해 원하는 서비스로 연결하는 과정을 정리했다.
그때까지만 해도 나름 만족스러웠다.
웹사이트도 잘 열렸고,
각 서비스도 원하는 주소로 접속할 수 있었다.
그런데 NAS를 계속 운영하다 보니 한 가지가 계속 마음에 걸렸다.
“지금의 외부 접속 방식을 굳이 그대로 유지해야 할까?”
이미 Cloudflare를 사용하고 있었고, 다른 방법을 찾아보다가 Cloudflare Tunnel을 알게 됐다.
이번에는 단순히 기능을 소개하는 것이 아니라, 실제로 내가 사용하고 있는 NAS에 Tunnel을 붙이면서 어떤 과정을 거쳤는지 기록해보려고 한다.

처음부터 기존 구조를 버릴 생각은 아니었다
Cloudflare Tunnel을 처음 알았다고 해서 바로 기존 구성을 전부 지운 것은 아니었다.
기존 Reverse Proxy는 이미 정상적으로 동작하고 있었다.
웹사이트도 열리고,
도메인도 연결되어 있고,
HTTPS도 정상적으로 사용하고 있었다.
그래서 처음에는
“일단 하나만 옮겨보자.”
라는 생각으로 시작했다.
문제가 생기더라도 기존 설정이 남아 있으니 다시 돌아갈 수 있었기 때문이다.
이게 직접 서버를 운영하면서 생긴 습관 중 하나다.
한 번에 전부 바꾸기보다는 하나를 바꾸고 확인하는 방식이 훨씬 마음이 편했다.
Cloudflare Tunnel은 Docker로 구성했다
이미 NAS에서 Docker를 사용하고 있었기 때문에 Cloudflare Tunnel도 Docker 컨테이너로 구성했다.
여기서부터는 기존에 WordPress나 다른 서비스를 만들 때와 조금 달랐다.
이번에는 단순히 하나의 웹서비스를 실행하는 것이 아니라,
NAS와 Cloudflare 사이를 연결해주는 역할
을 하는 컨테이너를 만드는 것이었다.
내 NAS에서는 별도의 cloudflared 컨테이너를 실행했다.
처음에는
“컨테이너 하나 실행하면 끝나는 것 아닌가?”
라고 생각했다.
그런데 역시 실제로 해보니 그렇지 않았다.
컨테이너가 실행되는 것과 Tunnel이 정상인 것은 달랐다
Docker 화면에서 컨테이너가 실행되고 있는 것을 확인했다.
상태도 Running이었다.
그래서 처음에는 성공했다고 생각했다.
그런데 Cloudflare에서 Tunnel 상태를 확인해보니 기대했던 것과 달랐다.
이때부터 컨테이너의 실제 실행 방식과 로그를 다시 확인하기 시작했다.
여기서 중요한 것을 하나 배웠다.
Docker에서 Running은 시작했다는 뜻이지, 내가 원하는 기능을 정상적으로 수행하고 있다는 뜻은 아니었다.
실행 중인 컨테이너라도 내부 명령이 잘못되어 있으면 원하는 일을 하지 않을 수 있었다.
실제 실행 명령을 다시 확인했다
내가 사용한 cloudflared 컨테이너의 EntryPoint는 정상적으로 들어가 있었다.
문제는 Command 쪽이었다.
처음 설정에서는 Tunnel을 실제로 실행하기 위한 명령이 제대로 전달되지 않았다.
로그에도 그와 관련된 메시지가 나타났다.
그래서 실행 명령을 다시 구성했다.
최종적으로는 tunnel run과 인증 토큰을 이용해 Tunnel이 실제로 실행되도록 수정했다.
이 부분은 Docker를 직접 운영하지 않았다면 쉽게 지나쳤을 것 같다.
단순히 이미지 이름만 맞으면 되는 것이 아니라,
컨테이너가 어떤 명령으로 실행되고 있는지까지 확인해야 한다
는 것을 다시 경험했다.
그런데 이번에는 다른 문제가 기다리고 있었다
실행 명령을 수정하고 나니 이제는 Tunnel 자체가 연결되기 시작했다.
그 순간에는
“이제 끝났구나.”
라고 생각했다.
그런데 브라우저로 사이트에 접속해보니 또 문제가 있었다.
Cloudflare에서 오류 화면이 나타났다.
처음에는 Tunnel이 아직 제대로 연결되지 않았다고 생각했다.
하지만 하나씩 확인해보니 이번에는 DNS와 Tunnel 설정을 함께 봐야 했다.
Cloudflare에서 연결 대상을 정확하게 지정해야 했다
Cloudflare Tunnel을 만들었다고 해서 모든 도메인이 자동으로 NAS 서비스와 연결되는 것은 아니었다.
어떤 도메인을 사용할 것인지,
그 도메인을 어느 Tunnel로 보낼 것인지,
그리고 Tunnel이 내부에서 어느 서비스로 연결할 것인지 각각 맞아야 했다.
결국 이런 연결고리를 하나씩 확인해야 했다.
도메인
↓
Cloudflare DNS
↓
Cloudflare Tunnel
↓
NAS 내부 서비스
이 중 하나라도 틀리면 브라우저에서는 정상적인 웹페이지 대신 오류 화면을 보게 된다.
처음 연결한 것은 두 번째 WordPress였다
첫 번째 테스트 대상으로 두 번째 WordPress를 선택했다.
이 서비스는 NAS 내부에서 별도의 Docker 컨테이너로 실행되고 있었다.
우선 Cloudflare Tunnel에서 새로운 Public Hostname을 만들고,
그 호스트 이름이 NAS 내부의 WordPress 서비스로 연결되도록 설정했다.
개념적으로는 이런 구조였다.
ittsman.com
↓
Cloudflare Tunnel
↓
NAS
↓
WordPress2
실제 내부 서비스에는 별도의 임의 포트를 사용하고 있었지만,
블로그에서는 보안을 위해 그 숫자를 공개하지 않으려고 한다.
그런데 처음에는 Synology 기본 화면이 나타났다
이 부분이 꽤 재미있었다.
분명 Cloudflare 설정을 했다고 생각했는데 브라우저에서 접속해보니 내가 만든 WordPress가 아니라 Synology의 기본 화면이 나타났다.
처음에는 WordPress가 잘못된 것인가 생각했다.
그런데 다시 생각해보면 WordPress 자체의 문제라기보다는 요청이 다른 곳으로 가고 있는 상황이었다.
이때부터 DNS와 Tunnel의 연결 상태를 다시 확인했다.
어떤 이름으로 접속하고 있는지,
그 이름이 어디를 가리키는지,
Tunnel에서는 어떤 Origin으로 보내고 있는지를 차례대로 확인했다.
결국 잘못 연결되어 있던 DNS 설정을 바로잡으면서 원하는 서비스로 연결됐다.
이번에는 1033 오류가 나왔다
설정을 수정하고 다시 테스트하는 과정에서 이번에는 Cloudflare 1033 오류가 나타났다.
처음 보면 상당히 당황스럽다.
사이트가 열리지 않으니
“Tunnel이 죽은 건가?”
라는 생각부터 들었다.
그래서 Cloudflare에서 Tunnel의 Connector 상태를 확인하고,
NAS의 cloudflared 컨테이너도 다시 확인했다.
그리고 DNS 설정도 함께 살펴봤다.
이때 한 가지 느낀 것은
오류 코드 하나만 보고 원인을 단정하면 안 된다는 것이었다.
Cloudflare에서 오류가 나왔다고 해서 반드시 Cloudflare 자체가 문제인 것은 아니었다.
중간에 연결되는 각각의 단계를 확인해야 했다.
1033을 해결했더니 이번에는 1016이었다
하나를 해결하면 또 하나가 나온다.
1033을 해결하고 다시 접속했는데 이번에는 1016 오류가 나타났다.
이번에도 처음에는 비슷하게 생각했다.
하지만 이번에는 범위를 조금씩 좁혀갔다.
Cloudflare Tunnel은 연결되어 있는가?
호스트 이름은 올바른가?
Tunnel의 서비스 대상은 정확한가?
NAS 내부에서 해당 서비스는 정상적으로 실행되고 있는가?
이렇게 하나씩 확인했다.
결국 DNS와 Tunnel Route, 내부 서비스 연결 관계를 다시 맞추면서 정상적으로 사이트를 열 수 있었다.
드디어 외부에서 WordPress가 정상적으로 열렸다
몇 번의 수정 끝에 브라우저에서 WordPress가 정상적으로 나타났다.
그 순간이 꽤 기억에 남는다.
처음에는 단순히
“Cloudflare Tunnel이라는 기능을 한번 써보자.”
라는 생각으로 시작했다.
그런데 실제로는
Docker 실행 방식도 확인해야 했고,
Cloudflare 설정도 봐야 했고,
DNS도 수정해야 했고,
오류 코드도 확인해야 했다.
결국 하나의 기능을 설치한 것이 아니라 하나의 연결 구조를 직접 만든 셈이었다.
두 번째 사이트도 같은 방식으로 옮겼다
첫 번째 Tunnel 연결이 성공하고 나니 나머지는 조금 편해졌다.
이제 어떤 부분을 확인해야 하는지 알게 됐기 때문이다.
그래서 기존 WordPress도 같은 방식으로 옮겼다.
이번에는
moneyiswater.net
↓
Cloudflare Tunnel
↓
NAS 내부 WordPress
형태로 연결했다.
그리고 www 주소 역시 기존에 사용하던 방식에 맞춰 연결했다.
첫 번째보다 훨씬 수월했다.
한 번 직접 만들어보고 나니 구조가 보이기 시작했기 때문이다.
Vaultwarden도 같은 방법으로 연결했다
그다음에는 Vaultwarden도 Tunnel에 추가했다.
별도의 서브도메인을 사용하고,
Tunnel에서 해당 호스트 이름을 Vaultwarden 서비스로 연결했다.
이렇게 하면서 Cloudflare Tunnel 하나에서 여러 서비스를 관리할 수 있다는 것도 직접 확인하게 됐다.
대략 이런 모습이었다.
Cloudflare Tunnel
│
├── 사이트 A → WordPress
│
├── 사이트 B → WordPress2
│
└── 서브도메인 → Vaultwarden
이전 Reverse Proxy에서 하던 역할을 Cloudflare 쪽에서도 비슷한 개념으로 구성할 수 있었다.
다만 연결 방식 자체는 달랐다.
가장 마지막에 기존 포트포워딩을 껐다
새 구조가 정상적으로 작동한다고 해서 바로 기존 설정을 지우지는 않았다.
먼저 외부에서 각각의 사이트를 확인했다.
WordPress도 접속해보고,
두 번째 WordPress도 확인하고,
Vaultwarden도 테스트했다.
관리자 페이지까지 실제로 접속해본 뒤에야 기존 공유기의 HTTP/HTTPS 포트포워딩을 껐다.
블로그에서는 실제 사용 포트는 공개하지 않고 예를 들어
외부 웹 연결 포트
→ NAS
정도의 표현으로만 남기려고 한다.
중요한 것은 숫자가 아니라 기존 외부 연결 방식을 제거하고 새로운 경로로 정상 작동하는 것을 확인한 뒤 정리했다는 점이었다.
포트포워딩을 끄고 다시 접속해봤다
이 순간이 이번 작업의 최종 테스트였다.
공유기에서 기존 외부 연결 설정을 끈 상태에서 다시 접속했다.
그리고 결과는 정상이었다.
브라우저에서 사이트가 열렸다.
관리자 페이지도 열렸다.
Vaultwarden도 정상적으로 접속됐다.
즉, 기존에 사용하던 경로가 없어졌는데도 서비스는 그대로 사용할 수 있었다.
이제 인터넷에서 들어온 요청은 Cloudflare를 거쳐 Tunnel을 통해 NAS 내부 서비스로 연결되는 구조가 된 것이다.
그제야 기존 설정도 하나씩 정리할 수 있었다
새로운 구조가 정상이라는 것을 확인한 뒤에야 예전에 만들어놓았던 Reverse Proxy 설정도 하나씩 정리했다.
이 과정에서 가장 신경 썼던 것은 아직 사용 중인 설정을 실수로 지우지 않는 것이었다.
그래서
새 경로 확인
→ 기존 경로와 비교
→ 실제 접속 테스트
→ 기존 설정 제거
순서로 하나씩 진행했다.
이렇게 하다 보니 NAS 설정을 바꿀 때는
“새로운 것을 만드는 것”과 “기존 것을 안전하게 없애는 것”이 별개의 작업
이라는 것도 알게 됐다.
이번 작업에서 가장 오래 걸린 것은 설치가 아니었다
Cloudflare Tunnel 자체를 만드는 것만 보면 아주 어려운 작업은 아니었다.
오히려 시간이 걸렸던 것은
“왜 안 되는지”
찾는 과정이었다.
컨테이너는 실행되고 있는가?
실행 명령은 올바른가?
Tunnel은 연결되어 있는가?
DNS는 어디를 가리키는가?
Cloudflare의 호스트 이름은 맞는가?
Origin 서비스는 살아 있는가?
이것들을 하나씩 확인해야 했다.
결국 서버 운영에서 중요한 것은
설치 방법을 아는 것보다 문제가 발생했을 때 어디부터 확인할지를 아는 것
이라는 생각이 들었다.
AI가 있어서 이 과정도 훨씬 수월했다
이번 작업에서도 막히는 부분은 그대로 AI에게 보여줬다.
Docker 설정을 보여주고,
로그를 보여주고,
Cloudflare 화면을 보여주고,
오류 메시지를 보여줬다.
그러면 지금 단계에서 무엇을 확인해야 할지 하나씩 좁혀갈 수 있었다.
특히 1033이나 1016처럼 처음 보는 오류가 나왔을 때
무작정 검색해서 수많은 글을 읽는 것보다
현재 내 환경을 기준으로 질문할 수 있다는 것
이 상당히 편했다.
그렇게 하나씩 확인하다 보니 결국 내가 직접 문제의 원인을 찾아가는 방식도 조금씩 익숙해졌다.
Cloudflare Tunnel을 만들고 나니 NAS를 바라보는 시선도 바뀌었다
처음 NAS를 인터넷에 연결했을 때는
“밖에서도 접속할 수 있으면 된다.”
정도로 생각했다.
그런데 지금은 조금 다르게 생각한다.
외부에서 접속할 수 있는 서비스와
내부에서만 사용해도 되는 서비스를 구분해야 하고,
각 서비스가 어떤 경로를 통해 연결되는지도 확인해야 한다.
그리고 기존에 사용하지 않는 연결은 정리해야 한다.
결국 중요한 것은 단순히 접속이 되는 것이 아니라
전체 연결 구조를 내가 이해하고 관리할 수 있어야 한다는 것이었다.
지금의 NAS 구조는 조금씩 달라지고 있다
예전에는 공유기를 통해 NAS로 직접 들어오는 구조였다.
지금은 외부 공개가 필요한 서비스에 대해서는 Cloudflare를 중간에 두고 Tunnel을 이용하고 있다.
단순하게 표현하면 이런 구조다.
인터넷
│
▼
Cloudflare
│
▼
Cloudflare Tunnel
│
▼
NAS
│
┌──────────┼──────────┐
▼ ▼ ▼
WordPress WordPress2 Vaultwarden
처음 NAS를 구축했을 때는 상상하지 못했던 구조다.
하지만 하나씩 직접 만들어보고 문제가 생길 때마다 수정하다 보니 여기까지 왔다.
이번 구축에서 가장 기억에 남은 것
이번 작업에서 가장 기억에 남는 것은 Cloudflare Tunnel 자체가 아니다.
오히려 “기존에 잘 사용하던 구조도 더 나은 방법이 있다면 바꿀 수 있다.”는 것을 직접 경험한 것이다.
처음에는 포트포워딩을 사용했다.
그다음에는 Reverse Proxy를 사용했다.
그리고 지금은 Cloudflare Tunnel을 사용하고 있다.
처음 구성이 틀렸던 것은 아니다.
그 당시에는 그 방법이 내가 알고 있던 가장 현실적인 방법이었다.
하지만 새로운 기술을 알게 되고 직접 테스트해보면서 구조를 바꿀 수 있었다.
NAS를 직접 운영한다는 것은 결국 이런 과정의 반복인 것 같다.
다음에는 모든 서비스를 공개하지 않아도 된다는 것을 알게 됐다
Cloudflare Tunnel로 웹서비스들을 옮기고 나니 또 하나가 보이기 시작했다.
Jellyfin이었다.
Jellyfin은 내가 사용하는 미디어 서버인데,
이 서비스까지 반드시 인터넷에 공개해야 하는지 다시 생각해보게 됐다.
웹사이트처럼 누구나 접속해야 하는 서비스와
내가 사용하는 서비스는 접근 방법을 다르게 가져갈 수 있지 않을까?
이런 생각에서 다음 단계로 Tailscale을 다시 살펴보게 됐다.
다음 글에서는 인터넷에 공개하지 않고도 외부에서 Jellyfin을 사용할 수 있도록 Tailscale을 이용해 개인 네트워크를 구성했던 과정을 기록해보려고 한다.