infra
Platform

모듈 맵

[Network] curl 명령어로 HTTP 상태 코드 및 헤더 분석하기

0 / 35 완료

펼치기
0 / 35 완료0%

Networking · 15 / 35

[Network] curl 명령어로 HTTP 상태 코드 및 헤더 분석하기

curl로 HTTP 헤더, 상태 코드, SSL 인증서를 점검합니다

🚨INCIDENT ALERT
HIGH

운영 반영 직후 헬스체크는 실패하지만 브라우저에서는 페이지가 열립니다. 응답 코드, 헤더, 리다이렉트, TLS 정보를 한 번에 확인하지 못해 원인 파악이 늦어집니다.

curl은 단순 다운로드 도구가 아니라 HTTP 장애를 분해하는 가장 빠른 현장 도구입니다.

HTTP 테스트와 상태 코드 점검 (curl)

웹 서버 응답이 이상하다, API가 갑자기 500 에러를 반환한다, SSL 인증서가 만료됐다는 알림이 왔다 — 이런 상황에서 브라우저를 열기 전에 CLI에서 즉시 확인할 수 있는 도구가 curl입니다. 이 챕터에서는 HTTP 메서드와 상태 코드 체계를 이해하고, curl의 핵심 옵션을 활용해 서버 상태를 정확하게 진단하는 방법을 배웁니다.


이번 챕터에서 배울 것
  • 1HTTP 메서드(GET/POST/PUT/PATCH/DELETE/HEAD/OPTIONS)와 멱등성 개념
  • 2HTTP 상태 코드 체계 (2xx 성공, 3xx 리다이렉션, 4xx 클라이언트 오류, 5xx 서버 오류)
  • 3502 / 503 / 504 Bad Gateway 오류 구분 및 원인 분석
  • 4curl 핵심 옵션(-I, -v, -s, -L, -k, -w, -X, -d, -H)과 실전 활용
  • 5SSL/TLS 인증서 만료 점검 및 openssl을 이용한 만료일 확인
  • 6서버 상태 모니터링 및 CI/CD 배포 헬스체크 자동화 스크립트 작성
실습 환경 준비
curl 설치 확인
curl --version
openssl 설치 확인 (SSL 인증서 점검에 필요)
openssl version
테스트용 HTTP 엔드포인트 (httpbin.org 활용 가능)

인터넷 연결이 필요합니다. 오프라인 환경이라면 로컬에서 python3 -m http.server 8000으로 간이 서버를 실행할 수 있습니다.

bc 명령 설치 확인 (응답 시간 임계값 비교 스크립트에 필요)
bc --version || sudo apt-get install -y bc
💡개념

HTTP 메서드와 상태 코드 체계

백엔드 API를 호출했는데 405 오류가 납니다. 또 다른 경우엔 GET으로 데이터를 삭제하는 코드가 있고, POST와 PUT을 혼용해서 클라이언트가 중복 요청을 보내도 서버가 멱등하게 처리되지 않습니다. HTTP 메서드와 상태 코드 체계를 정확히 알지 못하면 API 설계에서 이런 실수가 반복됩니다.

HTTP 메서드와 상태 코드 체계

HTTP 메서드 — 행위를 표현하는 동사

HTTP 요청은 어떤 작업을 할지 메서드(동사)로 표현합니다. REST API 설계와 서버 동작을 이해하는 데 필수적입니다.

메서드의미멱등성주요 사용 예
GET리소스 조회O페이지 조회, API 데이터 읽기
POST리소스 생성X회원 가입, 주문 생성
PUT리소스 전체 교체O사용자 정보 전체 수정
PATCH리소스 부분 수정X이메일만 변경
DELETE리소스 삭제O게시글 삭제
HEAD헤더만 요청O파일 크기 확인, 상태 점검
OPTIONS지원 메서드 조회OCORS 사전 요청

멱등성(Idempotency): 같은 요청을 여러 번 보내도 결과가 동일하면 멱등. GET으로 같은 페이지를 100번 요청해도 서버 상태는 변하지 않습니다.

HTTP 상태 코드 — 서버의 응답 의미

상태 코드는 3자리 숫자로, 첫 번째 자리가 대분류를 나타냅니다.

2xx — 성공

