로컬호스트(localhost) 뜻, 맥에서 서버를 띄우고 포트까지 직접 해 보니
localhost가 무엇인지 맥에서 직접 확인했습니다. 로컬호스트로 접속하면 서버 기록에는 ::1이 남았고, 서버를 끄면 연결이 실패했으며, 파이썬 기본 서버는 모든 주소에서 열려 있었습니다. 포트 확인과 정리 방법까지 담았습니다.
Finn ·

맥 터미널에서 curl로 http://localhost:8000/을 부르자 서버 기록에는 localhost가 아니라 ::1이라는 주소가 찍혔습니다. 같은 서버를 끄고 다시 부르면 curl: (7) 오류가 바로 나왔습니다. AI 코딩 도구가 "localhost:3000에서 열어 보세요"라고 할 때 그 로컬호스트(localhost)가 정확히 무엇인지, 새 임시 폴더에서 파이썬과 Node.js 서버를 직접 띄워 확인한 기록입니다.
localhost는 무엇이고, 실행해 보니 어땠나요?
localhost는 '지금 이 컴퓨터 자신'을 가리키는 이름입니다. 맥의 hosts 파일에서 이 이름은 127.0.0.1(IPv4)과 ::1(IPv6)로 이어져 있죠. localhost:8000의 8000은 그 컴퓨터 안에서 서버가 요청을 기다리는 포트 번호입니다.
직접 실행한 결과는 세 가지로 요약됩니다.
curl로localhost를 부르면 파이썬 서버 기록에::1로 찍혔습니다.- 파이썬 기본 서버는 특정 주소가 아니라 모든 주소(
*)에서 열려 있었습니다. - 서버를 끄자 같은 주소로는 접속 자체가 되지 않았습니다(
curl종료 코드 7).
그래서 AI 코딩 도구가 "localhost:3000에서 열어 보라"고 하면, 내 컴퓨터에서 방금 띄운 서버가 3000번 포트에서 기다리고 있다는 뜻입니다. 그 서버가 꺼지면 주소는 그대로여도 열리지 않습니다. 이번에는 브라우저 화면을 열지 않고 모두 curl로 확인했습니다.

