HTTP × HTTPS × TLS × gunicorn: 주문 쪽지, 자물쇠 봉투, 식당 매니저를 어린이 눈높이로

HTTP는 글자 주문 쪽지, TLS는 자물쇠 봉투, HTTPS는 쪽지를 봉투에 넣은 것, gunicorn은 매니저와 요리사다. 5056번 문 400 오류와 연결해 설명한다.

HTTP × HTTPS × TLS × gunicorn: 주문 쪽지, 자물쇠 봉투, 식당 매니저를 어린이 눈높이로

관련 기록: 자물쇠 없는 5056번 문에 https를 꽂아 400이 난 기록

1. 도입 (Context & Goal)

한 줄로 말하면 이렇습니다.

웹은 주문 쪽지(HTTP) 를 주고받는 식당이고, 자물쇠 봉투(TLS) 에 넣으면 주소가 https가 된다. gunicorn은 그 식당의 매니저와 요리사다. 쪽지 문에 자물쇠 말을 하면 주방까지 가기 전에 400이 난다.

당시 목표

  • 블로그 태그 http, https, gunicorn, tls를 비전공자와 어린이도 다시 설명할 수 있게 만들기
  • 지난 글의 HTTP ERROR 400이 요리 실패가 아니라 문지기 실패인 이유를 네 단어로 연결하기
  • 외울 정의 대신, 가게에서 누가 무엇을 하는지로 남기기

비유: 식당에 세 역할이 있다. 손님이 종이에 주문을 쓴다(HTTP). 소중한 주문은 자물쇠 봉투에 넣는다(TLS). 홀에는 매니저가 있고, 주방에는 요리사가 있다(gunicorn). 자물쇠 봉투를 받을 준비가 안 된 문지기는 봉투를 종이 주문으로 읽다가 돌려보낸다.

flowchart LR
  guest["손님 브라우저"] --> note["HTTP 주문 쪽지"]
  note --> lock["TLS 자물쇠 봉투"]
  lock --> door["문지기"]
  door --> manager["gunicorn 매니저"]
  manager --> cook["요리사 워커"]
  cook --> page["대시보드 페이지"]

2. 트러블슈팅 (Micro-Debugging)

이번 페이지의 “고장”은 버그 한 줄보다 이름이 섞이는 지점이다.

증상처럼 보이는 것실제에 가까운 것
HTTPS는 HTTP와 전혀 다른 언어HTTPS는 HTTP를 TLS 위에 올린 것이다. 주문서 양식은 같고, 운반 봉투만 다르다
TLS와 SSL은 다른 자물쇠 두 개SSL은 예전 이름이다. 지금 쓰는 자물쇠는 TLS다. 인증서를 아직도 SSL 인증서라고 부르는 경우가 많다
https://만 치면 어떤 문이든 안전해진다그 문이 자물쇠 악수를 받을 준비가 되어 있어야 한다. 준비 안 된 문은 400이 난다
400은 비밀번호가 틀려서400번대는 “손님 쪽 말이 이상하다”는 쪽이다. 이번 400은 주방 비밀번호 확인 전에 났다
gunicorn을 켜면 자물쇠가 생긴다gunicorn은 손님을 받아 파이썬 앱을 부르는 식당 운영이다. 자물쇠(TLS)는 따로 달아야 한다
요리사를 많이 두면 무조건 빠르다기본 요리사 1명은 주문 1개만 한다. 사람을 늘리면 메모리도 같이 늘어 주방이 비좁아질 수 있다

문지기가 기대하는 첫 마디가 다르다. 그냥 문(HTTP)은 GET / ...처럼 글자 주문으로 시작한다. 자물쇠 문(HTTPS)은 암호 악수인 ClientHello로 시작한다. 지난 로그의 \x16\x03\x01은 그 악수의 시작 신호다. 글자 문지기는 그 신호를 주문서로 읽지 못하고 Bad request version, 즉 400을 낸다.

flowchart LR
  Suspect["의심: 이름이 헷갈림"]
  Check["확인: 첫 마디가 글자인가 자물쇠인가"]
  Act["조치: 문 종류에 맞는 말로 들어가기"]
  Suspect --> Check --> Act

3. 해결 과정 & 코드 (Solution)

3-1. 네 단어를 가게 순서로 보기 (Before / After)

Before — 이름만 외운 상태

1
http, https, tls, gunicorn  →  약자 네 개

After — 누가 무엇을 하는지

1
2
손님 쪽지(HTTP) → 자물쇠 봉투(TLS) → 주소창의 https
접수 매니저 + 요리사(gunicorn) → 파이썬 대시보드