코드이름의미
200OK요청 성공, 응답 바디 포함
201CreatedPOST로 리소스 생성 성공
204No Content성공했지만 반환할 바디 없음 (DELETE 응답 등)

3xx — 리다이렉션

코드이름의미
301Moved Permanently영구 이동, 북마크 갱신 필요
302Found임시 이동
304Not Modified캐시 유효, 바디 없음

4xx — 클라이언트 오류

코드이름의미
400Bad Request잘못된 요청 형식
401Unauthorized인증 필요(미로그인)
403Forbidden인증은 됐지만 권한 없음
404Not Found리소스 없음
429Too Many Requests요청 속도 초과(rate limit)

5xx — 서버 오류

코드이름의미
500Internal Server Error서버 내부 오류(코드 버그 등)
502Bad Gateway게이트웨이가 업스트림에서 유효하지 않은 응답 수신
503Service Unavailable서버 과부하 또는 점검 중
504Gateway Timeout게이트웨이가 업스트림 응답 대기 시간 초과

502 vs 503 vs 504 구분

현장에서 자주 혼동되는 5xx 코드입니다.

클라이언트 → [Nginx 프록시] → [백엔드 앱 서버]

502: 백엔드가 응답했지만 내용이 이상함 (프로토콜 오류, 잘못된 응답)
503: 백엔드 서버가 완전히 다운됨 (연결 거부)
504: 백엔드 서버가 타임아웃 내에 응답하지 않음
500: 백엔드 서버 자체에서 오류 발생 (코드 예외, DB 오류 등)

💡개념

curl 핵심 옵션과 SSL 인증서 점검

배포 직후 API가 정상인지 확인하려 합니다. 브라우저에서는 되는데 서버에서 내부 API 호출이 안 됩니다. curl을 써서 직접 요청을 던져보면 원인이 바로 드러나는 경우가 많습니다. 헤더를 붙이는 방법, SSL 인증서 오류를 우회하는 방법, 응답 코드만 확인하는 방법 — 이 옵션들을 모르면 curl은 그냥 wget 대체 도구로만 씁니다.

curl 기본 동작 원리

curl(Client URL)은 다양한 프로토콜을 지원하는 CLI 데이터 전송 도구입니다. HTTP/HTTPS 외에도 FTP, SMTP, DNS 등을 지원합니다.

로컬 터미널
# 실습 디렉토리 준비
mkdir -p /tmp/networking/part3/exam_15 && cd /tmp/networking/part3/exam_15

# 기본 GET 요청 — 응답 바디를 표준 출력으로 출력
curl http://example.com

# HTTPS (SSL/TLS 검증 포함)
curl https://example.com
🔍실행 후 확인할 것
  • 핵심 출력명령 결과에서 성공/실패를 가르는 값을 먼저 확인합니다
  • 대상 식별IP, 포트, 인터페이스, 프로세스명처럼 다음 조치를 결정하는 필드를 봅니다
  • 다음 분기결과가 기대와 다르면 어느 계층을 이어서 점검할지 정합니다

주요 옵션 정리

옵션설명
-IHEAD 메서드로 헤더만 수신
-vverbose — 전체 HTTP 흐름 출력
-ssilent — 진행 표시줄 숨김
-o 파일응답 바디를 파일로 저장
-OURL의 파일명으로 저장
-L리다이렉트 자동 따라가기
-kSSL 인증서 검증 건너뜀 (비보안)
-w 형식요청 완료 후 지정 형식으로 정보 출력
-H "헤더"커스텀 헤더 추가
-d "데이터"POST 바디 데이터
-X 메서드HTTP 메서드 지정
-u 사용자:암호Basic 인증
--connect-timeout N연결 타임아웃(초)
--max-time N전체 요청 타임아웃(초)

SSL/TLS 인증서 점검

HTTPS 사이트의 인증서 만료일, 발급자, SANs(Subject Alternative Names) 정보를 확인하는 방법입니다.

로컬 또는 서버
# 인증서 상세 정보 확인
curl -vI https://example.com 2>&1 | grep -E "expire|issuer|subject|SSL"

# openssl을 이용한 만료일 확인 (더 명확)
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
  | openssl x509 -noout -dates

# 출력 예
# notBefore=Jan  1 00:00:00 2024 GMT
# notAfter=Jan  1 00:00:00 2025 GMT   ← 이 날짜 확인

