블로그로 돌아가기

curl 및 wget을 위한 프록시 설정: 시스템 관리자 및 DevOps를 위한 실용적인 예제

curl과 wget을 위한 프록시 설정에 대한 완벽한 가이드, 코드의 실용적인 예제, SOCKS5 지원, 인증 및 CI/CD 파이프라인에서의 자동화 포함.

📅2026년 4월 3일
```html

서버를 관리하거나 자동화 스크립트를 작성하거나 기업 인프라에 애플리케이션을 배포하는 경우 — 언젠가는 curl 또는 wget의 트래픽을 프록시를 통해 보내야 할 필요성에 직면하게 됩니다. 이는 기업 프록시일 수도 있고, 패키지를 다운로드할 때 지리적 차단을 우회하는 것이거나, 외부 API에 대한 대량 요청 시 IP를 회전하는 것일 수 있습니다. 이 기사에서는 실용적인 내용만 다룹니다: 명령어, 설정, 코드 예제와 함께 불필요한 내용은 생략합니다.

1. curl 및 wget이 프록시와 함께 작동하는 방법: 기본 메커니즘

설정 파일을 살펴보기 전에, 내부에서 무슨 일이 일어나고 있는지 이해하는 것이 중요합니다. 두 도구 모두 HTTP/HTTPS 및 SOCKS5라는 두 가지 기본 프록시 프로토콜을 지원합니다. 이들의 메커니즘은 다르며, 이는 특정 작업에 적합한 프록시 유형을 선택하는 데 영향을 미칩니다.

HTTP 프록시는 애플리케이션 프로토콜 수준에서 중개자로 작동합니다. curl이 HTTP 프록시를 통해 요청을 보낼 때, 실제로 프록시 서버에 "내 대신 이 URL로 GET 요청을 해줘"라고 말하는 것입니다. HTTPS 트래픽의 경우 CONNECT 메서드가 사용되며 — curl은 프록시에게 대상 호스트로의 터널을 설정해달라고 요청하고, 이후 TLS 핸드셰이크는 클라이언트와 대상 서버 간에 직접 발생합니다. 이는 중요합니다: 이 경우 프록시는 HTTPS 트래픽의 내용을 볼 수 없습니다.

SOCKS5는 더 낮은 수준에서 작동하며 — 애플리케이션 프로토콜에 구애받지 않고 TCP/UDP 연결을 프록시합니다. 이는 SOCKS5를 더 유연하게 만들어 줍니다: HTTP/HTTPS뿐만 아니라 다른 프로토콜도 통과시킬 수 있습니다. 또한 SOCKS5는 프록시 서버 측에서 DNS 해석을 지원합니다 — 이는 DNS 누수를 방지하는 데 매우 중요합니다.

💡 실습을 위한 주요 차이점:

단순히 파일을 다운로드하거나 API 요청을 해야 하는 경우 — HTTP 프록시로 충분합니다. 완전한 익명성이 필요하거나 DNS 누수를 우회해야 하거나 비표준 프로토콜로 작업해야 하는 경우 — SOCKS5를 사용하세요.

curl은 매우 초기 버전부터 두 프로토콜을 기본적으로 지원합니다. wget은 역사적으로 SOCKS5 지원이 더 제한적이었으며 — 이전 버전(1.19 이전)에서는 SOCKS5를 전혀 지원하지 않고, HTTP 프록시만 지원합니다. 이는 다양한 배포판에서 작동해야 하는 스크립트를 작성할 때 고려해야 할 사항입니다.

wget 버전을 확인하려면 wget --version 명령어를 사용할 수 있습니다. curl의 경우는 curl --version를 사용하면, libcurl 라이브러리가 어떤 프로토콜로 빌드되었는지 확인할 수 있습니다.

2. 환경 변수: 가장 빠른 설정 방법

curl 및 wget을 위한 프록시를 설정하는 가장 우아한 방법은 환경 변수를 사용하는 것입니다. 이는 시스템적으로 작동하므로, 각 스크립트를 변경할 필요 없이 세션에서 한 번만 변수를 설정하거나 사용자 프로필에 추가하면 됩니다.

두 도구 모두 동일한 표준 변수를 읽습니다:

# HTTP 트래픽을 위한
export http_proxy="http://proxy.example.com:3128"

# HTTPS 트래픽을 위한
export https_proxy="http://proxy.example.com:3128"

# 대문자로 복사 (일부 프로그램은 대문자만 읽음)
export HTTP_PROXY="http://proxy.example.com:3128"
export HTTPS_PROXY="http://proxy.example.com:3128"

# FTP (필요할 경우)
export ftp_proxy="http://proxy.example.com:3128"

# 예외 — 프록시를 통과하지 않는 주소
export no_proxy="localhost,127.0.0.1,::1,192.168.0.0/16,.internal.company.com"

중요한 점: curl은 버전에 따라 변수의 대소문자를 구분합니다. 예기치 않은 상황을 피하기 위해 — 항상 두 가지 버전을 모두 설정하세요: 소문자와 대문자. 이는 DevOps에서의 표준 관행입니다.

특정 사용자에 대해 설정이 지속적으로 적용되도록 하려면 ~/.bashrc 또는 ~/.profile에 이 줄들을 추가하세요. 시스템 스크립트 및 서비스의 경우 — /etc/environment 또는 systemd 유닛 파일의 Environment= 지시문을 통해 추가하세요.

# /etc/systemd/system/myservice.service
[Service]
Environment="http_proxy=http://proxy.example.com:3128"
Environment="https_proxy=http://proxy.example.com:3128"
Environment="no_proxy=localhost,127.0.0.1"
ExecStart=/usr/bin/myapp

프록시가 인증을 요구하는 경우, 사용자 이름과 비밀번호는 URL 변수에 직접 삽입됩니다:

export http_proxy="http://username:[email protected]:3128"
export https_proxy="http://username:[email protected]:3128"

⚠️ 보안:

생산 서버의 .bashrc 또는 환경 변수에 비밀번호를 평문으로 저장하지 마세요. HashiCorp Vault, AWS Secrets Manager와 같은 vault 솔루션을 사용하거나 최소한 변수 파일의 권한을 제한하세요.

3. 프록시와 함께 사용할 curl 플래그: 전체 분석

curl은 명령줄에서 프록시를 관리하기 위한 풍부한 플래그 세트를 제공합니다. 이는 시스템 설정을 변경하지 않고도 프록시를 통해 일회성 요청을 해야 할 때 유용합니다.

기본 플래그는 -x 또는 --proxy입니다:

# 기본 HTTP 프록시
curl -x http://proxy.example.com:3128 https://api.example.com/data

# 짧은 형식
curl -x proxy.example.com:3128 https://api.example.com/data

# 프로토콜을 명시적으로 지정
curl --proxy http://proxy.example.com:3128 https://api.example.com/data

# 프록시를 통해 외부 IP 확인
curl -x http://proxy.example.com:3128 https://api.ipify.org

환경 변수를 무시하고 직접 연결(설정된 프록시를 우회)하려면 --noproxy 플래그를 사용합니다:

# 특정 호스트에 대해 프록시 무시
curl --noproxy "internal.company.com" https://internal.company.com/api

# 프록시를 완전히 무시 (환경 변수가 설정되어 있어도)
curl --noproxy "*" https://api.example.com/data

프록시 연결을 디버깅하기 위한 유용한 플래그:

# 상세 모드: 모든 헤더가 표시되며, 프록시로의 CONNECT도 포함됨
curl -v -x http://proxy.example.com:3128 https://api.example.com/data

# 응답 헤더만 표시
curl -I -x http://proxy.example.com:3128 https://api.example.com/data

# 프록시를 통해 연결 시간 표시
curl -w "Connect: %{time_connect}s\nTotal: %{time_total}s\n" \
  -x http://proxy.example.com:3128 \
  -o /dev/null -s https://api.example.com/data

~/.curlrc 구성 파일을 통해 프록시를 설정하는 것은 매번 플래그를 입력하고 싶지 않을 때 편리합니다:

# ~/.curlrc
proxy = http://proxy.example.com:3128
proxy-user = username:password
noproxy = localhost,127.0.0.1,.internal.company.com

시스템 스크립트의 경우 별도의 구성 파일을 만들고 curl -K /path/to/config를 통해 명시적으로 지정할 수 있습니다 — 이는 다양한 작업에 대해 서로 다른 프록시 프로필을 가질 수 있게 해줍니다.

4. wget에서 프록시 설정: 플래그 및 구성 파일

wget은 curl보다 유연성이 떨어지지만, 일반적인 작업 — 파일 다운로드, 사이트의 재귀적 미러링 — 에 대해서는 충분한 기능을 제공합니다. wget에서 프록시는 환경 변수를 통해(위에서 설명한 대로), 명령줄 플래그를 통해, 그리고 ~/.wgetrc 구성 파일을 통해 설정할 수 있습니다.

wget의 프록시를 위한 명령줄 플래그:

# 플래그를 통한 HTTP 프록시
wget -e use_proxy=yes \
     -e http_proxy=http://proxy.example.com:3128 \
     https://example.com/file.tar.gz

# HTTPS 프록시를 통한
wget -e use_proxy=yes \
     -e https_proxy=http://proxy.example.com:3128 \
     https://example.com/file.tar.gz

# 인증이 필요한 경우
wget -e use_proxy=yes \
     -e http_proxy=http://username:[email protected]:3128 \
     https://example.com/file.tar.gz

# 특정 명령에 대해 프록시 비활성화 (환경 변수가 설정되어 있는 경우)
wget --no-proxy https://internal.company.com/file.tar.gz

~/.wgetrc 구성 파일은 지속적인 설정을 위한 선호하는 방법입니다:

# ~/.wgetrc
use_proxy = on
http_proxy = http://proxy.example.com:3128
https_proxy = http://proxy.example.com:3128
ftp_proxy = http://proxy.example.com:3128
no_proxy = localhost,127.0.0.1,.internal.company.com

# 프록시가 인증을 요구하는 경우
proxy_user = username
proxy_password = secretpassword

시스템 적용(모든 사용자)을 위해서는 /etc/wgetrc를 사용합니다 — 동일한 형식이지만 전역적으로 적용됩니다. 모든 다운로드 작업이 기업 프록시를 통해 이루어져야 하는 서버에 유용합니다.

실용적인 예: 깊이 및 속도 제한을 두고 프록시를 통해 사이트를 재귀적으로 다운로드하는 방법:

wget -e use_proxy=yes \
     -e http_proxy=http://proxy.example.com:3128 \
     --recursive \
     --level=2 \
     --limit-rate=500k \
     --wait=1 \
     --random-wait \
     --user-agent="Mozilla/5.0 (compatible; Googlebot/2.1)" \
     https://example.com/docs/

5. SOCKS5 프록시를 curl 및 wget에서: 설정 및 예제

SOCKS5는 익명성이 중요하거나 비표준 포트를 사용하는 작업에 더 선호되는 프로토콜입니다. 시스템 관리자 및 DevOps 엔지니어에게 SOCKS5는 SSH 터널을 통해 작업할 때, 그리고 주거용 프록시에 연결할 때 자주 사용됩니다. 이는 실제 사용자 트래픽을 모방합니다.

curl에서 SOCKS5는 프록시 URL에 특별한 접두사를 통해 지원됩니다:

# 클라이언트 측에서 DNS 해석 (DNS 누수 가능!)
curl --socks5 proxy.example.com:1080 https://api.example.com/data

# 프록시 측에서 DNS 해석 (추천!)
curl --socks5-hostname proxy.example.com:1080 https://api.example.com/data

# -x 플래그를 통해 프로토콜 명시적으로 지정
curl -x socks5h://proxy.example.com:1080 https://api.example.com/data

# 인증이 필요한 경우
curl -x socks5h://username:[email protected]:1080 https://api.example.com/data

# 환경 변수를 통한 SOCKS5
export all_proxy="socks5h://proxy.example.com:1080"
curl https://api.example.com/data

📌 socks5 vs socks5h — 차이점은 무엇인가요?

socks5 — DNS 요청이 로컬에서 수행되며, 프록시를 통해서는 TCP 연결만 진행됩니다. DNS 누수가 발생할 수 있습니다.
socks5h (h = hostname) — DNS 요청이 프록시 서버 측에서 수행됩니다. 완전한 익명성을 보장합니다. 대부분의 작업에 추천됩니다.

DevOps에서 인기 있는 시나리오는 SSH를 SOCKS5 프록시로 사용하여 트래픽을 배스천 호스트를 통해 터널링하는 것입니다:

# 로컬 포트 1080에서 SOCKS5 SSH 터널 열기
ssh -D 1080 -f -C -q -N [email protected]

# 이제 curl에서 이 터널을 사용합니다
curl -x socks5h://localhost:1080 https://internal-api.private.network/data

# 또는 세션의 모든 요청에 대해 환경 변수를 통해 사용
export all_proxy="socks5h://localhost:1080"
wget https://internal-resource.private.network/file.tar.gz

wget은 1.19 버전부터 SOCKS5를 지원합니다. 이전 버전(CentOS 7, Ubuntu 16.04)에서는 우회 솔루션인 proxychains, tsocks를 사용하거나 SOCKS5가 필요한 작업에 대해 curl로 전환해야 합니다.

6. 프록시 인증: 사용자 이름 및 비밀번호

대부분의 상업적 프록시 및 기업 프록시 서버는 인증을 요구합니다. 자격 증명을 전달하는 방법에는 여러 가지가 있으며 — 각 방법은 보안 측면에서 장단점이 있습니다.

방법 1: URL에 자격 증명 포함 — 간단하지만 안전하지 않습니다 (비밀번호가 프로세스 목록에 표시됨):

curl -x http://user:p%[email protected]:3128 https://api.example.com/data
# 비밀번호의 특수 문자는 URL 인코딩해야 합니다: @ → %40, : → %3A

방법 2: curl의 --proxy-user 플래그 — 비밀번호를 명령줄에 입력할 필요가 없으며, curl이 대화식으로 요청합니다:

# 플래그에 로그인 및 비밀번호 (여전히 ps aux에서 보임)
curl -x http://proxy.example.com:3128 \
     --proxy-user "username:password" \
     https://api.example.com/data

# 로그인만 — curl이 비밀번호를 대화식으로 요청합니다
curl -x http://proxy.example.com:3128 \
     --proxy-user "username" \
     https://api.example.com/data

방법 3: .netrc 파일을 통한 — 스크립트에 가장 안전한 방법입니다:

# ~/.netrc
machine proxy.example.com
login username
password secretpassword

# 파일 접근 권한 제한
chmod 600 ~/.netrc

# curl에서 사용
curl -x http://proxy.example.com:3128 --proxy-netrc https://api.example.com/data

방법 4: 비밀 저장소의 환경 변수를 통한 — CI/CD 및 프로덕션 환경에 권장됩니다:

# 스크립트에서 CI/CD가 설정한 변수에서 자격 증명을 읽습니다
#!/bin/bash
PROXY_URL="http://${PROXY_USER}:${PROXY_PASS}@proxy.example.com:3128"
curl -x "${PROXY_URL}" https://api.example.com/data

인증 방법 비교 표:

방법 편리함 보안성 적합한 경우
URL (user:pass@host) ⭐⭐⭐ 테스트
--proxy-user 플래그 ⭐⭐⭐ ⭐⭐ 일회성 명령
.netrc 파일 ⭐⭐ ⭐⭐⭐ 로컬 스크립트
환경 변수에서 vault ⭐⭐ ⭐⭐⭐⭐⭐ CI/CD, 프로덕션

7. 예외 및 no_proxy: 로컬 주소에 대한 프록시 우회 방법

기업 및 클라우드 환경에서는 종종 세밀한 설정이 필요합니다: 외부 트래픽은 프록시를 통해, 내부 트래픽은 직접 연결됩니다. no_proxy (또는 NO_PROXY) 변수를 사용하여 예외 목록을 설정할 수 있습니다.

# 기본 예외
export no_proxy="localhost,127.0.0.1,::1"

# 도메인에 대한 예외 (점이 있는 경우 — 모든 하위 도메인)
export no_proxy="localhost,127.0.0.1,.internal.company.com,.corp.local"

# IP 범위에 대한 예외 (CIDR 표기법은 모든 곳에서 작동하지 않음!)
export no_proxy="localhost,127.0.0.1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16"

# AWS의 경우: 메타데이터 엔드포인트 및 내부 주소 제외
export no_proxy="localhost,127.0.0.1,169.254.169.254,.amazonaws.com.internal"

⚠️ no_proxy의 중요한 특징:

CIDR 표기법 (10.0.0.0/8)은 모든 도구에서 지원되지 않습니다. curl은 7.86.0 버전부터 지원하며, wget은 전혀 지원하지 않습니다. 호환성을 위해 특정 IP 또는 10.와 같은 마스크를 나열하는 것이 좋습니다 (10.으로 시작하는 모든 것).

Kubernetes 환경에서 API 서버 및 내부 서비스를 제외해야 하는 실용적인 예:

export no_proxy="localhost,127.0.0.1,10.96.0.0/12,10.244.0.0/16,.cluster.local,.svc,.default"
export NO_PROXY="${no_proxy}"

8. CI/CD에서 프록시: GitHub Actions, GitLab CI, Docker

CI/CD 파이프라인에서 프록시를 설정하는 것은 기업 네트워크에서 작업하거나 인터넷 접근이 제한된 경우 DevOps 엔지니어가 가장 자주 수행하는 작업 중 하나입니다. 인기 있는 플랫폼에 대한 특정 구성을 살펴보겠습니다.

GitHub Actions

# .github/workflows/deploy.yml
name: 배포

on: [push]

jobs:
  deploy:
    runs-on: ubuntu-latest
    env:
      http_proxy: ${{ secrets.PROXY_URL }}
      https_proxy: ${{ secrets.PROXY_URL }}
      no_proxy: "localhost,127.0.0.1,.github.com"
    
    steps:
      - uses: actions/checkout@v3
      
      - name: 종속성 다운로드
        run: |
          curl -x "${http_proxy}" https://external-api.example.com/config.json -o config.json
          wget -e use_proxy=yes -e http_proxy="${http_proxy}" https://releases.example.com/app-v1.0.tar.gz

GitLab CI

# .gitlab-ci.yml
variables:
  http_proxy: "http://proxy.company.com:3128"
  https_proxy: "http://proxy.company.com:3128"
  no_proxy: "localhost,127.0.0.1,.gitlab.company.com"

build:
  stage: build
  script:
    - curl -x "${http_proxy}" https://registry.npmjs.org/package -o package.json
    - wget -e use_proxy=yes -e http_proxy="${http_proxy}" https://example.com/resource.tar.gz

Docker: 이미지 빌드 시 프록시 사용

# 빌드 인수로 프록시 전달
docker build \
  --build-arg http_proxy=http://proxy.example.com:3128 \
  --build-arg https_proxy=http://proxy.example.com:3128 \
  --build-arg no_proxy=localhost,127.0.0.1 \
  -t myapp:latest .

# Dockerfile에서 ARG를 사용하여 변수를 가져옵니다
# Dockerfile
FROM ubuntu:22.04

ARG http_proxy
ARG https_proxy
ARG no_proxy

ENV http_proxy=${http_proxy}
ENV https_proxy=${https_proxy}
ENV no_proxy=${no_proxy}

RUN apt-get update && apt-get install -y curl wget

RUN curl -x "${http_proxy}" https://example.com/setup.sh | bash

# 최종 이미지에서 프록시 변수를 지웁니다 (선택 사항)
ENV http_proxy=""
ENV https_proxy=""

Docker daemon에 대한 전역 프록시 설정 (프록시를 통한 docker pull):

# /etc/systemd/system/docker.service.d/proxy.conf
[Service]
Environment="HTTP_PROXY=http://proxy.example.com:3128"
Environment="HTTPS_PROXY=http://proxy.example.com:3128"
Environment="NO_PROXY=localhost,127.0.0.1,.internal.registry.com"

# docker 재시작
systemctl daemon-reload
systemctl restart docker

9. bash 스크립트에서 프록시 회전

외부 API나 서비스에 많은 요청을 해야 하는 경우 — 프록시 회전은 부하를 분산시키고 IP 차단을 피하는 데 도움이 됩니다. 이는 가격 모니터링, 데이터 수집 또는 다양한 지역에서 리소스의 가용성을 테스트할 때 특히 중요합니다.

이러한 작업에 적합한 것은 데이터 센터 프록시입니다 — 대량 요청 시 높은 속도와 안정성을 제공합니다.

#!/bin/bash
# rotate_proxy.sh — 목록에서 프록시 회전

PROXY_LIST=(
  "http://user:[email protected]:3128"
  "http://user:[email protected]:3128"
  "http://user:[email protected]:3128"
  "http://user:[email protected]:3128"
)

URLS_FILE="urls.txt"
OUTPUT_DIR="./results"
mkdir -p "${OUTPUT_DIR}"

PROXY_COUNT=${#PROXY_LIST[@]}
INDEX=0

while IFS= read -r url; do
  PROXY="${PROXY_LIST[$INDEX]}"
  FILENAME=$(echo "${url}" | md5sum | cut -d' ' -f1)
  
  echo "요청 중: ${url} 프록시 $((INDEX + 1))/${PROXY_COUNT}를 통해"
  
  curl -x "${PROXY}" \
       --max-time 30 \
       --retry 3 \
       --retry-delay 2 \
       --silent \
       --output "${OUTPUT_DIR}/${FILENAME}.html" \
       "${url}"
  
  if [ $? -eq 0 ]; then
    echo "  ✓ 성공"
  else
    echo "  ✗ 실패, 다음 프록시 시도 중..."
    INDEX=$(( (INDEX + 1) % PROXY_COUNT ))
    curl -x "${PROXY_LIST[$INDEX]}" \
         --max-time 30 \
         --silent \
         --output "${OUTPUT_DIR}/${FILENAME}.html" \
         "${url}"
  fi
  
  # 다음 프록시로 이동
  INDEX=$(( (INDEX + 1) % PROXY_COUNT ))
  
  # 요청 간 짧은 일시 정지
  sleep 0.5
  
done < "${URLS_FILE}"

echo "완료! 결과는 ${OUTPUT_DIR}에 저장되었습니다."

더 발전된 방법은 사용하기 전에 프록시의 작동 여부를 확인하는 것입니다:

#!/bin/bash
# check_proxy.sh — 프록시의 가용성 확인

check_proxy() {
  local proxy_url="$1"
  local test_url="https://api.ipify.org"
  
  result=$(curl -x "${proxy_url}" \
                --max-time 10 \
                --silent \
                --write-out "%{http_code}" \
                --output /dev/null \
                "${test_url}")
  
  if [ "${result}" -eq 200 ]; then
    echo "ALIVE"
  else
    echo "DEAD"
  fi
}

# 프록시를 통해 외부 IP 가져오기
get_proxy_ip() {
  local proxy_url="$1"
  curl -x "${proxy_url}" --max-time 10 --silent https://api.ipify.org
}

PROXY="http://user:[email protected]:3128"
STATUS=$(check_proxy "${PROXY}")
echo "프록시 상태: ${STATUS}"

if [ "${STATUS}" == "ALIVE" ]; then
  EXTERNAL_IP=$(get_proxy_ip "${PROXY}")
  echo "프록시를 통한 외부 IP: ${EXTERNAL_IP}"
fi

10. 문제 해결 및 일반적인 오류

프록시 작업은 초기 설정 시 오류가 발생하기 마련입니다. 가장 일반적인 문제와 진단 방법을 살펴보겠습니다.

상세 모드를 통한 진단

# curl의 최대한 상세한 출력
curl -vvv -x http://proxy.example.com:3128 https://api.example.com/data 2>&1 | head -50

# 출력에서 확인할 사항:
# * Connected to proxy.example.com — 프록시와의 연결이 설정됨
# CONNECT api.example.com:443 — 터널 요청
# HTTP/1.1 200 Connection established — 터널이 열림
# * SSL connection using TLS — TLS가 작동 중

# wget 디버깅
wget -d -e use_proxy=yes -e http_proxy=http://proxy.example.com:3128 https://api.example.com/data

일반적인 오류 및 해결책

오류 원인 해결책
407 Proxy Authentication Required 자격 증명이 전달되지 않음 URL 프록시에서 user:pass 추가 또는 --proxy-user 플래그 사용
Connection refused 잘못된 포트 또는 프록시가 사용 불가능함 포트 확인: nc -zv proxy.host 3128
SSL certificate error SSL 검사가 있는 기업 프록시 기업 CA 추가: --cacert /path/to/ca.crt
Could not resolve proxy DNS가 프록시 이름을 해석하지 못함 이름 대신 IP 사용 또는 DNS 확인
Timeout 프록시가 느리거나 과부하 상태임 타임아웃 증가: --max-time 60
```