[Dev] 화면 뒤에서 일어나는 일들 — 백엔드·네트워크 완전 지도
localhost가 왜 친구에게 안 열리는지부터 DNS·HTTP·API·보안·배포·홈서버까지, 백엔드와 네트워크의 전체 지형을 한 장의 지도로 그려봅니다.
🏷️ [NextX_R&D_Log] · 모두의연구소 아이펠 AI 에이전트 1기 [백엔드 — 화면 뒤에서 일어나는 일들] 학습 기록
지난 시간에 프레임워크·PRD·목업 데이터로 화면의 뼈대를 세웠습니다. 그런데 친구에게
localhost:3000링크를 보내면? — 아무것도 안 뜹니다. 오늘은 그 “왜?” 에서 출발해, 서버·네트워크·배포·보안까지 백엔드의 전체 지형을 한 장의 지도로 그려봅니다.
🧭 전체 지도 — 오늘 걸어볼 길
flowchart LR
A["왜 서버가 필요한가"] --> B["네트워크 기본기"]
B --> C["백엔드가 하는 일"]
C --> D["보안 — AI가 약한 곳"]
D --> E["배포 — 세상에 내보내기"]
E --> F["집에서 돌려보기"]
F --> G["프론트-백엔드 연결"]
이 순서대로 따라가면, 주소창에 URL을 치는 순간부터 화면이 뜨기까지 벌어지는 모든 일을 이해할 수 있습니다.
1️⃣ 왜 서버가 필요한가 — localhost의 한계
식당 비유로 이해하기
| 요소 | 식당 | 웹 |
|---|---|---|
| 손님 | 식탁에 앉은 사람 | 브라우저 (클라이언트) |
| 주방 | 요리를 만드는 곳 | 서버 (백엔드) |
| 메뉴판 | 주문할 수 있는 목록 | API 엔드포인트 |
| 주문서 | “파스타 1개요” | HTTP 요청 |
| 음식 | 나온 결과물 | HTTP 응답 (JSON, HTML…) |
localhost는 내 컴퓨터 안의 주방입니다. 내 식탁(브라우저)에서는 잘 먹을 수 있지만, 다른 건물(다른 컴퓨터)에서는 이 주방에 올 수 없습니다. 친구에게 링크를 보내면 친구의 브라우저는 자기 컴퓨터의 localhost를 찾게 되니까요.
💡
127.0.0.1과localhost는 같은 뜻입니다. “이 컴퓨터 자신”을 가리키는 특별한 주소이죠. 누구에게 보내든 받는 사람의 자기 자신을 가리킵니다.
클라이언트-서버 구조
flowchart LR
C1["👤 브라우저 A"] -->|요청| S["🖥️ 서버"]
C2["👤 브라우저 B"] -->|요청| S
C3["📱 모바일 앱"] -->|요청| S
S -->|응답| C1
S -->|응답| C2
S -->|응답| C3
서버는 “늘 켜져 있고, 여러 클라이언트의 요청을 받아 처리하는 컴퓨터”입니다. 클라이언트(브라우저, 앱)가 서버에 요청하면, 서버가 데이터를 가공해 응답합니다. 이것이 웹의 기본 구조입니다.
2️⃣ 네트워크 기본기 — 주소가 화면이 되기까지
도메인과 DNS — 인터넷의 전화번호부
IP 주소(185.199.108.153)는 사람이 외우기 어렵습니다. 그래서 도메인(domain) 이라는 이름표를 붙입니다.
1
code209.kr → DNS 조회 → 185.199.108.153
DNS(Domain Name System)는 도메인을 IP 주소로 바꿔주는 전화번호부입니다. 브라우저에 code209.kr을 치면 DNS가 실제 서버 주소를 알려줍니다. 이 과정은 커스텀 도메인 설정에서 직접 경험했죠.
호스팅과 클라우드
| 구분 | 전통 호스팅 | 클라우드 |
|---|---|---|
| 비유 | 월세 사무실 — 정해진 공간 | 공유 오피스 — 필요한 만큼 |
| 확장 | 서버 추가 시 이사 필요 | 클릭 몇 번으로 확장 |
| 비용 | 고정 월 요금 | 쓴 만큼 (종량제) |
| 예시 | 카페24, 가비아 | AWS, GCP, Azure |
포트와 방화벽 — 건물의 문과 경비원
IP 주소가 건물 주소라면, 포트(port)는 몇 호실입니다.
1
2
3
code209.kr:443 → 443번 방 = HTTPS 웹서버
code209.kr:22 → 22번 방 = SSH 터미널
localhost:3000 → 3000번 방 = 개발 서버
방화벽은 경비원입니다. “80번과 443번 문만 열어두고, 나머지는 막아라”처럼 어떤 포트를 열고 닫을지 결정합니다. 개발할 때 localhost:3000이 되는데 서버에선 안 된다면? 방화벽이 3000번 포트를 막고 있을 확률이 높습니다.
HTTP와 HTTPS — 택배 포장 방식
flowchart LR
B["브라우저"] -->|"HTTP (엽서)"| S1["서버"]
B -->|"HTTPS (🔒 밀봉 택배)"| S2["서버"]
- HTTP — 데이터를 평문(plain text)으로 보냅니다. 엽서처럼 누구나 볼 수 있습니다.
- HTTPS — SSL/TLS 암호화로 데이터를 밀봉합니다. 중간에 누가 열어봐도 내용을 알 수 없습니다.
⚠️ 2026년 기준, HTTPS는 선택이 아닌 필수입니다. 대부분의 브라우저가 HTTP 사이트에 “안전하지 않음” 경고를 표시합니다. 커스텀 도메인 설정에서 GitHub Pages의 무료 HTTPS를 이미 적용했습니다.
패킷 — 데이터의 택배 상자
웹에서 데이터가 한 덩어리로 이동하지 않습니다. 패킷(packet)이라는 작은 조각으로 나뉘어 각자 다른 경로로 이동한 뒤, 도착지에서 다시 조립됩니다. 택배를 여러 상자로 나눠 보내고 받는 쪽에서 합치는 것과 같습니다.
3️⃣ 백엔드가 실제로 하는 일 — 요청을 받아 처리하고 돌려주기
API 엔드포인트 — 주문할 수 있는 창구
API란 무엇인가에서 기본 개념을 배웠습니다. 백엔드에서 API는 구체적인 URL + 동작으로 나타납니다.
1
2
3
4
5
GET /api/products ← 상품 목록 가져오기
GET /api/products/42 ← 42번 상품 상세
POST /api/products ← 새 상품 등록
PUT /api/products/42 ← 42번 상품 수정
DELETE /api/products/42 ← 42번 상품 삭제
이 네 가지 동사(GET, POST, PUT, DELETE)가 REST API의 CRUD입니다.
요청과 응답의 흐름
sequenceDiagram
participant B as 브라우저
participant S as 서버
participant D as 데이터베이스
B->>S: GET /api/products
S->>D: SELECT * FROM products
D-->>S: [{id:1, name:"노트북"}, ...]
S-->>B: 200 OK + JSON
- 브라우저가 HTTP 요청을 보냅니다
- 서버가 요청을 해석하고 DB를 조회합니다
- DB가 데이터를 돌려주면
- 서버가 JSON으로 포장해서 응답합니다
JSON — 데이터의 공용어
1
2
3
4
5
6
{
"id": 42,
"name": "무선 키보드",
"price": 59000,
"in_stock": true
}
JSON(JavaScript Object Notation)은 서버와 클라이언트가 데이터를 주고받는 공용어입니다. 사람이 읽기 쉽고, 프로그래밍 언어를 가리지 않습니다. 지난 시간의 목업 데이터도 JSON이었습니다.
4️⃣ 보안 — 프로토타입과 프로덕트 사이, AI가 약한 곳
⚠️ AI는 “일단 돌아가는” 코드를 만듭니다. 목표가 ‘작동’이지 ‘안전’이 아니라서, 보안은 사람이 직접 챙겨야 합니다.
.env 파일 — 비밀 금고
1
2
3
# .env (절대 GitHub에 올리지 말 것!)
DATABASE_URL=postgresql://user:password@host:5432/mydb
API_SECRET_KEY=sk-super-secret-key-12345
.env 파일에 비밀 키를 저장하고, .gitignore에 등록해서 저장소에 올라가지 않게 합니다. AI가 생성한 코드에 API_KEY="sk-..." 같은 값이 하드코딩되어 있다면? 즉시 .env로 분리하세요.
💡 환경변수 접두사 주의:
NEXT_PUBLIC_,VITE_같은 접두사가 붙은 값은 브라우저에 노출됩니다. “PUBLIC”이라는 이름 그대로 — 비밀값엔 절대 쓰지 마세요.
인증(Authentication) vs 인가(Authorization)
| 인증 (Authentication) | 인가 (Authorization) | |
|---|---|---|
| 질문 | “너 누구야?” | “너 이거 해도 돼?” |
| 비유 | 신분증 확인 | 출입 권한 확인 |
| 예시 | 로그인 (ID/PW 확인) | 관리자만 삭제 가능 |
🔑 로그인(인증)에 성공했다고 모든 걸 할 수 있는 게 아닙니다. 일반 사용자가 다른 사람의 데이터를 삭제할 수 없어야 합니다(인가).
비밀번호와 해싱
비밀번호를 평문으로 저장하면 DB가 털리는 순간 모든 계정이 노출됩니다. 그래서 해시(hash) 함수로 일방통행 변환합니다.
1
"myPassword123" → 해시 → "$2b$10$X7jK9..."
해시값에서 원래 비밀번호를 역산할 수 없습니다. 로그인할 때는 입력된 비밀번호를 같은 방식으로 해싱해서 해시값끼리 비교합니다.
쿠키와 세션 — “로그인 상태 유지”의 비밀
sequenceDiagram
participant B as 브라우저
participant S as 서버
B->>S: POST /login (ID, PW)
S-->>B: 200 OK + Set-Cookie: session_id=abc123
Note over B: 쿠키 저장
B->>S: GET /mypage (Cookie: session_id=abc123)
S-->>B: 200 OK + 개인 데이터
- 로그인하면 서버가 세션 ID를 만들어 쿠키에 담아 보냅니다
- 이후 요청마다 브라우저가 자동으로 쿠키를 붙여 보냅니다
- 서버는 세션 ID로 “아, 이 사람이구나” 판단합니다
AI 코드 배포 전 점검 체크리스트
배포 전에 AI에게 이렇게 요청하세요:
“이 코드 전체를 보안 관점으로 점검해 줘. 하드코딩된 비밀값, 서버 입력 검증 누락, CORS 설정, 인증 취약점을 확인해.”
| 점검 항목 | 확인 내용 |
|---|---|
| 하드코딩된 키 | 코드에 API 키, DB 비밀번호가 직접 적혀 있나? |
| 서버 입력 검증 | 프론트엔드 검증만으로 끝나지 않았나? 서버에서도 검증하나? |
| CORS 설정 | 모든 주소(*)를 허용하고 있진 않나? |
| 인증/인가 | 로그인 없이 접근 가능한 API가 있나? |
5️⃣ 배포 — 세상에 내보내기
셋으로 나눠 올린다 (식당 비유)
현대 웹서비스는 보통 세 군데에 나눠 배포합니다.
| 무엇을 | 어디에 (예) | 식당 비유 | 왜 여기에? |
|---|---|---|---|
| 화면 (프론트) | Vercel, Netlify | 전 세계 여러 지점의 홀 | 손님 가까운 곳에서 빠르게 보여줘야 |
| 서버 (백엔드) | Render, Railway | 늘 켜진 주방 | 요청을 계속 처리해야 |
| 데이터 (DB) | Supabase 등 관리형 | 재료 창고 | 안전하게 보관해야 |
“왜 한 곳에 다 안 올려요?” — 각자 잘하는 게 다르기 때문입니다. GitHub Pages는 정적 사이트(프론트엔드)에 특화된 무료 배포 서비스입니다.
GitHub에 올리면 자동으로 배포됩니다
flowchart LR
L["로컬 코드"] -->|git push| G["GitHub"]
G -->|자동 감지| P["배포 플랫폼<br/>(Vercel 등)"]
P -->|빌드 & 배포| W["🌐 myapp.vercel.app"]
저장 → 올리기 → 자동 배포. 한 번 연결해 두면, 코드를 고치고 저장하기만 해도 세상에 반영됩니다.
배포에서 초보가 가장 많이 막히는 세 곳
| 문제 | 증상 | 처방 |
|---|---|---|
| 환경변수 빼먹기 | “로컬에선 됐는데 배포하니 안 돼” | .env는 Git에 안 올라감 → 배포 플랫폼 설정 화면에 따로 입력 |
| CORS 막힘 | 화면에서 서버 호출 시 에러 | 서버가 “이 프론트 주소에서 오는 요청은 허용”이라고 설정 |
| 무료의 함정 | 첫 방문자 화면이 느리거나 요금 폭탄 | 잠듦(spin-down), 기한, 요금 알림 확인 |
💡 요금 폭탄 방지 3원칙: ① 요금 알림 켜 둔다, ② 내 무료 한도를 안다, ③ 비밀 키를 지킨다(유출된 키로 남이 내 돈 쓸 수 있음).
2026년 무료 호스팅 비교
| 서비스 | 뭘 올리기 좋나 | 무료 특징 · 주의 |
|---|---|---|
| Cloudflare Pages | 정적·프론트 | 대역폭 무제한, 트래픽 걱정 최소 |
| GitHub Pages | 정적 전용 | 가장 단순, 코드 저장소에서 바로 |
| Vercel | 프론트·Next.js | 손이 가장 덜 감, 개인·비상업용 |
| Netlify | 정적·프론트 | Vercel 대안, 상업 이용 허용 |
| Render | 백엔드 API | 15분 안 쓰면 잠듦(~1분 걸림) |
| Supabase | 백엔드+DB | 7일 미사용 시 일시정지 |
⚠️ 공짜의 세계는 계속 줄어듭니다. Heroku(2022), Fly.io(2024), Glitch(2025)가 무료를 없앴습니다. “지금 무료인 것도 언젠가 바뀔 수 있다”는 전제로, 가입 전 공식 요금 페이지를 확인하세요.
6️⃣ 내 컴퓨터를 서버로 — 집에서 돌려보기
왜 기본적으로 안 되는가 — NAT
집 안의 기기들은 공유기가 나눠 준 사설 IP(192.168.x.x)를 씁니다. 바깥 인터넷에서 우리 집은 공유기 한 대로만 보이고(NAT), 곧장 내 노트북으로 연결이 안 됩니다.
전통 방법: 포트 포워딩 + DDNS
공유기 설정에서 특정 포트를 내 컴퓨터로 열어 주고, DDNS 서비스로 바뀌는 IP를 따라가는 방법입니다. 원리를 배우기엔 좋지만 주의가 큽니다.
- 집 네트워크가 인터넷에 직접 노출됩니다
- 요즘은 CGNAT(통신사가 IP를 여러 집이 공유)라 포트 포워딩 자체가 안 될 수 있습니다
요즘 편한 방법: 터널(Tunnel)
터널은 발상을 뒤집습니다. 밖에서 우리 집으로 들어오게 여는 대신, 내 컴퓨터가 바깥 서비스로 먼저 연결을 맺어 그 통로로 손님을 받습니다. 포트를 열 필요가 없고, CGNAT도 통과합니다.
| 도구 | 특징 | 무료 한도 | 추천 상황 |
|---|---|---|---|
| Cloudflare Tunnel | 포트 개방 불필요, HTTPS, 인증 | 대역폭 무제한 | 상시 운용 |
| ngrok | 한 줄 명령으로 즉시 공개 | 고정 주소 1개, 동시 3개 | 잠깐 시연·테스트 |
| Tailscale Funnel | 사설망 묶고 일부만 공개 | 무료·고정 주소 | 팀 내부 공유 |
1
2
3
# ngrok 예시 — 한 줄로 로컬 서버를 세상에 공개
ngrok http 3000
# → https://abc123.ngrok-free.app 주소 생성!
💡 “친구에게 잠깐 보여주고 싶다”면 ngrok이 가장 빠릅니다. 계속 켜 둘 상시 서비스라면 Cloudflare Tunnel이 무료이면서 대역폭 제한도 없어 든든합니다.
홈랩과 라즈베리파이
손바닥만 한 저전력 컴퓨터 라즈베리파이를 24시간 켜 두고 개인 서버로 쓰는 문화가 있습니다(홈랩, 셀프호스팅). 가족용 미디어 저장소, 집안 자동화, 개인 위키, 토이 프로젝트 같은 걸 직접 돌려보기 좋습니다.
🏠 집 서버는 재미있는 공부이자 취미입니다. 하지만 첫 진짜 배포는 앞에서 본 무료 클라우드(Cloudflare·Vercel·Render·Supabase)가 거의 항상 더 안전하고 손이 덜 갑니다. 원리는 집에서 익히고, 세상에 보여줄 땐 클라우드 — 이 조합이 초보에게 가장 무난합니다.
7️⃣ 프론트-백엔드 연결 — 화면과 서버를 AI로 잇기
가장 안정적인 순서
지난 시간에 목업 데이터로 화면을 먼저 만들었습니다. 백엔드가 생기면 이 순서로 잇습니다:
flowchart LR
M["1. 목업 화면 완성"] --> A["2. API 명세 문서 작성"]
A --> R["3. 가짜 데이터 → 진짜 호출로 교체"]
💡 핵심 원칙: “앱 전체를 한 번에 시킬까, 나눠 시킬까?” — 통째로 한 프롬프트에 맡기면 거의 실패합니다. “데이터 모양 → API → 화면” 처럼 작게 쪼개 시키면 실수를 일찍 잡습니다.
초보가 가장 많이 겪는 연결 문제
| 문제 | 증상 | 처방 |
|---|---|---|
| 계약 불일치 | 화면에 undefined 표시 | 프론트와 백엔드가 같은 API 명세 문서를 보고 개발 |
| 로딩·에러 상태 누락 | 데이터 오기 전 빈 화면, 오류 시 멈춤 | 모든 호출을 로딩 / 성공 / 에러 세 상태로 나눠 처리 |
| CORS·주소·환경변수 | “로컬에선 됐는데…” | 서버가 프론트 주소를 CORS 허용, 주소는 환경변수로 |
AI에게 연결을 시키는 프롬프트 전략
1
2
3
API 명세를 문서로 (근본 해결):
"엔드포인트 목록과 각 요청/응답 예시(JSON)를 명세 문서로 만들어 줘.
앞으로 이 문서를 기준으로 프론트와 백엔드를 짜자."
1
2
한 기능씩 끝까지 (수직 슬라이스):
"회원가입 한 기능을 화면-API-저장까지 하나로 완성하고 바로 테스트해."
1
2
3
목업→실제 전환:
"지금 화면이 쓰는 가짜 데이터를 방금 만든 실제 API 호출로 바꿔 줘.
문서(명세)의 요청/응답 모양은 그대로 유지하고, 로딩과 에러 처리도 넣어 줘."
🧠 오늘의 CS 핵심 개념 정리
| 개념 | 한 줄 정의 | 비유 |
|---|---|---|
| 클라이언트-서버 | 요청하는 쪽과 응답하는 쪽 | 손님과 주방 |
| DNS | 도메인 → IP 변환 | 전화번호부 |
| 포트 | 하나의 IP에서 여러 서비스 구분 | 건물의 호실 번호 |
| HTTP/HTTPS | 웹 통신 규약 / 암호화 버전 | 엽서 / 밀봉 택배 |
| API 엔드포인트 | 서버가 제공하는 요청 창구 | 식당 메뉴판 항목 |
| CRUD | Create·Read·Update·Delete | 생성·조회·수정·삭제 |
| JSON | 데이터 교환 형식 | 공용어 |
| 환경변수(.env) | 비밀값을 코드 밖에 보관 | 금고 |
| 해싱 | 일방통행 변환 (복원 불가) | 문서 파쇄기 |
| NAT | 사설 IP ↔ 공인 IP 변환 | 공유기의 문지기 |
| 터널 | 내 컴퓨터→외부 서비스로 통로 | 안에서 밖으로 뚫은 비밀 통로 |
💡 기술연구소 Insight — 백엔드는 “한 겹 덧입히기”
flowchart LR
subgraph "지난 시간"
HTML["HTML·CSS·JS"] --> FW["프레임워크"]
FW --> MOCK["목업 데이터"]
end
subgraph "오늘"
MOCK -->|"가짜 → 진짜"| API["API 서버"]
API --> DB["데이터베이스"]
end
subgraph "다음 단계"
DB --> DEPLOY["배포 🚀"]
end
지난 시간에 목업(가짜) 데이터로 화면을 만들었죠. 백엔드가 생기면, 그 “가짜 데이터를 불러오던 한 줄” 을 “진짜 서버에 요청하는 한 줄” 로 바꾸기만 하면 됩니다. 화면 코드는 거의 그대로입니다.
네트워크(연결)·보안(안전)·배포(공개) — 이 세 겹을 안전하게 덧입히면, 홀만 있던 가게에 드디어 주방이 생기는 순간입니다.
🔗 이어지는 R&D 일지
- 🚀 실전 프로젝트 → 파트너스 매칭 매니저 제작기
- 🧱 이전 수업 → 프레임워크·PRD·목업 데이터
- 🔌 API 기초 → API란 무엇인가 · 웹훅이란 무엇인가
- 🌐 배포 실전 → GitHub Pages 배포하기 · 커스텀 도메인·HTTPS
- 🧱 웹 기초 → 웹을 지탱하는 세 겹 · 이벤트 루프
- 🛠️ 작업대 → 바이브 코딩 작업대 · 터미널·셸·커널
📎 본 글은 주식회사 넥스트엑스(NEXT X) 기술연구소의 R&D 자산입니다. 함께 읽기 — 🛠️ 개발 대표 사례 · 📖 블로그 안내 · 📩 비즈니스 문의
