WireGuard con Docker usando wg-easy: tutorial paso a paso

WireGuard con Docker usando wg-easy: tutorial paso a paso

WireGuard con Docker usando wg-easy: tutorial paso a paso

wg-easy es una imagen Docker que envuelve WireGuard con una interfaz web para añadir y gestionar peers sin tocar la línea de comandos. Este tutorial cubre el setup completo: desde el compose hasta la conexión del primer cliente.

Por Javier · Actualizado: 2025-07-02

wg-easy es una imagen Docker que combina WireGuard con una interfaz web de administración, permitiendo desplegar una VPN propia en un servidor Linux. El módulo wireguard sigue corriendo en el kernel del host (incluido por defecto desde Linux 5.6), por lo que el contenedor necesita acceso real al sistema de red mediante NET_ADMIN y /dev/net/tun.

Si nunca has montado una VPN, esto es para ti

Llevas tiempo queriendo acceder a tu red de casa desde fuera, o conectar varios servidores sin abrir puertos a lo loco, pero cada vez que buscas «cómo montar WireGuard» acabas en una guía que empieza con apt install wireguard seguido de editar archivos de configuración a mano y regenerar claves desde la terminal. No es que sea imposible, es que da pereza cuando solo quieres que funcione.

Si ya tienes Docker en tu servidor y sabes lo que es un docker-compose.yml, tienes todo lo que necesitas. wg-easy envuelve WireGuard en un contenedor con una interfaz web donde añades clientes, ves el estado del túnel y generas QR codes para el móvil, sin tocar un solo archivo de configuración a mano.

En este post montamos todo desde cero: el contenedor, la configuración mínima necesaria y cómo conectar tu primer dispositivo. Sin compilar nada, sin módulos de kernel adicionales si tienes un Linux moderno, y siendo honesto sobre qué limitaciones tiene esta solución antes de que te lleves una sorpresa.

Por qué importa

Kernel incluido de serie

En Linux 5.6 o superior el módulo WireGuard ya viene en mainline: no compilas nada, solo confirmas que está cargado.

UI web integrada

wg-easy levanta un panel en el puerto 51821 desde el que añades peers y obtienes el QR para el móvil en segundos.

Config persistente en volumen

Claves y perfiles se guardan en /etc/wireguard; el contenedor puede recrearse sin perder ningún peer configurado.

Red real, no virtualizada

Docker no abstrae WireGuard del kernel: NET_ADMIN y /dev/net/tun son obligatorios; verifica que tu VPS los permite antes de empezar.

Lo que necesitas antes de empezar

Para que todo funcione, el servidor tiene que cumplir unos requisitos concretos. No es complicado, pero vale la pena revisarlos antes de ejecutar ningún comando.

Sistema operativo y kernel: cualquier distribución Linux con kernel 5.6 o superior. Desde esa versión, el módulo wireguard viene en mainline sin compilar nada. Ubuntu 20.04 LTS y Debian 11 en adelante lo incluyen. Si tienes dudas:

uname -r
modinfo wireguard

Docker y Docker Compose: necesitas ambos instalados. La forma más limpia es seguir la guía oficial de Docker para tu distro; el paquete del repositorio de Ubuntu suele ir muy por detrás en versión.

Red: el servidor tiene que tener una IP pública estática o un dominio DNS que apunte a ella. wg-easy necesita saber con qué dirección van a conectarse los clientes.

Puertos abiertos en el firewall: 51820/UDP para el túnel WireGuard y 51821/TCP para la interfaz web. Si estás en un VPS, revisa también el panel del proveedor; muchos tienen un firewall externo independiente del sistema operativo.

Nota sobre VPS con OpenVZ: si tu proveedor usa virtualización OpenVZ, es posible que no permita NET_ADMIN ni /dev/net/tun. Con KVM o Xen no hay problema. Antes de desplegar, verifica con ls /dev/net/tun.

El docker-compose.yml que voy a usar

wg-easy se configura principalmente a través de variables de entorno. El compose queda bastante limpio:

