웹/클라우드/인프라로 돌아가기
웹/클라우드/인프라신윤섭·2026년 7월 20일

내 노트북은 왜 인터넷에서 안 보이나: 사설 IP, NAT, 그리고 터널의 함정

공유

"친구한테 보여주고 싶은데요"

Claude Code로 주말 내내 만든 앱이 드디어 localhost:3000에서 잘 돈다. 옆자리 친구한테 자랑하고 싶어서 물어본다. "이거 친구가 자기 집에서 접속하게 하려면 어떻게 해?" 에이전트가 답한다. "터미널에 ngrok http 3000을 실행하세요. 공개 URL이 하나 나올 겁니다."

시키는 대로 하니 정말로 https://무슨무슨.ngrok.app 같은 주소가 뜨고, 친구가 그 주소로 앱을 본다. 신기하다. 그런데 여기서 한 번쯤 멈춰서 이상하다고 느꼈어야 정상이다. 내 노트북 IP를 친구한테 알려주면 그만 아닌가? 왜 굳이 낯선 프로그램을 하나 더 깔아야 접속이 되는 걸까?

이 질문의 답 안에 네트워크의 기본기 절반이 들어 있다. 그리고 그 ngrok 한 줄이 실제로 무슨 문을 열었는지 모르고 넘어가면, 데모하려던 앱이 아니라 내 노트북 전체가 인터넷에 노출되는 사고로 이어진다. 바이브 코딩으로 만든 걸 남한테 보여주는 순간마다 마주치는 지점이라 짚고 넘어갈 값어치가 있다.

내 컴퓨터에는 주소가 두 개 있다

친구한테 내 IP를 알려주려고 주소를 확인해보면 상황이 좀 헷갈린다. 노트북 설정에서 본 IP는 192.168.0.12 같은 건데, "내 IP 확인" 사이트에 들어가면 203.0.113.7처럼 전혀 다른 숫자가 나온다. 어느 게 진짜 내 주소일까. 둘 다 맞다. 층위가 다를 뿐이다.

192.168.0.12사설 IP다. 우리 집 공유기가 집 안 기기들한테 나눠준 번호다. 공유기는 노트북한테 .12, 휴대폰한테 .13, TV한테 .14 하는 식으로 내부에서만 통하는 번호를 붙인다. 건물로 치면 방 번호에 가깝다. 101호, 102호는 이 건물 안에서만 의미가 있지, 옆 건물에도 101호가 따로 있다. 실제로 전국 수백만 집이 똑같이 192.168.0.12를 쓰고 있어도 아무 문제가 없다. 각자 자기 집 안에서만 통하는 번호이기 때문이다.

203.0.113.7공인 IP다. 통신사가 우리 집 공유기 하나에 배정한, 인터넷 전체에서 유일한 주소다. 건물 외벽에 붙은 도로명 주소인 셈이다. 택배 기사도, 손님도, 도둑도 이 주소를 보고 찾아온다. 밖에서 우리 집을 가리킬 수 있는 주소는 이거 하나뿐이고, 방 번호는 밖에서 부를 수 없다.

사설 IP로 쓰기로 약속된 번호 대역은 정해져 있다. 10.x.x.x, 172.16.x.x부터 172.31.x.x까지, 그리고 가정용 공유기가 즐겨 쓰는 192.168.x.x다. RFC1918이라는 표준 문서가 이 세 대역을 "내부 전용"으로 못 박아뒀다. 그래서 인터넷의 중간 장비들은 이 주소가 목적지로 찍힌 요청을 보면 "이건 어느 집 내부 번호지 인터넷 주소가 아니다"라며 길을 아예 잡아주지 않는다. 클라우드에서 AWS VPC나 GCP 내부망을 구성할 때 서버들한테 붙는 10.x.x.x 주소도 정확히 같은 사설 대역이다. 집이든 클라우드든 "내부에서만 통하는 주소"라는 개념은 똑같다.

나는 나가는데, 남은 왜 못 들어오나

여기서 진짜 궁금한 대목. 내 노트북은 사설 IP만 있는데도 유튜브도 잘 보고 API도 잘 호출한다. 나가는 건 되는데 왜 남이 들어오는 건 안 될까. 이 비대칭을 만드는 게 NAT(Network Address Translation), 우리말로 하면 주소 변환이다. 공유기가 하는 핵심 일이 이거다.

내가 유튜브에 접속하면 요청은 이렇게 나간다. 노트북(192.168.0.12)이 요청을 공유기한테 넘기면, 공유기가 출발지 주소를 자기 공인 IP(203.0.113.7)로 바꿔치기해서 인터넷으로 내보낸다. 그러면서 수첩에 "방금 .12가 유튜브한테 보낸 요청, 답장 오면 얘한테 돌려줄 것"이라고 적어둔다. 유튜브 입장에서는 요청을 보낸 게 공인 IP 하나로만 보인다. 답장이 그 공인 IP로 돌아오면, 공유기가 수첩을 뒤져서 "아, 이건 .12가 기다리던 답장"이라며 노트북한테 정확히 전달한다. 집 안 기기 수십 대가 공인 IP 하나를 공유하면서도 각자 답장을 제대로 받는 게 이 수첩 덕분이다.

