GitHub Actions è uno strumento potente per l'automazione: esegue test, distribuisce applicazioni, raccoglie dati e svolge decine di altri compiti. Ma non appena il workflow inizia a interagire con risorse esterne — marketplace, piattaforme pubblicitarie, API estere — si imbatte immediatamente in geo-blocchi e limiti IP. L'unica soluzione è collegare un proxy direttamente nel pipeline.
Perché un proxy in GitHub Actions: scenari reali
Molti team utilizzano GitHub Actions non solo per distribuire codice, ma anche per automatizzare compiti aziendali: monitoraggio dei prezzi dei concorrenti, raccolta di dati dai marketplace, verifica automatica dei conti pubblicitari e test di siti da diverse regioni. Tutti questi compiti condividono un problema comune: il runner di GitHub Actions ha un IP fisso da un intervallo di Microsoft Azure, e molti servizi lo bloccano o lo limitano.
Ecco situazioni specifiche in cui non si può fare a meno del proxy:
- Scraping di Wildberries, Ozon, Avito — queste piattaforme hanno da tempo inserito gli intervalli IP dei provider cloud nelle blacklist. Una richiesta dal runner di GitHub Actions verrà bloccata o riceverà un captcha già al secondo o terzo tentativo.
- Test geo-targetizzati — i marketer e gli ingegneri QA controllano come appare un sito o una pubblicità per gli utenti di Mosca, Berlino o New York. Senza proxy, il runner vedrà sempre contenuti per una sola regione.
- Interazione con API limitate per regione — alcune API (ad esempio, versioni regionali di Google Ads, Facebook Marketing API con impostazioni specifiche) restituiscono dati diversi a seconda della geolocalizzazione della richiesta.
- Monitoraggio dei concorrenti — la raccolta automatica di prezzi, promozioni e assortimenti richiede richieste regolari, facilmente rilevabili per l'IP ripetuto del data center.
- Automazione delle verifiche pubblicitarie — gli arbitraggi e i marketer performance avviano controlli automatici sullo stato degli annunci, saldi e metriche tramite script in CI/CD.
- Test di integrazione con servizi esterni — alcuni servizi bloccano le richieste dagli intervalli Azure per motivi di sicurezza, e i test semplicemente falliscono senza spiegazioni.
In tutti questi casi, il proxy risolve il problema in modo radicale: il workflow inizia a sembrare una richiesta da un normale utente della città desiderata, e non da un server cloud Microsoft.
Come GitHub Actions lavora con la rete
Prima di configurare il proxy, è importante comprendere l'architettura della rete in GitHub Actions. Quando si avvia un workflow su un runner standard ubuntu-latest, il compito viene eseguito su una macchina virtuale nell'infrastruttura di Microsoft Azure. Ogni macchina di questo tipo ha un IP pubblico da intervalli Azure — ed è proprio questo IP che vedono i servizi esterni.
Caratteristiche chiave della rete in GitHub Actions:
- L'IP cambia ad ogni avvio — ma rimane all'interno di intervalli noti di Azure, facilmente rilevabili.
- Non c'è supporto integrato per proxy — GitHub non fornisce un meccanismo nativo per il proxying del traffico.
- Le variabili d'ambiente funzionano globalmente — se si imposta
HTTP_PROXYa livello di job, tutti i passaggi all'interno di quella job utilizzeranno il proxy. - Self-hosted runners — un'alternativa in cui si esegue il runner sul proprio server. In questo caso, il proxy viene configurato a livello di server, non di workflow.
Per la maggior parte dei compiti, l'approccio ottimale è configurare il proxy tramite variabili d'ambiente direttamente nel file del workflow (.github/workflows/your-workflow.yml). Questo è un metodo universale che funziona per la maggior parte degli strumenti: curl, wget, richieste Python, http Node.js, Go net/http e altri.
Quale tipo di proxy scegliere per CI/CD
La scelta del tipo di proxy dipende dal compito. Per i pipeline CI/CD, ci sono tre opzioni rilevanti, ognuna con la propria nicchia:
| Tipo di proxy | Per quali compiti | Velocità | Livello di fiducia |
|---|---|---|---|
| Proxy residenziali | Scraping di siti protetti, geo-targeting, monitoraggio dei marketplace | Media | Alto — IP reali domestici |
| Proxy mobili | Test delle versioni mobili, interazione con i social media, API di Facebook/TikTok | Media | Massimo — IP degli operatori |
| Proxy dei data center | Test di integrazione, richieste a API non protette, carico elevato | Alta | Media |
Regola pratica: se il tuo workflow esegue scraping di Wildberries, Ozon o altri marketplace con protezione anti-bot — utilizza proxy residenziali. Se stai testando conti pubblicitari di Facebook Ads o TikTok Ads — utilizza proxy mobili. Per test di integrazione semplici e richieste a API aperte, sono sufficienti i proxy dei data center: sono più veloci e più economici.
💡 Importante sui protocolli
Per GitHub Actions è preferibile utilizzare proxy HTTP/HTTPS — sono supportati dalla maggior parte degli strumenti senza configurazioni aggiuntive. SOCKS5 funziona anch'esso, ma richiede un'indicazione esplicita in ogni strumento. Se il tuo provider supporta entrambi i protocolli — inizia con HTTP.
Configurazione del proxy tramite variabili d'ambiente
Il modo più universale per collegare un proxy in GitHub Actions è impostare le variabili d'ambiente standard HTTP_PROXY, HTTPS_PROXY e NO_PROXY. La maggior parte degli strumenti da riga di comando e dei linguaggi di programmazione li rileva automaticamente.
La struttura di base di un workflow con proxy appare così:
name: Workflow con 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 (per verifica)
run: curl -s https://api.ipify.org
- name: Run main script
run: python scripts/scraper.py
Fai attenzione al blocco NO_PROXY — qui devono essere aggiunti gli indirizzi a cui non deve essere proxyato il traffico. Al minimo, includi localhost e 127.0.0.1. È anche consigliato aggiungere github.com, affinché le operazioni con il repository (checkout, push) avvengano direttamente.
Se il proxy non richiede autenticazione (solo IP e porta), il formato si semplifica:
env:
HTTP_PROXY: http://203.0.113.10:8080
HTTPS_PROXY: http://203.0.113.10:8080
NO_PROXY: localhost,127.0.0.1
Per i proxy SOCKS5 cambia solo lo schema nell'URL:
env:
HTTP_PROXY: socks5://user:password@proxy-host:1080
HTTPS_PROXY: socks5://user:password@proxy-host:1080
Proxy per curl, wget e richieste HTTP nel shell
Se le variabili d'ambiente sono impostate a livello di job (come mostrato sopra), curl e wget le rileveranno automaticamente. Ma a volte è necessario specificare il proxy esplicitamente — ad esempio, per un passaggio specifico o durante il debug.
Specificazione esplicita del proxy in 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
# Verifica tramite proxy
curl -x http://${{ secrets.PROXY_USER }}:${{ secrets.PROXY_PASS }}@${{ secrets.PROXY_HOST }}:${{ secrets.PROXY_PORT }} \
-s https://api.ipify.org?format=json
Per 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
Un passaggio utile per il debug è aggiungere all'inizio del workflow un controllo dell'indirizzo IP. Se il proxy funziona correttamente, vedrai l'IP del server proxy, e non di Azure:
- name: Verify proxy is active
run: |
echo "=== IP senza proxy ==="
curl -s --noproxy '*' https://api.ipify.org || echo "Richiesta diretta fallita"
echo ""
echo "=== IP tramite proxy ==="
curl -s https://api.ipify.org
Proxy negli script Python all'interno del workflow
Python è uno dei linguaggi più popolari per gli script in CI/CD. La libreria requests legge automaticamente le variabili d'ambiente HTTP_PROXY e HTTPS_PROXY, se sono impostate. Ma per una gestione più flessibile è meglio passare esplicitamente il proxy.
Esempio di script Python con passaggio esplicito del proxy tramite variabili d'ambiente:
import os
import requests
# Leggi i dati del proxy dalle variabili d'ambiente
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}',
}
# Usa il proxy nella richiesta
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"Lunghezza del contenuto: {len(response.content)}")
Nel file del workflow è necessario passare le variabili come segreti separati (non come URL completo), affinché lo script possa raccoglierli:
- 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
Per lavorare con Playwright o Selenium in Python, la configurazione del proxy è leggermente diversa:
# 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")
# ... logica successiva
browser.close()
Proxy in Node.js e npm-task
Node.js non legge automaticamente le variabili di sistema HTTP_PROXY — è necessario utilizzare librerie speciali o configurare esplicitamente il proxy. L'opzione più comoda è il pacchetto https-proxy-agent o axios con configurazione proxy.
// Utilizzando 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(`Richiesta fallita: ${error.message}`);
throw error;
}
}
fetchData('https://api.example.com/prices')
.then(data => console.log(JSON.stringify(data, null, 2)))
.catch(() => process.exit(1));
Per comandi npm (ad esempio, se npm cerca di scaricare pacchetti tramite un proxy aziendale) la configurazione è più semplice:
- 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 (ripristina dopo l'uso)
run: |
npm config delete proxy
npm config delete https-proxy
Archiviazione sicura dei dati del proxy in GitHub Secrets
Non memorizzare mai i dati del proxy (host, porta, login, password) direttamente nel file del workflow in chiaro. È un grave errore di sicurezza: i file del workflow sono memorizzati nel repository e possono essere visibili a tutti i membri del progetto o addirittura pubblicamente.
Il metodo corretto è GitHub Secrets. Ecco una guida passo-passo:
- Apri il repository su GitHub
- Vai su Settings → Secrets and variables → Actions
- Clicca su New repository secret
- Crea quattro segreti:
PROXY_HOST,PROXY_PORT,PROXY_USER,PROXY_PASS - Nel workflow, accedi a essi tramite la sintassi
${{ secrets.PROXY_HOST }}
🔒 Misure di sicurezza aggiuntive
- Utilizza Environment secrets invece di Repository secrets, se diversi ambienti (staging/production) utilizzano proxy diversi
- Limita l'accesso ai segreti tramite Environment protection rules — richiedi conferma manuale per la produzione
- Ruota regolarmente le credenziali del proxy — cambia le password ogni 30–90 giorni
- Non stampare i valori dei segreti nei log tramite
echo— GitHub li maschera automaticamente, ma è meglio non rischiare
Se utilizzi proxy rotativi (quando l'IP cambia ad ogni richiesta o secondo un programma), spesso è sufficiente memorizzare solo un endpoint — il provider del proxy gestisce autonomamente il pool di IP. In questo caso, nei segreti ci sarà solo un host e la porta del gateway di rotazione.
Rotazione del proxy e gestione degli errori nel pipeline
Anche i proxy di alta qualità a volte possono fallire: l'IP può finire in un ban temporaneo, la sessione può interrompersi, il server può non rispondere. Per i pipeline CI/CD che funzionano automaticamente senza supervisione, è importante prevedere la gestione di tali situazioni.
Strategia 1: Retry con lo stesso 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"Il tentativo {attempt + 1} è fallito: {e}")
if attempt < max_retries - 1:
print(f"Riprovo tra {delay} secondi...")
time.sleep(delay)
delay *= 2 # Ritardo esponenziale
raise Exception(f"Tutti i {max_retries} tentativi sono falliti per {url}")
Strategia 2: Lista di proxy con switch
Se hai più server proxy, puoi memorizzare la loro lista in un unico segreto (separati da virgola) e passare a un altro in caso di errore:
import os
import requests
import random
# Il segreto PROXY_LIST contiene: "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) # Ordine casuale
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 fallito: {e}, provando il successivo...")
raise Exception("Tutti i proxy esauriti")
Strategia 3: Utilizzo di un endpoint rotativo
L'opzione più semplice è utilizzare un provider di proxy con un unico gateway rotativo. In questo caso, ti connetti a un solo indirizzo, e il provider assegna automaticamente diversi IP da un pool. Non è necessaria alcuna logica di rotazione nel codice — basta una riga di connessione.
Scenari reali: scraping, test, monitoraggio dei prezzi
Esaminiamo tre scenari specifici che si incontrano più frequentemente nei team che utilizzano GitHub Actions con proxy.
Scenario 1: Monitoraggio giornaliero dei prezzi su Wildberries
I venditori dei marketplace spesso impostano la raccolta automatica dei prezzi dei concorrenti. Il workflow viene avviato secondo un programma (ad esempio, ogni mattina alle 7:00), raccoglie i dati e li salva in Google Sheets o li invia su Telegram.
name: Monitoraggio Prezzi Giornaliero
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: 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
Scenario 2: Test geo-targetizzati del sito
I marketer e i team QA utilizzano proxy per controllare come il sito o la pubblicità appaiono per gli utenti di diverse città. È particolarmente rilevante per il controllo dei prezzi regionali, dei contenuti e dei reindirizzamenti.
name: Test Geo-targetizzati del Sito
on:
push:
branches: [main]
pull_request:
jobs:
test-moscow:
runs-on: ubuntu-latest
name: Test da Mosca
steps:
- uses: actions/checkout@v4
- name: Esegui test geo (proxy RU/Mosca)
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 dalla Germania
steps:
- uses: actions/checkout@v4
- name: Esegui test geo (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
Scenario 3: Verifica automatica dei conti pubblicitari
Gli arbitraggi e i marketer performance utilizzano spesso GitHub Actions per controllare automaticamente lo stato dei conti pubblicitari di Facebook Ads, saldi e metriche. Le richieste all'API di Facebook Marketing dagli intervalli Azure possono attivare controlli di sicurezza aggiuntivi — il proxy aiuta a bypassarli.
name: Controllo Salute del Conto Pubblicitario
on:
schedule:
- cron: '*/30 6-22 * * *' # Ogni 30 minuti dalle 6 alle 22 MSK
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: Controlla i conti 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
📋 Checklist prima di avviare il workflow con proxy
- ✅ I dati del proxy sono stati aggiunti a GitHub Secrets (non nel file del workflow)
- ✅ Le variabili
NO_PROXYincludonogithub.com - ✅ Aggiunto un passaggio di verifica IP per il debug
- ✅ Implementata la gestione degli errori e la logica di retry
- ✅ Il tipo di proxy corrisponde al compito (residenziali per siti protetti)
- ✅ Impostate notifiche sugli errori (Telegram, Slack o email)
- ✅ Il workflow è stato testato manualmente tramite
workflow_dispatchprima di aggiungere la pianificazione
Conclusione
Configurare un proxy in GitHub Actions non è un compito difficile se si conosce l'approccio corretto. Ecco le conclusioni chiave di questa guida:
- Variabili d'ambiente
HTTP_PROXY/HTTPS_PROXY— un modo universale che funziona per la maggior parte degli strumenti senza modificare il codice. - GitHub Secrets — l'unico posto corretto per memorizzare le credenziali del proxy.
- Il tipo di proxy è importante: per lo scraping di marketplace protetti sono necessari IP residenziali, per le piattaforme pubblicitarie — proxy mobili, per semplici richieste API sono sufficienti i proxy dei data center.
- La logica di retry è obbligatoria per i pipeline che funzionano senza supervisione secondo un programma.
- Un passaggio di verifica IP all'inizio del workflow risparmierà ore di debug.
Se il tuo workflow di GitHub Actions lavora con marketplace, piattaforme pubblicitarie o qualsiasi servizio con protezione anti-bot, ti consigliamo di utilizzare proxy residenziali — hanno IP reali di utenti domestici e bloccano significativamente meno rispetto agli indirizzi cloud dei server GitHub. Per compiti legati a Facebook Ads, TikTok o altre piattaforme social, la scelta ottimale saranno proxy mobili con IP degli operatori — offrono il massimo livello di fiducia da parte delle piattaforme.