HTTP — 주문 쪽지

HTTP는 웹에서 자료를 달라고 손님이 먼저 말을 거는 약속이다. 브라우저가 손님이고, 서버가 식당이다. 손님이 쪽지를 보내고, 식당이 답장을 준다. 둘 사이에 “지금 몇 번째 손님이었지?”를 서버가 자동으로 기억하지는 않는다. 그래서 HTTP를 상태가 없는 대화라고 한다. 로그인 기억은 나중에 쿠키 같은 추가 쪽지로 붙인다.

쪽지는 크게 두 장이다.

  • 요청: “이거 주세요.” GET은 메뉴를 가져오기, POST는 주문서(입력값)를 맡기기.
  • 응답: “여기 있습니다” 또는 “그 말 못 알아듣겠어요.” 숫자 상태 코드가 붙는다.

어린이용 상태 코드 세 개만 기억하면 된다.

코드가게 말뜻
200주문 나왔습니다성공
400주문서가 식당 말이 아닙니다손님 쪽 형식 오류
404그 메뉴는 없습니다주소는 왔지만 방이 없음

최소 쪽지 모양은 이렇다.

1
2
GET / HTTP/1.1
Host: 77.42.64.226:5056

5056은 건물 문 번호다. 잘 알려진 기본 문은 HTTP가 80번, HTTPS가 443번이다. 우리 대시보드는 그 기본 문 대신 5056번 그냥 문을 연 것이다.

TLS — 자물쇠 봉투

TLS는 인터넷으로 지나가는 대화를 지키는 자물쇠 약속이다. 웹에서만 쓰는 것은 아니고, 메일 같은 다른 대화에도 쓸 수 있다. 웹에서는 세 가지를 지킨다.

  1. 남이 못 읽게 — 길에서 봉투를 열어도 주문이 안 보인다. (암호화)
  2. 몰래 못 고치게 — 길에서 “피자”를 “빈 접시”로 바꾸면 들킨다. (무결성)
  3. 식당이 맞는지 — 간판을 베낀 가게가 아니라, 인증서에 적힌 그 가게인지 확인한다. (인증)

인증서는 가게 신분증이다. 신뢰하는 기관이 “이 도메인의 주인”이라고 적어 준다. 도메인 없는 IP만으로는 그 신분증을 받기 어렵다. 그래서 지난 글의 정문은 아직 그냥 문(HTTP)이다.

자물쇠를 채우기 직전, 손님과 식당은 짧게 맞춘다. 이걸 TLS 악수라고 한다. 첫 신호가 \x16으로 시작하면 “지금 자물쇠 이야기를 시작한다”는 뜻이다.

HTTPS — 쪽지를 봉투에 넣은 것

HTTPS는 새 주문 언어가 아니다. 같은 HTTP 쪽지를 TLS 봉투에 넣어 보내는 것이다. 주소는 http 대신 https로 시작한다. 기본 문 번호는 443이다.

그래서 이런 그림이 된다.

1
https  =  HTTP 주문 쪽지  +  TLS 자물쇠 봉투

브라우저가 주소창의 http://를 몰래 https://로 바꾸는 일이 있다. 보안 습관으로는 착하지만, 봉투를 받을 구멍이 없는 5056번 문에서는 400이 된다. 맥북에서 http://로 열면 200, 그록봇이 https://로 바꾸면 400이었던 이유가 이것이다.

gunicorn — 매니저와 요리사

파이썬 앱(대시보드)은 요리 레시피다. 레시피만으로는 건물 문을 열고 손님 쪽지를 읽지 못한다. gunicorn이 그 사이를 맡는다.

  • 매니저(arbiter): 요리사 수를 지키고, 쓰러지면 다시 세운다. 손님 접시를 직접 만지지 않는다.
  • 요리사(worker): 쪽지를 읽어 파이썬 함수를 부르고, 나온 결과를 다시 쪽지(응답)로 보낸다.
  • WSGI: 홀과 주방이 주문을 주고받는 정해진 양식이다. gunicorn이 app(environ, start_response)처럼 앱을 부른다.

기본 요리사(sync worker)는 한 번에 주문 1개다. 지난 글에서 요리사를 2명으로 둔 이유는, RSI처럼 오래 걸리는 요리 중에도 다른 손님이 문 앞에서 얼지 않게 하려는 것이다. gunicorn 문서는 워커 수를 보통 CPU 코어당 2~4명부터 본다고 한다. 한 명 더 뽑을 때마다 앱을 통째로 드는 프로세스가 생겨 메모리가 늘어난다.

