サーバーを管理したり、自動化スクリプトを書いたり、企業インフラストラクチャにアプリケーションをデプロイしたりする場合、curlやwgetのトラフィックをプロキシ経由で流す必要に直面することがあるでしょう。これは、企業プロキシ、パッケージのダウンロード時に地理的ブロックを回避するため、または外部APIへの大量リクエスト時にIPをローテーションするためかもしれません。この記事では、実践的な内容のみを提供します: コマンド、設定、無駄のないコード例です。
1. curlとwgetがプロキシで動作する仕組み: 基本メカニズム
設定ファイルに入る前に、内部で何が起こっているのかを理解することが重要です。両方のツールは、HTTP/HTTPSとSOCKS5の2つの主要なプロキシプロトコルをサポートしています。メカニズムは異なり、特定のタスクに適したプロキシの種類に影響を与えます。
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や環境変数にパスワードを平文で保存しないでください。Vaultソリューション(HashiCorp Vault、AWS Secrets Manager)を使用するか、少なくとも変数ファイルの権限を制限してください。
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 # プロキシを完全に無視(env変数が設定されていても) 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 # 特定のコマンドのためにプロキシを無効にする(env変数が設定されている場合) 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. curlとwgetのSOCKS5プロキシ: 設定と例
SOCKS5は、匿名性が重要なタスクや非標準ポートでの作業により好まれるプロトコルです。システム管理者やDevOpsエンジニアにとって、SOCKS5はSSHトンネルを介して作業する際や、居住用プロキシに接続する際によく使用されます。これらは実際のユーザーのトラフィックを模倣します。
curlでは、SOCKS5はプロキシのURLに特別なプレフィックスを使用してサポートされています:
# クライアント側でのDNS解決を伴うSOCKS5(DNSリークの可能性あり!) curl --socks5 proxy.example.com:1080 https://api.example.com/data # プロキシ側でのDNS解決を伴うSOCKS5(推奨!) 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とsocks5hの違いは何ですか?
socks5 — DNSリクエストはローカルで実行され、プロキシを介してはTCP接続のみが行われます。DNSリークの可能性があります。socks5h(h = hostname) — DNSリクエストはプロキシサーバー側で実行されます。完全な匿名性。ほとんどのタスクに推奨されます。
DevOpsでの一般的なシナリオは、SSHをSOCKS5プロキシとして使用してバスティオンホストを介してトラフィックをトンネリングすることです:
# ローカルポート1080でSOCKS5トンネルを開く 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エンジニアにとって最も一般的なタスクの1つです。人気のあるプラットフォームの具体的な設定を見ていきましょう。
GitHub Actions
# .github/workflows/deploy.yml
name: Deploy
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デーモンのためのグローバルプロキシ設定(プロキシを介して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 "生存中" else echo "死んでいます" 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}" == "生存中" ]; 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 |