Volver al blog

Configuración de proxy en Docker para descargar imágenes y aplicaciones en contenedores: guía completa

Analizamos cómo configurar un proxy en Docker para descargar imágenes a través de firewalls corporativos y para aplicaciones dentro de contenedores, con ejemplos de configuración y escenarios reales.

📅4 de abril de 2026
```html

¿Trabajas con Docker en una red corporativa, en un servidor con acceso restringido o quieres que tus contenedores salgan a Internet a través de una IP específica? Sin la configuración adecuada del proxy, Docker simplemente no podrá descargar imágenes de Docker Hub o de cualquier otro registro. En este artículo, analizaremos todos los niveles de proxy: desde el demonio hasta un contenedor separado.

¿Por qué necesita Docker un proxy?

Docker es una herramienta que constantemente accede a recursos externos. En cada docker pull o docker build, el demonio accede a Docker Hub, GitHub Container Registry, Google Container Registry o a tu registro privado. Y aquí es donde comienzan los problemas.

Situaciones en las que no se puede prescindir de un proxy:

  • Red corporativa con firewall — todo el tráfico debe pasar a través de un servidor proxy corporativo, de lo contrario, la conexión se bloquea.
  • Restricciones geográficas — Docker Hub o registros específicos no están disponibles desde tu país o centro de datos.
  • Servidor restringido sin acceso directo a Internet — VPS en un entorno cerrado, donde Internet solo está disponible a través de un gateway.
  • Control del tráfico saliente de los contenedores — deseas que las aplicaciones dentro de los contenedores salgan a la red a través de una IP específica, por ejemplo, para scraping, solicitudes API o pruebas de contenido geodependiente.
  • Anonimización de solicitudes — ocultar la IP real del servidor al acceder a servicios externos desde el contenedor.
  • Limitación de tasa — Docker Hub limita el número de solicitudes de pull para usuarios anónimos (100 pulls cada 6 horas). A través de un proxy con rotación de IP se puede eludir esta restricción.

Es importante entender que Docker no es una sola aplicación, sino un sistema de varios componentes. El demonio (dockerd) vive en el host y realiza pulls de imágenes. Los contenedores son procesos aislados con sus propias configuraciones de red. Por lo tanto, la configuración del proxy para el demonio y para los contenedores son dos tareas diferentes que se abordan de manera distinta.

Tres niveles de proxy en Docker

Antes de meterse en las configuraciones, es necesario entender la arquitectura. En Docker hay tres niveles independientes, cada uno de los cuales requiere una configuración de proxy separada:

Nivel Qué hace Dónde se configura
Demonio de Docker Descarga imágenes (docker pull), accede a registros sobrescritura de systemd o daemon.json
Construcción de Docker Ejecuta comandos durante la construcción de la imagen (RUN apt-get, pip install, etc.) ARG y ENV en Dockerfile o --build-arg
Contenedor en ejecución Aplicación en ejecución que realiza solicitudes HTTP ENV al ejecutar docker run o en docker-compose.yml

Un error típico es configurar el proxy solo en un nivel y preguntarse por qué las imágenes aún no se descargan o la aplicación no ve el proxy. Vamos a analizar cada nivel en detalle.

Configuración del proxy para el demonio de Docker (pull de imágenes)

Esta es la configuración más importante si deseas descargar imágenes a través de un proxy. El demonio de Docker es un servicio del sistema que se inicia a través de systemd. No ve las variables de entorno de tu usuario o incluso de root. Debes pasar el proxy específicamente al entorno del servicio.

Método 1: a través de la sobrescritura de systemd (recomendado)

Crea un directorio para sobrescribir la configuración del servicio:

sudo mkdir -p /etc/systemd/system/docker.service.d

Crea un archivo /etc/systemd/system/docker.service.d/http-proxy.conf con el siguiente contenido:

[Service]
Environment="HTTP_PROXY=http://username:password@proxy-host:port"
Environment="HTTPS_PROXY=http://username:password@proxy-host:port"
Environment="NO_PROXY=localhost,127.0.0.1,::1,your-private-registry.example.com"

Si el proxy no requiere autenticación, simplemente elimina username:password@. Después de crear el archivo, recarga la configuración de systemd y reinicia Docker:

sudo systemctl daemon-reload
sudo systemctl restart docker

Verifica que la configuración se haya aplicado:

sudo systemctl show --property=Environment docker

En la salida deberían aparecer tus variables HTTP_PROXY y HTTPS_PROXY.

Método 2: a través de ~/.docker/config.json (Docker Desktop y versiones nuevas)

A partir de Docker Engine 23.0, hay una forma más conveniente: configurar el proxy a través del archivo de configuración del cliente. Crea o edita el archivo ~/.docker/config.json:

{
  "proxies": {
    "default": {
      "httpProxy": "http://username:password@proxy-host:port",
      "httpsProxy": "http://username:password@proxy-host:port",
      "noProxy": "localhost,127.0.0.1,::1"
    }
  }
}

Este método es conveniente porque no requiere privilegios de root y no necesita reiniciar el demonio. La configuración se pasa automáticamente a los contenedores durante la construcción como argumentos de build. Sin embargo, para gestionar las solicitudes de pull del propio demonio, aún se necesita el método a través de systemd.

💡 Importante sobre NO_PROXY

Siempre agrega a NO_PROXY las direcciones de tus registros y servicios internos. De lo contrario, Docker intentará acceder a ellos a través del proxy y recibirá errores de conexión. Una lista típica: localhost,127.0.0.1,::1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16

Proxy dentro del contenedor durante la construcción (build-time)

Cuando Docker construye una imagen y ejecuta comandos como RUN apt-get install, RUN pip install o RUN npm install, estos comandos se ejecutan dentro de un contenedor temporal. Por defecto, no tiene acceso al proxy del host. Debes pasar explícitamente el proxy a través de argumentos de build.

Pasar el proxy a través de --build-arg

docker build \
  --build-arg HTTP_PROXY=http://proxy-host:port \
  --build-arg HTTPS_PROXY=http://proxy-host:port \
  --build-arg NO_PROXY=localhost,127.0.0.1 \
  -t my-image .

Configuración en Dockerfile

Si el proxy solo es necesario durante la construcción y no deseas que se incluya en la imagen final, utiliza ARG en lugar de ENV:

FROM ubuntu:22.04

# Declaramos los argumentos de construcción
ARG HTTP_PROXY
ARG HTTPS_PROXY
ARG NO_PROXY

# Los usamos en los comandos
RUN apt-get update && apt-get install -y curl wget

# Después de este bloque, el proxy no estará en ENV del contenedor

Si el proxy es necesario también en el contenedor en ejecución, utiliza ENV:

FROM python:3.11

ENV HTTP_PROXY=http://proxy-host:port
ENV HTTPS_PROXY=http://proxy-host:port
ENV NO_PROXY=localhost,127.0.0.1

RUN pip install requests beautifulsoup4

CMD ["python", "app.py"]

⚠️ Atención: seguridad

No codifiques el nombre de usuario y la contraseña del proxy directamente en el Dockerfile si la imagen será pública o se almacenará en un repositorio. Utiliza --build-arg y pasa los valores desde las variables de entorno del sistema CI/CD. El comando docker history puede mostrar los valores de ARG, por lo que para secretos utiliza los secretos de Docker BuildKit.

Proxy para contenedores en ejecución (runtime)

Este es el escenario más común para aplicaciones que realizan solicitudes HTTP durante su ejecución: scrapers, bots, microservicios que necesitan salir a través de una IP específica. Aquí la configuración es muy sencilla: solo necesitas pasar las variables de entorno al iniciar el contenedor.

A través de docker run

docker run \
  -e HTTP_PROXY=http://username:password@proxy-host:port \
  -e HTTPS_PROXY=http://username:password@proxy-host:port \
  -e NO_PROXY=localhost,127.0.0.1 \
  my-image

La mayoría de las bibliotecas HTTP populares capturan automáticamente las variables HTTP_PROXY y HTTPS_PROXY: Python requests, curl, wget, net/http de Go, Node.js https-proxy-agent y otras. No necesitas escribir nada adicional en el código.

A través del archivo .env

Es más conveniente almacenar la configuración en un archivo .env y pasarlo completo:

# Archivo .env
HTTP_PROXY=http://username:password@proxy-host:port
HTTPS_PROXY=http://username:password@proxy-host:port
NO_PROXY=localhost,127.0.0.1
docker run --env-file .env my-image

Proxy SOCKS5 en el contenedor

Si utilizas un proxy SOCKS5 (por ejemplo, los proxies residenciales suelen soportar este protocolo), la sintaxis es un poco diferente:

docker run \
  -e ALL_PROXY=socks5://username:password@proxy-host:port \
  my-image

Ten en cuenta: no todas las bibliotecas soportan SOCKS5 a través de la variable de entorno sin dependencias adicionales. Python requests requiere la instalación de requests[socks], curl debe ser compilado con soporte para libcurl-socks.

Proxy en Docker Compose

En proyectos reales, rara vez se utiliza el simple docker run. La mayoría de las veces se trabaja con Docker Compose, donde varios servicios están descritos en un solo archivo. La configuración del proxy se realiza aquí a nivel de cada servicio o a través de un archivo de variables.

Opción 1: environment en docker-compose.yml

version: '3.8'

services:
  scraper:
    image: my-scraper:latest
    environment:
      - HTTP_PROXY=http://username:password@proxy-host:port
      - HTTPS_PROXY=http://username:password@proxy-host:port
      - NO_PROXY=localhost,127.0.0.1
    restart: unless-stopped

  api:
    image: my-api:latest
    # Este servicio sin proxy — solo accede a recursos internos
    ports:
      - "8080:8080"

Opción 2: a través del archivo .env (recomendado)

Crea un .env en el directorio con docker-compose.yml. Docker Compose captura automáticamente este archivo:

# .env
PROXY_HOST=proxy-host
PROXY_PORT=8080
PROXY_USER=username
PROXY_PASS=password
version: '3.8'

services:
  scraper:
    image: my-scraper:latest
    environment:
      - HTTP_PROXY=http://${PROXY_USER}:${PROXY_PASS}@${PROXY_HOST}:${PROXY_PORT}
      - HTTPS_PROXY=http://${PROXY_USER}:${PROXY_PASS}@${PROXY_HOST}:${PROXY_PORT}
      - NO_PROXY=localhost,127.0.0.1

Proxy durante la construcción en Compose

Si en Compose hay una sección build y necesitas pasar el proxy durante la construcción:

version: '3.8'

services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
      args:
        HTTP_PROXY: http://${PROXY_USER}:${PROXY_PASS}@${PROXY_HOST}:${PROXY_PORT}
        HTTPS_PROXY: http://${PROXY_USER}:${PROXY_PASS}@${PROXY_HOST}:${PROXY_PORT}
    environment:
      - HTTP_PROXY=http://${PROXY_USER}:${PROXY_PASS}@${PROXY_HOST}:${PROXY_PORT}
      - HTTPS_PROXY=http://${PROXY_USER}:${PROXY_PASS}@${PROXY_HOST}:${PROXY_PORT}

Qué tipo de proxy elegir para Docker

La elección del tipo de proxy depende de la tarea. Para entornos Docker, hay tres tipos principales, cada uno con su propio nicho:

Tipo de proxy Velocidad Anonimato Mejor escenario para Docker
Data Center ⚡ Alta Media Pull de imágenes, pipelines de CI/CD, eludir limitaciones de tasa de Docker Hub
Residenciales 🔄 Media Alta Scraping de sitios con protección, API con restricciones geográficas, pruebas
Móviles 🔄 Media Máxima Aplicaciones que trabajan con API móviles (Instagram, TikTok)

Para pull de imágenes y CI/CD, los proxies de data center son los más óptimos, ya que ofrecen la máxima velocidad al descargar grandes imágenes (varios gigabytes) y una conexión estable para construcciones largas.

Para contenedores scraper, que necesitan eludir la protección de los sitios y parecer un usuario normal, son más adecuados los proxies residenciales. Tienen IP de usuarios reales, lo que reduce la probabilidad de bloqueo incluso con solicitudes intensivas.

Para aplicaciones que trabajan con plataformas móviles — Instagram Graph API, TikTok API, versiones móviles de servicios — vale la pena considerar los proxies móviles. Utilizan IP de operadores de telefonía móvil y generan mínimas sospechas en los sistemas anti-bot.

Protocolos: HTTP vs SOCKS5

El demonio de Docker solo soporta proxies HTTP/HTTPS — SOCKS5 no funciona para pull de imágenes. Si tienes un proxy SOCKS5 y necesitas descargar imágenes, tendrás que usar un convertidor local como privoxy o microsocks, que aceptará HTTP y lo proxeará a través de SOCKS5.

Para contenedores en ejecución, la situación es mejor: la mayoría de las bibliotecas HTTP soportan SOCKS5 directamente a través de la variable ALL_PROXY=socks5://....

Errores comunes y cómo solucionarlos

Analicemos los problemas más comunes que se encuentran al configurar un proxy en Docker:

Error 1: El proxy está configurado en el host, pero Docker no lo ve

Síntoma:

Error de respuesta del demonio: Get "https://registry-1.docker.io/v2/": dial tcp: connection refused

Causa: El demonio de Docker se ejecuta como un servicio del sistema y no hereda las variables de entorno del usuario actual, incluso si has establecido export HTTPS_PROXY=... en la terminal.

Solución: Configura el proxy a través de la sobrescritura de systemd (método 1 de la sección anterior). Asegúrate de ejecutar systemctl daemon-reload && systemctl restart docker.

Error 2: apt-get / pip / npm no funcionan durante la construcción

Síntoma:

Err:1 http://archive.ubuntu.com/ubuntu focal InRelease
No se pudo conectar a archive.ubuntu.com:80

Causa: La configuración del proxy para el demonio no se aplica automáticamente a los comandos dentro de RUN en el Dockerfile. Son dos contextos diferentes.

Solución: Pasa el proxy a través de --build-arg o utiliza ~/.docker/config.json con la sección proxies (Docker 23.0+, pasa automáticamente los argumentos durante la construcción).

Error 3: Servicios internos no accesibles a través del proxy

Síntoma:

curl: (7) Falló al conectar con internal-service.local puerto 8080: Conexión rechazada

Causa: El proxy intenta proxear solicitudes a direcciones internas que no son accesibles desde el exterior.

Solución: Agrega todos los dominios internos y subredes a NO_PROXY. Para redes corporativas, una lista típica es: localhost,127.0.0.1,::1,.internal,.local,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16

Error 4: La autenticación del proxy no funciona — caracteres especiales en la contraseña

Si la contraseña contiene caracteres especiales (@, #, %), la URL se analiza incorrectamente.

Solución: Codifica la contraseña en URL-encoding. Por ejemplo, p@ss#wordp%40ss%23word. En Python, puedes obtener rápidamente la versión codificada:

python3 -c "from urllib.parse import quote; print(quote('p@ss#word', safe=''))"
# Salida: p%40ss%23word

Error 5: El proxy funciona, pero el certificado SSL no se verifica

Los proxies corporativos a menudo realizan inspección SSL (MITM) y sustituyen certificados. Docker emite el siguiente error:

x509: certificado firmado por una autoridad desconocida

Solución: Agrega el certificado raíz corporativo a los certificados de confianza en el host y reinicia Docker. En Ubuntu/Debian:

sudo cp corporate-ca.crt /usr/local/share/ca-certificates/
sudo update-ca-certificates
sudo systemctl restart docker

Error 6: Kubernetes / Docker Swarm — el proxy no funciona en todos los nodos

En entornos de clúster, debes configurar el proxy en cada nodo por separado. Para Kubernetes, también necesitas configurar las variables de entorno en los manifiestos de pods o a través de ConfigMap. Esto se puede automatizar a través de Ansible u otras herramientas de gestión de configuración.

Conclusión

Configurar un proxy en Docker no es una sola configuración, sino tres niveles independientes: el demonio para pull de imágenes, build-time para la construcción y runtime para contenedores en ejecución. Al entender esta arquitectura, podrás gestionar de manera flexible qué tráfico pasa a través del proxy y cuál va directamente.

Breve lista de verificación para una configuración correcta:

  • ✅ Para pull de imágenes — configura la sobrescritura de systemd con las variables HTTP_PROXY y HTTPS_PROXY
  • ✅ Para la construcción — pasa el proxy a través de --build-arg o ~/.docker/config.json
  • ✅ Para runtime — usa variables de entorno a través de -e o --env-file
  • ✅ Siempre configura NO_PROXY para direcciones internas
  • ✅ No almacenes contraseñas de proxy en el Dockerfile — utiliza build-args y archivos .env
  • ✅ Para pipelines de CI/CD, elige proxies de data center rápidos
  • ✅ Para contenedores scraper — proxies residenciales o móviles

Si tus aplicaciones en contenedores realizan solicitudes a servicios externos, scrapean datos o trabajan con API que tienen restricciones geográficas, recomendamos utilizar proxies residenciales — ofrecen un alto nivel de confianza por parte de los servicios y un riesgo mínimo de bloqueos incluso con un trabajo intensivo.

```