문제는 밖에서 먼저 노크하는 경우다. 낯선 사람이 203.0.113.7로 접속을 시도하면, 공유기 수첩에는 이 요청에 대응하는 항목이 없다. 내가 먼저 내보낸 적이 없으니까. 공유기는 "이걸 안쪽 어느 기기한테 보내라는 거지?" 하다가 답을 못 찾고 그냥 버린다. 그래서 사설 IP 뒤에 있는 내 노트북은 인터넷에서 먼저 말을 걸 수는 있어도, 남이 먼저 말을 걸어오지는 못한다. 딱히 보안을 신경 써서가 아니라 NAT 구조상 저절로 생긴 방어막이다. 바이브 코더한테는 공짜로 얻은 담장인 셈이다.

친구한테 그냥 IP를 알려줘도 접속이 안 됐던 이유가 이거다. 공인 IP를 알려줘봤자 공유기가 "안쪽 누구?"에서 막히고, 사설 IP는 애초에 인터넷에서 길이 없다. 그래서 뭔가 특별한 걸 해줘야 남이 들어올 수 있다.

NAT의 비대칭: 나가는 요청은 통과하고 밖에서 먼저 오는 요청은 버려지며, 터널이 이 담장을 우회한다
NAT의 비대칭: 나가는 요청은 통과하고 밖에서 먼저 오는 요청은 버려지며, 터널이 이 담장을 우회한다

담장에 문을 내는 두 가지 방법

NAT가 막아둔 담장을 일부러 뚫는 방법이 두 가지다.

첫 번째가 포트 포워딩이다. 공유기 관리자 페이지에 들어가서 규칙을 하나 박아넣는다. "밖에서 공인 IP의 3000번 포트로 들어오는 건 안쪽 192.168.0.12의 3000번으로 보내라." 공유기 수첩에 상시 항목을 하나 고정해두는 것과 같다. 이제 밖에서 203.0.113.7:3000을 두드리면 공유기가 곧장 내 노트북으로 연결해준다. 담장에 문을 하나 뚫고 상시 개방해둔 셈이다.

두 번째가 터널이다. ngrok이나 Cloudflare Tunnel이 이 방식을 쓴다. 발상이 영리하다. 밖에서 안으로 들어오는 게 막혀 있다면, 안에서 밖으로 나가는 연결을 먼저 걸어두면 된다. ngrok을 실행하면 내 노트북이 ngrok 서버로 먼저 연결을 하나 뚫는다. 나가는 연결이니까 NAT가 순순히 통과시킨다. 그다음부터는 친구가 ngrok이 준 공개 URL로 접속하면, ngrok 서버가 그 요청을 이미 뚫려 있는 통로로 흘려보내 내 노트북까지 배달한다. 공유기 설정을 건드릴 필요도 없고 명령어 한 줄이면 끝난다. AI 에이전트가 포트 포워딩 대신 거의 항상 터널을 권하는 이유가 이 간편함이다.

편하다는 건 알겠다. 그런데 두 방법 다 결과는 똑같다. 방금까지 나만 보던 localhost:3000이 이제 전 세계 누구나 URL만 알면 접속할 수 있는 상태가 됐다.

터널을 열면 실제로 뭐가 열리나

localhost:3000이 그냥 "내 앱"이라고 생각하면 이 노출이 별것 아니게 느껴진다. 하지만 개발 중인 서버는 완성된 서비스와 많이 다르다.

개발 서버에는 보통 인증이 헐겁다. 로그인 붙이기 전이라 관리자 페이지가 그냥 열려 있고, 에러가 나면 코드 어느 줄에서 터졌는지 스택 트레이스가 화면에 그대로 찍힌다. 프론트엔드가 아직 안 가린 내부 API가 노출돼 있고, 소스맵이 켜져 있어 내 코드가 브라우저에서 다 읽히기도 한다. 무엇보다 개발 중에는 .env에 진짜 API 키를 넣어두고 돌리는 경우가 많다. 터널은 이 상태를 통째로 인터넷에 올린다. 나만 본다는 전제로 대충 열어둔 뒷문 전부가 공개되는 것이다.

"URL이 랜덤이라 아무도 모를 텐데"라는 생각은 앞선 글에서도 나온 착각이다. 인터넷에는 열린 주소를 24시간 훑는 자동 스캐너가 돌아다니고, 그 URL은 채팅으로 공유하는 순간, 로그에 찍히는 순간, 브라우저 히스토리에 남는 순간부터 언제든 샐 수 있다. 무료 터널 URL은 쓰고 버리는 임시 주소라, 내가 통로를 닫은 뒤 같은 이름을 다른 사람이 이어받는 상황도 생긴다. 예전에 그 주소를 알던 서비스가 이제는 남의 서버로 연결되는 골치 아픈 상황으로 번지기도 한다.

