Servidor de WireGuard con Pi-Hole
En mi cruzada de conseguir una conexión a internet lo más segura posible he configurado mi servidor local para conseguir que todo mi tráfico sea tunelado a través de WireGuard a mi servidor y que, cualquier tráfico que desee acceder a internet, tenga además que pasar por Pi-Hole para conseguir un internet sin anuncios* y más seguro.
¿Qué es WireGuard?
WireGuard es un protocolo VPN moderno que permite establecer túneles cifrados entre pares.
WireGuard nos presenta las siguientes ventajas1 frente a otros servidores VPN:
- Tamaño: El proyecto es el más pequeño en su categoría, permitiendo un análisis “cómodo” del código fuente, comparado con otros clientes como OpenVPN.
- Velocidad: Usando primitivas modernas permite obtener una velocidad superior a cualquier otro cliente VPN.
- Encriptación: Basada en parejas de llaves públicas y privadas.
- Silenciosa: Aunque los paquetes son fácilmente reconocibles, un servidor nunca responderá a un cliente salvo que este sepa la llave pública a la que el servidor puede llegar a querer escuchar.
Configuración
Una comunicación mediante WireGuard deberá estar conformado por el servidor y el cliente.
Servidor WireGuard
Para configurar un servidor WireGuard se deberá:
- Habilitar el puerto $51820$ en el firewall del router y del servidor. Solo será necesario habilitar el tráfico UDP.
- Configurar una regla NAT que establezca que el tráfico de la tarjeta de red que se esté usando (por ejemplo
enp1s0) pase por una red interna que por estándar se nombraráwg0. - Se configurarán las llaves del servidor, las cuales usará para encriptar el tráfico de los clientes. Para generar estas llaves se usarán los comandos
1wg genkey > private.key
2wg pubkey < private.key > public.key- Se definirá la IP de la interfaz
wg0, la llave privada del servidor y las llaves públicas de los dispositivos que se conectarán al mismo. Además de eso se definirá una IP o rango de IPs que estos dispositivos tomarán en esta redwg0. A continuación se muestra una configuración en NixOS:
1{
2 # enable NAT
3 networking.nat.enable = true;
4 networking.nat.externalInterface = "enp1s0";
5 networking.nat.internalInterfaces = [ "wg0" ];
6 networking.firewall.trustedInterfaces = [ "wg0" ];
7 networking.firewall.allowedUDPPorts = [ 51820 ];
8
9 networking.wireguard.interfaces = {
10 wg0 = {
11 ips = [ "10.100.0.1/24" ];
12 listenPort = 51820;
13
14 privateKey = "${config.globals.wireguard_server_privatekey}";
15 peers = [
16 { # TFN
17 publicKey = "${config.globals.wireguard_tfn_publickey}";
18 allowedIPs = [ "10.100.0.2/32" ];
19 }
20 { # NomadUSB
21 publicKey = "${config.globals.wireguard_nomadusb_publickey}";
22 allowedIPs = [ "10.100.0.3/32" ];
23 }
24 ];
25 };
26 };
27}Cliente WireGuard
Se deberán generar una pareja de llaves privada pública y compartir esta llave pública con el servidor al que se desee conectar. Para conectar un cliente se deberán añadir los siguientes parámetros:
- Llave privada del cliente
- Llave pública del cliente
- Dirección del cliente, en el caso del teléfono sería
10.100.0.2 - Servidor
DNS, en principio cualquiera que deseemos, pero si se desea que el tráfico vaya a través de Pi-Hole tendremos que usar10.100.0.1, que es la IP del servidor que a su vez correrá Pi-Hole como explicaré más adelante. - Llave pública del servidor
- El Endpoint, que será
ip.pu.bli.ca:51820 - IPs permitidas, en mi caso la que asigne el servidor, es decir
0.0.0.0/0
Pi-Hole
Pi-hole es una utilidad que crea un servidor DNS que permite almacenar en su memoria páginas visitadas y restringir el acceso a las mismas. Pi-Hole es muy útil si se desea, por temas de seguridad, restringir IPs maliciosas, como páginas que descargan virus; IPs de anuncios, como los dominios de ads.google.com; o dominios que son usados puramente como trackers.
Saber que Pi-Hole no sustituye un firewall ni un sistema IDS, pero reduce considerablemente la exposición a trackers y dominios maliciosos.
Instalación
Para instalar Pi-Hole recomiendo encarecidamente usar docker compose y usar el network mode de host, quedando en NixOS de la siguiente forma:
{ config, pkgs, ... }:
{
virtualisation.docker.enable = true;
virtualisation.oci-containers = {
backend = "docker";
containers.pihole = {
image = "pihole/pihole:latest";
environment = {
TZ = "Europe/Madrid";
PUID = "1000";
PGID = "1000";
FTLCONF_webserver_api_password = "${config.globals.pihole_password}";
};
volumes = [
"/home/gabriel/Docker/Pihole/etc-pihole:/etc/pihole"
"/home/gabriel/Docker/Pihole/etc-dnsmasq.d:/etc/dnsmasq.d"
];
ports = [
"53:53/tcp"
"53:53/udp"
"67:67/udp"
"80:80/tcp"
];
networks = [ "host" ];
autoStart = true;
};
};
networking.firewall.allowedTCPPorts = [ 80 ];
}Configuración de Pi-Hole
Con el programa instalado con el scrip anterior, tendremos el puerto $53$ que hará de DNS. Deberemos configurar los dominios de Pi-Hole.
Denotar que, en la configuración anteriormente mostrada, los puertos 53, 67 y 80 están expuestas al exterior de la máquina, por lo que cualquier usuario podría acceder a ellos. Esto ha sido hecho en mi caso ya que deseo que otros usuarios sean capaces de usar este proxy para asegurar su tráfico, pero en el caso de que solo se fuera a usar Pi-Hole para proteger el tráfico de WireGuard recomiendo usar 127.0.0.1:xx:xx para que Pi-Hole solo sea accesible al propio servidor.2
Pi-Hole y WireGuard
Finalmente para que WireGuard use Pi-Hole deberemos configurar desde el cliente que la opción 10.100.0.1. Se podría hacer que docker usara por defecto este DNS, pero eso causaría que, en caso de que Pi-Hole se colgara nos quedaríamos sin acceso a Wireguad.
Recomiendo encarecidamente leer la página oficial y ver las ventajas del protocolo de forma más detallada del siguiente video. ↩︎
Algo que me gustaría también aclarar es que todo esto está en mi red local, no teninedo expuestos estos puertos a internet. Si así fuera habría que implementar algún tipo de rate limiting al uso del DNS para evitor un posible ataque DDoS. ↩︎