إذا كنت تدير خوادم، أو تكتب سكربتات الأتمتة، أو تقوم بنشر التطبيقات في بنية تحتية مؤسسية - عاجلاً أم آجلاً ستواجه الحاجة لتوجيه حركة مرور curl أو wget عبر بروكسي. قد يكون هذا بروكسي مؤسسي، أو لتجاوز القيود الجغرافية عند تنزيل الحزم، أو لتدوير IP عند إجراء طلبات جماعية لواجهات برمجة التطبيقات الخارجية. في هذه المقالة - فقط الممارسة: الأوامر، التكوينات، أمثلة التعليمات البرمجية دون حشو.
1. كيف تعمل curl و wget مع البروكسي: الآليات الأساسية
قبل الغوص في التكوينات، من المهم فهم ما يحدث تحت الغطاء. يدعم كلا الأداتين بروتوكولين أساسيين للبروكسي: HTTP/HTTPS و SOCKS5. الآلية مختلفة، وهذا يؤثر على نوع البروكسي الذي يجب اختياره لمهمة معينة.
بروكسي HTTP يعمل كوسيط على مستوى بروتوكول التطبيق. عندما ترسل curl طلبًا عبر بروكسي HTTP، فإنها تقول حرفيًا لخادم البروكسي: "قم بعمل طلب GET على هذا URL بدلاً مني". بالنسبة لحركة مرور 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) أو على الأقل قيد حقوق الوصول إلى ملف المتغيرات.
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
أعلام مفيدة لاستكشاف اتصالات البروكسي:
# وضع verbose: يظهر جميع الرؤوس، بما في ذلك 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 هو بروتوكول مفضل أكثر للمهام التي تتطلب الخصوصية أو العمل مع المنافذ غير القياسية. غالبًا ما يستخدم SOCKS5 من قبل مديري النظام ومهندسي DevOps عند العمل عبر أنفاق SSH، وكذلك عند الاتصال بـ بروكسي سكنية، التي تحاكي حركة مرور المستخدمين الحقيقيين.
في curl، يتم دعم SOCKS5 من خلال بادئة خاصة في URL البروكسي:
# SOCKS5 مع حل DNS على جانب العميل (قد يكون هناك تسرب DNS!) curl --socks5 proxy.example.com:1080 https://api.example.com/data # SOCKS5 مع حل 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 محليًا، بينما يتم تمرير الاتصال عبر البروكسي فقط عبر IP. قد يحدث تسرب DNS.socks5h (h = hostname) - يتم تنفيذ طلب DNS على جانب خادم البروكسي. خصوصية كاملة. موصى به لمعظم المهام.
سيناريو شائع في DevOps - استخدام SSH كبروكسي SOCKS5 لتوجيه حركة المرور عبر مضيف الباستيون:
# فتح نفق SSH مع SOCKS5 على المنفذ المحلي 1080 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 SOCKS5 بدءًا من الإصدار 1.19. في الإصدارات الأقدم (CentOS 7، Ubuntu 16.04) سيتعين عليك استخدام حلول بديلة: proxychains، tsocks، أو الانتقال إلى curl للمهام التي تتطلب SOCKS5.
6. المصادقة على البروكسي: اسم المستخدم وكلمة المرور
تتطلب معظم البروكسي التجارية وخوادم البروكسي المؤسسية المصادقة. هناك عدة طرق لنقل بيانات الاعتماد - كل منها له مزاياه وعيوبه من حيث الأمان.
الطريقة 1: بيانات الاعتماد في URL - بسيطة، ولكن غير آمنة (كلمة المرور مرئية في قائمة العمليات):
curl -x http://user:p%[email protected]:3128 https://api.example.com/data # يجب ترميز الرموز الخاصة في كلمة المرور: @ → %40، : → %3A
الطريقة 2: العلم --proxy-user في curl - يمكن عدم تحديد كلمة المرور في سطر الأوامر، ستطلب 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 الملف | ⭐⭐ | ⭐⭐⭐ | سكربتات محلية |
| متغيرات البيئة من الخزنة | ⭐⭐ | ⭐⭐⭐⭐⭐ | 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: البروكسي عند بناء الصور
# تمرير البروكسي عبر build args 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
إذا كنت بحاجة إلى إجراء عدد كبير من الطلبات إلى واجهات برمجة التطبيقات الخارجية أو الخدمات - فإن تدوير البروكسي يسمح بتوزيع الحمل وتجنب الحظر حسب 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. استكشاف الأخطاء وإصلاحها والأخطاء الشائعة
العمل مع البروكسي لا مفر منه أن يرافقه أخطاء - خاصة عند الإعداد الأولي. دعونا نستعرض أكثر المشاكل شيوعًا وطرق تشخيصها.
التشخيص باستخدام وضع verbose
# إخراج curl الأكثر تفصيلاً curl -vvv -x http://proxy.example.com:3128 https://api.example.com/data 2>&1 | head -50 # ما يجب مراقبته في الإخراج: # * متصل بـ 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 |
لم يتم تمرير بيانات الاعتماد | أضف user:pass إلى URL البروكسي أو العلم --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 |