이 노출이 특히 위험한 건, 뚫린 게 저 멀리 있는 클라우드 서버가 아니라 내 노트북 자체라는 점이다. 카톡도 은행 앱도 다 깔려 있는 그 노트북이다. 클라우드 서버가 털리면 서버 하나 날리고 다시 만들면 되지만, 내 개인 기기가 노출되는 건 무게가 다르다.

에이전트가 잘 놓치는 지점

AI 코딩 도구는 "작동하게" 만드는 데 최적화돼 있다. "친구가 접속하게 해줘"라고 하면 접속되게 해준다. 그게 얼마나 활짝 여는 일인지는 알아서 따져주지 않는다. 몇 가지 상황에서 특히 그렇다.

로컬 데모를 부탁하면 터널을 권한다. 방금 본 그대로다. 요즘은 로컬에 띄운 MCP 서버를 외부에서 연결하려고 터널을 여는 경우도 늘었는데, MCP 서버를 노출한다는 건 그 서버가 내 컴퓨터에서 파일을 읽거나 명령을 실행할 권한을 밖에다 여는 것이라 더 조심해야 한다. 클라우드에 배포할 때는 방향이 반대로 어긋난다. 프론트, 백엔드, DB를 다 각각 공인 IP 붙은 서버로 띄워버리는 식이다. 백엔드와 DB는 사설 대역 안에 숨겨두고 필요한 입구만 밖으로 내는 게 정석인데, 에이전트가 만들어준 인프라 설정에는 DB에 떡하니 공인 IP가 붙어 있곤 한다.

공통점은 하나다. 무엇을 공개하고 무엇을 사설망에 숨길지 정하는 판단은 에이전트가 대신 해주지 않는다는 것. 코드는 맡겨도, 노출 범위를 정하는 책임은 사람한테 남는다.

그래서 어떻게 열어야 하나

잠깐 데모라면 터널을 아예 쓰지 말라는 건 아니다. 편리한 도구가 맞다. 다만 여는 김에 몇 가지는 챙긴다. 앱에 최소한의 로그인이나 비밀번호는 걸어두고, 되도록 개인 노트북 대신 따로 띄운 테스트 환경에서 연다. 터널 도구가 제공하는 접근 제한 기능, 그러니까 아는 사람 IP만 허용하거나 기본 인증을 붙이는 옵션을 켜둔다. 그리고 데모가 끝나면 터널을 곧바로 닫는다. "이따 닫아야지"의 그 이따까지 통로는 계속 열려 있다.

클라우드에 올릴 때는 기본값을 뒤집어서 생각하면 편하다. 사용자한테 보여줄 웹 프론트만 공개하고, 백엔드와 DB는 사설 대역에 두는 걸 출발점으로 삼는다. 밖에서 닿아야 하는 부분만 로드 밸런서나 리버스 프록시 같은 앞단을 통해 골라서 연다. 사설 IP 대역은 인터넷에서 길이 없다는 그 성질을, 숨기는 도구로 적극 활용하는 것이다. 에이전트가 만들어준 설정 파일에서 0.0.0.0으로 바인딩하는 부분이나 아무한테나 열어둔 규칙이 보이면, "이 리소스가 지금 인터넷에 바로 노출돼 있나"를 한 번 의심하고 확인하는 습관이 사고를 크게 줄인다.

정리

내 노트북이 인터넷에서 안 보였던 건 고장이 아니라 NAT가 만들어준 담장 덕분이었다. 사설 IP는 집 안 방 번호, 공인 IP는 건물 주소이고, 나가는 요청은 통과하지만 밖에서 먼저 오는 노크는 공유기가 버린다. 포트 포워딩이든 터널이든, 남을 들어오게 한다는 건 이 담장에 문을 내는 일이다. ngrok http 3000 한 줄은 접속 문제를 푼 게 아니라 담장에 문을 하나 뚫은 것이고, 그 문 안쪽에는 완성된 서비스가 아니라 뒷문이 열린 개발 서버가, 그것도 내 개인 노트북 위에 놓여 있다. 편하게 열 수 있는 도구일수록, 지금 내가 무엇을 어디까지 열고 있는지는 내가 알고 있어야 한다.

YS

신윤섭

데이너스 대표 | AI 교육 & AX 컨설팅

81개 이상의 AI/AX 교육 과정을 설계하고, 50여 기업과 기관에서 강의했습니다. 강남세브란스, 삼성전자, 현대자동차 등 다양한 조직의 AI 역량 강화를 지원하고 있습니다.

AI 교육이 필요하신가요?

조직에 맞는 맞춤형 AI/AX 교육 프로그램을 설계해드립니다. 커리큘럼 상담부터 시작해보세요.

같은 주제의 다른 글