그렇다면 localhost라는 글자가 어떻게 숫자 주소로 바뀌는 걸까요? 먼저 hosts 파일부터 보겠습니다.
함께 읽을 글
이름이 주소로 바뀌는 곳, hosts 파일
맥에서 /etc/hosts를 찾아보고, 시스템이 이 이름을 어떻게 풀이하는지 함께 물어보면 이렇게 나옵니다.
$ grep -n localhost /etc/hosts && dscacheutil -q host -a name localhost
4:# localhost is used to configure the loopback interface
7:127.0.0.1 localhost
9:::1 localhost
name: localhost
ipv6_address: ::1
name: localhost
ip_address: 127.0.0.1hosts 파일에 IPv4와 IPv6 두 줄이 있고, 이름 풀이 결과도 ::1과 127.0.0.1 둘 다 돌려줍니다. 표준 문서인 RFC 6761의 localhost 절도 같은 내용을 담고 있어요. localhost 이름에 대한 IPv4·IPv6 주소 질의는 각각의 루프백 주소로 풀린다고 봐도 된다고 하고, 이름 풀이 라이브러리는 이 이름을 DNS 서버로 보내지 않아야 한다(SHOULD NOT)고 적고 있습니다.
서버를 띄우고 접속하는 방법
이름의 정체를 알았으니 이제 실제로 서버를 띄워 보겠습니다. 파이썬에 들어 있는 http.server로 site 폴더를 8000번 포트에 열고, 1초 뒤 curl로 불렀습니다.
$ mkdir -p site && printf '<h1>안녕, localhost</h1>\n' > site/index.html && (python3 -m http.server 8000 --directory site > server.log 2>&1 &) && sleep 1 && curl -s http://localhost:8000/
<h1>안녕, localhost</h1>이 단계는 1.0초 걸렸고, 대부분은 서버가 뜨기를 기다린 sleep 1입니다. 파이썬 문서에 따르면 포트를 따로 주지 않아도 기본값은 8000이고, --directory로 보여 줄 폴더를 정할 수 있습니다.
세 가지 주소로 접속하면 기록이 어떻게 다를까요?
같은 서버를 숫자 주소 두 가지로도 불러 보고, 서버 기록을 열었습니다.
$ curl -s http://127.0.0.1:8000/ && curl -s 'http://[::1]:8000/' && cat server.log
<h1>안녕, localhost</h1>
<h1>안녕, localhost</h1>
::1 - - [27/Oct/2026 18:04:10] "GET / HTTP/1.1" 200 -
::ffff:127.0.0.1 - - [27/Oct/2026 18:04:10] "GET / HTTP/1.1" 200 -
::1 - - [27/Oct/2026 18:04:10] "GET / HTTP/1.1" 200 -세 번 모두 같은 페이지가 돌아왔습니다. 기록의 첫 줄은 앞 단계의 localhost 요청으로, ::1로 남았습니다. 127.0.0.1 요청은 ::ffff:127.0.0.1 꼴로 적혔죠. 이름 풀이가 두 주소를 다 돌려줬는데 왜 curl이 ::1로 접속했는지는 이 측정만으로 가를 수 없습니다. 궁금하다면 curl에 주소를 숫자로 직접 넣어 비교해 보세요.
![localhost, 127.0.0.1, [::1] 세 주소로 접속했을 때 응답과 파이썬 서버 기록에 남은 주소를 비교한 표](/content/lab-localhost-server/images/v-01.webp)
포트를 쓰고 있는 프로그램 찾기
"이 포트를 누가 쓰고 있지?"가 궁금할 때는 lsof로 듣고 있는(LISTEN) 프로그램을 찾을 수 있습니다.
$ lsof -nP -iTCP:8000 -sTCP:LISTEN | awk '{print $1, $3, $5, $8, $9, $10}'
COMMAND USER TYPE NODE NAME
Python finn IPv6 TCP *:8000 (LISTEN)*:8000은 이 서버가 특정 주소 하나가 아니라 모든 주소에서 열려 있다는 표시입니다. 파이썬 문서에도 기본적으로 모든 인터페이스에 바인드한다고 나와 있어요. 다시 말해 localhost로 확인했다고 해서 내 컴퓨터에서만 열린 것은 아닙니다.
같은 포트로 또 띄울 때 나는 오류
AI 에이전트가 개발 서버를 여러 번 띄우다 보면 자주 만나는 상황입니다. 8000번이 이미 쓰이는 상태에서 같은 포트로 하나 더 띄우면 이렇게 됩니다.
$ python3 -m http.server 8000 2>&1 | tail -1
OSError: [Errno 48] Address already in use이럴 때는 바로 앞의 방법으로 그 포트를 쥔 프로그램을 먼저 찾아보세요. 그런 다음 끌지, 다른 포트를 쓸지 정하면 됩니다.
내 컴퓨터에서만 열리게 하려면?
그런데 모든 주소에서 열린 서버가 부담스럽다면 어떻게 할까요? --bind 127.0.0.1을 주면 됩니다. 8001번 포트에 이렇게 띄우고, 두 서버의 상태를 나란히 봤습니다.
$ (python3 -m http.server 8001 --bind 127.0.0.1 --directory site > server2.log 2>&1 &) && sleep 1 && lsof -nP -iTCP:8000 -iTCP:8001 -sTCP:LISTEN | awk '{print $1, $9}' && curl -s http://localhost:8001/
COMMAND NAME
Python *:8000
Python 127.0.0.1:8001
<h1>안녕, localhost</h1>8000번은 *:8000, 8001번은 127.0.0.1:8001로 열렸고, localhost:8001로도 페이지가 돌아왔습니다. 파이썬 http.server 문서는 이 명령이 서버를 localhost에만 바인드한다고 설명합니다. 또 http.server는 기본적인 보안 검사만 하므로 실제 서비스용으로는 권하지 않는다고 적고 있죠. 혼자 만든 정적 페이지를 잠깐 확인하는 용도라면 주소를 127.0.0.1로 묶어 두는 쪽이 낫다고 판단합니다.

