수강생 전용 보너스 시리즈예요. 수강생은 로그인하면 바로 볼 수 있어요.

1강 / 전체 30강

서버와 클라이언트 — 웹 요청은 어떻게 오가는가

10분 읽기 조회 0

웹 요청이 DNS→TCP→TLS→HTTP로 오가는 과정을 curl -v·-w로 관찰하고, 로컬 서버로 200·301·404·501 응답과 curl 오류 번호를 직접 확인합니다.

🎯 학습 목표

이 강을 마치면 주소창에 주소를 입력한 순간부터 화면이 뜨기까지의 단계를 설명하고, curl로 요청 줄·헤더·상태 코드를 직접 읽을 수 있습니다. 인프라 업무에서 가장 흔한 신고는 「사이트가 안 열려요」인데, 그 뒤에는 이름 조회 실패·연결 거부·인증서 오류·서버 오류처럼 전혀 다른 원인이 숨어 있습니다. 단계를 알면 어디서 멈췄는지 명령 한 줄로 가려낼 수 있습니다.

  • 웹 요청이 DNS → TCP → TLS → HTTP 순서로 진행됨을 curl 출력으로 확인한다
  • HTTP 메서드와 상태 코드 범주(2xx~5xx)를 구분한다
  • 로컬 웹 서버를 띄워 200·301·404·501 응답을 직접 만든다
  • curl 오류 번호(6·7·35)로 막힌 단계를 짚는다

실습 환경은 Ubuntu 24.04(WSL2), curl 8.5.0, Python 3.12.3이며, 모든 출력은 실제 실행 결과입니다.

🧭 클라이언트·서버와 요청의 네 단계

클라이언트는 요청을 먼저 보내는 쪽, 서버는 특정 포트(80, 443 등)를 열고 기다리다 응답하는 쪽입니다. 역할은 기계가 아니라 프로그램의 행동으로 정해집니다. 웹 서버도 데이터베이스에 질의할 때는 클라이언트가 되므로, 장애를 추적할 때는 「이 구간에서 누가 클라이언트인가」부터 정하면 어느 로그를 볼지가 분명해집니다.

https://example.com/ 요청은 ① DNS 조회(이름 → IP) ② TCP 연결(443번 포트와 연결) ③ TLS 핸드셰이크(암호화 협상·인증서 검증) ④ HTTP 요청·응답 순서로 진행됩니다. curl의 -w로 각 단계가 끝난 시각(요청 시작부터 누적 초)을 재면 순서가 그대로 보입니다.

$ curl -s -o /dev/null -w 'dns=%{time_namelookup} tcp=%{time_connect} tls=%{time_appconnect} first_byte=%{time_starttransfer} total=%{time_total}\n' https://example.com/
dns=0.015210 tcp=0.103678 tls=0.226590 first_byte=0.334274 total=0.334376

숫자는 매번 달라도 순서는 같습니다. dns만 길면 DNS 서버, tcp~tls 구간이 길면 암호화 협상, tls~first_byte 구간이 길면 서버가 응답을 만드는 데 오래 걸린 것입니다.

📨 HTTP 메시지 — 메서드·상태 코드·헤더

HTTP의 의미 규칙은 RFC 9110(2022)에 정리되어 있습니다. 요청은 요청 줄(메서드·경로·버전) + 헤더 + 빈 줄 + 본문, 응답은 상태 줄(버전·코드·사유 문구) + 헤더 + 빈 줄 + 본문입니다. 헤더는 본문 형식(content-type), 이동할 주소(Location) 같은 부가 정보를 담습니다.

메서드용도반복해도 안전한가
GET / HEAD조회 / 헤더만 조회안전·멱등
POST데이터 제출·처리매번 새 처리가 일어날 수 있음
PUT자원 통째로 교체멱등
DELETE자원 삭제멱등

멱등은 같은 요청을 여러 번 보내도 결과 상태가 한 번 보낸 것과 같다는 뜻입니다. 재시도할 때 GET·PUT은 다시 보내도 되지만, POST는 주문이 두 번 들어갈 수 있어 따로 대비합니다.

