Nếu bạn quản trị máy chủ, viết các script tự động hóa hoặc triển khai ứng dụng trong hạ tầng doanh nghiệp — sớm hay muộn bạn sẽ phải đối mặt với nhu cầu chuyển lưu lượng curl hoặc wget qua proxy. Điều này có thể là proxy doanh nghiệp, vượt qua các khối địa lý khi tải xuống gói, hoặc xoay vòng IP khi thực hiện các yêu cầu hàng loạt đến API bên ngoài. Trong bài viết này — chỉ có thực hành: các lệnh, cấu hình, ví dụ mã mà không có nước.
1. Cách curl và wget hoạt động với proxy: cơ chế cơ bản
Trước khi đi vào các cấu hình, điều quan trọng là phải hiểu những gì đang xảy ra bên trong. Cả hai công cụ đều hỗ trợ hai giao thức proxy chính: HTTP/HTTPS và SOCKS5. Cơ chế của chúng khác nhau, và điều này ảnh hưởng đến loại proxy nào nên chọn cho nhiệm vụ cụ thể.
Proxy HTTP hoạt động như một trung gian ở cấp độ giao thức ứng dụng. Khi curl gửi yêu cầu qua proxy HTTP, nó thực sự nói với máy chủ proxy: “hãy thực hiện yêu cầu GET đến URL này thay cho tôi”. Đối với lưu lượng HTTPS, phương thức CONNECT được sử dụng — curl yêu cầu proxy thiết lập một đường hầm đến máy chủ đích, sau đó quá trình bắt tay TLS diễn ra trực tiếp giữa khách hàng và máy chủ đích. Điều này rất quan trọng: trong trường hợp này, proxy không nhìn thấy nội dung của lưu lượng HTTPS.
SOCKS5 hoạt động ở cấp độ thấp hơn — nó proxy các kết nối TCP/UDP mà không phụ thuộc vào giao thức ứng dụng. Điều này làm cho SOCKS5 linh hoạt hơn: nó có thể chuyển không chỉ HTTP/HTTPS mà còn các giao thức khác. Hơn nữa, SOCKS5 hỗ trợ phân giải DNS ở phía máy chủ proxy — điều này cực kỳ quan trọng để ngăn chặn rò rỉ DNS.
💡 Sự khác biệt chính cho thực hành:
Nếu chỉ cần tải xuống một tệp hoặc thực hiện một yêu cầu API — proxy HTTP là đủ. Nếu cần tính ẩn danh hoàn toàn, vượt qua rò rỉ DNS hoặc làm việc với các giao thức không chuẩn — hãy sử dụng SOCKS5.
curl hỗ trợ cả hai giao thức một cách bản địa từ những phiên bản rất sớm. wget về mặt lịch sử có hỗ trợ SOCKS5 hạn chế hơn — trong các phiên bản cũ (trước 1.19) không có hỗ trợ SOCKS5, chỉ có proxy HTTP. Điều này cần được xem xét khi viết các script cần hoạt động trên các bản phân phối khác nhau.
Kiểm tra phiên bản wget có thể thực hiện bằng lệnh wget --version. Đối với curl — curl --version, ở đó cũng sẽ thấy các giao thức mà thư viện libcurl được biên dịch với.
2. Biến môi trường: cách nhanh nhất để cấu hình
Cách tinh tế nhất để cấu hình proxy cho curl và wget — thông qua các biến môi trường. Điều này hoạt động một cách hệ thống: không cần thay đổi từng script, chỉ cần thiết lập biến một lần trong phiên làm việc hoặc thêm chúng vào hồ sơ người dùng.
Cả hai công cụ đều đọc cùng một biến tiêu chuẩn:
# Đối với lưu lượng HTTP export http_proxy="http://proxy.example.com:3128" # Đối với lưu lượng HTTPS export https_proxy="http://proxy.example.com:3128" # Nhân đôi ở dạng chữ hoa (một số chương trình chỉ đọc chúng) export HTTP_PROXY="http://proxy.example.com:3128" export HTTPS_PROXY="http://proxy.example.com:3128" # Đối với FTP (nếu cần) export ftp_proxy="http://proxy.example.com:3128" # Ngoại lệ — các địa chỉ KHÔNG đi qua proxy export no_proxy="localhost,127.0.0.1,::1,192.168.0.0/16,.internal.company.com"
Một điểm quan trọng: curl nhạy cảm với chữ hoa chữ thường của các biến tùy thuộc vào phiên bản. Để không có bất ngờ — luôn thiết lập cả hai phiên bản: chữ thường và chữ hoa. Đây là thực hành tiêu chuẩn trong DevOps.
Để các cài đặt được áp dụng liên tục cho người dùng cụ thể, hãy thêm các dòng vào ~/.bashrc hoặc ~/.profile. Đối với các script và dịch vụ hệ thống — vào /etc/environment hoặc vào tệp đơn vị systemd thông qua chỉ thị 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
Nếu proxy yêu cầu xác thực, tên đăng nhập và mật khẩu được chèn trực tiếp vào URL của biến:
export http_proxy="http://username:[email protected]:3128" export https_proxy="http://username:[email protected]:3128"
⚠️ An toàn:
Không lưu trữ mật khẩu dưới dạng văn bản rõ ràng trong .bashrc hoặc trong các biến môi trường trên các máy chủ sản xuất. Sử dụng các giải pháp vault (HashiCorp Vault, AWS Secrets Manager) hoặc ít nhất hãy hạn chế quyền truy cập vào tệp chứa các biến.
3. Cờ curl để làm việc với proxy: phân tích đầy đủ
curl cung cấp một bộ cờ phong phú để quản lý proxy ngay từ dòng lệnh. Điều này rất tiện lợi khi cần thực hiện một yêu cầu tạm thời qua proxy mà không thay đổi cài đặt hệ thống.
Cờ chính — -x hoặc --proxy:
# Proxy HTTP cơ bản curl -x http://proxy.example.com:3128 https://api.example.com/data # Dạng ngắn curl -x proxy.example.com:3128 https://api.example.com/data # Với chỉ định rõ ràng giao thức curl --proxy http://proxy.example.com:3128 https://api.example.com/data # Kiểm tra IP bên ngoài qua proxy curl -x http://proxy.example.com:3128 https://api.ipify.org
Để bỏ qua các biến môi trường và kết nối trực tiếp (bỏ qua proxy đã cấu hình), sử dụng cờ --noproxy:
# Bỏ qua proxy cho một máy chủ cụ thể curl --noproxy "internal.company.com" https://internal.company.com/api # Bỏ qua proxy hoàn toàn (ngay cả khi các biến env được thiết lập) curl --noproxy "*" https://api.example.com/data
Các cờ hữu ích cho việc gỡ lỗi các kết nối proxy:
# Chế độ Verbose: thấy tất cả các tiêu đề, bao gồm CONNECT đến proxy curl -v -x http://proxy.example.com:3128 https://api.example.com/data # Chỉ tiêu đề phản hồi curl -I -x http://proxy.example.com:3128 https://api.example.com/data # Hiển thị thời gian kết nối qua proxy 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
Cấu hình proxy qua tệp cấu hình ~/.curlrc — tiện lợi nếu không muốn nhập cờ mỗi lần:
# ~/.curlrc
proxy = http://proxy.example.com:3128
proxy-user = username:password
noproxy = localhost,127.0.0.1,.internal.company.com
Đối với các script hệ thống, bạn có thể tạo một cấu hình riêng và chỉ định rõ ràng qua curl -K /path/to/config — điều này cho phép có các hồ sơ proxy khác nhau cho các nhiệm vụ khác nhau.
4. Cấu hình proxy trong wget: cờ và tệp cấu hình
wget ít linh hoạt hơn curl, nhưng cho các nhiệm vụ điển hình — tải xuống tệp, gương trang web đệ quy — khả năng của nó hoàn toàn đủ. Proxy trong wget có thể được cấu hình theo ba cách: thông qua biến môi trường (đã xem xét ở trên), thông qua cờ dòng lệnh và thông qua tệp cấu hình ~/.wgetrc.
Cờ dòng lệnh wget cho proxy:
# Proxy HTTP qua cờ wget -e use_proxy=yes \ -e http_proxy=http://proxy.example.com:3128 \ https://example.com/file.tar.gz # HTTPS qua proxy wget -e use_proxy=yes \ -e https_proxy=http://proxy.example.com:3128 \ https://example.com/file.tar.gz # Với xác thực wget -e use_proxy=yes \ -e http_proxy=http://username:[email protected]:3128 \ https://example.com/file.tar.gz # Tắt proxy cho một lệnh cụ thể (nếu các biến env được thiết lập) wget --no-proxy https://internal.company.com/file.tar.gz
Tệp cấu hình ~/.wgetrc — cách ưu tiên để cấu hình vĩnh viễn:
# ~/.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 # Nếu proxy yêu cầu xác thực proxy_user = username proxy_password = secretpassword
Đối với ứng dụng hệ thống (tất cả người dùng), sử dụng /etc/wgetrc — cùng định dạng, nhưng áp dụng toàn cầu. Tiện lợi cho các máy chủ, nơi tất cả các thao tác tải xuống phải đi qua proxy doanh nghiệp.
Ví dụ thực tiễn: tải xuống đệ quy một trang web qua proxy với giới hạn độ sâu và tốc độ:
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. Proxy SOCKS5 trong curl và wget: cấu hình và ví dụ
SOCKS5 — giao thức ưu tiên hơn cho các nhiệm vụ mà tính ẩn danh hoặc làm việc với các cổng không chuẩn là quan trọng. Đối với các quản trị viên hệ thống và kỹ sư DevOps, SOCKS5 thường được sử dụng khi làm việc qua các đường hầm SSH, cũng như khi kết nối với proxy cư trú, giả lập lưu lượng của người dùng thực.
Trong curl, SOCKS5 được hỗ trợ thông qua tiền tố đặc biệt trong URL proxy:
# SOCKS5 với phân giải DNS ở phía khách hàng (có thể có rò rỉ DNS!) curl --socks5 proxy.example.com:1080 https://api.example.com/data # SOCKS5 với phân giải DNS ở phía proxy (được khuyến nghị!) curl --socks5-hostname proxy.example.com:1080 https://api.example.com/data # Qua cờ -x với chỉ định rõ ràng giao thức curl -x socks5h://proxy.example.com:1080 https://api.example.com/data # Với xác thực curl -x socks5h://username:[email protected]:1080 https://api.example.com/data # SOCKS5 qua biến môi trường export all_proxy="socks5h://proxy.example.com:1080" curl https://api.example.com/data
📌 socks5 vs socks5h — sự khác biệt là gì?
socks5 — yêu cầu DNS được thực hiện cục bộ, qua proxy chỉ có kết nối TCP. Có thể có rò rỉ DNS.socks5h (h = hostname) — yêu cầu DNS được thực hiện ở phía máy chủ proxy. Tính ẩn danh hoàn toàn. Được khuyến nghị cho hầu hết các nhiệm vụ.
Kịch bản phổ biến trong DevOps — sử dụng SSH như một proxy SOCKS5 để định tuyến lưu lượng qua máy chủ bastion:
# Mở đường hầm SSH với SOCKS5 trên cổng cục bộ 1080 ssh -D 1080 -f -C -q -N [email protected] # Bây giờ sử dụng đường hầm này trong curl curl -x socks5h://localhost:1080 https://internal-api.private.network/data # Hoặc qua biến môi trường cho tất cả các yêu cầu trong phiên export all_proxy="socks5h://localhost:1080" wget https://internal-resource.private.network/file.tar.gz
wget hỗ trợ SOCKS5 bắt đầu từ phiên bản 1.19. Trong các phiên bản cũ hơn (CentOS 7, Ubuntu 16.04) sẽ phải sử dụng các giải pháp thay thế: proxychains, tsocks, hoặc chuyển sang curl cho các nhiệm vụ yêu cầu SOCKS5.
6. Xác thực trên proxy: tên đăng nhập và mật khẩu
Hầu hết các proxy thương mại và máy chủ proxy doanh nghiệp yêu cầu xác thực. Có một số cách để truyền thông tin đăng nhập — mỗi cách có ưu và nhược điểm riêng về mặt bảo mật.
Cách 1: Thông tin đăng nhập trong URL — đơn giản, nhưng không an toàn (mật khẩu có thể thấy trong danh sách quy trình):
curl -x http://user:p%[email protected]:3128 https://api.example.com/data # Ký tự đặc biệt trong mật khẩu cần được mã hóa URL: @ → %40, : → %3A
Cách 2: Cờ --proxy-user trong curl — mật khẩu có thể không cần chỉ định trong dòng lệnh, curl sẽ yêu cầu nó một cách tương tác:
# Tên đăng nhập và mật khẩu trong cờ (vẫn có thể thấy trong ps aux) curl -x http://proxy.example.com:3128 \ --proxy-user "username:password" \ https://api.example.com/data # Chỉ tên đăng nhập — curl sẽ hỏi mật khẩu một cách tương tác curl -x http://proxy.example.com:3128 \ --proxy-user "username" \ https://api.example.com/data
Cách 3: Qua tệp .netrc — an toàn nhất cho các script:
# ~/.netrc machine proxy.example.com login username password secretpassword # Hạn chế quyền truy cập vào tệp chmod 600 ~/.netrc # Sử dụng trong curl curl -x http://proxy.example.com:3128 --proxy-netrc https://api.example.com/data
Cách 4: Qua các biến môi trường từ kho bí mật — được khuyến nghị cho CI/CD và môi trường sản xuất:
# Trong script đọc thông tin đăng nhập từ các biến (do CI/CD thiết lập)
#!/bin/bash
PROXY_URL="http://${PROXY_USER}:${PROXY_PASS}@proxy.example.com:3128"
curl -x "${PROXY_URL}" https://api.example.com/data
Bảng so sánh các phương pháp xác thực:
| Phương pháp | Sự tiện lợi | An toàn | Phù hợp cho |
|---|---|---|---|
URL (user:pass@host) |
⭐⭐⭐ | ⭐ | Kiểm tra |
| Cờ --proxy-user | ⭐⭐⭐ | ⭐⭐ | Lệnh tạm thời |
| Tệp .netrc | ⭐⭐ | ⭐⭐⭐ | Script cục bộ |
| Biến env từ vault | ⭐⭐ | ⭐⭐⭐⭐⭐ | CI/CD, sản xuất |
7. Ngoại lệ và no_proxy: cách bỏ qua proxy cho các địa chỉ cục bộ
Trong các môi trường doanh nghiệp và đám mây, thường cần tinh chỉnh: lưu lượng bên ngoài — qua proxy, bên trong — trực tiếp. Biến no_proxy (hoặc NO_PROXY) cho phép chỉ định danh sách ngoại lệ.
# Các ngoại lệ cơ bản export no_proxy="localhost,127.0.0.1,::1" # Ngoại lệ theo miền (với dấu chấm — tất cả các miền con) export no_proxy="localhost,127.0.0.1,.internal.company.com,.corp.local" # Ngoại lệ theo dải IP (cú pháp CIDR không hoạt động ở mọi nơi!) export no_proxy="localhost,127.0.0.1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16" # Đối với AWS: loại trừ endpoint metadata và các địa chỉ nội bộ export no_proxy="localhost,127.0.0.1,169.254.169.254,.amazonaws.com.internal"
⚠️ Tính năng quan trọng của no_proxy:
Cú pháp CIDR (10.0.0.0/8) không được tất cả các công cụ hỗ trợ. curl hỗ trợ nó bắt đầu từ phiên bản 7.86.0. wget — không hỗ trợ. Để tương thích, tốt nhất là liệt kê các IP cụ thể hoặc mặt nạ kiểu 10. (tất cả những gì bắt đầu bằng 10.).
Ví dụ thực tiễn cho môi trường Kubernetes, nơi cần loại trừ máy chủ API và các dịch vụ nội bộ:
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. Proxy trong CI/CD: GitHub Actions, GitLab CI, Docker
Cấu hình proxy trong các pipeline CI/CD — một trong những nhiệm vụ thường xuyên nhất của các kỹ sư DevOps làm việc trong các mạng doanh nghiệp hoặc với quyền truy cập internet hạn chế. Hãy xem xét các cấu hình cụ thể cho các nền tảng phổ biến.
GitHub Actions
# .github/workflows/deploy.yml
name: Triển khai
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: Tải xuống các phụ thuộc
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: proxy khi xây dựng hình ảnh
# Truyền proxy qua các tham số xây dựng 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 . # Trong Dockerfile sử dụng ARG để lấy các biến
# 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 # Xóa các biến proxy trong hình ảnh cuối (tùy chọn) ENV http_proxy="" ENV https_proxy=""
Cấu hình proxy toàn cầu cho Docker daemon (cho docker pull qua proxy):
# /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" # Khởi động lại docker systemctl daemon-reload systemctl restart docker
9. Xoay vòng proxy trong các bash-script
Nếu bạn cần thực hiện một số lượng lớn yêu cầu đến các API hoặc dịch vụ bên ngoài — xoay vòng proxy cho phép phân phối tải và tránh bị chặn theo IP. Điều này đặc biệt quan trọng khi theo dõi giá, thu thập dữ liệu hoặc kiểm tra tính khả dụng của các tài nguyên từ các khu vực khác nhau.
Đối với những nhiệm vụ như vậy, proxy trung tâm dữ liệu rất phù hợp — chúng cung cấp tốc độ cao và độ ổn định khi thực hiện các yêu cầu hàng loạt.
#!/bin/bash # rotate_proxy.sh — xoay vòng proxy từ danh sách 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 "Yêu cầu: ${url} qua proxy $((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 " ✓ Thành công" else echo " ✗ Thất bại, thử proxy tiếp theo..." INDEX=$(( (INDEX + 1) % PROXY_COUNT )) curl -x "${PROXY_LIST[$INDEX]}" \ --max-time 30 \ --silent \ --output "${OUTPUT_DIR}/${FILENAME}.html" \ "${url}" fi # Chuyển sang proxy tiếp theo INDEX=$(( (INDEX + 1) % PROXY_COUNT )) # Một khoảng dừng nhỏ giữa các yêu cầu sleep 0.5 done < "${URLS_FILE}" echo "Hoàn tất! Kết quả đã được lưu vào ${OUTPUT_DIR}"
Một biến thể nâng cao hơn — kiểm tra tính khả dụng của proxy trước khi sử dụng:
#!/bin/bash # check_proxy.sh — kiểm tra tính khả dụng của proxy 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 "CÒN SỐNG" else echo "CHẾT" fi } # Lấy IP bên ngoài qua proxy 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 "Trạng thái proxy: ${STATUS}" if [ "${STATUS}" == "CÒN SỐNG" ]; then EXTERNAL_IP=$(get_proxy_ip "${PROXY}") echo "IP bên ngoài qua proxy: ${EXTERNAL_IP}" fi
10. Gỡ lỗi và các lỗi thường gặp
Làm việc với proxy không thể tránh khỏi các lỗi — đặc biệt là khi thiết lập ban đầu. Hãy xem xét những vấn đề phổ biến nhất và cách chẩn đoán chúng.
Chẩn đoán bằng chế độ verbose
# Đầu ra chi tiết nhất của curl curl -vvv -x http://proxy.example.com:3128 https://api.example.com/data 2>&1 | head -50 # Những gì cần xem trong đầu ra: # * Kết nối đến proxy.example.com — kết nối với proxy đã được thiết lập # CONNECT api.example.com:443 — yêu cầu đường hầm # HTTP/1.1 200 Connection established — đường hầm đã mở # * SSL connection using TLS — TLS hoạt động # Gỡ lỗi wget wget -d -e use_proxy=yes -e http_proxy=http://proxy.example.com:3128 https://api.example.com/data
Các lỗi thường gặp và giải pháp
| Lỗi | Nguyên nhân | Giải pháp |
|---|---|---|
407 Proxy Authentication Required |
Không truyền thông tin đăng nhập | Thêm user:pass vào URL proxy hoặc cờ --proxy-user |
Connection refused |
Cổng không đúng hoặc proxy không khả dụng | Kiểm tra cổng: nc -zv proxy.host 3128 |
SSL certificate error |
Proxy doanh nghiệp với kiểm tra SSL | Thêm CA doanh nghiệp: --cacert /path/to/ca.crt |
Could not resolve proxy |
DNS không phân giải được tên proxy | Sử dụng IP thay vì tên hoặc kiểm tra DNS |
Timeout |
Proxy chậm hoặc quá tải | Tăng thời gian chờ: --max-time 60 |