services:
  wg-easy:
    image: ghcr.io/wg-easy/wg-easy
    container_name: wg-easy
    environment:
      - LANG=es
      - WG_HOST=tu.dominio.o.ip
      - PASSWORD_HASH=$$2y$$10$$hash_generado_con_bcrypt
      - WG_DEFAULT_DNS=1.1.1.1
      - WG_DEFAULT_ADDRESS=10.8.0.x
    volumes:
      - ./wg-easy-data:/etc/wireguard
    ports:
      - "51820:51820/udp"
      - "51821:51821/tcp"
    cap_add:
      - NET_ADMIN
      - SYS_MODULE
    devices:
      - /dev/net/tun:/dev/net/tun
    sysctls:
      - net.ipv4.conf.all.src_valid_mark=1
      - net.ipv4.ip_forward=1
    restart: unless-stopped
  • WG_HOST: la IP pública o dominio del servidor. Es lo que los clientes usarán para conectarse. Sin esto, nada funciona.
  • PASSWORD_HASH: contraseña para acceder a la UI web, hasheada con bcrypt. Más abajo explico cómo generarla.
  • cap_add: NET_ADMIN: necesario para crear y gestionar interfaces de red. WireGuard sigue ejecutándose en el kernel del host; Docker no lo abstrae.
  • /dev/net/tun: dispositivo de red virtual del kernel. Sin acceso a él, no hay túnel.
  • net.ipv4.ip_forward=1: habilita el reenvío de paquetes entre interfaces, imprescindible para que el tráfico de los clientes salga a internet.

Cómo generar el hash de contraseña

wg-easy a partir de la versión 14 ya no acepta contraseña en texto plano; hay que pasarle un hash bcrypt. Si tienes apache2-utils instalado:

htpasswd -nbB admin tucontraseña | cut -d ":" -f 2

O directamente con Docker, sin instalar nada en el host:

docker run --rm -it ghcr.io/wg-easy/wg-easy wgpw tucontraseña

El resultado es algo como $2y$10$.... En el compose los $ hay que duplicarlos ($$) porque Docker Compose interpreta $variable como variable de entorno.

Arrancar el contenedor y verificar que levanta

Con el compose listo, arranca el stack y observa los logs:

docker compose up -d
docker compose logs -f wg-easy

Los primeros logs deberían mostrar que WireGuard carga el módulo del kernel y la interfaz wg0 se crea correctamente. Si aparece Cannot open TUN/TAP dev /dev/net/tun, el VPS no tiene el dispositivo disponible.

Una vez arriba, la UI web está en http://ip-del-servidor:51821. Entra con la contraseña que configuraste.

En mi setup lo tengo detrás de nginx con SSL vía Let’s Encrypt. La UI de wg-easy no tiene soporte para autenticación multifactor, así que exponerla directamente en internet sin ninguna capa extra no me parece prudente. Un reverse proxy con certificado y, si quieres ir más fino, autenticación básica de nginx por encima, reduce bastante la superficie de ataque.

Añadir peers y conectar clientes

Desde la UI, el botón New Client abre un diálogo donde introduces un nombre para el peer. wg-easy genera el par de claves usando criptografía de curva elíptica Curve25519, que es lo que WireGuard usa internamente para el intercambio de claves.

Al crear el peer aparece un código QR. Para conectar el móvil:

  1. Instala la app oficial de WireGuard (iOS o Android).
  2. Toca el botón + y elige Escanear QR.
  3. Activa la conexión.

Para un equipo de escritorio Linux o Windows, descarga el archivo de configuración (botón de descarga junto al QR) e impórtalo en el cliente WireGuard correspondiente.

Verificar que la conexión funciona

Desde el cliente, una vez conectado, comprueba que la IP pública que ves es la del servidor:

curl https://ifconfig.me

Debería devolver la IP del servidor VPN, no la de tu conexión local. En la UI de wg-easy verás el peer con la marca de tiempo del último handshake y los bytes transferidos actualizándose.