Node.js 서버도 똑같을까요?
AI 코딩 도구가 자주 말하는 3000번 포트도 확인해 봤습니다. Node.js로 한 줄짜리 서버를 3000번에 띄웠습니다.
$ (node -e "require('http').createServer((req, res) => res.end('node 서버 응답\n')).listen(3000)" > node.log 2>&1 &) && sleep 1 && curl -s http://localhost:3000/
node 서버 응답localhost:3000이라는 주소도 결국 '내 컴퓨터의 3000번 포트에서 기다리는 프로그램'일 뿐입니다. 파이썬이든 Node.js든 그 포트에 프로그램이 떠 있으면 응답하죠.
서버를 끈 뒤 접속이 거부될 때
반대로 서버가 없으면 어떻게 될까요? 8000번에서 듣던 프로그램을 끄고 0.5초 뒤 다시 불렀습니다.
$ kill $(lsof -tiTCP:8000 -sTCP:LISTEN) && sleep 0.5 && curl -sS http://localhost:8000/
curl: (7) Failed to connect to localhost port 8000 after 0 ms: Couldn't connect to servercurl은 종료 코드 7과 함께 서버에 연결할 수 없다고 알렸습니다. 흔히 Connection refused로 검색하게 되는 상황이 바로 이렇습니다. 주소는 맞는데 그 포트에서 기다리는 프로그램이 없는 거죠. AI가 알려 준 localhost 주소가 열리지 않는다면 서버 실행 창이 꺼지지 않았는지부터 확인해 보세요.

Claude Code에게 포트 정리를 맡긴 결과
마지막으로 남은 3000번과 8001번 서버의 정리를 Claude Code에게 맡겼습니다. 명령 한 줄만 달라고 요청하고, 받은 답을 그대로 실행한 뒤 두 포트를 다시 확인했습니다.
$ claude --model opus -p "맥 터미널에서 3000번과 8001번 포트에서 듣고 있는 프로그램을 찾아 끄는 명령 한 줄만 출력해. 설명이나 코드 블록 표시는 붙이지 마." > cmd.txt && cat cmd.txt && sh cmd.txt; sleep 0.5; lsof -nP -iTCP:3000 -iTCP:8001 -sTCP:LISTEN || echo '3000, 8001에서 듣는 프로그램 없음'
lsof -tiTCP:3000,8001 -sTCP:LISTEN | xargs kill
3000, 8001에서 듣는 프로그램 없음돌려받은 명령은 앞에서 쓴 lsof -t 방식을 두 포트로 넓힌 것이었고, 실행 뒤 두 포트에는 듣는 프로그램이 남지 않았습니다. 이 단계는 10.9초 걸렸는데, 요청부터 받은 명령을 실행해 확인하기까지 단계 전체의 시간입니다. AI가 준 명령을 바로 실행하는 방식이라면, 이번처럼 실행 뒤 포트를 다시 조회하는 확인 줄을 붙여 두는 편이 안전합니다.
측정 조건과 한계
모든 단계는 2026-10-27 18:04 KST에 macOS(darwin arm64)의 새 임시 폴더에서 한 번씩 실행했습니다. Homebrew로 설치된 python3, Node.js v22.23.1, Claude Code 2.1.309(로그인된 상태, --model opus)를 썼습니다.
| 단계 | 걸린 시간 | 종료 코드 |
|---|---|---|
| hosts 파일의 localhost | 0.0초 | 0 |
| localhost:8000에 서버 띄우기 | 1.0초 | 0 |
| 127.0.0.1과 [::1]로 접속 | 0.0초 | 0 |
| 8000번 포트를 쓰는 프로그램 | 0.1초 | 0 |
| 같은 포트로 또 띄우면 | 0.1초 | 0 |
| 내 컴퓨터에서만 열기 (--bind 127.0.0.1) | 1.1초 | 0 |
| Node.js로 localhost:3000 | 1.0초 | 0 |
| 서버를 끄고 다시 접속하면 | 0.6초 | 7 |
| Claude Code에게 남은 서버 정리 맡기기 | 10.9초 | 0 |
한 번씩만 실행했고 시간에는 sleep 대기가 포함되므로, 속도를 비교하는 값으로 읽으면 안 됩니다. 브라우저에서의 동작이나 같은 와이파이의 다른 기기에서 접속되는지는 이번에 재지 않았습니다. 다른 운영체제에서는 hosts 파일 내용이나 서버 기록의 주소 표기가 다를 수 있으니, 같은 명령으로 직접 확인해 보세요.
참고 자료
- http.server — HTTP 서버 docs.python.org
- www.rfc-editor.org/rfc/rfc6761.html www.rfc-editor.org