GitHub Actions es una poderosa herramienta de automatización: ejecuta pruebas, despliega aplicaciones, recopila datos y realiza decenas de otras tareas. Pero tan pronto como el workflow comienza a acceder a recursos externos — marketplaces, plataformas publicitarias, API extranjeras — se enfrenta a bloqueos geográficos y límites de IP. La solución es simple: conectar un proxy directamente en el pipeline.
¿Por qué usar un proxy en GitHub Actions: escenarios reales?
Muchos equipos utilizan GitHub Actions no solo para desplegar código, sino también para automatizar tareas empresariales: monitoreo de precios de competidores, recolección de datos de marketplaces, verificación automática de cuentas publicitarias y pruebas de sitios desde diferentes regiones. Todos estos problemas comparten una misma dificultad: el runner de GitHub Actions tiene una IP fija de los rangos de Microsoft Azure, y muchos servicios lo bloquean o limitan.
Aquí hay situaciones concretas donde un proxy es indispensable:
- Scraping de Wildberries, Ozon, Avito — estas plataformas han incluido desde hace tiempo los rangos de IP de proveedores de nube en listas negras. Una solicitud desde el runner de GitHub Actions será bloqueada o recibirá un captcha ya en el segundo o tercer intento.
- Pruebas geotargetizadas — los marketers y QA verifican cómo se ve un sitio o publicidad para usuarios de Moscú, Berlín o Nueva York. Sin un proxy, el runner siempre "verá" contenido de una sola región.
- Trabajo con API limitadas por región — algunas API (por ejemplo, versiones regionales de Google Ads, Facebook Marketing API con configuraciones específicas) devuelven diferentes datos dependiendo de la geolocalización de la solicitud.
- Monitoreo de competidores — la recolección automática de precios, promociones y surtidos requiere solicitudes regulares, que son fácilmente detectadas por la IP repetida del centro de datos.
- Automatización de verificaciones publicitarias — los traders y marketers de rendimiento ejecutan verificaciones automáticas del estado de anuncios, balances y métricas a través de scripts en CI/CD.
- Pruebas de integración con servicios externos — algunos servicios bloquean solicitudes de rangos de Azure por razones de seguridad, y las pruebas simplemente fallan sin explicaciones.
En todos estos casos, un proxy resuelve el problema de manera radical: el workflow comienza a parecerse a una solicitud de un usuario normal de la ciudad deseada, y no de un servidor en la nube de Microsoft.
Cómo funciona GitHub Actions con la red
Antes de configurar un proxy, es importante entender la arquitectura de la red en GitHub Actions. Cuando ejecutas un workflow en un runner estándar ubuntu-latest, la tarea se ejecuta en una máquina virtual dentro de la infraestructura de Microsoft Azure. Cada una de estas máquinas tiene una IP pública de los rangos de Azure — y es esta IP la que ven los servicios externos.
Características clave de la red en GitHub Actions:
- La IP cambia con cada ejecución — pero permanece dentro de los rangos conocidos de Azure, que son fácilmente detectables.
- No hay soporte nativo para proxies — GitHub no proporciona un mecanismo nativo para proxy de tráfico.
- Las variables de entorno funcionan de manera global — si configuras
HTTP_PROXYa nivel de job, todos los pasos dentro de esa job usarán el proxy. - Runners autoalojados — una alternativa donde ejecutas un runner en tu propio servidor. En este caso, el proxy se configura a nivel de servidor, no de workflow.
Para la mayoría de las tareas, el enfoque óptimo es configurar el proxy a través de variables de entorno directamente en el archivo del workflow (.github/workflows/your-workflow.yml). Este es un método universal que funciona para la mayoría de las herramientas: curl, wget, Python requests, Node.js http, Go net/http y otras.
Qué tipo de proxy elegir para CI/CD
La elección del tipo de proxy depende de la tarea. Para los pipelines de CI/CD, hay tres opciones relevantes, cada una con su propio nicho:
| Tipo de proxy | Para qué tareas | Velocidad | Nivel de confianza |
|---|---|---|---|
| Proxies residenciales | Scraping de sitios protegidos, geotargeting, monitoreo de marketplaces | Promedio | Alto — IP residenciales reales |
| Proxies móviles | Pruebas de versiones móviles, trabajo con redes sociales, Facebook/TikTok API | Promedio | Máximo — IP de operadores |
| Proxies de centros de datos | Pruebas de integración, solicitudes a API no protegidas, alta carga | Alta | Promedio |
Regla práctica: si tu workflow hace scraping de Wildberries, Ozon u otros marketplaces con protección anti-bots, utiliza proxies residenciales. Si pruebas cuentas publicitarias de Facebook Ads o TikTok Ads, usa proxies móviles. Para pruebas de integración simples y solicitudes a API abiertas, son suficientes los proxies de centros de datos: son más rápidos y económicos.
💡 Importante sobre los protocolos
Para GitHub Actions, es preferible usar proxies HTTP/HTTPS — son soportados por la mayoría de las herramientas sin configuraciones adicionales. SOCKS5 también funciona, pero requiere especificación explícita en cada herramienta. Si tu proveedor soporta ambos protocolos, comienza con HTTP.
Configuración del proxy a través de variables de entorno
La forma más universal de conectar un proxy en GitHub Actions es establecer las variables de entorno estándar HTTP_PROXY, HTTPS_PROXY y NO_PROXY. La mayoría de las herramientas de línea de comandos y lenguajes de programación las capturan automáticamente.
La estructura básica de un workflow con proxy se ve así:
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 del repositorio
uses: actions/checkout@v4
- name: Verificar IP actual (para comprobación)
run: curl -s https://api.ipify.org
- name: Ejecutar script principal
run: python scripts/scraper.py
Presta atención al bloque NO_PROXY — aquí debes añadir las direcciones a las que no se debe proxyficar el tráfico. Como mínimo, esto incluye localhost y 127.0.0.1. También se recomienda añadir github.com, para que las operaciones con el repositorio (checkout, push) se realicen directamente.
Si el proxy no requiere autenticación (solo IP y puerto), el formato se simplifica:
env:
HTTP_PROXY: http://203.0.113.10:8080
HTTPS_PROXY: http://203.0.113.10:8080
NO_PROXY: localhost,127.0.0.1
Para proxies SOCKS5, solo cambia el esquema en la URL:
env:
HTTP_PROXY: socks5://user:password@proxy-host:1080
HTTPS_PROXY: socks5://user:password@proxy-host:1080
Proxy para curl, wget y solicitudes HTTP en shell
Si las variables de entorno están establecidas a nivel de job (como se mostró anteriormente), curl y wget las capturarán automáticamente. Pero a veces es necesario pasar el proxy explícitamente — por ejemplo, para un paso específico o durante la depuración.
Especificación explícita del proxy en curl:
- name: Obtener datos con 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
# Verificación a través del proxy
curl -x http://${{ secrets.PROXY_USER }}:${{ secrets.PROXY_PASS }}@${{ secrets.PROXY_HOST }}:${{ secrets.PROXY_PORT }} \
-s https://api.ipify.org?format=json
Para wget:
- name: Descargar con wget a través del 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 paso útil para la depuración es añadir al inicio del workflow una verificación de la dirección IP. Si el proxy funciona correctamente, verás la IP del servidor proxy, y no la de Azure:
- name: Verificar que el proxy está activo
run: |
echo "=== IP sin proxy ==="
curl -s --noproxy '*' https://api.ipify.org || echo "La solicitud directa falló"
echo ""
echo "=== IP a través del proxy ==="
curl -s https://api.ipify.org
Proxy en scripts de Python dentro del workflow
Python es uno de los lenguajes más populares para scripts en CI/CD. La biblioteca requests lee automáticamente las variables de entorno HTTP_PROXY y HTTPS_PROXY, si están establecidas. Pero para un control más flexible, es mejor pasar el proxy explícitamente.
Ejemplo de un script de Python con paso explícito del proxy a través de variables de entorno:
import os
import requests
# Leemos los datos del proxy de las variables de entorno
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}',
}
# Usamos el proxy en la solicitud
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"Estado: {response.status_code}")
print(f"Longitud del contenido: {len(response.content)}")
En el archivo del workflow, debes pasar las variables como secretos separados (no como una URL completa), para que el script pueda recopilarlas:
- name: Ejecutar scraper de 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
Para trabajar con Playwright o Selenium en Python, la configuración del proxy es un poco diferente:
# 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")
# ... lógica adicional
browser.close()
Proxy en Node.js y tareas npm
Node.js no lee automáticamente las variables del sistema HTTP_PROXY — debes usar bibliotecas especiales o configurar el proxy explícitamente. La opción más conveniente es el paquete https-proxy-agent o axios con configuración de proxy.
// Usando 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 solicitud falló: ${error.message}`);
throw error;
}
}
fetchData('https://api.example.com/prices')
.then(data => console.log(JSON.stringify(data, null, 2)))
.catch(() => process.exit(1));
Para comandos npm (por ejemplo, si npm intenta descargar paquetes a través de un proxy corporativo), la configuración es más simple:
- name: Configurar 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: Instalar dependencias
run: npm install
- name: Restablecer proxy npm (limpiar después de usar)
run: |
npm config delete proxy
npm config delete https-proxy
Almacenamiento seguro de datos de proxy en GitHub Secrets
Nunca almacenes datos de proxy (host, puerto, usuario, contraseña) directamente en el archivo del workflow en texto claro. Este es un grave error de seguridad: los archivos del workflow se almacenan en el repositorio y pueden ser visibles para todos los participantes del proyecto o incluso públicamente.
El enfoque correcto es usar GitHub Secrets. Aquí tienes una guía paso a paso:
- Abre el repositorio en GitHub
- Ve a Settings → Secrets and variables → Actions
- Haz clic en New repository secret
- Crea cuatro secretos:
PROXY_HOST,PROXY_PORT,PROXY_USER,PROXY_PASS - En el workflow, accede a ellos a través de la sintaxis
${{ secrets.PROXY_HOST }}
🔒 Medidas de seguridad adicionales
- Usa Environment secrets en lugar de Repository secrets, si diferentes entornos (staging/production) utilizan diferentes proxies
- Limita el acceso a los secretos a través de Environment protection rules — requiere confirmación manual para producción
- Rota regularmente las credenciales del proxy — cambia las contraseñas cada 30–90 días
- No imprimas los valores de los secretos en los logs a través de
echo— GitHub los oculta automáticamente, pero es mejor no arriesgarse
Si utilizas proxies rotativos (cuando la IP cambia con cada solicitud o según un horario), a menudo es suficiente almacenar solo un endpoint — el proveedor de proxy gestiona automáticamente el grupo de IP. En este caso, los secretos contendrán solo un host y puerto del gateway de rotación.
Rotación de proxy y manejo de errores en el pipeline
Incluso los proxies de alta calidad pueden fallar a veces: la IP puede ser temporalmente bloqueada, la sesión puede interrumpirse, el servidor puede no responder. Para los pipelines de CI/CD que funcionan automáticamente sin supervisión, es importante prever el manejo de tales situaciones.
Estrategia 1: Reintento con el mismo 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"Intento {attempt + 1} falló: {e}")
if attempt < max_retries - 1:
print(f"Reintentando en {delay} segundos...")
time.sleep(delay)
delay *= 2 # Retraso exponencial
raise Exception(f"Todos los {max_retries} intentos fallaron para {url}")
Estrategia 2: Lista de proxies con conmutación
Si tienes varios servidores proxy, puedes almacenar su lista en un solo secreto (separados por comas) y cambiar al siguiente en caso de error:
import os
import requests
import random
# El secreto 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) # Orden aleatorio
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 falló: {e}, intentando el siguiente...")
raise Exception("Todos los proxies agotados")
Estrategia 3: Uso de un endpoint rotativo
La opción más simple es usar un proveedor de proxy con un único gateway rotativo. En este caso, te conectas a una dirección, y el proveedor automáticamente te asigna diferentes IP de un grupo. No se necesita lógica de rotación en el código — solo una línea de conexión es suficiente.
Escenarios reales: scraping, pruebas, monitoreo de precios
Consideremos tres escenarios concretos que son más comunes entre los equipos que utilizan GitHub Actions con proxies.
Escenario 1: Monitoreo diario de precios en Wildberries
Los vendedores de marketplaces a menudo configuran la recolección automática de precios de competidores. El workflow se ejecuta según un horario (por ejemplo, cada mañana a las 7:00), recopila datos y los guarda en Google Sheets o los envía a Telegram.
name: Monitor de Precios Diario
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: Configurar Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Instalar dependencias
run: pip install requests beautifulsoup4 gspread
- name: Ejecutar scraper de precios
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: Subir artefacto de resultados
uses: actions/upload-artifact@v4
with:
name: price-data-${{ github.run_id }}
path: output/prices.json
Escenario 2: Pruebas geotargetizadas de un sitio
Los marketers y equipos de QA utilizan proxies para verificar cómo se ve un sitio o publicidad para usuarios de diferentes ciudades. Esto es especialmente relevante para verificar precios regionales, contenido y redirecciones.
name: Pruebas de Sitio Geotargetizadas
on:
push:
branches: [main]
pull_request:
jobs:
test-moscow:
runs-on: ubuntu-latest
name: Prueba desde Moscú
steps:
- uses: actions/checkout@v4
- name: Ejecutar pruebas geográficas (proxy RU/Moscú)
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: Prueba desde Alemania
steps:
- uses: actions/checkout@v4
- name: Ejecutar pruebas geográficas (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
Escenario 3: Verificación automática de cuentas publicitarias
Los traders y marketers de rendimiento a menudo utilizan GitHub Actions para verificar automáticamente el estado de las cuentas publicitarias de Facebook Ads, balances y métricas. Las solicitudes a la API de Facebook Marketing desde rangos de Azure pueden provocar verificaciones de seguridad adicionales — el proxy ayuda a eludir esto.
name: Verificación de Salud de Cuentas Publicitarias
on:
schedule:
- cron: '*/30 6-22 * * *' # Cada 30 minutos de 6 a 22 MSK
jobs:
check-accounts:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Configurar Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Instalar dependencias
run: pip install requests
- name: Verificar cuentas de 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
📋 Lista de verificación antes de ejecutar el workflow con proxy
- ✅ Los datos del proxy han sido añadidos a GitHub Secrets (no en el archivo del workflow)
- ✅ Las variables
NO_PROXYincluyengithub.com - ✅ Se ha añadido un paso de verificación de IP para depuración
- ✅ Se ha implementado manejo de errores y lógica de reintento
- ✅ El tipo de proxy se ajusta a la tarea (residenciales para sitios protegidos)
- ✅ Se han configurado notificaciones de errores (Telegram, Slack o email)
- ✅ El workflow ha sido probado manualmente a través de
workflow_dispatchantes de añadir el horario
Conclusión
Configurar un proxy en GitHub Actions no es una tarea complicada si conoces el enfoque correcto. Las conclusiones clave de esta guía son:
- Variables de entorno
HTTP_PROXY/HTTPS_PROXY— un método universal que funciona para la mayoría de las herramientas sin necesidad de modificar el código. - GitHub Secrets — el único lugar correcto para almacenar las credenciales del proxy.
- El tipo de proxy es importante: para scraping de marketplaces protegidos se necesitan IP residenciales, para plataformas publicitarias — móviles, para solicitudes simples a API, son suficientes los proxies de centros de datos.
- La lógica de reintento es obligatoria para los pipelines que funcionan sin supervisión según un horario.
- Un paso de verificación de IP al inicio del workflow ahorrará horas de depuración.
Si tu workflow de GitHub Actions trabaja con marketplaces, plataformas publicitarias o cualquier servicio con protección anti-bots, te recomendamos utilizar proxies residenciales — tienen IP reales de usuarios domésticos y son mucho menos propensos a bloqueos en comparación con las direcciones en la nube de los servidores de GitHub. Para tareas relacionadas con Facebook Ads, TikTok u otras plataformas sociales, la mejor opción son los proxies móviles con IP de operadores — proporcionan el máximo nivel de confianza por parte de las plataformas.
```