Si el handshake no ocurre, revisa estos puntos:

  • ¿El puerto 51820/UDP está abierto en el firewall del servidor y en el panel del proveedor si es un VPS?
  • ¿WG_HOST apunta a la IP o dominio correctos?
  • ¿El módulo del kernel está cargado? (lsmod | grep wireguard)

Mantenimiento y actualizaciones

wg-easy almacena toda la configuración (claves, peers, configuración de WireGuard) en el volumen persistente montado en /etc/wireguard. Esto significa que puedes actualizar la imagen sin perder nada:

docker compose pull
docker compose up -d

Los peers existentes siguen funcionando sin reconfigurar nada. Para hacer una copia de seguridad:

tar czf wg-easy-backup-$(date +%Y%m%d).tar.gz wg-easy-data/

Guárdala en algún sitio que no sea el mismo servidor. Las claves están en wg-easy-data/wg0.conf si en algún momento necesitas inspeccionarlas.

Seguridad: lo que hace y lo que no hace wg-easy

WireGuard en sí es sólido. La criptografía que usa (Curve25519 para intercambio de claves, ChaCha20 para cifrado simétrico, Poly1305 para autenticación de mensajes) está bien auditada y la base de código es pequeña comparada con OpenVPN o IPsec.

wg-easy es una capa de gestión, no de seguridad adicional. Algunas cosas a tener en cuenta:

  • La UI no tiene 2FA. Si la expones directamente en internet, cualquiera puede intentar fuerza bruta contra el formulario de login. Un reverse proxy con rate limiting o autenticación adicional es una capa razonable.
  • El contenedor necesita privilegios reales del kernel. NET_ADMIN y acceso a /dev/net/tun no son capacidades menores; el contenedor tiene más acceso al sistema que uno típico. No es un problema si confías en la imagen, pero conviene saberlo.
  • Rotación de claves: wg-easy no rota claves automáticamente. Si un peer se compromete, elimínalo desde la UI y crea uno nuevo.
  • Logs de conexión: WireGuard por diseño no registra quién se conecta ni cuándo. Es una característica de privacidad del protocolo, no un olvido de wg-easy. Si necesitas auditoría de accesos, tendrás que añadir logging a nivel de red por separado.

Preguntas frecuentes

Q: ¿Funciona wg-easy en cualquier VPS o servidor?

A: Depende del proveedor. Los VPS basados en KVM o dedicados suelen permitirlo sin problema. Los basados en OpenVZ pueden no soportar NET_ADMIN ni /dev/net/tun, que son requisitos del contenedor. Antes de montar nada, comprueba con tu proveedor si permiten capabilities de red avanzadas.

Q: ¿Necesito compilar el módulo WireGuard en el servidor?

A: En kernels Linux 5.6 o superiores (disponibles desde marzo de 2020) el módulo wireguard viene incluido en mainline, sin compilar nada. Solo tienes que asegurarte de que está cargado con 'modprobe wireguard'. En kernels más antiguos sí habría que compilarlo o usar un DKMS.

Q: ¿Qué pasa si expongo la UI web directamente a internet?

A: La UI de wg-easy no ofrece autenticación multifactor, solo usuario y contraseña. Exponerla directamente en el puerto 51821 sin ninguna capa extra (reverse proxy con acceso restringido, VPN de gestión, fail2ban) es un riesgo real. Lo más prudente es restringir ese puerto a tu IP o ponerlo detrás de un proxy con auth adicional.

Q: ¿Cómo añado un nuevo cliente o peer a la VPN?

A: Desde la propia interfaz web de wg-easy. Pulsas 'Add client', le das un nombre y la UI genera automáticamente el par de claves y un QR code. En móvil importas ese QR con la app oficial de WireGuard y ya está operativo en segundos.

Q: ¿Cuántos puertos tengo que abrir en el firewall?

A: Solo dos: el 51820/UDP para el túnel VPN (el que usan los clientes para conectarse) y el 51821/TCP si quieres acceder a la interfaz web desde fuera. Este último conviene restringirlo; el 51820/UDP sí tiene que ser accesible desde internet para que los peers puedan establecer la conexión.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *