Una forma sencilla de acceder a equipos de casa que tienen conexión a internet pero no tienen IP pública. Se usa software para [redes privadas virtuales](https://es.wikipedia.org/wiki/Red_privada_virtual) *VPN*, en este caso [Wireguard](https://www.wireguard.com/).

De esta manera podemos acceder a un equipo por ejemplo en nuestra casa usando como "puente" a un servidor con IP pública, la ventaja de usar una VPN como Wireguard es que es muy rápida, fácil de configurar, usa criptografía asimétrica y además se pueden agregar pares (equipos en la vpn) de manera sencilla. Wireguard establece un túnel de conexiones fuertemente cifradas entre pares.

## Esquema

![vpn-1](/static/imgs/posts/vpn-simple1.jpg)

### Requisitos

- Un servidor con IP pública al que tengamos acceso.
- Una computadora en casa con conexión a internet a la que queremos acceder.
- Se asume que tanto el servidor como la computadora funcionan con alguna distribución de GNU/Linux, aunque wireguard está disponible para otros sistemas operativos.

#### Instalación de Wireguard

La guía oficial están en [https://www.wireguard.com/install/](https://www.wireguard.com/install/), sin embargo para no agregar *ppas* a nuestro repositorio de paquetes, lo conveniente es instalar construyendo desde el código fuente, los pasos que seguí:

    :::bash
    sudo apt-get install libmnl-dev libelf-dev linux-headers-$(uname -r) build-essential pkg-config
	# clonando el repositorio
	git clone https://git.zx2c4.com/WireGuard
	# construyendo
	cd WireGuard/src
	make
	# instalando en el sistema
	sudo make install

## Configuración

Usaremos archivos de configuración, recordando que para esta vpn sólo habrán dos pares; el servidor y la computadora en casa.

Para una guía mas detallada se puede seguir [https://www.wireguard.com/quickstart/](https://www.wireguard.com/quickstart/)

### Generando claves de acceso

Primero se deben generar el par de claves pública y privada usando wireguard en **ambos** equipos.

    :::bash
	# clave privada
    sudo wg genkey > private.txt
	# clave publica
	sudo wg pubkey < private.txt > public.txt

Usaremos el contenido de `private.txt` y `public.txt` para copiarlo en los archivos de configuración y permitir el acceso de los equipos a nuestra VPN.

### Servidor

Ahora creamos el archivo `/etc/wireguard/10-mivpn.conf` donde 

    [Interface]
	# La clave privada es el contenido del archivo private.txt 
    PrivateKey = eI0Tf4v...
    ListenPort = 10100

    # Peer equipo de casa
    [Peer]
	# Aqui copiamos la llave publica del equipo de casa (archivo public.txt)
    PublicKey = Aoc0F8e...
    # indicamos que se aceptan conexiones de cualquier IP
    AllowedIPs = 0.0.0.0/0

Luego es conveniente crear un script bash para configurar la interfaz de red y aplicar las configuraciones a wireguard directamente. Por ejemplo en el script `setup-vpn.sh`:

    :::bash
	#!/bin/bash
	interface=wg0
	conf=/etc/wireguard/10-mivpn.conf
    # configuracion de interfaces de red del tipo "wireguard"
	ip link del dev $interface 2>/dev/null || true
	ip link add $interface type wireguard
	ip addr add 50.50.50.49 dev $interface
	ip link set $interface up
    # aplicando configuracion a wireguard
	wg setconf $interface $conf
	wg show

	exit 0

Ahora ejecutamos el script para configurar las interfaces de red y configurar la VPN.

    :::bash
	sudo ./setup-vpn.sh

### Computadora en casa	

Creamos el archivo `/etc/wireguard/10-mivpn.conf` con:

    [Interface]
	# La clave privada es el contenido del archivo private.txt 
    PrivateKey = C8M-25...
    ListenPort = 10100

    # Peer Servidor
    [Peer]
	# Aqui copiamos la llave publica del servidor (archivo public.txt)
    PublicKey = 9Fvpn4...
    # indicamos que se aceptan conexiones de cualquier IP
    AllowedIPs = 0.0.0.0/0
	# indicamos la IP publica del servidor y el puerto en que este escucha
	Endpoint = <IP pública del servidor>:10100
	# ajustamos intervalo de tiempo para enviar un paquete para mantener la conexion
	PersistentKeepalive = 120

De igual manera creamos un script para levantar la vpn fácilmente por ejemplo `setup-vpn.sh`:

    :::bash
	#!/bin/bash
	interface=wg0
	conf=/etc/wireguard/10-mivpn.conf
    # configuracion de interfaces de red del tipo "wireguard"
	ip link del dev $interface 2>/dev/null || true
	ip link add $interface type wireguard
	ip addr add 50.50.50.50 dev $interface
	ip link set $interface up
    # aplicando configuracion a wireguard
	wg setconf $interface $conf
	wg show

	exit 0

Luego ejecutamos el script `sudo bash setup-vpn.sh`

## Realizando pruebas

Podemos comprobar en ambos equipos la configuración de wireguard con:

    sudo wg show
	
Que debería mostrar los cambios que hemos aplicado, es importante también asegurarse que las interfaces de red estén funcionales con:

    ip a
	
Que debería mostrarnos una interfaz del tipo wg0 con ipv4 50.50.50.x según sea el servidor o la computadora de casa.

Finalmente abrimos la conexión de la VPN, desde el equipo de casa con:

    :::bash
	ping 50.50.50.49
	
Que debería responder positivamente. Hay que notar que el único equipo capaz de abrir la conexión en este caso es la computadora de casa por que sabe como llegar al servidor, esto por la línea ``Endpoint = <IP pública del servidor>:10100`` en su archivo de configuración. Como este apunta a una IP pública accesible por internet, el equipo de casa puede llegar al servidor y al recibir las peticiones, *wireguard* en el servidor también establece un túnel hacia el equipo de casa.

Para renovar automáticamente la conexión se usa `PersistentKeepalive = 120` para enviar un paquete cada 120 segundos, también por ejemplo en `/etc/crontab` del equipo de casa se puuede hacer que se envien peticiones ICMP (ping) al servidor para que vaya constantemente reavivando la conexión y guardando en archivos el resultado del intento de conexión.

Finalmente si el resultado es positivo ya podemos conectarnos al equipo de casa **a través** del servidor primero, solo bastaría acceder al servidor desde cualquier lugar y apuntar al equipo de casa (IP: 50.50.50.50) para establecer comunicación "directa".

Hay gran cantidad de usos para este tipo de conexiones, por ejemplo servir una página web alojada en un equipo en nuestra casa y usar un servidor sólo como **proxy** que dirija todas las peticiones desde internet a nuestro equipo de casa, y las respuestas del equipo de casa hacia internet, los ejemplos de uso son muy variados y espero esta guía te haya servido.