범주의미자주 보는 코드
2xx성공200, 201, 204
3xx다른 곳으로 이동301, 302, 304
4xx요청 쪽 문제400, 401, 403, 404, 405, 429
5xx서버 쪽 문제500, 501, 502, 503, 504

4xx는 「요청을 고쳐라」, 5xx는 「서버를 봐라」입니다. 502·504는 앞단 프록시가 뒤쪽 서버에서 제대로 된 응답을 못 받았다는 뜻이라 뒤의 애플리케이션부터 확인합니다.

💻 실습 — curl로 관찰하고 로컬 서버 띄우기

1단계: curl -v로 전체 대화 보기

$ curl -sv -o /dev/null https://example.com/
* Host example.com:443 was resolved.
* IPv4: 172.66.147.243, 104.20.23.154
*   Trying 172.66.147.243:443...
* Connected to example.com (172.66.147.243) port 443
… 생략 …
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384 / X25519 / id-ecPublicKey
* ALPN: server accepted h2
*  subjectAltName: host "example.com" matched cert's "example.com"
*  SSL certificate verify ok.
… 생략 …
> GET / HTTP/2
> Host: example.com
> User-Agent: curl/8.5.0
> Accept: */*
>
< HTTP/2 200
< content-type: text/html; charset=utf-8
< allow: GET, HEAD
… 생략 …
  • was resolved·IPv4: — DNS 단계 결과, Connected … port 443 — TCP 연결 성공입니다.
  • SSL certificate verify ok — 인증서 이름이 주소와 맞고 신뢰할 수 있습니다. ALPN: server accepted h2는 HTTP/2로 대화하기로 합의했다는 뜻입니다.
  • > 줄은 보낸 요청, < 줄은 받은 응답입니다. -s는 진행 막대를 숨기고, 본문은 -o /dev/null로 버렸습니다.
$ curl -s -o /dev/null -w '%{http_code}\n' https://example.com/nothing
404

상태 코드 숫자만 뽑는 이 형태는 「200이 아니면 알림」 같은 점검 스크립트에 그대로 쓰입니다. 헤더만 보려면 HEAD 요청인 curl -I를 씁니다.

2단계: 로컬 웹 서버 띄우기

$ mkdir -p site/docs && cd site
$ echo '<h1>hello</h1>' > index.html
$ echo 'doc' > docs/index.html
$ python3 -m http.server 8000 --bind 127.0.0.1

--bind 127.0.0.1은 내 컴퓨터 안에서만 접속되게 합니다. 빼면 모든 네트워크 인터페이스에 열려 같은 와이파이의 다른 기기도 폴더를 볼 수 있습니다. 새 터미널에서 요청합니다.

$ curl -v http://127.0.0.1:8000/
* Connected to 127.0.0.1 (127.0.0.1) port 8000
> GET / HTTP/1.1
> Host: 127.0.0.1:8000
… 생략 …
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Server: SimpleHTTP/0.6 Python/3.12.3
< Content-type: text/html
< Content-Length: 15
… 생략 …
<h1>hello</h1>

IP·http라 DNS·TLS 단계가 없습니다. Content-Length: 15는 본문과 줄바꿈을 합친 바이트 수입니다.

3단계: 301·404·501 만들기

$ curl -i http://127.0.0.1:8000/docs
HTTP/1.0 301 Moved Permanently
Server: SimpleHTTP/0.6 Python/3.12.3
Date: Wed, 21 Oct 2026 11:09:50 GMT
Location: /docs/
Content-Length: 0

$ curl -L http://127.0.0.1:8000/docs
doc
$ curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8000/missing.html
404
$ curl -i -X POST -d name=kim http://127.0.0.1:8000/
HTTP/1.0 501 Unsupported method ('POST')
… 생략 …
  • 폴더 주소 끝에 /가 없으면 301로 /docs/를 알려 줍니다. curl은 -L을 붙여야 따라갑니다.
  • 이 서버는 POST 기능 자체가 없어 501입니다. 기능은 있지만 그 주소에서 허용하지 않을 때는 405를 씁니다.

서버 터미널에는 "POST / HTTP/1.1" 501 -처럼 요청마다 한 줄씩 기록이 남습니다. 끝나면 Ctrl+C로 종료합니다.

⚠️ 자주 하는 실수와 해결

curl은 실패하면 괄호 안에 오류 번호를 보여 주며, 이 번호가 곧 멈춘 단계입니다.

$ curl http://no-such-host.invalid/
curl: (6) Could not resolve host: no-such-host.invalid
$ curl http://127.0.0.1:8000/
curl: (7) Failed to connect to 127.0.0.1 port 8000 after 0 ms: Couldn't connect to server
$ curl https://127.0.0.1:8000/
curl: (35) OpenSSL/3.0.13: error:0A00010B:SSL routines::wrong version number
  • (6) DNS 단계 실패 — 오타·도메인 만료·DNS 설정을 봅니다. 서버는 아무것도 받지 못했습니다.
  • (7) 그 포트에서 기다리는 프로그램이 없음 — 서버 꺼짐, 포트 번호 틀림을 확인합니다(위는 서버를 끈 뒤 실행).
  • (35) http 전용 포트에 https로 접속 — 상대가 평문으로 답해 「wrong version number」가 납니다.
$ python3 -m http.server 8000 --bind 127.0.0.1
… 생략 …
OSError: [Errno 98] Address already in use

이미 8000번을 쓰는 서버가 있는데 또 띄우면 이 오류가 납니다. 한 포트에는 한 프로그램만 바인드할 수 있으니 기존 서버를 끄거나 다른 포트를 씁니다. 또 http.server는 공식 문서가 운영 환경에 권장하지 않는다고 밝힌 학습용 도구이므로 잠깐 쓰고 바로 끕니다.

✏️ 확인 문제

  1. dns=0.01 tcp=0.03 tls=0.05 first_byte=2.80일 때 먼저 의심할 곳은? ① DNS 서버 ② 인증서 ③ 서버의 응답 생성 ④ 주소 오타 정답 ③ — 연결은 0.05초에 끝났고 첫 바이트까지 2.75초가 걸렸습니다.
  2. 헤더만 받아 보는 옵션은? ① -L ② -I ③ -o ④ -X DELETE 정답 ② — -I는 HEAD 요청입니다.
  3. 301과 Location: /docs/를 받았습니다. curl로 내용까지 받으려면? 정답 -L을 붙인다 — curl은 기본적으로 리다이렉트를 따라가지 않습니다.
  4. curl: (7) … Couldn't connect to server의 뜻은? ① 도메인이 없다 ② 그 포트에서 기다리는 프로그램이 없다 ③ 인증서 만료 ④ 서버가 500을 냄 정답 ② — 500이라면 연결은 성공한 것입니다.
  5. POST 결제 요청을 자동 재시도하게 만들 때 주의점은? 정답 중복 처리 방지 장치가 필요하다 — POST는 멱등이 아니어서 반복하면 새 처리가 일어날 수 있습니다.

📝 핵심 요약과 다음 강 예고

  • 요청 흐름: DNS → TCP → TLS → HTTP, curl -w로 단계별 시간 측정
  • 상태 코드: 2xx 성공, 3xx 이동, 4xx 요청 문제, 5xx 서버 문제
  • curl 옵션: -v 전체 대화, -I 헤더, -L 리다이렉트, -X 메서드, -w 출력 형식
  • 오류 번호: (6) 이름 조회, (7) 연결, (35) TLS

다음 강에서는 앞의 세 단계, 즉 IP 주소와 포트, DNS 레코드, HTTPS 인증서를 ip·dig·openssl로 하나씩 열어 봅니다.

📚 참고 자료

관련 주제

  • 클라이언트-서버 모델
  • HTTP 메서드
  • HTTP 상태 코드
  • curl
  • 요청 헤더
  • 리다이렉트
  • 멱등성
  • http.server
  • 개발·프로그래밍
  • 개발·프로그래밍 강의
  • 클라우드·인프라 실무 — 서버부터 도커·쿠버네티스까지 30강
  • NUGUNA
  • 누구나

📚 시리즈 전체 공유

클라우드·인프라 실무 — 서버부터 도커·쿠버네티스까지 30강

이 강의가 속한 시리즈는 총 30강(수강생 전용 보너스 · 1~3강 무료)입니다. 처음부터 배우려는 동료에게 시리즈 전체를 알려 주세요.

댓글

0/1000

불러오는 중...