Cómo montar una VPN WireGuard con wg-easy en Docker
Índice de contenidos
- Puntos clave
- ¿Qué es WireGuard y qué aporta wg-easy?
- ¿Cómo es el docker-compose.yml de wg-easy?
- ¿Cómo completar el asistente de primer arranque?
- ¿Cómo añadir clientes y escanear el QR?
- ¿Cómo abrir el puerto en el router y el cortafuegos?
- Preguntas frecuentes
- ¿Es seguro exponer wg-easy a Internet?
- ¿Qué diferencia hay entre wg-easy v14 y v15?
- ¿Puedo usar wg-easy para conectar dos servidores, no solo móviles?
- Conclusión
- Fuentes
wg-easy es la forma más sencilla de autoalojar una VPN WireGuard: un contenedor que reúne el servidor y un panel web para crear clientes con un clic. Esta guía lo levanta con Docker Compose en su versión 15, completa el asistente de primer arranque en el puerto 51821 y conecta tu primer dispositivo con un código QR.
Acceder a tus servicios caseros desde el móvil, cifrar el tráfico en una red wifi pública o unir dos servidores como si estuvieran en la misma sala son tareas para una VPN, y WireGuard es hoy la forma más rápida y segura de tenerla propia. El problema es que configurar WireGuard a mano, con sus claves y su archivo wg0.conf, intimida a quien empieza. Para eso está wg-easy: un contenedor que levanta el servidor WireGuard y le añade un panel web desde el que creas clientes con un clic y los conectas escaneando un código QR. En esta guía lo montas con Docker Compose, completas el asistente de la versión 15 y conectas tu primer dispositivo. La misma explicación está disponible en inglés.
Puntos clave
- wg-easy reúne el servidor WireGuard y su interfaz de gestión en una sola imagen; su última versión es la v15.3.0, publicada el 18 de mayo de 2026, y acumula unas 26.400 estrellas en GitHub con licencia AGPL-3.0.
- La v15 es una reescritura completa: casi todas las variables de entorno de la v14 (
WG_HOST,PASSWORD,WG_DEFAULT_ADDRESS…) han desaparecido y ahora la configuración se hace en un asistente web de primer arranque y en el panel de administración. - Usa dos puertos: 51820/udp para el túnel WireGuard y 51821/tcp para la interfaz web. La imagen oficial es
ghcr.io/wg-easy/wg-easy:15; conviene fijar esa etiqueta porque:latesttodavía apunta a la vieja v14. - El contenedor necesita las capacidades NET_ADMIN y SYS_MODULE y varios
sysctlsde reenvío de paquetes; sin ellos el túnel no encamina el tráfico. - WireGuard vive en el kernel de Linux desde la versión 5.6 (marzo de 2020) y son apenas 4.000 líneas de código, frente a los cientos de miles de OpenVPN o IPsec.
¿Qué es WireGuard y qué aporta wg-easy?
WireGuard es un protocolo de VPN moderno, diseñado por Jason A. Donenfeld, que sustituye a veteranos como OpenVPN e IPsec con una fracción de su complejidad. Establece un túnel cifrado sobre UDP (por defecto en el puerto 51820) usando criptografía fija y actual: Curve25519 para el intercambio de claves, ChaCha20 para cifrar y Poly1305 para autenticar. Su gran baza es la sencillez: está integrado en el kernel de Linux desde la versión 5.6 y son unas 4.000 líneas de código, lo que reduce muchísimo la superficie que hay que auditar. Linus Torvalds lo resumió en la lista del kernel comparándolo con las alternativas: "quizá el código no sea perfecto, pero lo he ojeado y, frente a los horrores que son OpenVPN e IPsec, es una obra de arte".
Toda esa elegancia tiene un precio para el recién llegado: WireGuard no trae interfaz. Configurarlo significa generar pares de claves con wg genkey, escribir a mano el archivo wg0.conf del servidor y el de cada cliente, y mantener sincronizadas las IP y las claves públicas. Es sencillo cuando lo entiendes, pero un muro cuando empiezas.
Ahí entra wg-easy. Es un proyecto de código abierto que empaqueta el servidor WireGuard junto con una interfaz web de administración en un único contenedor. Desde esa web creas clientes con un clic, ves su estado de conexión y su consumo de datos, y descargas su configuración o la muestras como código QR para escanearla desde el móvil. En la práctica, convierte una tarea de administrador de sistemas en algo que cualquiera puede montar en diez minutos, y por eso es una de las formas más populares de autoalojar una VPN. Si vienes de la guía de redes en Docker, verás que aquí el contenedor toca la red del anfitrión de una manera especial.
¿Cómo es el docker-compose.yml de wg-easy?
Antes de nada, ten en cuenta el cambio grande de 2025: wg-easy v15 fue una reescritura completa que eliminó casi todas las variables de entorno de la v14. Ya no defines WG_HOST ni la contraseña en el compose; en su lugar, el contenedor arranca "vacío" y te guía por un asistente web la primera vez. Esto simplifica el archivo, pero sorprende a quien busca tutoriales antiguos. Crea una carpeta para el proyecto y guarda dentro este docker-compose.yml, tomado del repositorio oficial:
services:
wg-easy:
image: ghcr.io/wg-easy/wg-easy:15
container_name: wg-easy
restart: unless-stopped
ports:
- "51820:51820/udp"
- "51821:51821/tcp"
environment:
INSECURE: "true"
volumes:
- etc_wireguard:/etc/wireguard
- /lib/modules:/lib/modules:ro
cap_add:
- NET_ADMIN
- SYS_MODULE
sysctls:
- net.ipv4.ip_forward=1
- net.ipv4.conf.all.src_valid_mark=1
volumes:
etc_wireguard:
Merece la pena entender cada bloque. La imagen se fija en ghcr.io/wg-easy/wg-easy:15 porque, curiosamente, la etiqueta :latest todavía apunta a la antigua v14 mientras el equipo termina de pulir la nueva rama; no confíes en :latest aquí. Se publican dos puertos: el 51820/udp, por el que viaja el túnel WireGuard, y el 51821/tcp, que sirve la interfaz web. Las capacidades NET_ADMIN y SYS_MODULE permiten al contenedor crear la interfaz de red del túnel y cargar el módulo del kernel; los sysctls activan el reenvío de paquetes para que el tráfico de tus clientes salga a Internet a través del servidor. El volumen etc_wireguard guarda la base de datos SQLite con tu configuración y tus clientes, así que sobrevive a reinicios y actualizaciones.
La variable INSECURE: "true" es el detalle que más quebraderos de cabeza da. La v15 se niega a permitir el inicio de sesión por HTTP plano salvo que se lo pidas expresamente; si accedes por http://IP:51821 sin ella, verás un aviso de "no puedes iniciar sesión con una conexión insegura". Para probar en tu red local está bien activarla, pero en cuanto expongas el panel a Internet debes ponerlo detrás de HTTPS (por ejemplo con Traefik) y quitar esa variable. Arráncalo y comprueba que responde:
docker compose up -d
docker compose ps
Si es tu primer contenedor en la máquina, repasa antes cómo instalar Docker en Ubuntu 24.04 para tener el motor y el plugin de Compose listos.
¿Cómo completar el asistente de primer arranque?
Con el contenedor en marcha, abre http://IP-DEL-SERVIDOR:51821 en el navegador. En lugar de una pantalla de login, la v15 te recibe con un asistente de configuración que solo aparece la primera vez. El primer paso es crear la cuenta de administrador: eliges un nombre de usuario y una contraseña (con su confirmación). Estas credenciales sustituyen al viejo PASSWORD_HASH que se ponía en el compose; ahora se guardan cifradas en la base de datos SQLite del volumen.
El segundo paso decide si empiezas de cero o importas una configuración previa. Si migras desde una instalación antigua, aquí puedes subir tu archivo wg0.json; si es una instalación nueva, sigues adelante. A continuación defines el dato más importante, el Host: la dirección pública (un dominio o una IP fija) a la que se conectarán tus clientes desde fuera. Si tienes IP dinámica en casa, usa un nombre DDNS. También confirmas el puerto del túnel (51820 por defecto). Al terminar, wg-easy genera las claves del servidor y te deja en el panel, ya operativo.
A partir de aquí, la administración vive en la web. La v15 añadió mejoras que la v14 no tenía: autenticación en dos pasos con TOTP, soporte de IPv6 y notación CIDR, y una API con autenticación básica para automatizar. Todo ello sin tocar el compose: los ajustes finos (rango de direcciones de los clientes, servidores DNS que se les entregan, AllowedIPs) se cambian desde la propia interfaz, en la sección de administración.
¿Cómo añadir clientes y escanear el QR?
Esta es la parte por la que wg-easy merece la pena. En el panel, pulsa "New Client", dale un nombre descriptivo (por ejemplo "Móvil de Ana" o "Portátil-trabajo") y confirma. wg-easy genera al instante el par de claves de ese cliente, le asigna una IP dentro del rango de la VPN y lo muestra en la lista con un interruptor de activación y sus estadísticas de datos enviados y recibidos.
Para conectar un teléfono, instala la app oficial de WireGuard (está en Google Play y en la App Store), pulsa el icono del código QR junto al cliente en el panel y escanéalo desde la app: el túnel queda configurado sin teclear nada. Para un ordenador, usa el botón de descarga que te da el archivo .conf de ese cliente e impórtalo en la aplicación de escritorio de WireGuard. Cada dispositivo debe usar su propio cliente; no compartas una misma configuración entre varios, porque las claves y las IP son únicas.
Una vez conectado, todo el tráfico del dispositivo (o solo el de tu red interna, según los AllowedIPs que definas) viaja cifrado hasta tu servidor. Un truco habitual es entregar a los clientes un DNS propio: si apuntas su DNS a un Pi-hole en tu red, además de la VPN tendrás bloqueo de anuncios en el móvil estés donde estés. Si prefieres una malla entre muchos nodos en lugar de un modelo cliente-servidor, echa un vistazo a Headscale, que resuelve otro escenario distinto.
¿Cómo abrir el puerto en el router y el cortafuegos?
Para que tus clientes lleguen al servidor desde Internet, el paquete UDP tiene que atravesar dos barreras. La primera es tu router: si el servidor está en tu casa, entra en su configuración y crea una regla de reenvío de puertos (port forwarding) que envíe el UDP 51820 a la IP local de la máquina que ejecuta wg-easy. Ojo con un detalle: se reenvía el puerto del túnel (51820/udp), no el de la interfaz web (51821), que no debe quedar expuesto a Internet sin protección.
La segunda barrera es el cortafuegos del propio servidor. Con ufw, la regla es directa:
sudo ufw allow 51820/udp
En un VPS en la nube, esta regla equivale a abrir el puerto en el grupo de seguridad del proveedor. El panel web (51821) es mejor no publicarlo: accede a él por la propia VPN una vez conectado, o ponlo detrás de un proxy inverso con HTTPS y su propia autenticación. Recuerda que si expones la web, la variable INSECURE debe desaparecer y el tráfico ir por TLS. Con el 51820/udp abierto en el router y en el cortafuegos, tus clientes ya pueden levantar el túnel desde cualquier red.
Preguntas frecuentes
¿Es seguro exponer wg-easy a Internet?
El túnel WireGuard (puerto 51820/udp) está diseñado para estar expuesto: no responde a paquetes sin la clave correcta, así que es prácticamente invisible para un escáner. Lo que no debes exponer sin protección es el panel web (51821/tcp). Publica solo el puerto UDP en tu router, accede a la interfaz por la propia VPN o colócala tras un proxy inverso con HTTPS. Nunca dejes la variable INSECURE activada en un servicio accesible desde Internet.
¿Qué diferencia hay entre wg-easy v14 y v15?
La v15 fue una reescritura completa. La diferencia más visible es que casi todas las variables de entorno desaparecieron: en la v14 configurabas WG_HOST, la contraseña y el rango de IP en el compose, mientras que en la v15 todo eso se hace en el asistente web y en el panel. La v15 añade además base de datos SQLite, doble factor con TOTP, IPv6, notación CIDR y una API. Como la etiqueta :latest aún sirve la v14, fija :15 en la imagen si quieres la nueva.
¿Puedo usar wg-easy para conectar dos servidores, no solo móviles?
Sí. Aunque su caso típico es el acceso remoto de dispositivos personales (móvil, portátil), cada cliente que creas es un peer de WireGuard normal, así que puedes instalar el cliente de WireGuard en otro servidor e importar su configuración para unir ambas redes. Ajustando los AllowedIPs de ese cliente en el panel, decides qué subredes viajan por el túnel, lo que permite escenarios de red entre sedes (site-to-site) sencillos.
Conclusión
wg-easy convierte el montaje de una VPN WireGuard, que a mano intimida, en un asistente de diez minutos: un docker-compose.yml corto, un panel web y un código QR bastan para tener acceso remoto cifrado a tu infraestructura. Recuerda lo esencial de la versión 15: fija la etiqueta :15, la configuración vive en el asistente de primer arranque y no en variables de entorno, y el puerto que se abre al mundo es el 51820/udp, nunca el panel sin proteger. El siguiente paso natural es entregar a tus clientes un DNS con Pi-hole para llevar el bloqueo de anuncios contigo, o comparar este modelo cliente-servidor con la malla de Headscale si vas a conectar muchos nodos.
Fuentes
Código fuente
Accede a todo el código fuente de este artículo en GitHub.
Ver en GitHub