Ha sido necesario que llegue 2025 para que hablemos de algo relacionado con contenedores en este blog. En concreto, vamos a hablar de Gluetun. Tal y como sus mantendores lo definen es un “Cliente VPN en un contenedor Docker ligero para múltiples proveedores de VPN, escrito en Go y que utiliza OpenVPN o Wireguard, DNS sobre TLS, con algunos servidores proxy integrados”
Gluetun: Una navaja suiza de clientes VPN que incluye servidores de proxy
En realidad, con la pequeña introducción y el título de esta sección se puede entender que es Gluetun. Aún así, vamos a intentar explicarlo un poco mejor. Gluetun es una imagen de contenedor que consiste básicamente en una ingente cantidad de clientes VPN para que utilices el que más te convenga. A lo anterior hay que sumarle que en la imagen tienes a tu disposición servidores de proxy.
Y al juntar estas dos características tenemos un contenedor que puede hacer de proxy con VPN integrada para tus contenedores o para tus dispositivos dentro de la red LAN. Incluso, en el caso de los contenedores, sin ni siquiera hacer uso del servicio de proxy puedes hacer que el acceso a la red de tus contenedores sea a través de Gluetun. Así que tendrás tus servicios en contenedores a través de una VPN.
Por último, como tiene soporte tanto para ARM como para x86 en sus versiones de 32 y 64 bits, te permite montar este juguetito en cualquier Raspberry u otra SBC, así como cualquier MiniPC a tu disposición de una manera rápida y simple.
Las características más importantes de Gluetun son:
- Imagen muy ligera basada en Alpine Linux.
- Soporte para múltiples proveedores de VPN: AirVPN, Cyberghost, ExpressVPN, FastestVPN, Giganews, HideMyAss, IPVanish, IVPN, Mullvad, NordVPN, Perfect Privacy, Privado, Private Internet Access, PrivateVPN, ProtonVPN, PureVPN, SlickVPN, Surfshark, TorGuard, VPNSecure.me, VPNUnlimited, Vyprvpn, WeVPN, Windscribe.
- Soporte para OpenVPN para todos los servidores.
- Soporte para Wireguard. En función del proveedor VPN hay soporte para Kernel y espacio de usuario, soporte usando custom provider o puede que el soporte en este caso no esté disponible. Este soporte esta en progreso y su avance puede consultarse aquí.
- DNS over TLS. Además permite elegir el proveedor de DOT e incluso indicar múltiples proveedores.
- Bloqueo DNS de hostnames e IPs maliciosas.
- Firewall integrado.
- Servidores proxy integrados. Shadowsocks y HTTP.
- Conexión de otros contenedores y otros dispositivos LAN a Gluetun.
- Posibilidad de uso como contenedor sidecar en Kubernetes.
Gluetun como VPN para tus contenedores
La primera manera de usar Gluetun que vamos a ver es como VPN para tus contenedores. De este modo se puede hacer que tus contenedores usen el stack de red de tu contenedor Gluetun. Esto se traduce que los contenedores que quieras estarán usando una VPN.
Arrancando tu contenedor Gluetun
Todas las características definidas anteriormente se materializan en una imagen de contenedor disponible en DockerHub. Por lo que en este apartado vamos a ver como arrancar nuestro contenedor de Gluetun.
Lo primero a tener en cuenta es que Gluetun soporta tanto OpenVPN como WireGuard. En este artículo nos centraremos en la opción de OpenVPN, pero puedes encontrar más información sobre como trabajar con WireGuard en esta página del Wiki de Gluetun. Así que, continuando con OpenVPN, puedes encontrar todas las opciones disponibles aquí.
Una vez elegido el protocolo OpenVPN como nuestra opción, el requisito fundamental es tener una cuenta en un servicio de VPN de los compatibles con Gluetun. En mi caso he estado probado las cuentas gratuitas de ProtonVPN y de PrivadoVPN y he detectado un requisito bastante importante en el caso de las cuentas gratuitas. No todos los proveedores permiten conexiones VPN con clientes no oficiales en la versión gratuita. En mi caso, perdí bastante tiempo con PrivadoVPN porque no conseguí hacer funcionar la cuenta gratuita con Gluetun hasta que descubrí que solo puedes usar la cuenta gratuita desde su cliente oficial. Pero el error que mostraba mi contenedor en el arranque es que las credenciales no eran correctas. Por lo que ante esta situación estaba claro que la configuración la iba a realizar con ProtonVPN.
Así que ya están decididos los dos requisitos fundamentales: El protocolo (OpenVPN) y el proveedor de VPN (ProtonVPN). Por lo que estamos listos para iniciar nuestro contenedor. Pero antes de continuar, y solo si el sistema donde vas a iniciar tu contenedor es de 32 bits, como en el caso de las primeras Raspberry Pi, debes tener en cuenta los requisitos que indican en el wiki de Gluetun.
Por tanto para arrancar nuestro contenedor Gluetun, este sería un buen ejemplo:
docker run -it --rm --name=gluetun_noroute2host \
--cap-add=NET_ADMIN \
--device /dev/net/tun \
-v /store/gluetun:/gluetun \
-e VPN_TYPE=openvpn \
-e VPN_SERVICE_PROVIDER=protonvpn \
-e OPENVPN_USER=[TU_USUARIO_DEL_PROVEEDOR] \
-e OPENVPN_PASSWORD=[TU_PASSWORD_DEL_PROVEEDOR] \
-e FREE_ONLY=on \
-e DOT=on \
-e TZ="Europe/Madrid" \
-e UPDATER_PERIOD=24h \
qmcgaw/gluetun
En este comando hay dos tipos de opciones que paso a explicar:
- Opciones propias de Docker:
-it
: Opcional. Es la forma corta de las opciones--interative
y--tty
. Inicia el contenedor en modo interactivo y con un pseudo-terminal.--rm
: Opcional. Para el ejemplo queremos que cuando se detenga el contenedor se elimine automáticamente.--name=gluetun_noroute2host
: Simplemente sirve para indicar un nombre para nuestro contenedor. Lo establecemos porque después será necesario referenciarlo en los contenedores que hagan uso de este.--cap-add=NET_ADMIN
: Requerido por Gluetun. Por defecto un contenedor corre en un modo “sin privilegios”. Con esta opción se dan privilegios adicionales sobre el stack de red.--device /dev/net/tun
: Requerido por Gluetun. Añade el dispositivo /dev/net/tun del sistema al contenedor. Este dispositivo es la interfaz virtual de network TUNnel.-v /store/gluetun:/gluetun
: Requerido por Gluetun. Mapea una ubicación del host a la ruta /gluetun del contenedor.qmcgaw/gluetun
: Requerido por Gluetun. Es el nombre de la imagen de contenedor oficial de Gluetun.
- Opciones de Gluetun. Estas opciones funcionan a través de variables de entorno con la opción de docker
-e
:- VPN_TYPE: En nuestro ejemplo la establecemos
openvpn
. Pero también es la opción por defecto si no se indica este parámetro. - VPN_SERVICE_PROVIDER: Indica un proveedor de servicio válido. En este caso
protonvpn
. Pero puede ser cualquier otro del que se disponga una cuenta. Aquí está la lista de proveedores válidos. - OPENVPN_USER: Aquí se debe indicar el nombre de tu usuario en el proveedor elegido.
- OPENVPN_PASSWORD: Igualmente que el parámetro anterior, pero en este caso para el password.
- FREE_ONLY: Parámetro específico de protonvpn para indicar que solo use los servidores disponibles en el plan gratuito. Aquí puedes ver todas las opciones específicas de protonvpn.
- DOT: Habilita DNS over TLS. Por defecto ya está habilitado.
- TZ: Especifica un Timezone para ver correctamente los tiempos en los logs.
- UPDATER_PERIOD: Opcional. Actualiza los servidores disponibles alojados en memoria en el intervalo especificado. En este caso 24 horas.
- VPN_TYPE: En nuestro ejemplo la establecemos
La lista anterior es una propuesta para este artículo pero puedes comprobar por ti mismo todas las opciones disponibles.
Una vez ejecutado el comando, ya tendrás tu contenedor de Gluetun funcionando con las opciones indicadas. Como hemos arrancado el contenedor en modo interactivo puedes ver en tu terminal si todo hay ido bien en el arranque.
Hacer que un contenedor esté en el mismo namespace de red que otro
Ahora que ya tenemos nuestro conenedor de Gluetun funcionando la pregunta es: ¿Y como hago para que otro de mis contenedores lo aproveche? Y la respuesta es: haciendo que tus otros contenedores usen el mismo namespace de red que ya tiene el contenedor de Gluetun. De esta manera tus contenedores asociados al mismo namespace de red estarán en el mismo stack de red que el de gluetun. Tanto es así, que podrás acceder a los servicios de cualquiera de los contenedores en el mismo espacio de red a través de localhost.
Pero ¡atención! Que como los mapeos de puertos son únicos en el namespace de red, no puedes usar los mismos puertos para diferentes contenedores dentro del mismo namespace de red. Esto último es algo con lo que hay que tener mucho cuidado.
La implementación de esta estrategia se hace con la opción --network
de docker. Esta opción indica a que red se conecta un contenedor. Por defecto, si no se indica esta opción, se conecta al bridge por defecto de docker. Pero la opción te permite cambiar este comportamiento. En concreto la vamos a especificar así: --network:container:NOMBRE_DE_TU_CONTENEDOR
. Por ejemplo:
docker run --rm --network:container:gluetun_noroute2host hello-world
La orden anterior ejecuta el contenedor hello-world de docker en la misma pila de red que nuestro contenedor gluetun.
Esta misma opción se puede configurar dentro de un docker-compose donde estén los dos contenedores, aunque siendo así la sintaxis es algo diferente. Además también es algo distinto según el caso:
- Si el contenedor que vaya a usar gluetun esta en el mismo fichero compose, la configuración análoga sería incluir en el servicio que vaya a usar gluetun la siguiente linea en el docker-compose.yml:
network_mode: "service:NOMBRE_DEL_SERVICIO_GLUETUN_EN_FICHERO_COMPOSE"
- Si por el contrario, el contenedor que va a usar gluetun está en otro fichero compose la configuración incluir sería distinta:
network_mode: "container:gluetun"
Tienes más información sobre estas configuraciones en la siguiente página del wiki de Gluetun
Probando el acceso VPN para otro contenedor
Con la explicación anterior, ya solo nos queda demostrar que podemos hacer que otro de nuestros contenedores o servicios contenerizados pueden usar este contenedor Gluetun para acceder a Internet a través del servicio VPN configurado en Gluetun. Para esta prueba vamos a usar una imagen básica de Alpine Linux y a seguir estas instrucciones.
En primer lugar, vamos a probar a arrancar este contenedor básico de Alpine sin pasar por nuestro contenedor de Gluetun. Además le pasaremos un comando con la opción -c
para que sea ejecutado en el arranque del contenedor. Este comando es wget -qO- https://ipinfo.io
y básicamente lo que hace es mostrar con que ip está saliendo el contenedor a Internet.
docker run --rm alpine:latest \
sh -c "apk add wget && wget -qO- https://ipinfo.io"
Y el resultado es que actualmente el contenedor de manera pública sale a Internet con una ip de España. He ofuscado el resto de datos:
{
"ip": "X.X.X.X",
"city": "Xxxxx",
"region": "Xxxxxxxx",
"country": "ES",
"loc": "X,Y",
"org": "Xxxxx Xxxxxx XX",
"postal": "NNNNN",
"timezone": "Europe/Madrid",
"readme": "https://ipinfo.io/missingauth"
}
Y justo a continuación, vamos a ejecutar la misma orden, pero configurando nuestro contenedor para que use la red del contenedor de gluetun.
docker run --rm --network=container:gluetun_noroute2host alpine:latest \
sh -c "apk add wget && wget -qO- https://ipinfo.io"
Es por ello que ahora el resultado es una dirección ip de Japón. Vuelvo a ofuscar algunas partes de la salida.
{
"ip": "X.X.X.X",
"hostname": "Xxxxx",
"city": "Osaka",
"region": "Osaka",
"country": "JP",
"loc": "X,Y",
"org": "Xxxxx Xxxxxx XX",
"postal": "NNNNN",
"timezone": "Asia/Tokyo",
"readme": "https://ipinfo.io/missingauth"
}
Como publicar puertos de tus contenedores mientras hacen uso de Gluetun
Personalmente esta es una de las cosas que más me ha costado entender al principio. Ya se ha comentado anteriormente en este artículo, pero hay que tener en cuenta que nuestros contenedores están conectados a la red o al namespace de red del contenedor de gluetun. ¿Y que implica esto? Pues algunos detalles como los que enumero a continuación:
- Dentro del mismo namespace de red, no puedes usar un mismo puerto para publicar servicios de varios contenedores. Esta publicación es única dentro del namespace y no se puede repetir.
- Además, con respecto a esto, la publicación de puertos hay que hacerla en el contenedor base de la pila de red que estamos usando, es decir, nuestro contenedor de gluetun. Por tanto, si tienes un servidor web usando la red del contenedor de gluetun, la publicación de este servicio web hay que hacerla al iniciar el contenedor de gluetun.
- Todos los contenedores haciendo uso del mismo stack de red pueden comunicarse entre ellos usando localhost.
Voy a intentar explicar esto con un ejemplo. En concreto voy a usar la imagen de contenedor public-ip-monitor para intentar aclarar esta casuística. La funcionalidad de esta imagen es similar a lo que hacíamos con la imagen de Alpine Linux y el comando para obtener nuestra ip en Internet. Pero en este caso, tenemos un servidor web (el que trae embebido el cli de php) que correrá en el puerto 80. Este servidor web simplemente muestra un registro de la dirección ip de Internet de nuestro contendedor.
Antes de nada, si no tienes arrancado el contenedor de gluetun, hay que volver a arrancarlo. Además, hay que tener en cuenta todo lo que te he contado antes y hacer la publicación del puerto para el servidor web del otro contenedor (el de public-ip-monitor) que arrancaremos después. Así que para vamos a iniciar nuestro contenedor de Gluetun y a la vez vamos a publicar el puerto 80 del futuro contenedor en el puerto 8080 con la opción -p 8080:80
:
docker run -it --rm --name=gluetun_noroute2host \
--cap-add=NET_ADMIN \
--device /dev/net/tun \
-v /store/gluetun:/gluetun \
-p 8080:80 \
-e VPN_TYPE=openvpn \
-e VPN_SERVICE_PROVIDER=protonvpn \
-e OPENVPN_USER=[TU_USUARIO_DEL_PROVEEDOR] \
-e OPENVPN_PASSWORD=[TU_PASSWORD_DEL_PROVEEDOR] \
-e FREE_ONLY=on \
-e DOT=on \
-e TZ="Europe/Madrid" \
-e UPDATER_PERIOD=24h \
qmcgaw/gluetun
Ahora ya se puede arrancar el contenedor public-ip-monitor con el servidor web que muestra el histórico de nuestra ip “pública”.
docker run --network="container:gluetun_noroute2host" \
--name public-ip-monitor \
outlyernet/public-ip-monitor
Y antes de probar a acceder a este contenedor, es necesario hacer un paso adicional. La imagen public-ip-monitor-tiene una particularidad. Es necesario forzar que se “auto-descubra” nuestra ip en Internet con un comando ejecutado desde el propio contenedor. No se hace de manera automática. Para ello tendremos que hacer uso del subcomando docker exec
tal que así:
docker exec public-ip-monitor /update
Este comando ejecuta el script update.sh en la raíz del sistema de ficheros del contenedor. Y este script obtiene nuestra ip y la guarda en un log, que después se visualiza en el servidor web.
Ahora ya podemos ir a un navegador, acceder a la ip de nuestro host de docker y al puerto 8080, es decir, http://[TU_HOST_DOCKER]:8080. De este modo, estaremos accediendo al servidor web de nuestro contenedor public-ip-monitor. Y aquí esta el resultado:
Gluetun como servidor proxy
El otro modo de funcionamiento de Gluetun es como proxy para cualquier servicio que pueda configurarse para funcionar a través de proxy. Puede ser un servicio contenerizado o simplemente el navegador web de cualquiera de los dispositivos de tu red.
Gluetun tiene disponibles dos tipos de servidor proxy: HTTP y Shadowsocks. Para nuestros ejemplos vamos a usar la opción de HTTP, pero puedes consultar toda la información para las ambas opciones aquí.
Iniciando tu contenedor gluetun con servidor proxy incluido
Para arrancar gluetun con servicio de proxy incluido vamos a usar un comando similar a cuando lo lanzamos sin proxy pero añadiendo las respectivas opciones para activar el servicio de proxy HTTP.
docker run -it --rm --name=gluetun_noroute2host \
--cap-add=NET_ADMIN \
--device /dev/net/tun \
-p 8888:8888 \
-v /store/gluetun:/gluetun \
-e VPN_TYPE=openvpn \
-e VPN_SERVICE_PROVIDER=protonvpn \
-e OPENVPN_USER=[TU_USUARIO_DEL_PROVEEDOR] \
-e OPENVPN_PASSWORD=[TU_PASSWORD_DEL_PROVEEDOR] \
-e FREE_ONLY=on \
-e DOT=on \
-e TZ="Europe/Madrid" \
-e UPDATER_PERIOD=24h \
-e HTTPPROXY=on \
qmcgaw/gluetun
Solo se han añadido un par de opciones. De estas opciones, la primera es propia de docker:
-p 8888:8888
: Expone el puerto 8888 del contenedor de Gluetun en el puerto 8888 del host de Docker. El puerto 8888 es en el corre el servicio de proxy HTTP de Gluetun.
Y la segunda es específica de gluetun, por lo que está definida como variable de entorno con la opción -e
:
- HTTPPROXY: Como su propio nombre indica. Al establecer esta variable a
on
habilita el servicio de proxy HTTP de Gluetun.
Configurar otros dispositivos para que funcionen a través del proxy de Gluetun
Tras arrancar el contenedor de gluetun con el servicio de proxy, ya solo nos queda conectar alguno de nuestros servicios, dispositivos o programas a este proxy. ¿Que te parece si lo hacemos con Firefox?
En primer lugar, vamos a comprobar de que país es nuestra ip actual sin configurar ningún tipo de proxy. El servicio que usaremos para ello es IPinfo.io.
Como puedes ver, la ubicación normal de mi ip es España. Pero ahora vamos a activar el proxy en Firefox y a ver que pasa. Para ello configuraremos dentro de Firefox la dirección de red de nuestro contenedor de Gluetun así como su puerto. En mi caso, tengo corriendo el contenedor en mi Raspberry Pi llamada raspibox, y en cuanto al puerto a usar, solo hay que tener en cuenta que el puerto del proxy HTTP de Gluetun es el 8888. Además, si miras el comando de ejecución de docker ejecutado anteriormente verás que dicho puerto está expuesto en el 8888. Por tanto la configuración de proxy quedaría así:
Si tienes dudas sobre como configurar un proxy HTTP en Firefox puedes ver como hacerlo en esta página de la documntación oficial de Firefox. En cualquier caso, tras la configuración del proxy en Firefox el resultado es el siguiente:
Como puedes ver, mi ubicación ha cambiado y ahora ¡estamos navegando a través de un servicio proxy que además funciona sobre una VPN!
Bonus Track: Algunas cositas más…
Ficheros docker-compose de ejemplo
Aunque todos los ejemplos los hemos explicado mediante docker run
, he dejado ficheros docker-compose.yml para cada uno de los ejemplos que hemos visto en esta guía en el repositorio del blog. La lista de ficheros de ejemplo es la siguiente:
- Fichero docker-compose básico para arranque de Gluetun.
- Fichero docker-compose básico para arranque de Gluetun con ProtonVPN
- Fichero docker-compose para arranque de Gluetun incluyendo proxy HTTP
- Fichero docker-compose para arranque de Gluetun incluyendo proxy HTTP con ProtonVPN
- Fichero docker-compose con Gluetun y Public-Ip-Monitor y ProtonVPN como proveedor
Usar Gluetun para listar los servidores disponibles de tu proveedor VPN
Como ya hemos comentado al principio de este artículo, Gluetun está preparado para funcionar con un montón de proveedores de VPN. Y muchos de ellos tienen configuración específica adicional donde puedes definir donde se ubican los servidores de VPN a los que te quieres conectar. Dependiendo del proveedor puedes elegir la región, el país o incluso la ciudad. Es por ello que Gluetun provee un modo de ejecución donde te permite ejecutar el contenedor Gluetun solo para listar los servidores del proveedor elegido. Este modo lista los servidores disponibles, la información de sus características, y al acabar, simplemente finaliza su ejecución. Esto se explica aquí.
Este modo de ejecución funciona lanzando el contenedor de gluetun así:
docker run --rm \
-v /yourpath:/gluetun \
qmcgaw/gluetun \
format-servers -yourprovider
Y si lo personalizamos con el volumen que ya usamos en los comandos anteriores, y para el proveedor ProtonVPN. El comando quedaría así:
docker run --rm \
-v /store/gluetun:/gluetun \
qmcgaw/gluetun \
format-servers -protonvpn
Y la salida sería esta:
| Country | Region | City | Hostname | VPN | Free | Port forwarding | Secure | Tor |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| Albania | | Tirana | `al-01.protonvpn.net` | openvpn | ❌ | ✅ | | |
| Albania | | Tirana | `al-01.protonvpn.net` | wireguard | ❌ | ✅ | | |
| Albania | | Tirana | `al-02.protonvpn.net` | openvpn | ❌ | ✅ | | |
| Albania | | Tirana | `al-02.protonvpn.net` | wireguard | ❌ | ✅ | | |
| Algeria | | Algiers | `dz-02.protonvpn.net` | openvpn | ❌ | ✅ | | |
| Algeria | | Algiers | `dz-02.protonvpn.net` | wireguard | ❌ | ✅ | | |
| Algeria | | Algiers | `dz-01.protonvpn.net` | openvpn | ❌ | ✅ | | |
| Algeria | | Algiers | `dz-01.protonvpn.net` | wireguard | ❌ | ✅ | | |
| Angola | | Luanda | `ao-02.protonvpn.net` | openvpn | ❌ | ✅ | | |
| Angola | | Luanda | `ao-02.protonvpn.net` | wireguard | ❌ | ✅ | | |
| Argentina | | | `node-ar-03.protonvpn.net` | openvpn | ❌ | ❌ | | |
| Argentina | | | `node-ar-03.protonvpn.net` | wireguard | ❌ | ❌ | | |
| Argentina | | | `node-ar-04.protonvpn.net` | openvpn | ❌ | ❌ | | |
| Argentina | | | `node-ar-04.protonvpn.net` | wireguard | ❌ | ❌ | | |
| Argentina | | Buenos Aires | `node-ar-03.protonvpn.net` | openvpn | ❌ | ❌ | | |
| Argentina | | Buenos Aires | `node-ar-03.protonvpn.net` | wireguard | ❌ | ❌ | | |
| Argentina | | Buenos Aires | `node-ar-04.protonvpn.net` | openvpn | ❌ | ✅ | | |
| Argentina | | Buenos Aires | `node-ar-04.protonvpn.net` | wireguard | ❌ | ✅ | | |
...
...
...
Elige bien tu proveedor VPN para Gluetun
Esto es simplemente un consejo que puede parecer muy básico pero que es muy importante. No todos los servicios de VPN ofrecen todos los servicios ni siquiera en su plan de pago. Pero en el caso de los planes gratuitos cada uno pone sus limitaciones y pueden ser muy diferentes de un proveedor a otro. Te pongo algunos ejemplos…
ProtonVPN funciona muy bien pero en el plan gratuito los países están limitados a solo unos pocos. Esto suele ser normal en los planes gratis. Pero también tiene limitaciones con el tráfico P2P que se pueden solventar en su plan de pago.
Otro ejemplo puede ser PrivadoVPN, he probado su aplicación Android y no tiene esas limitaciones en el tráfico P2P, pero si tiene límite de GB de tráfico al mes en su plan gratuito. Y no solo eso, tras estar alguna que otra hora intentando hacer funcionar Gluetun con PrivadoVPN en su plan gratuito, acabé dándome cuenta que PrivadoVPN no permite usar otras aplicaciones que no sean la oficial para el plan gratis. Pasaron horas hasta que me dí cuenta porque el error en Gluetun siempre era de credenciales incorrectas.
Así que para elegir tu proveedor VPN, además de tener en cuenta el coste, piensa en el uso que le vas a dar y evalúa cual es el mejor para este uso.
Enlaces de interés:
Artículo anterior