인증서 만료 N일 전 알림을 자동화하는 확인 방법:

로컬 터미널
#!/bin/bash
# SSL 만료까지 남은 일수 확인
DOMAIN="example.com"
EXPIRY=$(echo | openssl s_client -connect "${DOMAIN}:443" -servername "${DOMAIN}" 2>/dev/null \
  | openssl x509 -noout -enddate | cut -d= -f2)

EXPIRY_EPOCH=$(date -d "$EXPIRY" +%s)
NOW_EPOCH=$(date +%s)
DAYS_LEFT=$(( (EXPIRY_EPOCH - NOW_EPOCH) / 86400 ))

echo "${DOMAIN}: 인증서 만료까지 ${DAYS_LEFT}일 남음"

if [ "$DAYS_LEFT" -lt 30 ]; then
  echo "경고: 30일 이내 만료 예정!"
fi

로컬 터미널
mkdir -p /tmp/networking/part3/http-curl && cd /tmp/networking/part3/http-curl
# 로컬 테스트 서버 스크립트 생성
cat > test_server.py << 'EOF'
from http.server import HTTPServer, BaseHTTPRequestHandler
import json

class Handler(BaseHTTPRequestHandler):
    def do_GET(self):
        if self.path == '/health':
            self.send_response(200)
            self.send_header('Content-Type', 'application/json')
            self.end_headers()
            self.wfile.write(json.dumps({'status':'ok'}).encode())
        elif self.path == '/api/users':
            self.send_response(200)
            self.send_header('Content-Type', 'application/json')
            self.end_headers()
            data = [{'id':1,'name':'alice'},{'id':2,'name':'bob'}]
            self.wfile.write(json.dumps(data).encode())
        else:
            self.send_response(404)
            self.end_headers()
    def do_POST(self):
        length = int(self.headers.get('Content-Length', 0))
        body = self.rfile.read(length)
        self.send_response(201)
        self.send_header('Content-Type', 'application/json')
        self.end_headers()
        self.wfile.write(json.dumps({'created': True, 'data': body.decode()}).encode())
    def log_message(self, *args): pass

HTTPServer(('127.0.0.1', 8765), Handler).serve_forever()
EOF
echo "# 테스트 서버 실행 (백그라운드)"
echo "# python3 test_server.py &"
curl로 HTTP 헤더와 상태 코드 확인

curl -I 헤더 확인

로컬 또는 서버
# 기본 헤더 확인 (HEAD 메서드)
curl -I https://www.google.com

# 출력 예시
# HTTP/2 200
# content-type: text/html; charset=UTF-8
# date: Mon, 27 Jan 2025 01:00:00 GMT
# expires: Mon, 27 Jan 2025 01:00:00 GMT
# cache-control: private, max-age=0
# server: gws
# x-xss-protection: 0
# x-frame-options: SAMEORIGIN

확인 포인트:

  • HTTP/2 200 — 프로토콜 버전과 상태 코드
  • content-type — 응답 형식 (text/html, application/json 등)
  • server — 웹 서버 소프트웨어 (Nginx, Apache, gws 등)
  • cache-control — 캐싱 정책
로컬 또는 서버
# 리다이렉트를 따라가며 최종 목적지 확인
curl -I -L http://naver.com

# HTTP/1.1 301 Moved Permanently      ← 첫 번째 응답
# location: https://www.naver.com/    ← 리다이렉트 대상
# ...
# HTTP/2 200                          ← 최종 목적지 응답

상태 코드만 빠르게 확인

로컬 또는 서버
# 상태 코드만 숫자로 출력
curl -s -o /dev/null -w "%{http_code}" https://www.google.com
# 출력: 200

# 줄바꿈 추가
curl -s -o /dev/null -w "%{http_code}\n" https://www.google.com

# 여러 사이트 일괄 점검
for url in https://google.com https://naver.com https://example.com; do
  code=$(curl -s -o /dev/null -w "%{http_code}" --connect-timeout 5 "$url")
  echo "$url → $code"
done

응답 시간 측정

로컬 또는 서버
# 상세한 타이밍 정보 출력
curl -o /dev/null -s -w "
DNS 조회:      %{time_namelookup}s
TCP 연결:      %{time_connect}s
TLS 핸드셰이크: %{time_appconnect}s
첫 바이트까지:  %{time_starttransfer}s
전체 시간:     %{time_total}s
전송 크기:     %{size_download} bytes
" https://www.google.com