gunicorn을 켰다는 사실만으로 TLS 구멍이 생기지는 않는다. 지난 서버 로그의 Starting gunicorn 23.0.0은 “식당 운영을 바꿨다”는 뜻이지 “자물쇠를 달았다”는 뜻이 아니다.


3-2. 면접 연습 종합: 질문 → 내 답 → 점수 → 모범 답

학습용 셀프 점검이다. 내 답은 비워 두었다.

라운드 A — 400은 어느 단계에서 났나?

질문 A1. 대시보드에 로그인 비밀번호 검사가 있는데, 왜 그 코드를 고쳐도 이번 400이 안 사라질 수 있나?

내 답. (아직 없음)

점수. (미채점)

모범 답. HTTP 서버는 먼저 “이 말이 주문 쪽지인가”를 본다. \x16으로 시작하는 TLS 악수는 쪽지가 아니라서, 방 주소 확인과 비밀번호 검사까지 가지 못한다. 고칠 곳은 로그인 함수가 아니라 문 종류(http인지 https인지) 다.

라운드 B — 워커를 늘리면 자물쇠가 해결되나?

질문 B1. 요리사를 10명으로 늘리고 gunicorn을 재시작하면, 그록봇의 https://아이피:5056 400이 사라지나? 안 사라진다면 무엇이 먼저 필요한가?

내 답. (아직 없음)

점수. (미채점)

모범 답. 안 사라진다. 워커는 이미 통과한 주문을 나누는 주방 인원이다. 400은 주문이 주방 대기열에 들어가기 전이다. 먼저 필요한 것은 그 문이 TLS 악수를 받게 하는 일(도메인과 인증서)이거나, 자동화는 브라우저 대신 서버 안 http://127.0.0.1:5056 뒷문을 쓰는 일이다.


3-3. 점수 한눈에

라운드주제점수(대략)한 줄 피드백
A1400은 문지기 단계미채점비밀번호 코드는 아직 실행되지 않음
B1gunicorn은 TLS가 아님미채점인원 충원으로 자물쇠가 생기지 않음

성장 곡선: 네 약자를 한 줄로 말할 수 있으면 이번 페이지의 목표에 닿은 것이다. “HTTP는 쪽지, TLS는 봉투, HTTPS는 쪽지+봉투, gunicorn은 매니저와 요리사.”


4. 딥다이브 (What I Learned)

Framework Deep-Dive

MDN 기준으로 HTTP는 손님이 먼저 요청을 보내고 서버가 응답하는 약속이다. 세션은 연결을 열고, 요청을 보내고, 상태 코드와 본문이 담긴 응답을 받는 흐름이다. Cloudflare와 RFC 2818 기준으로 HTTPS는 그 HTTP를 TLS 위에서 쓰는 것이며, 기본 포트 443에서 서버가 기대하는 첫 데이터는 주문 줄이 아니라 ClientHello다. gunicorn 설계 문서 기준으로 매니저 프로세스는 워커를 관리할 뿐 손님 소켓을 직접 다루지 않고, 기본 sync 워커는 요청을 한 번에 하나씩 처리한다.

Performance & Memory (리스크)

sync 워커 1명이 긴 RSI를 붙잡으면 그 워커는 다른 새로고침을 못 받는다. 워커를 늘리면 동시에 붙잡을 수 있는 긴 요리가 늘어나지만, 프로세스마다 앱 메모리를 쓴다. TLS 악수는 주방 속도 문제가 아니라 문지기 문제라서, 워커 수로 400을 줄일 수 없다.

Industry Convention

실서비스에서 “개발용으로 혼자 받던 서버”를 gunicorn 같은 프로세스 매니저로 바꾸는 것은 흔한 다음 단계다. 그다음 정석은 도메인과 공개 인증서로 HTTPS를 붙이는 것이다. IP만 연 HTTP는 임시 출입문이다. 인증서를 아직 SSL 인증서라고 불러도, 실제 대화 약속은 TLS다.

주니어 실전 팁 3가지

  1. 주소의 s 하나는 “쪽지를 봉투에 넣겠다”는 뜻이다. 문에 봉투 구멍이 있는지 먼저 본다.
  2. 로그 첫 바이트가 \x16이면 주방 코드보다 TLS 악수를 의심한다.
  3. gunicorn 워커 수는 자물쇠 개수가 아니다. 긴 작업과 메모리 한도 사이에서 고른다.

확인에 쓴 자료

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.