GitHub Actions — мощный инструмент автоматизации: он запускает тесты, деплоит приложения, собирает данные и выполняет десятки других задач. Но как только workflow начинает обращаться к внешним ресурсам — маркетплейсам, рекламным платформам, зарубежным API — он тут же сталкивается с геоблокировками и лимитами по IP. Решение одно: подключить прокси прямо в пайплайн.
Зачем прокси в GitHub Actions: реальные сценарии
Многие команды используют GitHub Actions не только для деплоя кода, но и для автоматизации бизнес-задач: мониторинга цен конкурентов, сбора данных с маркетплейсов, автоматической проверки рекламных кабинетов и тестирования сайтов из разных регионов. Все эти задачи объединяет одна проблема — runner GitHub Actions имеет фиксированный IP из диапазона Microsoft Azure, и многие сервисы его блокируют или ограничивают.
Вот конкретные ситуации, когда без прокси не обойтись:
- Парсинг Wildberries, Ozon, Авито — эти платформы давно занесли диапазоны IP облачных провайдеров в чёрные списки. Запрос с runner GitHub Actions будет заблокирован или получит капчу уже на 2–3 попытке.
- Геотаргетированное тестирование — маркетологи и QA-инженеры проверяют, как выглядит сайт или реклама для пользователей из Москвы, Берлина или Нью-Йорка. Без прокси runner всегда будет "видеть" контент для одного региона.
- Работа с API, ограниченными по региону — часть API (например, региональные версии Google Ads, Facebook Marketing API с определёнными настройками) возвращает разные данные в зависимости от геолокации запроса.
- Мониторинг конкурентов — автоматический сбор цен, акций и ассортимента требует регулярных запросов, которые легко детектируются по повторяющемуся IP дата-центра.
- Автоматизация рекламных проверок — арбитражники и performance-маркетологи запускают автоматические проверки статуса объявлений, балансов и метрик через скрипты в CI/CD.
- Интеграционные тесты с внешними сервисами — некоторые сервисы блокируют запросы из Azure-диапазонов по соображениям безопасности, и тесты просто падают без объяснений.
Во всех этих случаях прокси решает проблему радикально: workflow начинает выглядеть как запрос от обычного пользователя из нужного города, а не от облачного сервера Microsoft.
Как GitHub Actions работает с сетью
Прежде чем настраивать прокси, важно понять архитектуру сети в GitHub Actions. Когда вы запускаете workflow на стандартном ubuntu-latest runner, задача выполняется на виртуальной машине в инфраструктуре Microsoft Azure. У каждой такой машины есть публичный IP из диапазонов Azure — и именно этот IP видят внешние сервисы.
Ключевые особенности сети в GitHub Actions:
- IP меняется при каждом запуске — но остаётся в пределах известных диапазонов Azure, которые легко детектируются.
- Нет встроенной поддержки прокси — GitHub не предоставляет нативного механизма проксирования трафика.
- Переменные окружения работают глобально — если выставить
HTTP_PROXYна уровне job, все шаги внутри этой job будут использовать прокси. - Self-hosted runners — альтернатива, при которой вы запускаете runner на своём сервере. В этом случае прокси настраивается на уровне сервера, а не workflow.
Для большинства задач оптимальный подход — настройка прокси через переменные окружения прямо в файле workflow (.github/workflows/your-workflow.yml). Это универсальный метод, который работает для большинства инструментов: curl, wget, Python requests, Node.js http, Go net/http и других.
Какой тип прокси выбрать для CI/CD
Выбор типа прокси зависит от задачи. Для CI/CD пайплайнов актуальны три варианта, и у каждого своя ниша:
| Тип прокси | Для каких задач | Скорость | Уровень доверия |
|---|---|---|---|
| Резидентные прокси | Парсинг защищённых сайтов, геотаргетинг, мониторинг маркетплейсов | Средняя | Высокий — реальные домашние IP |
| Мобильные прокси | Тестирование мобильных версий, работа с соцсетями, Facebook/TikTok API | Средняя | Максимальный — операторские IP |
| Прокси дата-центров | Интеграционные тесты, запросы к незащищённым API, высокая нагрузка | Высокая | Средний |
Практическое правило: если ваш workflow парсит Wildberries, Ozon или другие маркетплейсы с антибот-защитой — берите резидентные прокси. Если тестируете рекламные кабинеты Facebook Ads или TikTok Ads — мобильные. Для простых интеграционных тестов и запросов к открытым API достаточно прокси дата-центров: они быстрее и дешевле.
💡 Важно про протоколы
Для GitHub Actions предпочтительнее использовать HTTP/HTTPS прокси — они поддерживаются большинством инструментов без дополнительных настроек. SOCKS5 тоже работает, но требует явного указания в каждом инструменте. Если ваш провайдер поддерживает оба протокола — начните с HTTP.
Настройка прокси через переменные окружения
Самый универсальный способ подключить прокси в GitHub Actions — выставить стандартные переменные окружения HTTP_PROXY, HTTPS_PROXY и NO_PROXY. Большинство инструментов командной строки и языков программирования автоматически подхватывают их.
Базовая структура workflow с прокси выглядит так:
name: Workflow with Proxy
on:
schedule:
- cron: '0 9 * * *'
workflow_dispatch:
jobs:
scrape-data:
runs-on: ubuntu-latest
env:
HTTP_PROXY: http://${{ secrets.PROXY_USER }}:${{ secrets.PROXY_PASS }}@${{ secrets.PROXY_HOST }}:${{ secrets.PROXY_PORT }}
HTTPS_PROXY: http://${{ secrets.PROXY_USER }}:${{ secrets.PROXY_PASS }}@${{ secrets.PROXY_HOST }}:${{ secrets.PROXY_PORT }}
NO_PROXY: localhost,127.0.0.1,github.com
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Check current IP (для проверки)
run: curl -s https://api.ipify.org
- name: Run main script
run: python scripts/scraper.py
Обратите внимание на блок NO_PROXY — в него нужно добавить адреса, к которым не нужно проксировать трафик. Как минимум это localhost и 127.0.0.1. Также рекомендуется добавить github.com, чтобы операции с репозиторием (checkout, push) шли напрямую.
Если прокси без аутентификации (только IP и порт), формат упрощается:
env:
HTTP_PROXY: http://203.0.113.10:8080
HTTPS_PROXY: http://203.0.113.10:8080
NO_PROXY: localhost,127.0.0.1
Для SOCKS5 прокси меняется только схема в URL:
env:
HTTP_PROXY: socks5://user:password@proxy-host:1080
HTTPS_PROXY: socks5://user:password@proxy-host:1080
Прокси для curl, wget и HTTP-запросов в shell
Если переменные окружения выставлены на уровне job (как показано выше), curl и wget подхватят их автоматически. Но иногда нужно передать прокси явно — например, для конкретного шага или при отладке.
Явное указание прокси в curl:
- name: Fetch data with proxy
run: |
curl -x http://${{ secrets.PROXY_USER }}:${{ secrets.PROXY_PASS }}@${{ secrets.PROXY_HOST }}:${{ secrets.PROXY_PORT }} \
-s \
-o output.json \
https://api.example.com/data
# Проверка через прокси
curl -x http://${{ secrets.PROXY_USER }}:${{ secrets.PROXY_PASS }}@${{ secrets.PROXY_HOST }}:${{ secrets.PROXY_PORT }} \
-s https://api.ipify.org?format=json
Для wget:
- name: Download with wget via proxy
run: |
wget -e "https_proxy=http://${{ secrets.PROXY_USER }}:${{ secrets.PROXY_PASS }}@${{ secrets.PROXY_HOST }}:${{ secrets.PROXY_PORT }}" \
-q \
-O data.html \
https://target-site.com/page
Полезный шаг для отладки — добавить в начало workflow проверку IP-адреса. Если прокси работает корректно, вы увидите IP прокси-сервера, а не Azure:
- name: Verify proxy is active
run: |
echo "=== IP without proxy ==="
curl -s --noproxy '*' https://api.ipify.org || echo "Direct request failed"
echo ""
echo "=== IP through proxy ==="
curl -s https://api.ipify.org
Прокси в Python-скриптах внутри workflow
Python — один из самых популярных языков для скриптов в CI/CD. Библиотека requests автоматически читает переменные окружения HTTP_PROXY и HTTPS_PROXY, если они выставлены. Но для более гибкого управления лучше передавать прокси явно.
Пример Python-скрипта с явной передачей прокси через переменные окружения:
import os
import requests
# Читаем данные прокси из переменных окружения
proxy_host = os.environ.get('PROXY_HOST')
proxy_port = os.environ.get('PROXY_PORT')
proxy_user = os.environ.get('PROXY_USER')
proxy_pass = os.environ.get('PROXY_PASS')
proxies = {
'http': f'http://{proxy_user}:{proxy_pass}@{proxy_host}:{proxy_port}',
'https': f'http://{proxy_user}:{proxy_pass}@{proxy_host}:{proxy_port}',
}
# Используем прокси в запросе
response = requests.get(
'https://www.wildberries.ru/catalog/123456/detail.aspx',
proxies=proxies,
timeout=30,
headers={
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
}
)
print(f"Status: {response.status_code}")
print(f"Content length: {len(response.content)}")
В файле workflow нужно передать переменные как отдельные секреты (не в виде полного URL), чтобы скрипт мог их собрать:
- name: Run Python scraper
env:
PROXY_HOST: ${{ secrets.PROXY_HOST }}
PROXY_PORT: ${{ secrets.PROXY_PORT }}
PROXY_USER: ${{ secrets.PROXY_USER }}
PROXY_PASS: ${{ secrets.PROXY_PASS }}
run: python scripts/scraper.py
Для работы с Playwright или Selenium в Python конфигурация прокси немного отличается:
# Playwright
from playwright.sync_api import sync_playwright
import os
proxy_url = f"http://{os.environ['PROXY_USER']}:{os.environ['PROXY_PASS']}@{os.environ['PROXY_HOST']}:{os.environ['PROXY_PORT']}"
with sync_playwright() as p:
browser = p.chromium.launch(
proxy={
"server": proxy_url
}
)
page = browser.new_page()
page.goto("https://target-site.com")
# ... дальнейшая логика
browser.close()
Прокси в Node.js и npm-задачах
Node.js не читает системные переменные HTTP_PROXY автоматически — нужно либо использовать специальные библиотеки, либо настраивать прокси явно. Самый удобный вариант — пакет https-proxy-agent или axios с proxy-конфигурацией.
// С использованием axios
const axios = require('axios');
const proxyConfig = {
host: process.env.PROXY_HOST,
port: parseInt(process.env.PROXY_PORT),
auth: {
username: process.env.PROXY_USER,
password: process.env.PROXY_PASS
}
};
async function fetchData(url) {
try {
const response = await axios.get(url, {
proxy: proxyConfig,
timeout: 30000,
headers: {
'User-Agent': 'Mozilla/5.0 (compatible; MyBot/1.0)'
}
});
return response.data;
} catch (error) {
console.error(`Request failed: ${error.message}`);
throw error;
}
}
fetchData('https://api.example.com/prices')
.then(data => console.log(JSON.stringify(data, null, 2)))
.catch(() => process.exit(1));
Для npm-команд (например, если npm пытается скачать пакеты через корпоративный прокси) конфигурация проще:
- name: Configure npm proxy
run: |
npm config set proxy http://${{ secrets.PROXY_USER }}:${{ secrets.PROXY_PASS }}@${{ secrets.PROXY_HOST }}:${{ secrets.PROXY_PORT }}
npm config set https-proxy http://${{ secrets.PROXY_USER }}:${{ secrets.PROXY_PASS }}@${{ secrets.PROXY_HOST }}:${{ secrets.PROXY_PORT }}
- name: Install dependencies
run: npm install
- name: Reset npm proxy (очищаем после использования)
run: |
npm config delete proxy
npm config delete https-proxy
Безопасное хранение данных прокси в GitHub Secrets
Никогда не храните данные прокси (хост, порт, логин, пароль) прямо в файле workflow в открытом виде. Это грубая ошибка безопасности: файлы workflow хранятся в репозитории и могут быть видны всем участникам проекта или вообще публично.
Правильный подход — GitHub Secrets. Вот пошаговая инструкция:
- Откройте репозиторий на GitHub
- Перейдите в Settings → Secrets and variables → Actions
- Нажмите New repository secret
- Создайте четыре секрета:
PROXY_HOST,PROXY_PORT,PROXY_USER,PROXY_PASS - В workflow обращайтесь к ним через синтаксис
${{ secrets.PROXY_HOST }}
🔒 Дополнительные меры безопасности
- Используйте Environment secrets вместо Repository secrets, если разные окружения (staging/production) используют разные прокси
- Ограничьте доступ к секретам через Environment protection rules — требуйте ручного подтверждения для production
- Регулярно ротируйте учётные данные прокси — меняйте пароли каждые 30–90 дней
- Не выводите значения секретов в логи через
echo— GitHub маскирует их автоматически, но лучше не рисковать
Если вы используете ротирующие прокси (когда IP меняется при каждом запросе или по расписанию), часто достаточно хранить только один endpoint — прокси-провайдер сам управляет пулом IP. В этом случае в секретах будет только один хост и порт шлюза ротации.
Ротация прокси и обработка ошибок в пайплайне
Даже качественные прокси иногда дают сбои: IP может попасть во временный бан, сессия может оборваться, сервер может не ответить. Для CI/CD-пайплайнов, которые работают автоматически без надзора, важно предусмотреть обработку таких ситуаций.
Стратегия 1: Retry с тем же прокси
import requests
import time
import os
def fetch_with_retry(url, max_retries=3, delay=5):
proxies = {
'http': f"http://{os.environ['PROXY_USER']}:{os.environ['PROXY_PASS']}@{os.environ['PROXY_HOST']}:{os.environ['PROXY_PORT']}",
'https': f"http://{os.environ['PROXY_USER']}:{os.environ['PROXY_PASS']}@{os.environ['PROXY_HOST']}:{os.environ['PROXY_PORT']}",
}
for attempt in range(max_retries):
try:
response = requests.get(url, proxies=proxies, timeout=30)
response.raise_for_status()
return response
except requests.exceptions.RequestException as e:
print(f"Attempt {attempt + 1} failed: {e}")
if attempt < max_retries - 1:
print(f"Retrying in {delay} seconds...")
time.sleep(delay)
delay *= 2 # Экспоненциальная задержка
raise Exception(f"All {max_retries} attempts failed for {url}")
Стратегия 2: Список прокси с переключением
Если у вас несколько прокси-серверов, можно хранить их список в одном секрете (через запятую) и переключаться при ошибке:
import os
import requests
import random
# Секрет PROXY_LIST содержит: "host1:port1:user1:pass1,host2:port2:user2:pass2"
proxy_list_raw = os.environ.get('PROXY_LIST', '').split(',')
def parse_proxy(proxy_str):
parts = proxy_str.strip().split(':')
if len(parts) == 4:
host, port, user, password = parts
return {
'http': f'http://{user}:{password}@{host}:{port}',
'https': f'http://{user}:{password}@{host}:{port}',
}
return None
proxies = [p for p in [parse_proxy(raw) for raw in proxy_list_raw] if p]
def fetch_with_proxy_rotation(url):
random.shuffle(proxies) # Случайный порядок
for proxy in proxies:
try:
response = requests.get(url, proxies=proxy, timeout=20)
if response.status_code == 200:
return response
except Exception as e:
print(f"Proxy failed: {e}, trying next...")
raise Exception("All proxies exhausted")
Стратегия 3: Использование ротирующего endpoint
Самый простой вариант — использовать прокси-провайдера с единым ротирующим gateway. В этом случае вы подключаетесь к одному адресу, а провайдер автоматически выдаёт разные IP из пула. Никакой логики ротации в коде не нужно — достаточно одной строки подключения.
Реальные сценарии: парсинг, тесты, мониторинг цен
Рассмотрим три конкретных сценария, которые чаще всего встречаются у команд, использующих GitHub Actions с прокси.
Сценарий 1: Ежедневный мониторинг цен на Wildberries
Селлеры маркетплейсов часто настраивают автоматический сбор цен конкурентов. Workflow запускается по расписанию (например, каждое утро в 7:00), собирает данные и сохраняет их в Google Sheets или отправляет в Telegram.
name: Daily Price Monitor
on:
schedule:
- cron: '0 4 * * *' # 07:00 МСК (UTC+3)
jobs:
monitor-prices:
runs-on: ubuntu-latest
env:
HTTP_PROXY: http://${{ secrets.PROXY_USER }}:${{ secrets.PROXY_PASS }}@${{ secrets.PROXY_HOST }}:${{ secrets.PROXY_PORT }}
HTTPS_PROXY: http://${{ secrets.PROXY_USER }}:${{ secrets.PROXY_PASS }}@${{ secrets.PROXY_HOST }}:${{ secrets.PROXY_PORT }}
NO_PROXY: github.com,api.github.com
steps:
- uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install dependencies
run: pip install requests beautifulsoup4 gspread
- name: Run price scraper
env:
GOOGLE_SHEETS_KEY: ${{ secrets.GOOGLE_SHEETS_KEY }}
TELEGRAM_BOT_TOKEN: ${{ secrets.TELEGRAM_BOT_TOKEN }}
TELEGRAM_CHAT_ID: ${{ secrets.TELEGRAM_CHAT_ID }}
run: python scripts/price_monitor.py
- name: Upload results artifact
uses: actions/upload-artifact@v4
with:
name: price-data-${{ github.run_id }}
path: output/prices.json
Сценарий 2: Геотаргетированное тестирование сайта
Маркетологи и QA-команды используют прокси для проверки, как сайт или реклама выглядят для пользователей из разных городов. Особенно актуально для проверки региональных цен, контента и редиректов.
name: Geo-targeted Site Tests
on:
push:
branches: [main]
pull_request:
jobs:
test-moscow:
runs-on: ubuntu-latest
name: Test from Moscow
steps:
- uses: actions/checkout@v4
- name: Run geo tests (RU/Moscow proxy)
env:
HTTP_PROXY: http://${{ secrets.PROXY_RU_USER }}:${{ secrets.PROXY_RU_PASS }}@${{ secrets.PROXY_RU_HOST }}:${{ secrets.PROXY_RU_PORT }}
HTTPS_PROXY: http://${{ secrets.PROXY_RU_USER }}:${{ secrets.PROXY_RU_PASS }}@${{ secrets.PROXY_RU_HOST }}:${{ secrets.PROXY_RU_PORT }}
run: |
python tests/geo_test.py --region=RU --city=Moscow
test-germany:
runs-on: ubuntu-latest
name: Test from Germany
steps:
- uses: actions/checkout@v4
- name: Run geo tests (DE proxy)
env:
HTTP_PROXY: http://${{ secrets.PROXY_DE_USER }}:${{ secrets.PROXY_DE_PASS }}@${{ secrets.PROXY_DE_HOST }}:${{ secrets.PROXY_DE_PORT }}
HTTPS_PROXY: http://${{ secrets.PROXY_DE_USER }}:${{ secrets.PROXY_DE_PASS }}@${{ secrets.PROXY_DE_HOST }}:${{ secrets.PROXY_DE_PORT }}
run: |
python tests/geo_test.py --region=DE
Сценарий 3: Автоматическая проверка рекламных кабинетов
Арбитражники и performance-маркетологи нередко используют GitHub Actions для автоматической проверки статуса рекламных аккаунтов Facebook Ads, балансов и метрик. Запросы к Facebook Marketing API из Azure-диапазонов могут вызывать дополнительные проверки безопасности — прокси помогает обойти это.
name: Ad Account Health Check
on:
schedule:
- cron: '*/30 6-22 * * *' # Каждые 30 минут с 6 до 22 МСК
jobs:
check-accounts:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install dependencies
run: pip install requests
- name: Check Facebook Ads accounts
env:
HTTP_PROXY: http://${{ secrets.PROXY_USER }}:${{ secrets.PROXY_PASS }}@${{ secrets.PROXY_HOST }}:${{ secrets.PROXY_PORT }}
HTTPS_PROXY: http://${{ secrets.PROXY_USER }}:${{ secrets.PROXY_PASS }}@${{ secrets.PROXY_HOST }}:${{ secrets.PROXY_PORT }}
FB_ACCESS_TOKEN: ${{ secrets.FB_ACCESS_TOKEN }}
ACCOUNT_IDS: ${{ secrets.FB_ACCOUNT_IDS }}
TELEGRAM_BOT_TOKEN: ${{ secrets.TELEGRAM_BOT_TOKEN }}
TELEGRAM_CHAT_ID: ${{ secrets.TELEGRAM_CHAT_ID }}
run: python scripts/check_fb_accounts.py
📋 Чек-лист перед запуском workflow с прокси
- ✅ Данные прокси добавлены в GitHub Secrets (не в файл workflow)
- ✅ Переменные
NO_PROXYвключаютgithub.com - ✅ Добавлен шаг проверки IP для отладки
- ✅ Реализована обработка ошибок и retry-логика
- ✅ Тип прокси соответствует задаче (резидентные для защищённых сайтов)
- ✅ Настроены уведомления об ошибках (Telegram, Slack или email)
- ✅ Workflow протестирован вручную через
workflow_dispatchперед добавлением расписания
Заключение
Настройка прокси в GitHub Actions — это не сложная задача, если знать правильный подход. Ключевые выводы из этого руководства:
- Переменные окружения
HTTP_PROXY/HTTPS_PROXY— универсальный способ, который работает для большинства инструментов без изменения кода. - GitHub Secrets — единственное правильное место для хранения учётных данных прокси.
- Тип прокси важен: для парсинга защищённых маркетплейсов нужны резидентные IP, для рекламных платформ — мобильные, для простых API-запросов подойдут прокси дата-центров.
- Retry-логика обязательна для пайплайнов, работающих без надзора по расписанию.
- Шаг проверки IP в начале workflow сэкономит часы отладки.
Если ваш GitHub Actions workflow работает с маркетплейсами, рекламными платформами или любыми сервисами с антибот-защитой, рекомендуем использовать резидентные прокси — они имеют реальные IP домашних пользователей и значительно реже вызывают блокировки по сравнению с облачными адресами GitHub-серверов. Для задач, связанных с Facebook Ads, TikTok или другими социальными платформами, оптимальным выбором будут мобильные прокси с операторскими IP — они обеспечивают максимальный уровень доверия со стороны платформ.