출력 항목 설명:

  • time_namelookup: DNS 조회 시간
  • time_connect: TCP 3-way handshake 완료까지
  • time_appconnect: TLS 핸드셰이크 완료까지 (HTTPS)
  • time_starttransfer: 서버가 첫 번째 바이트를 보낼 때까지
  • time_total: 전체 완료 시간

curl -v verbose로 전체 HTTP 흐름 디버깅

curl -v 출력 구조 이해

로컬 또는 서버
curl -v https://httpbin.org/get

출력에서 각 접두사의 의미:

*   Trying 54.208.105.16:443...         ← DNS/TCP 정보 (* = curl 내부 정보)
* Connected to httpbin.org port 443     ← TCP 연결 성공
* SSL connection using TLSv1.3          ← TLS 버전
* Server certificate:                   ← 인증서 정보 시작
*  subject: CN=httpbin.org
*  start date: Jan  1 00:00:00 2024 GMT
*  expire date: Jan  1 00:00:00 2025 GMT
*  SSL certificate verify ok.           ← 인증서 검증 성공
>                                       ← > = 내가 보낸 요청 헤더
> GET /get HTTP/2
> Host: httpbin.org
> User-Agent: curl/7.88.1
> Accept: */*
>
< HTTP/2 200                            ← < = 서버의 응답 헤더
< date: Mon, 27 Jan 2025 01:00:00 GMT
< content-type: application/json
< content-length: 305
<
{                                       ← 응답 바디 (접두사 없음)
  "headers": { ... }
}

POST 요청으로 API 테스트

로컬 또는 서버
# JSON 바디로 POST 요청
curl -v -X POST https://httpbin.org/post \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer mytoken123" \
  -d '{"username": "testuser", "action": "login"}'

# Form 데이터로 POST
curl -v -X POST https://httpbin.org/post \
  -F "username=testuser" \
  -F "password=secret"

# PUT 요청
curl -X PUT https://httpbin.org/put \
  -H "Content-Type: application/json" \
  -d '{"name": "updated name"}'

# DELETE 요청
curl -X DELETE https://httpbin.org/delete \
  -H "Authorization: Bearer mytoken123"

SSL 인증서 오류 디버깅

로컬 또는 서버
# 인증서 검증 실패 시 상세 정보
curl -v https://expired.badssl.com/ 2>&1

# 주요 에러 메시지
# * SSL certificate problem: certificate has expired     ← 만료
# * SSL certificate problem: self-signed certificate     ← 자체 서명
# * SSL certificate problem: unable to get local issuer certificate ← 체인 불완전

# 임시 우회 (운영 환경에서는 절대 사용 금지!)
curl -k https://expired.badssl.com/

# 특정 CA 인증서 지정
curl --cacert /path/to/company-ca.crt https://internal.example.com/

타임아웃 설정

로컬 또는 서버
# 연결 타임아웃 3초, 전체 응답 타임아웃 10초
curl --connect-timeout 3 --max-time 10 https://example.com

# 응답 없는 서버 빠르게 탐지
curl -s -o /dev/null -w "%{http_code}" \
  --connect-timeout 3 --max-time 5 \
  http://192.168.1.200/health
# 출력: 000 (연결 실패 시)

서버 상태 모니터링 스크립트 작성

기본 헬스체크 스크립트

로컬 터미널
#!/bin/bash
# /usr/local/bin/http-healthcheck.sh

TARGETS=(
  "https://www.example.com|200"
  "https://api.example.com/health|200"
  "https://www.google.com|200"
)

FAILED=0

for entry in "${TARGETS[@]}"; do
  url=$(echo "$entry" | cut -d'|' -f1)
  expected=$(echo "$entry" | cut -d'|' -f2)

  actual=$(curl -s -o /dev/null -w "%{http_code}" \
    --connect-timeout 5 --max-time 10 "$url")

  if [ "$actual" = "$expected" ]; then
    echo "[OK]   $url → $actual"
  else
    echo "[FAIL] $url → 예상: $expected, 실제: $actual"
    FAILED=$((FAILED + 1))
  fi
done

exit $FAILED

응답 시간 임계값 모니터링

로컬 터미널
#!/bin/bash
# 응답 시간이 2초를 초과하면 경고

URL="https://api.example.com/v1/status"
THRESHOLD=2.0

TIMING=$(curl -o /dev/null -s -w "%{time_total}" \
  --connect-timeout 5 --max-time 10 "$URL")

echo "응답 시간: ${TIMING}s"

# bc로 부동소수점 비교
if (( $(echo "$TIMING > $THRESHOLD" | bc -l) )); then
  echo "경고: 응답 시간 임계값(${THRESHOLD}s) 초과!"
  exit 1
fi
echo "정상"

SSL 인증서 만료 일괄 점검

로컬 터미널
#!/bin/bash
# 여러 도메인의 SSL 만료일 일괄 점검

DOMAINS=("www.example.com" "api.example.com" "static.example.com")
WARN_DAYS=30

for domain in "${DOMAINS[@]}"; do
  EXPIRY=$(echo | openssl s_client -connect "${domain}:443" \
    -servername "${domain}" 2>/dev/null \
    | openssl x509 -noout -enddate 2>/dev/null | cut -d= -f2)

  if [ -z "$EXPIRY" ]; then
    echo "[ERROR] $domain: 인증서 조회 실패"
    continue
  fi

  EXPIRY_EPOCH=$(date -d "$EXPIRY" +%s 2>/dev/null)
  NOW_EPOCH=$(date +%s)
  DAYS_LEFT=$(( (EXPIRY_EPOCH - NOW_EPOCH) / 86400 ))

  if [ "$DAYS_LEFT" -lt 0 ]; then
    echo "[EXPIRED] $domain: 이미 만료됨"
  elif [ "$DAYS_LEFT" -lt "$WARN_DAYS" ]; then
    echo "[WARN]    $domain: ${DAYS_LEFT}일 후 만료 (${EXPIRY})"
  else
    echo "[OK]      $domain: ${DAYS_LEFT}일 남음"
  fi
done

cron에 등록하여 매일 점검:

로컬 터미널
# crontab -e
0 9 * * * /usr/local/bin/ssl-check.sh | mail -s "SSL 만료 점검 결과" admin@example.com

증상

로컬 터미널
$ curl -I https://api.example.com/v1/users
HTTP/1.1 502 Bad Gateway
Server: nginx/1.24.0
Date: Mon, 27 Jan 2025 01:00:00 GMT
Content-Type: text/html

원인 분석과 점검 순서

단계 1 — 백엔드 서버 포트 리스닝 확인

로컬 터미널
# Nginx 프록시가 8080으로 백엔드를 바라본다고 가정
ss -antp | grep 8080
# 출력이 없으면 백엔드 서버가 다운된 것

단계 2 — 백엔드 직접 접근 테스트

로컬 또는 서버
# Nginx를 우회하고 백엔드 직접 호출
curl -v http://127.0.0.1:8080/v1/users

# 연결 거부 시
# curl: (7) Failed to connect to 127.0.0.1 port 8080: Connection refused
# → 백엔드 프로세스 다운

# 응답이 오면 Nginx 설정 문제

단계 3 — Nginx 에러 로그 확인

로컬 터미널
# Nginx 에러 로그에서 upstream 관련 메시지 확인
tail -50 /var/log/nginx/error.log | grep upstream

# 예시 에러 메시지
# *1 connect() failed (111: Connection refused) while connecting to upstream
# → 백엔드 서비스 다운
# *1 upstream timed out (110: Connection timed out) while reading response header
# → 백엔드 응답 타임아웃

단계 4 — 백엔드 서비스 재시작

위험 명령어

이 명령은 실행 중인 서비스 상태를 바꿔 순간적인 중단이나 설정 반영 실패를 만들 수 있습니다. 운영 트래픽 영향과 재시작 후 확인 명령을 먼저 준비하세요.

서버 터미널
# 애플리케이션 서비스 상태 확인 및 재시작
systemctl status myapp
systemctl restart myapp

# Docker 컨테이너인 경우
docker ps | grep myapp
docker restart myapp-container

502 유형별 Nginx 설정 해결책

Nginx
# proxy_connect_timeout: 백엔드 연결 타임아웃 (기본 60s)
# proxy_read_timeout: 응답 대기 타임아웃 (기본 60s)
# 느린 API의 경우 늘려줄 수 있음

upstream backend {
    server 127.0.0.1:8080;
    keepalive 32;
}

server {
    location /api/ {
        proxy_pass http://backend;
        proxy_connect_timeout 5s;
        proxy_read_timeout 30s;
        proxy_send_timeout 30s;
    }
}

증상

로컬 터미널
$ curl https://api.example.com/health
curl: (60) SSL certificate problem: certificate has expired
More details here: https://curl.se/docs/sslcerts.html

curl failed to verify the legitimacy of the server and therefore
could not establish a secure connection to it.

브라우저에서는 "NET::ERR_CERT_DATE_INVALID" 오류로 표시됩니다.

즉각적인 현황 파악

로컬 터미널
# 1. 만료일 확인
echo | openssl s_client -connect api.example.com:443 -servername api.example.com 2>/dev/null \
  | openssl x509 -noout -dates
# notAfter=Dec 31 23:59:59 2024 GMT  ← 만료됨

# 2. 발급자 확인 (Let's Encrypt인지, 상용 CA인지)
echo | openssl s_client -connect api.example.com:443 2>/dev/null \
  | openssl x509 -noout -issuer -subject

# 3. 임시 우회로 서비스 동작 확인 (장애 범위 파악)
curl -k https://api.example.com/health
# 200이면 인증서만 문제, 서비스는 살아있음

인증서 종류별 갱신 방법

Let's Encrypt (Certbot)

위험 명령어

이 명령은 실행 중인 서비스 상태를 바꿔 순간적인 중단이나 설정 반영 실패를 만들 수 있습니다. 운영 트래픽 영향과 재시작 후 확인 명령을 먼저 준비하세요.

로컬 터미널
# 상태 확인
certbot certificates

# 수동 갱신
certbot renew --cert-name api.example.com

# 강제 갱신 (만료 전이라도)
certbot renew --force-renewal --cert-name api.example.com

# Nginx 리로드
systemctl reload nginx

상용 CA (DigiCert, Sectigo 등)

  1. CA 포털에서 새 인증서 신청/다운로드
  2. 기존 인증서 파일 교체:
    로컬 터미널
    cp new-cert.pem /etc/nginx/ssl/api.example.com.crt
    cp new-key.pem /etc/nginx/ssl/api.example.com.key
    nginx -t && systemctl reload nginx
    

재발 방지 — 자동 갱신 설정

위험 명령어

이 명령은 실행 중인 서비스 상태를 바꿔 순간적인 중단이나 설정 반영 실패를 만들 수 있습니다. 운영 트래픽 영향과 재시작 후 확인 명령을 먼저 준비하세요.

서버 터미널
# Certbot 자동 갱신 타이머 확인
systemctl status certbot.timer

# 없으면 cron으로 설정
# crontab -e
0 3 * * * certbot renew --quiet && systemctl reload nginx

💼
실무 맥락
현업 패턴

실무에서 curl이 필수인 이유

curl은 브라우저 없이 HTTP 통신의 모든 계층을 CLI에서 직접 제어하고 검사할 수 있는 도구입니다. GUI가 없는 서버 환경, 자동화 스크립트, CI/CD 파이프라인에서 없어서는 안 됩니다.

개발자 관점

로컬 또는 서버
# API 개발 중 빠른 테스트
curl -X POST http://localhost:8080/api/login \
  -H "Content-Type: application/json" \
  -d '{"email":"test@example.com","password":"1234"}'

# 응답 헤더에서 토큰 추출
TOKEN=$(curl -s -X POST http://localhost:8080/api/login \
  -H "Content-Type: application/json" \
  -d '{"email":"test@example.com","password":"1234"}' \
  | python3 -c "import sys,json; print(json.load(sys.stdin)['token'])")

# 추출한 토큰으로 인증 API 테스트
curl -H "Authorization: Bearer $TOKEN" http://localhost:8080/api/users/me

인프라/운영 관점

로컬 터미널
# 로드밸런서 뒤의 각 백엔드 서버가 올바른 응답을 하는지 확인
# (Server 헤더나 X-Served-By 헤더로 어느 백엔드가 응답했는지 파악)
for i in {1..10}; do
  curl -s -o /dev/null -w "%{http_code} - %header{x-served-by}\n" \
    https://api.example.com/health
done

# Prometheus/Grafana 없는 환경에서 수동 모니터링
watch -n 5 'curl -s -o /dev/null -w "Status: %{http_code} | Time: %{time_total}s\n" \
  https://api.example.com/health'

CI/CD 파이프라인에서의 활용

로컬 터미널
# 배포 후 헬스체크 (배포 스크립트에 포함)
deploy_app() {
  # ... 배포 로직 ...

  # 배포 후 최대 60초간 헬스체크 재시도
  for i in {1..12}; do
    STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
      --connect-timeout 3 --max-time 5 \
      https://api.example.com/health)

    if [ "$STATUS" = "200" ]; then
      echo "배포 성공: 서비스 정상 응답"
      return 0
    fi

    echo "시도 $i/12: 상태 코드 $STATUS, 5초 후 재시도..."
    sleep 5
  done

  echo "배포 실패: 헬스체크 타임아웃"
  return 1
}

자격증 및 면접 포인트

  • HTTP 상태 코드 외우기: 200/201/204/301/302/400/401/403/404/429/500/502/503/504는 반드시 설명할 수 있어야 합니다.
  • curl -v 출력 해석: TLS 핸드셰이크, 요청/응답 헤더 흐름을 설명할 수 있어야 합니다.
  • 502 vs 503 차이: Nginx/Apache 프록시 구성 면접에서 자주 나오는 질문입니다.
  • SSL 갱신 자동화: Let's Encrypt + Certbot 자동 갱신 설정은 실무 기초 역량입니다.

핵심 명령어 정리

명령설명
curl -I URLHEAD 요청으로 헤더만 확인
curl -v URL전체 HTTP 흐름 verbose 출력
curl -s -o /dev/null -w "%{http_code}" URL상태 코드만 출력
curl -L URL리다이렉트 자동 추적
curl -o 파일 URL응답을 파일로 저장
curl -k URLSSL 검증 건너뜀 (임시 테스트용)
curl -X POST -d '...' -H 'Content-Type: application/json' URLJSON POST 요청
curl --connect-timeout 3 --max-time 10 URL타임아웃 설정

정리

  • HTTP 메서드(GET/POST/PUT/DELETE)는 행위를, 상태 코드는 결과를 표현합니다.
  • curl -I로 빠르게 헤더와 상태 코드를 확인하고, curl -v로 전체 흐름을 디버깅합니다.
  • curl -s -o /dev/null -w "%{http_code}"는 자동화 스크립트에서 상태 코드만 추출하는 표준 패턴입니다.
  • SSL 인증서 만료 전 자동 알림과 certbot 자동 갱신을 설정하면 장애를 예방할 수 있습니다.
  • 502는 게이트웨이의 업스트림 문제, 503은 서비스 완전 다운, 504는 타임아웃으로 구분합니다.

지식 확인

퀴즈 — 5문제

Q1

HTTP 상태 코드 502 Bad Gateway가 의미하는 것은 무엇입니까?

Q2

curl -I 옵션의 역할은 무엇입니까?

Q3

curl -s -o /dev/null -w "%{http_code}" URL 명령의 목적은 무엇입니까?

Q4

SSL 인증서 만료로 인한 curl 에러 메시지로 올바른 것은 무엇입니까?

Q5

curl -v 옵션으로 확인할 수 없는 정보는 무엇입니까?

0 / 5 답변

🧪 실습으로 확인하기

포트는 열렸다는데 왜 안 되지? — ss/netstat/telnet으로 TCP 진단

초급

"포트 8080 열었는데요?"와 "왜 안 돼요?" 사이의 간극을 메우는 실습. ss로 바인딩 상태를 확인하고, telnet/nc으로 원격 연결을 테스트하고, iptables 방화벽을 진단하고, 바인딩 주소(0.0.0.0 vs 127.0.0.1)까지 수정하는 4단계 TCP 포트 진단 플로우를 완성한다.

35📋 4단계💻 직접 환경
실습 시작하기 →

이것도 배워보세요

networking중급 · 50
[Network] Connection Timeout과 Read Timeout 장애 실전 디버깅
Networking 트랙 계속
docker입문 · 30
[Docker] 백엔드 개발자에게 Docker와 컨테이너 가상화가 필수인 이유
Docker 트랙 시작점