Назад к блогу

Прокси в GitHub Actions и CI/CD пайплайнах: полное руководство с примерами кода

Разбираемся, как подключить прокси к GitHub Actions workflow — чтобы автоматические задачи не получали блокировки и работали из нужного региона.

📅20 июля 2026 г.

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. Вот пошаговая инструкция:

  1. Откройте репозиторий на GitHub
  2. Перейдите в Settings → Secrets and variables → Actions
  3. Нажмите New repository secret
  4. Создайте четыре секрета: PROXY_HOST, PROXY_PORT, PROXY_USER, PROXY_PASS
  5. В 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 — они обеспечивают максимальный уровень доверия со стороны платформ.