GitHub Actions est un puissant outil d'automatisation : il exécute des tests, déploie des applications, collecte des données et effectue des dizaines d'autres tâches. Mais dès que le workflow commence à accéder à des ressources externes — places de marché, plateformes publicitaires, API étrangères — il se heurte immédiatement à des géoblocages et des limites IP. La solution est simple : connecter un proxy directement dans le pipeline.
Pourquoi un proxy dans GitHub Actions : scénarios réels
De nombreuses équipes utilisent GitHub Actions non seulement pour déployer du code, mais aussi pour automatiser des tâches commerciales : surveillance des prix des concurrents, collecte de données sur les places de marché, vérification automatique des comptes publicitaires et tests de sites depuis différentes régions. Tous ces tâches partagent un même problème : le runner GitHub Actions a une IP fixe provenant de la plage Microsoft Azure, et de nombreux services le bloquent ou le limitent.
Voici des situations concrètes où un proxy est indispensable :
- Parsing de Wildberries, Ozon, Avito — ces plateformes ont depuis longtemps mis sur liste noire les plages IP des fournisseurs de cloud. Une requête depuis le runner GitHub Actions sera bloquée ou recevra un captcha après 2 à 3 tentatives.
- Tests géolocalisés — les marketeurs et les ingénieurs QA vérifient à quoi ressemble le site ou la publicité pour les utilisateurs de Moscou, Berlin ou New York. Sans proxy, le runner "verra" toujours le contenu d'une seule région.
- Travail avec des API limitées par région — certaines API (par exemple, les versions régionales de Google Ads, Facebook Marketing API avec des paramètres spécifiques) renvoient des données différentes selon la géolocalisation de la requête.
- Surveillance des concurrents — la collecte automatique des prix, des promotions et de l'assortiment nécessite des requêtes régulières, facilement détectables par l'IP répétée du centre de données.
- Automatisation des vérifications publicitaires — les arbitragistes et les marketeurs de performance lancent des vérifications automatiques de l'état des annonces, des soldes et des métriques via des scripts dans CI/CD.
- Tests d'intégration avec des services externes — certains services bloquent les requêtes provenant des plages Azure pour des raisons de sécurité, et les tests échouent sans explications.
Dans tous ces cas, le proxy résout le problème de manière radicale : le workflow commence à ressembler à une requête d'un utilisateur ordinaire de la ville souhaitée, et non d'un serveur cloud Microsoft.
Comment GitHub Actions fonctionne avec le réseau
Avant de configurer un proxy, il est important de comprendre l'architecture réseau dans GitHub Actions. Lorsque vous lancez un workflow sur un runner standard ubuntu-latest, la tâche s'exécute sur une machine virtuelle dans l'infrastructure Microsoft Azure. Chaque machine de ce type a une IP publique provenant des plages Azure — et c'est cette IP que voient les services externes.
Caractéristiques clés du réseau dans GitHub Actions :
- L'IP change à chaque exécution — mais reste dans les plages connues d'Azure, qui sont facilement détectables.
- Pas de support intégré pour les proxys — GitHub ne fournit pas de mécanisme natif pour le proxy de trafic.
- Les variables d'environnement fonctionnent globalement — si vous définissez
HTTP_PROXYau niveau du job, toutes les étapes de ce job utiliseront le proxy. - Runners auto-hébergés — une alternative où vous exécutez un runner sur votre propre serveur. Dans ce cas, le proxy est configuré au niveau du serveur, et non du workflow.
Pour la plupart des tâches, l'approche optimale est de configurer le proxy via des variables d'environnement directement dans le fichier workflow (.github/workflows/your-workflow.yml). C'est une méthode universelle qui fonctionne pour la plupart des outils : curl, wget, Python requests, Node.js http, Go net/http et autres.
Quel type de proxy choisir pour CI/CD
Le choix du type de proxy dépend de la tâche. Pour les pipelines CI/CD, trois options sont pertinentes, chacune ayant sa niche :
| Type de proxy | Pour quelles tâches | Vitesse | Niveau de confiance |
|---|---|---|---|
| Proxys résidentiels | Parsing de sites protégés, géotargeting, surveillance des places de marché | Moyenne | Élevé — IP réelles de domiciles |
| Proxys mobiles | Tests de versions mobiles, travail avec les réseaux sociaux, API Facebook/TikTok | Moyenne | Maximal — IP des opérateurs |
| Proxys de centre de données | Tests d'intégration, requêtes à des API non sécurisées, charge élevée | Élevée | Moyenne |
Règle pratique : si votre workflow parse Wildberries, Ozon ou d'autres places de marché avec protection anti-bot — optez pour des proxys résidentiels. Si vous testez des comptes publicitaires Facebook Ads ou TikTok Ads — utilisez des proxys mobiles. Pour des tests d'intégration simples et des requêtes à des API ouvertes, des proxys de centre de données suffisent : ils sont plus rapides et moins chers.
💡 Important sur les protocoles
Pour GitHub Actions, il est préférable d'utiliser des proxys HTTP/HTTPS — ils sont pris en charge par la plupart des outils sans configurations supplémentaires. SOCKS5 fonctionne également, mais nécessite une spécification explicite dans chaque outil. Si votre fournisseur prend en charge les deux protocoles — commencez par HTTP.
Configuration du proxy via des variables d'environnement
Le moyen le plus universel de connecter un proxy dans GitHub Actions est de définir les variables d'environnement standard HTTP_PROXY, HTTPS_PROXY et NO_PROXY. La plupart des outils en ligne de commande et des langages de programmation les détectent automatiquement.
La structure de base d'un workflow avec proxy ressemble à ceci :
name: Workflow avec 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: Vérifier l'IP actuelle (pour vérification)
run: curl -s https://api.ipify.org
- name: Exécuter le script principal
run: python scripts/scraper.py
Notez le bloc NO_PROXY — il faut y ajouter les adresses pour lesquelles le trafic ne doit pas être proxy. Au minimum, cela inclut localhost et 127.0.0.1. Il est également recommandé d'ajouter github.com, afin que les opérations avec le dépôt (checkout, push) se fassent directement.
Si le proxy n'a pas d'authentification (juste l'IP et le port), le format est simplifié :
env:
HTTP_PROXY: http://203.0.113.10:8080
HTTPS_PROXY: http://203.0.113.10:8080
NO_PROXY: localhost,127.0.0.1
Pour les proxys SOCKS5, seule la schéma dans l'URL change :
env:
HTTP_PROXY: socks5://user:password@proxy-host:1080
HTTPS_PROXY: socks5://user:password@proxy-host:1080
Proxy pour curl, wget et requêtes HTTP dans le shell
Si les variables d'environnement sont définies au niveau du job (comme montré ci-dessus), curl et wget les détecteront automatiquement. Mais parfois, il est nécessaire de transmettre le proxy explicitement — par exemple, pour une étape spécifique ou lors du débogage.
Indication explicite du proxy dans curl :
- name: Récupérer des données avec 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
# Vérification via le proxy
curl -x http://${{ secrets.PROXY_USER }}:${{ secrets.PROXY_PASS }}@${{ secrets.PROXY_HOST }}:${{ secrets.PROXY_PORT }} \
-s https://api.ipify.org?format=json
Pour wget :
- name: Télécharger avec 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
Une étape utile pour le débogage consiste à ajouter au début du workflow une vérification de l'adresse IP. Si le proxy fonctionne correctement, vous verrez l'IP du serveur proxy, et non celle d'Azure :
- name: Vérifier que le proxy est actif
run: |
echo "=== IP sans proxy ==="
curl -s --noproxy '*' https://api.ipify.org || echo "La requête directe a échoué"
echo ""
echo "=== IP via proxy ==="
curl -s https://api.ipify.org
Proxy dans les scripts Python au sein du workflow
Python est l'un des langages les plus populaires pour les scripts dans CI/CD. La bibliothèque requests lit automatiquement les variables d'environnement HTTP_PROXY et HTTPS_PROXY, si elles sont définies. Mais pour un contrôle plus flexible, il est préférable de transmettre le proxy explicitement.
Exemple de script Python avec transmission explicite du proxy via des variables d'environnement :
import os
import requests
# Lecture des données proxy depuis les variables d'environnement
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}',
}
# Utilisation du proxy dans la requête
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"Statut : {response.status_code}")
print(f"Longueur du contenu : {len(response.content)}")
Dans le fichier workflow, il faut transmettre les variables comme des secrets séparés (et non sous forme d'URL complète), afin que le script puisse les rassembler :
- name: Exécuter le scraper Python
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
Pour travailler avec Playwright ou Selenium en Python, la configuration du proxy est légèrement différente :
# 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")
# ... logique ultérieure
browser.close()
Proxy dans Node.js et les tâches npm
Node.js ne lit pas automatiquement les variables système HTTP_PROXY — il faut soit utiliser des bibliothèques spéciales, soit configurer le proxy explicitement. L'option la plus pratique est le package https-proxy-agent ou axios avec une configuration de proxy.
// Avec 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(`La requête a échoué : ${error.message}`);
throw error;
}
}
fetchData('https://api.example.com/prices')
.then(data => console.log(JSON.stringify(data, null, 2)))
.catch(() => process.exit(1));
Pour les commandes npm (par exemple, si npm essaie de télécharger des paquets via un proxy d'entreprise), la configuration est plus simple :
- name: Configurer le proxy npm
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: Installer les dépendances
run: npm install
- name: Réinitialiser le proxy npm (nettoyage après utilisation)
run: |
npm config delete proxy
npm config delete https-proxy
Stockage sécurisé des données proxy dans GitHub Secrets
Ne stockez jamais les données proxy (hôte, port, identifiant, mot de passe) directement dans le fichier workflow en clair. C'est une grave erreur de sécurité : les fichiers workflow sont stockés dans le dépôt et peuvent être visibles par tous les participants au projet ou même publiquement.
La bonne approche — GitHub Secrets. Voici un guide étape par étape :
- Ouvrez le dépôt sur GitHub
- Allez dans Settings → Secrets and variables → Actions
- Cliquez sur New repository secret
- Créez quatre secrets :
PROXY_HOST,PROXY_PORT,PROXY_USER,PROXY_PASS - Dans le workflow, référez-vous à eux via la syntaxe
${{ secrets.PROXY_HOST }}
🔒 Mesures de sécurité supplémentaires
- Utilisez Environment secrets au lieu de Repository secrets, si différents environnements (staging/production) utilisent différents proxys
- Limitez l'accès aux secrets via Environment protection rules — exigez une confirmation manuelle pour la production
- Rotez régulièrement les identifiants proxy — changez les mots de passe tous les 30 à 90 jours
- Ne sortez pas les valeurs des secrets dans les logs via
echo— GitHub les masque automatiquement, mais il vaut mieux ne pas prendre de risques
Si vous utilisez des proxys rotatifs (lorsque l'IP change à chaque requête ou selon un calendrier), il est souvent suffisant de stocker un seul endpoint — le fournisseur de proxy gère lui-même le pool d'IP. Dans ce cas, les secrets ne contiendront qu'un seul hôte et le port de la passerelle de rotation.
Rotation des proxys et gestion des erreurs dans le pipeline
Même des proxys de qualité peuvent parfois échouer : l'IP peut être temporairement bannie, la session peut être interrompue, le serveur peut ne pas répondre. Pour les pipelines CI/CD qui fonctionnent automatiquement sans supervision, il est important de prévoir la gestion de telles situations.
Stratégie 1 : Retry avec le même proxy
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"Tentative {attempt + 1} échouée : {e}")
if attempt < max_retries - 1:
print(f"Nouvelle tentative dans {delay} secondes...")
time.sleep(delay)
delay *= 2 # Délai exponentiel
raise Exception(f"Toutes les {max_retries} tentatives ont échoué pour {url}")
Stratégie 2 : Liste de proxys avec basculement
Si vous avez plusieurs serveurs proxy, vous pouvez stocker leur liste dans un seul secret (séparés par des virgules) et basculer en cas d'erreur :
import os
import requests
import random
# Le secret PROXY_LIST contient : "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) # Ordre aléatoire
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 échoué : {e}, tentative suivante...")
raise Exception("Tous les proxys épuisés")
Stratégie 3 : Utilisation d'un endpoint rotatif
L'option la plus simple consiste à utiliser un fournisseur de proxy avec une passerelle rotative unique. Dans ce cas, vous vous connectez à une seule adresse, et le fournisseur délivre automatiquement différentes IP d'un pool. Aucune logique de rotation dans le code n'est nécessaire — une seule ligne de connexion suffit.
Scénarios réels : parsing, tests, surveillance des prix
Examinons trois scénarios concrets qui se rencontrent le plus souvent chez les équipes utilisant GitHub Actions avec des proxys.
Scénario 1 : Surveillance quotidienne des prix sur Wildberries
Les vendeurs de places de marché configurent souvent la collecte automatique des prix des concurrents. Le workflow s'exécute selon un calendrier (par exemple, chaque matin à 7h00), collecte des données et les enregistre dans Google Sheets ou les envoie sur Telegram.
name: Moniteur de prix quotidien
on:
schedule:
- cron: '0 4 * * *' # 07:00 MSK (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: Configurer Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Installer les dépendances
run: pip install requests beautifulsoup4 gspread
- name: Exécuter le scraper de prix
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: Télécharger l'artefact des résultats
uses: actions/upload-artifact@v4
with:
name: price-data-${{ github.run_id }}
path: output/prices.json
Scénario 2 : Tests géolocalisés du site
Les marketeurs et les équipes QA utilisent des proxys pour vérifier à quoi ressemblent le site ou la publicité pour les utilisateurs de différentes villes. C'est particulièrement pertinent pour vérifier les prix régionaux, le contenu et les redirections.
name: Tests de site géolocalisés
on:
push:
branches: [main]
pull_request:
jobs:
test-moscow:
runs-on: ubuntu-latest
name: Test depuis Moscou
steps:
- uses: actions/checkout@v4
- name: Exécuter les tests géo (proxy RU/Moscou)
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 depuis l'Allemagne
steps:
- uses: actions/checkout@v4
- name: Exécuter les tests géo (proxy DE)
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
Scénario 3 : Vérification automatique des comptes publicitaires
Les arbitragistes et les marketeurs de performance utilisent souvent GitHub Actions pour vérifier automatiquement l'état des comptes publicitaires Facebook Ads, les soldes et les métriques. Les requêtes à l'API Facebook Marketing depuis des plages Azure peuvent déclencher des vérifications de sécurité supplémentaires — le proxy aide à contourner cela.
name: Vérification de la santé des comptes publicitaires
on:
schedule:
- cron: '*/30 6-22 * * *' # Toutes les 30 minutes de 6h à 22h MSK
jobs:
check-accounts:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Configurer Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Installer les dépendances
run: pip install requests
- name: Vérifier les comptes Facebook Ads
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
📋 Liste de contrôle avant de lancer le workflow avec proxy
- ✅ Les données proxy ont été ajoutées dans GitHub Secrets (pas dans le fichier workflow)
- ✅ Les variables
NO_PROXYincluentgithub.com - ✅ Étape de vérification de l'IP ajoutée pour le débogage
- ✅ Gestion des erreurs et logique de retry implémentées
- ✅ Type de proxy correspondant à la tâche (résidentiels pour les sites protégés)
- ✅ Notifications d'erreurs configurées (Telegram, Slack ou email)
- ✅ Workflow testé manuellement via
workflow_dispatchavant d'ajouter le calendrier
Conclusion
Configurer un proxy dans GitHub Actions n'est pas une tâche difficile si l'on connaît la bonne approche. Voici les points clés de ce guide :
- Les variables d'environnement
HTTP_PROXY/HTTPS_PROXY— un moyen universel qui fonctionne pour la plupart des outils sans modification de code. - GitHub Secrets — le seul endroit correct pour stocker les identifiants proxy.
- Le type de proxy est important : pour le parsing des places de marché protégées, des IP résidentielles sont nécessaires, pour les plateformes publicitaires — des proxys mobiles, pour des requêtes API simples, des proxys de centre de données suffisent.
- La logique de retry est obligatoire pour les pipelines fonctionnant sans supervision selon un calendrier.
- Une étape de vérification de l'IP au début du workflow fera gagner des heures de débogage.
Si votre workflow GitHub Actions travaille avec des places de marché, des plateformes publicitaires ou tout service avec protection anti-bot, nous vous recommandons d'utiliser des proxys résidentiels — ils possèdent de vraies IP d'utilisateurs domestiques et provoquent beaucoup moins de blocages par rapport aux adresses cloud des serveurs GitHub. Pour les tâches liées à Facebook Ads, TikTok ou d'autres plateformes sociales, le choix optimal sera des proxys mobiles avec des IP d'opérateurs — ils assurent un niveau de confiance maximal de la part des plateformes.
```