<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Federico Jensen</title>
    <description>The latest articles on DEV Community by Federico Jensen (@federico_jensen).</description>
    <link>https://dev.to/federico_jensen</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2986200%2F2cd0eeba-f0ca-49b4-b9ba-44af10bcb14e.png</url>
      <title>DEV Community: Federico Jensen</title>
      <link>https://dev.to/federico_jensen</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/federico_jensen"/>
    <language>en</language>
    <item>
      <title>Comprendiendo cómo funciona OpenVPN y configurar un Split Tunnel basado en usuarios (NixOS)</title>
      <dc:creator>Federico Jensen</dc:creator>
      <pubDate>Sun, 06 Jul 2025 21:14:30 +0000</pubDate>
      <link>https://dev.to/federico_jensen/comprendiendo-como-funciona-openvpn-y-configurar-un-split-tunnel-basado-en-usuarios-nixos-2n15</link>
      <guid>https://dev.to/federico_jensen/comprendiendo-como-funciona-openvpn-y-configurar-un-split-tunnel-basado-en-usuarios-nixos-2n15</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Ninguna IA ha estado involucrada en la creación de este artículo.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Introducción
&lt;/h2&gt;

&lt;p&gt;En este artículo veremos, detalladamente, como &lt;a href="https://openvpn.net/client/" rel="noopener noreferrer"&gt;OpenVPN&lt;/a&gt; manipula el networking de nuestro Linux para lograr la "magia" que conocemos como &lt;em&gt;Full Tunnel&lt;/em&gt; (conexión VPN típica). Luego hablaremos sobre los peligros del &lt;em&gt;DNS Leak&lt;/em&gt; y como solucionarlo. Finalmente revisaremos como podemos usar &lt;code&gt;iproute2&lt;/code&gt; para lograr tener un &lt;em&gt;Split Tunnel&lt;/em&gt; basado en una división de trafico dado el usuario (UID) que genere el trafico.&lt;/p&gt;

&lt;p&gt;Este artículo es extenso y detallado, no asume grandes conocimientos previos; y esta redactado en una forma secuencial, aclaratoria y reflexiva. O sea, si estas con prisa, aquí no encontraras un código para "copiar y pegar"; esto mas bien es una exploración profunda del funcionamiento de redes, Linux y los VPNs.&lt;/p&gt;

&lt;p&gt;A considerar, en este artículo: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No se asumen conocimientos avanzados de redes, por tanto, pasamos bastante tiempo explicando de manera sencilla y prolongada determinados términos que ya podrías conocer perfectamente. &lt;/li&gt;
&lt;li&gt;Uso la distribución de Linux conocida como &lt;a href="https://nixos.org/" rel="noopener noreferrer"&gt;NixOS&lt;/a&gt;. Si usan otra distribución este artículo puede ser igualmente útil, pero seguramente deberán adaptar los ejemplos. &lt;/li&gt;
&lt;li&gt;No se usa el firewall (&lt;code&gt;iptables&lt;/code&gt;/&lt;code&gt;nftables&lt;/code&gt;) para lograr el Split Tunnel, solo &lt;code&gt;iproute2&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Usare como proveedor de VPN (servidor), los servicios de pago de &lt;a href="https://airvpn.org/" rel="noopener noreferrer"&gt;AirVPN&lt;/a&gt; (no he recibido compensación económica de ellos para este post). Es muy poco probable, pero si usan otro servidor VPN, podrían tener que adaptar algunos de mis ejemplos a su situación particular. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Vamos a ello!&lt;/p&gt;




&lt;h2&gt;
  
  
  Contexto
&lt;/h2&gt;

&lt;p&gt;Generalmente al usar OpenVPN, como cliente de VPN, nuestra red se configurara de forma automática para que todo el trafico sea cifrado y enviado por un "túnel". Este túnel es un concepto abstracto y que, aunque es una buena analogía, entender realmente cómo funciona puede ser mas complejo. &lt;/p&gt;

&lt;p&gt;La "entrada al túnel" sera nuestro computador y la "salida del túnel" algún lugar perteneciente al servidor VPN donde nos estemos conectado. Realmente la "entrada al túnel" es mas que una interfaz de red virtual configurada con una serie de reglas de ruteo, que canalizan la gran mayoría de nuestras conexiones salientes para que sean cifradas hasta una locación remota. Esa locación remota, "la salida del túnel", es un servidor VPN que toma dichos conexiones salientes y las direcciona a internet. Luego las respuestas de internet retornan al servidor VPN y este realiza el proceso inverso hasta nuestro equipo. &lt;/p&gt;

&lt;p&gt;De esta manera, "ante el mundo", nosotros estamos donde esta el servidor VPN y &lt;strong&gt;no&lt;/strong&gt; en en nuestra locación real. Adicionalmente, a ojos del ISP (empresa que nos provee de internet) el trafico esta totalmente ofuscado, siendo imposible que puedan rastrear realmente el contenido de los datos transferidos, como tampoco su destino (ojo, esto solo si tenemos todo bien configurado... vamos a ver algo que se llama &lt;em&gt;DNS Leak&lt;/em&gt;, que puede "romper" parte del anonimato).&lt;/p&gt;

&lt;p&gt;Este caso que he expuesto es el mas común, desear que todo el trafico del equipo use el túnel; esto se denomina &lt;em&gt;Full Tunnel&lt;/em&gt;. Esta configuración es la que generalmente se aplica de forma automática por OpenVPN u cualquier otro cliente de VPN. Pero existe otro tipo de implementación un cliente de VPN, la de &lt;em&gt;Split Tunnel&lt;/em&gt;.  &lt;/p&gt;

&lt;p&gt;En Split Tunnel dividimos el trafico siguiendo una o varias reglas. Si la regla se cumple, el trafico usará el túnel; y en caso que no, el trafico saldrá de alguna otra forma a internet. Esta "otra forma" puede ser directamente a internet (como normalmente), o también, podría ser algun otro túnel paralelo administrado por otro cliente de VPN.&lt;/p&gt;

&lt;p&gt;Las "reglas" que definen como dividimos el trafico pueden ser variadas. En este artículo nos centraremos específicamente en una división basada en UID (IDs de usuarios de Linux). O sea, que solo el trafico generado por un usuario especifico sea enrutado por el túnel, el resto que salga a internet de forma directa.&lt;/p&gt;

&lt;p&gt;Dependiendo de la complejidad de las "reglas", la forma de implementarlas puede recurrir pequeñas o grandes manipulaciones de nuestro networking. En esta guiá veremos que solo usando las tablas de ruteo y sus regla se puede lograr el Split Tunnel. &lt;strong&gt;No&lt;/strong&gt; usaremos módulos de &lt;em&gt;firewall&lt;/em&gt; como &lt;a href="https://www.man7.org/linux/man-pages/man8/iptables.8.html" rel="noopener noreferrer"&gt;iptables&lt;/a&gt; o &lt;a href="https://www.nftables.org/projects/nftables/index.html" rel="noopener noreferrer"&gt;nftables&lt;/a&gt;; algo que podría ser necesario si las reglas que deseamos aplicar para la división de trafico fueran mas complejas que solo UIDs.  &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Durante las ultimas semanas he estado implementado una configuración de Split Tunnel para lograr tener funcionando, en paralelo, OpenVPN y Tailscale. En este proceso he aprendido bastante sobre que sucede en nuestro sistema, a nivel de redes, cuando estos clientes se auto-configuran. En este artículo espero aclarar dudas de lo que &lt;strong&gt;realmente&lt;/strong&gt; sucede en nuestro networking.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;En el próximo artículo podrán encontrar las siguientes secciones: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Examinación profunda de como OpenVPN configura de forma automática nuestro networking para darnos un Full Tunnel. &lt;/li&gt;
&lt;li&gt;Sobre DNS, OpenVPN, el peligro del &lt;em&gt;DNS Leak&lt;/em&gt; y como arreglarlo.&lt;/li&gt;
&lt;li&gt;Proceso para desactivar las configuraciones automáticas de OpenVPN, dándonos la oportunidad de manualmente definir el networking del túnel. &lt;/li&gt;
&lt;li&gt;Paso a paso de los comandos necesarias para lograr tener un Split Tunnel con OpenVPN basado en UID. Con una explicación clara de las configuraciones de networking creadas y de los métodos para probar su correcto funcionamiento.&lt;/li&gt;
&lt;li&gt;Uso de un Script para automatizar los procesos de generar un Split Tunnel en nuestro NixOS. &lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;Si ustedes quieren ir directamente al tema del Split Tunnel, pueden ignorar la parte 1 y 2 del artículo. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Por ultimo recordar que estaré usando &lt;a href="https://nixos.org/" rel="noopener noreferrer"&gt;NixOS&lt;/a&gt;, mi distribución de Linux favorita para &lt;em&gt;Home Servers&lt;/em&gt;. Pero en general, todo la información presentada en este artículo debería ser fácilmente "traducible" a otras distribuciones siempre que estas usen &lt;a href="https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/about/" rel="noopener noreferrer"&gt;iproute2&lt;/a&gt; para la gestión del networking y &lt;a href="https://systemd.io/" rel="noopener noreferrer"&gt;systemd&lt;/a&gt; para la gestión de servicios. &lt;/p&gt;




&lt;h2&gt;
  
  
  Explorando la configuración por defecto de OpenVPN y el Full Tunnel
&lt;/h2&gt;

&lt;p&gt;El cliente de OpenVPN es bastante flexible en su funcionamiento. Esto quiere decir que realmente la manera en la cual establece su conexión con el servidor VPN y la forma el la cual manipule nuestro networking para crear el túnel es variada. Esta se ajustara a: 1) lo especificado en el &lt;code&gt;.ovpn&lt;/code&gt; (archivo de configuración de la conexión OpenVPN) y 2) las configuraciones remotas que el servidor VPN "inyecte" en nuestro equipo (ya veremos mas de esto...). &lt;/p&gt;

&lt;p&gt;Nosotros nos pondremos en una situación "convencional", donde el servidor VPN al cual nos estamos conectados pertenece a un proveedor de pago. En mi caso siempre he usado &lt;a href="https://airvpn.org/" rel="noopener noreferrer"&gt;AirVPN&lt;/a&gt;, así que este artículo basará sus puntos en el uso de este servicio. De todos modos, independiente de lo anterior, en general no deberían encontrar gran diferencia si usan otro proveedor... siempre y cuando permita el uso del cliente OpenVPN, claro.&lt;/p&gt;

&lt;h3&gt;
  
  
  Instalando y configurando OpenVPN
&lt;/h3&gt;

&lt;p&gt;OpenVPN solo necesita del archivo &lt;code&gt;.ovpn&lt;/code&gt; para funcionar. Este archivo contiene toda la información de lo que debe hacer OpenVPN para: conectarse, autentificarse y establecer el túnel con el servidor VPN. En mi caso ya he generado el archivo &lt;code&gt;.ovpn&lt;/code&gt; desde la interfaz web de AirVPN. Y lo he guardado en &lt;code&gt;/etc/nixos/airvpn.ovpn&lt;/code&gt;. Su contenido se ve así:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
client
dev tun
remote america3.vpn.airdns.org 443
resolv-retry infinite
nobind
persist-key
persist-tun
auth-nocache
verb 3
explicit-exit-notify 5
push-peer-info
setenv UV_IPV6 yes
remote-cert-tls server
comp-lzo no
data-ciphers AES-256-GCM:AES-256-CBC:AES-192-GCM:AES-192-CBC:AES-128-GCM:AES-128-CBC
data-ciphers-fallback AES-256-CBC
proto udp
auth SHA512
...
&amp;lt;...certificados...&amp;gt;
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nota 1: He omitido mostrar los certificados contenidos en mi &lt;code&gt;.ovpn&lt;/code&gt;... claramente. &lt;/p&gt;

&lt;p&gt;Nota 2: Puede ser buena idea comparar su &lt;code&gt;.ovpn&lt;/code&gt; con el mio. Si ven que su cliente OpenVPN no se comporta como yo explico a continuación, seguramente son diferencias en lo declarado en este archivo de configuración. &lt;/p&gt;

&lt;p&gt;Por otro lado, he &lt;a href="https://nixos.wiki/wiki/OpenVPN" rel="noopener noreferrer"&gt;instalado OpenVPN en mi NixOS&lt;/a&gt; modificando el &lt;code&gt;configuration.nix&lt;/code&gt; y he usado el nombre &lt;code&gt;airVPN&lt;/code&gt; como nombre de la instancia de OpenVPN.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
services.openvpn = {
  servers = {
    airVPN = {
      config = "config /etc/nixos/airvpn.ovpn"; 
    };
  };
};
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pueden ver que simplemente estoy pasando la ruta del &lt;code&gt;.ovpn&lt;/code&gt; al parámetro &lt;a href="https://search.nixos.org/options?channel=25.05&amp;amp;show=services.openvpn.servers.%3Cname%3E.config&amp;amp;from=0&amp;amp;size=50&amp;amp;sort=relevance&amp;amp;type=packages&amp;amp;query=services.openvpn." rel="noopener noreferrer"&gt;config&lt;/a&gt;. NixOS se encargará, automáticamente, de crear un servicio (administrado por &lt;code&gt;systemd&lt;/code&gt;) para iniciar y conectar OpenVPN al servidor VPN indicado en el &lt;code&gt;.ovpn&lt;/code&gt; durante el inicio del sistema. El servicio llevará por nombre uno asignado por NixOS; en mi caso el servicio ha quedado con el nombre: &lt;code&gt;openvpn-airVPN.service&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Con todo eso listo, se puede usar el comando &lt;code&gt;sudo nixos-rebuild switch&lt;/code&gt; para crear una nueva &lt;em&gt;generación de NixOS&lt;/em&gt;. Posterior a un reinicio del sistema, al usar &lt;code&gt;systemctl status openvpn-airVPN.service&lt;/code&gt; vamos a poder confirmar que OpenVPN esta andando correctamente. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo2brxku9xo4uk7hyyx1x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo2brxku9xo4uk7hyyx1x.png" alt="Servicio de OpenVPN activo y funcionando" width="800" height="176"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Si entramos a &lt;a href="https://my-ip.cc/" rel="noopener noreferrer"&gt;una web&lt;/a&gt; para ver nuestra IP, verán que, a los ojos del mundo, estamos en una locación remota y adicionalmente no existirá datos de nuestra ISP:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxia9myo5ns7xmmdy5gl2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxia9myo5ns7xmmdy5gl2.png" alt="IP anonima segun my-ip.cc" width="755" height="486"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Por ultimo, podemos hacer una prueba desde la terminal y deberían ver un resultado muy similar:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;curl https://ipv4.ipleak.net/json/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;OpenVPN esta funcionando perfectamente en modo Full Tunnel :)&lt;/p&gt;

&lt;h3&gt;
  
  
  Analizando lo que ha manipulado OpenVPN durante su inicio en un escenario de funcionamiento "normal"
&lt;/h3&gt;

&lt;p&gt;¿Que ha "tocado" OpenVPN para darnos acceso a internet "mágicamente" al otro lado del mundo?. Una forma fácil de investigar esto es usar el comando &lt;code&gt;journalctl -b | grep 'openvpn'&lt;/code&gt;. Con este vamos a ver los logs de OpenVPN emitidos desde el ultimo inicio del sistema. &lt;/p&gt;

&lt;p&gt;Estos logs muestran cosas... muchas cosas... pero para entenderlo solo nos enfocaremos en lo principal. De manera secuencial iremos revisando los logs y haciendo coherencia de que esta pasando en nuestro equipo. Vamos a ello.&lt;/p&gt;

&lt;p&gt;Nota: Solo muestro los segmentos de logs mas relevantes para nuestro análisis. &lt;/p&gt;

&lt;p&gt;1) Inicia nuestro OpenVPN en la versión 2.6.14 usando &lt;a href="https://www.openssl-library.org/" rel="noopener noreferrer"&gt;OpenSSL&lt;/a&gt; 3.4.1.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;openvpn[945]: OpenVPN 2.6.14...
openvpn[945]: library versions: OpenSSL 3.4.1...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;2) Primero OpenVPN debe establecer comunicación con el servidor VPN. Para eso usa la información indicada en la directriz &lt;code&gt;remote&lt;/code&gt; del &lt;code&gt;.ovpn&lt;/code&gt;. Generalmente aquí esta la IP del servidor VPN, en mi caso es un hostname (otra opción valida). Así que primero OpenVPN usará la red normal (y el DNS que tengamos configurado en nuestro equipo) para resolver el dominio. Luego de un par de intentos, mi OpenVPN logra resolver el hostname en la IP &lt;code&gt;184.75.223.237:443&lt;/code&gt;. Esta es la &lt;code&gt;ip:port&lt;/code&gt; donde AirVPN me esta "ofreciendo" un servidor VPN y es el lugar con el cual el cliente OpenVPN va a intentar establecer comunicación.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;openvpn[945]: RESOLVE: Cannot resolve host address: america3.vpn.airdns.org:443...
openvpn[945]: Restart pause, 1 second(s)
...
openvpn[945]: UDPv4 link remote: [AF_INET]184.75.223.237:443
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nosotros denominaremos a &lt;code&gt;184.75.223.237:443&lt;/code&gt; como: &lt;strong&gt;la dirección pública del peer/servidor VPN remoto&lt;/strong&gt;.  &lt;/p&gt;

&lt;p&gt;3) OpenVPN realiza una prueba de nuestras interfaces de red y busca "como" salir a internet. Si notamos la linea &lt;code&gt;net_route_v4_best_gw&lt;/code&gt; veremos que OpenVPN ha decidido usar mi interfaz &lt;code&gt;enp0s3&lt;/code&gt;, con la gateway asociada &lt;code&gt;192.168.1.1&lt;/code&gt;, para alcanzar internet. Luego de esto, OpenVPN procede a autentificarse con el peer remoto usando los certificados encontrados en el &lt;code&gt;.ovpn&lt;/code&gt;. Finalmente OpenVPN se ha conectado de forma exitosa y segura con el servidor VPN de AirVPN.&lt;/p&gt;

&lt;p&gt;Importante de identificar en este segmento: mi interfaz ethernet, con la cual tengo internet en mi servidor, tiene por &lt;strong&gt;nombre&lt;/strong&gt; &lt;code&gt;enp0s3&lt;/code&gt;. Y esta pertenece, como es de esperar, a una red local privada (mi hogar); donde la &lt;strong&gt;gateway&lt;/strong&gt; (router) tiene la IP de &lt;code&gt;192.168.1.1&lt;/code&gt;. Si los paquetes son enrutados a esta IP, mediante &lt;code&gt;enp0s3&lt;/code&gt;, salen a internet.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;openvpn[945]: TLS: Initial packet from [AF_INET]184.75.223.237:443...
openvpn[945]: net_route_v4_best_gw result: via 192.168.1.1 dev enp0s3
openvpn[945]: Validating certificate extended key usage
openvpn[945]: Peer Connection Initiated with [AF_INET]184.75.223.237:443
openvpn[945]: TLS: tls_multi_process: initial untrusted session promoted to trusted
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;4) Es importante aclara, a pesar del punto 3), que OpenVPN aun &lt;strong&gt;no&lt;/strong&gt; tiene un túnel creado. Solo se ha autentificado con el servidor VPN de AirVPN y tiene la capacidad e intercambiar información para proseguir el proceso de configuración.  &lt;/p&gt;

&lt;p&gt;Ahora viene lo interesante: El servidor VPN enviá, de forma remota, hacia nosotros una serie de configuraciones. &lt;strong&gt;Esto se denomina PUSH&lt;/strong&gt;. Dicho de otra manera, el servidor remoto nos dará una serie de instrucciones de "como proceder" con la &lt;strong&gt;configuración local de nuestro equipo&lt;/strong&gt; para habilitar un túnel que nos permita salir a internet &lt;strong&gt;a través del servidor remoto&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;openvpn[945]: PUSH: Received control message:...
openvpn[945]: OPTIONS IMPORT...
openvpn[945]: OPTIONS IMPORT...
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Si analizamos el contenido del PUSH encontraremos la información clave. Aquí he destacado los tres parámetros mas importantes:&lt;/p&gt;

&lt;p&gt;-&lt;code&gt;ifconfig 10.10.238.249 255.255.255.0&lt;/code&gt;: Es la IP y mascara que serán asignadas a la interfaz virtual que será creada en nuestro equipo (entrada al túnel). Si usamos ambos valores IP y mascara podemos &lt;a href="https://www.calculadora-redes.com/" rel="noopener noreferrer"&gt;calcular&lt;/a&gt; la red que conforma el túnel: &lt;code&gt;10.10.238.0/24&lt;/code&gt;. &lt;br&gt;
-&lt;code&gt;route-gateway 10.10.238.1&lt;/code&gt;: Es la IP de la gateway donde la interfaz virtual debe enviar sus conexiones para salir a internet (salida del túnel). Como de es de esperar de una gateway, este es la primera IP del rango &lt;code&gt;10.10.238.0/24&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;dhcp-option DNS 10.6.214.1&lt;/code&gt;: Es la IP(v4) del servidor DNS que nuestro proveedor de VPN ofrece. Veremos este tema, con mas detall, en un capitulo posterior. Generalmente tiene el mismo valor que la IP de la gateway.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Estos valores serán usados para manipular el networking de nuestro equipo y es importante no olvidarlos. &lt;/p&gt;

&lt;p&gt;5) Ahora OpenVPN implementará las configuraciones que han llegado por el PUSH para &lt;em&gt;setear&lt;/em&gt; nuestra red. En primer lugar volverá a confirmar la interfaz física por donde puede salir a internet. Como vimos antes, en la punto 2), en mi caso es la interfaz ethernet &lt;code&gt;enp0s3&lt;/code&gt;, con gateway &lt;code&gt;192.168.1.1&lt;/code&gt;. En esta comprobación también veremos la mascara que usa dicha IP, en mi caso &lt;code&gt;255.255.255.0&lt;/code&gt;, por lo cual podemos calcular la red local: &lt;code&gt;192.168.1.0/24&lt;/code&gt; (la típica de toda la vida).&lt;/p&gt;

&lt;p&gt;Posteriormente OpenVPN creará una &lt;strong&gt;interfaz de red virtual&lt;/strong&gt;. Esta, por defecto, lleva el nombre de &lt;code&gt;tun0&lt;/code&gt;. Seguidamente le fijará a &lt;code&gt;tun0&lt;/code&gt; la IP indicada por las instrucciones PUSH (&lt;code&gt;ifconfig&lt;/code&gt;): &lt;code&gt;10.10.238.249/24&lt;/code&gt;. Y finalmente la pasará a estado "up" (encenderá la interfaz).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;openvpn[945]: ROUTE_GATEWAY 192.168.1.1/255.255.255.0 IFACE=enp0s3...
openvpn[945]: TUN/TAP device tun0 opened
openvpn[945]: net_addr_v4_add: 10.10.238.249/24 dev tun0
openvpn[945]: net_iface_up: set tun0 up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Es importante destacar que en este ultimo paso de encender la interfaz &lt;code&gt;tun0&lt;/code&gt; (paso a "up"), el Kernel de Linux automáticamente añadirá, a las &lt;em&gt;tablas de ruteo&lt;/em&gt; del sistema, la información para que dicha interfaz quede asociada a la red correcta. Esta configuración (entre otra) la podemos ver usando &lt;code&gt;ip route&lt;/code&gt;, y se ve así:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;10.10.238.0/24 dev tun0 proto kernel scope link src 10.10.238.249&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Esto se lee como: "cualquier conexión que vaya a alguna dirección del rango  &lt;code&gt;10.10.238.0/24&lt;/code&gt;, enviala por la interfaz &lt;code&gt;tun0&lt;/code&gt; y usa la IP de origen (&lt;em&gt;src&lt;/em&gt;) &lt;code&gt;10.10.238.249&lt;/code&gt;". Con esto básicamente podemos hablar con cualquier dispositivo de la red &lt;code&gt;10.10.238.0/24&lt;/code&gt; mediante &lt;code&gt;tun0&lt;/code&gt;, incluyendo la gateway, que justamente esta en &lt;code&gt;10.10.238.1&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Nota: También se añade otro ruteo, un poco mas oculto de detectar: &lt;code&gt;local 10.10.238.249 dev tun0 proto kernel scope host src 10.10.238.249&lt;/code&gt;. Este se puede observar en la tabla de rutas "local": &lt;code&gt;ip route show table local&lt;/code&gt;. En esta tabla de rutas están centralizados los ruteos relacionados a paquetes &lt;em&gt;localhost&lt;/em&gt; y &lt;em&gt;bradcast&lt;/em&gt;. Esta regla se lee como: "cualquier trafico local dirigido a &lt;code&gt;10.10.238.249&lt;/code&gt; envialo a &lt;code&gt;tun0&lt;/code&gt; con IP de origen &lt;code&gt;10.10.238.249&lt;/code&gt;". Simplemente permite que nos podemos auto-enviar trafico a notros mismos por &lt;code&gt;tun0&lt;/code&gt; si usamos nuestra propia IP. &lt;/p&gt;

&lt;p&gt;6) Posteriormente a encender &lt;code&gt;tun0&lt;/code&gt; y tenerla conectada a la red &lt;code&gt;10.10.238.0/24&lt;/code&gt;, OpenVPN utilizará otras instrucción, indicadas en el PUSH, para configurar nuestras rutas. Estas configuraciones permitirán "focalizar" (casi*) todas las conexiones de nuestro equipo a &lt;code&gt;tun0&lt;/code&gt;en vez de &lt;code&gt;enp0s3&lt;/code&gt; (la interfaz normal). En el proceso, se indicara específicamente la gateway e interfaz a usar. Por ultimo, también se añadirá una regla para que el propio túnel funcione correctamente.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;openvpn[945]: net_route_v4_add: 184.75.223.237/32 via 192.168.1.1 dev [NULL] table 0 metric -1
openvpn[945]: net_route_v4_add: 0.0.0.0/1 via 10.10.238.1 dev [NULL] table 0 metric -1
openvpn[945]: net_route_v4_add: 128.0.0.0/1 via 10.10.238.1 dev [NULL] table 0 metric -1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Si usamos &lt;code&gt;ip route&lt;/code&gt; veremos estas reglas ya implementadas en nuestras tablas de ruteo (ignoremos otros ruteos que puedan aparecer en la tabla por el momento).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;0.0.0.0/1 via 10.10.238.1 dev tun0&lt;/code&gt; y &lt;code&gt;128.0.0.0/1 via 10.10.238.1 dev tun0&lt;/code&gt;: Estas dos se usan en combinación y forman parte de un "truco" que usan muchos clientes de VPN. &lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Explico el "truco": Nosotros queremos enviar TODO el trafico generado por el sistema mediante &lt;code&gt;tun0&lt;/code&gt; a la gateway correspondiente, y normalmente para decir "todas las IPs" usaríamos un ruteo como &lt;code&gt;0.0.0.0/0 via 10.10.238.1 dev tun0&lt;/code&gt;. &lt;code&gt;0.0.0.0/0&lt;/code&gt; es literalmente TODO absoluto. El ruteo se leería como: "enviá el todo absoluto a la gateway &lt;code&gt;10.10.238.1&lt;/code&gt; mediante la interfaz &lt;code&gt;tun0&lt;/code&gt;". Pero resulta que ese ruteo es "tan poderosa" que &lt;strong&gt;no&lt;/strong&gt; puede convivir con otros ruteos mas granulares que podríamos (y necesitamos) ocupar. La solución es dividir el "ruteo absoluto" en dos. Usando de forma combinada el rango &lt;code&gt;0.0.0.0/1&lt;/code&gt; y &lt;code&gt;128.0.0.0/1&lt;/code&gt; virtualmente estamos cubriendo, a igual que con &lt;code&gt;0.0.0.0/0&lt;/code&gt;, todas las conexiones salientes. Pero ahora el sistema &lt;strong&gt;si&lt;/strong&gt; analizará posibles otros ruteos (configurados en la misma tabla) que podrían definir el uso de rutas alternativas. Nuevamente, es solo un truco, porque si usamos &lt;code&gt;0.0.0.0/0&lt;/code&gt; el sistema simplemente descartá cualquier otro ruteo definido en la misma tabla.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;O sea, podemos leer estas declaraciones de ruteo como: "Todo trafico que salga dirigido a una IP perteneciente al rango &lt;code&gt;0.0.0.0/1&lt;/code&gt; o &lt;code&gt;128.0.0.0/1&lt;/code&gt; (todas las IPs existentes), envialo a la gateway &lt;code&gt;10.10.238.1&lt;/code&gt; mediante la interfaz &lt;code&gt;tun0&lt;/code&gt; al menos que otro ruteo (en la misma tabla) diga lo contrario".&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;184.75.223.237 via 192.168.1.1 dev enp0s3&lt;/code&gt;: Esta regla se lee como: "Si hay paquetes que se dirigen a &lt;code&gt;184.75.223.237&lt;/code&gt;, usa la gateway &lt;code&gt;192.168.1.1&lt;/code&gt; mediante la interfaz &lt;code&gt;enp0s3&lt;/code&gt;". Si recordamos &lt;code&gt;184.75.223.237&lt;/code&gt; es la IP publica del servidor VPN remoto. Con esto logramos evitar que el trafico al servidor VPN sea canalizado por dentro del propio túnel (lo cual generaría un problema recursivo). Visto de otra manera: "Que todo trafico use &lt;code&gt;tun0&lt;/code&gt; para ir a internet, pero usa &lt;code&gt;enp0s3&lt;/code&gt; para mantener la conexión del túnel al servidor VPN".&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;7) Con las configuraciones listas, el sistema termina de activar el canal de datos y finalmente &lt;em&gt;setea&lt;/em&gt; un timer para verificar constantemente que el túnel esta activo y funcionando.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;openvpn[945]: Initialization Sequence Completed
openvpn[945]: Data Channel: cipher 'AES-256-GCM', peer-id: 2, compression: 'stub'
openvpn[945]: Timers: ping 10, ping-restart 60
openvpn[945]: Protocol options: explicit-exit-notify 5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Revisando las tablas de ruteo
&lt;/h3&gt;

&lt;p&gt;Veamos el panorama completo. Ahora que OpenVPN ya ha iniciado, revisemos la totalidad de nuestras reglas y tablas de ruteo.&lt;/p&gt;

&lt;p&gt;Si hacemos &lt;code&gt;ip rule&lt;/code&gt; para ver las reglas:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0:  from all lookup local
32766:  from all lookup main
32767:  from all lookup default
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esta son las reglas que el sistema operativo revisa para determinar que tabla de ruteo usar. Cada paquete que el equipo debe enrutar es leído (sus propiedades) y se busca un &lt;em&gt;match&lt;/em&gt; usando las tablas listadas. Se revisan en orden de prioridad, de menor a mayor número. La tabla &lt;code&gt;local&lt;/code&gt; (que siempre es la primera con valor 0) tiene en su interior los ruteos de paquetes &lt;em&gt;localhost&lt;/em&gt; y &lt;em&gt;brodcast&lt;/em&gt;. La podemos ignorar, y aunque tiene una gran importancia en el funcionamiento de red, no viene a tema por ahora. La segunda tabla, &lt;code&gt;main&lt;/code&gt;, es la tabla principal y, por defecto, es la que contiene los ruteos de todas las conexiones salientes del equipo. La ultima tabla, &lt;code&gt;default&lt;/code&gt;, cumple la función de dar termino y bloquear cualquier paquete que no sea coherente con las reglas especificadas hasta el momento, por eso siempre lleva el numero mas grande (32767). &lt;/p&gt;

&lt;p&gt;Ahora veremos el contenido de la tabla de ruteo &lt;em&gt;main&lt;/em&gt; usando &lt;code&gt;ip route&lt;/code&gt; (por defecto al usar &lt;code&gt;ip route&lt;/code&gt; vemos la tabla &lt;em&gt;main&lt;/em&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0.0.0.0/1 via 10.10.238.1 dev tun0 
default via 192.168.1.1 dev enp0s3 proto dhcp src 192.168.1.13 metric 100 
10.10.238.0/24 dev tun0 proto kernel scope link src 10.10.238.249 
128.0.0.0/1 via 10.10.238.1 dev tun0 
184.75.223.237 via 192.168.1.1 dev enp0s3 
192.168.1.0/24 dev enp0s3 proto kernel scope link src 192.168.1.13 metric 100 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dentro de una tabla de ruteo se busca una coincidencia entre las rutas listadas y las propiedades del paquete de datos que sale a la red. Si hace &lt;em&gt;match&lt;/em&gt;, se usa dicha ruta para el paquete. Las decisiones se toman de menor nivel de granularidad de IP a mayor. O sea, un ruteo que especifique por donde enviar trafico de UNA sola IP (Ej: &lt;code&gt;184.75.223.237&lt;/code&gt;) tiene &lt;strong&gt;mas&lt;/strong&gt; poder de prioridad que un ruteo que engloba un rango de IPs (Ej: &lt;code&gt;10.10.238.0/24&lt;/code&gt;). Y una mascara pequeña (Ej: &lt;code&gt;128.0.0.0/1&lt;/code&gt;) tiene &lt;strong&gt;menos&lt;/strong&gt; prioridad que una mascara grande (Ej: &lt;code&gt;192.168.1.0/24&lt;/code&gt;). Existen 2 excepciones. El uso de &lt;code&gt;0.0.0.0/0&lt;/code&gt; domina a cualquier otro ruteo y es absoluto. Y la palabra especial &lt;code&gt;default&lt;/code&gt; se interpreta como: "si ninguna otra ruta de esta tabla hace &lt;em&gt;match&lt;/em&gt; con el paquete, usa esta ruta". Por ultimo, si una tabla de ruteo no tiene &lt;code&gt;default&lt;/code&gt; y un paquete no encuentra una ruta a usar porque no existe &lt;em&gt;match&lt;/em&gt;, el paquete "sale" de dicha tabla de ruteo y pasa a usar la siguiente listada en las reglas (&lt;code&gt;ip rule&lt;/code&gt;). &lt;/p&gt;

&lt;p&gt;Analicemos los ruteos. Existen dos rutas que ya estaban en la tabla &lt;code&gt;main&lt;/code&gt;, incluso antes que OpenVPN iniciara, y que quiero mencionar:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;default via 192.168.1.1 dev enp0s3 proto dhcp src 192.168.1.13 metric 100&lt;/code&gt;: Este ruteo es, por defecto, el que ha sido agregado mediante &lt;a href="https://www.redeszone.net/tutoriales/internet/que-es-protocolo-dhcp/" rel="noopener noreferrer"&gt;DHCP&lt;/a&gt; para que nuestra interfaz ethernet &lt;code&gt;enp0s3&lt;/code&gt; tenga acceso a internet. Se puede leer como: "Por defecto, si no hay otro &lt;em&gt;match&lt;/em&gt; en esta tabla, enviá todo el paquete a la gateway &lt;code&gt;192.168.1.1&lt;/code&gt; mediante la interfaz &lt;code&gt;enp0s3&lt;/code&gt; con una IP de origen de &lt;code&gt;192.168.1.13&lt;/code&gt; (la IP local de nuestro equipo)". Sin este ruteo, nuestra interfaz física simplemente no funciona, no tendríamos internet y OpenVPN ni siquiera podría entablar la comunicación inicial con el servidor.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;192.168.1.0/24 dev enp0s3 proto kernel scope link src 192.168.1.13 metric 100&lt;/code&gt;: Este segundo ruteo es añadido automáticamente, por el Kernel, cuando la interfaz &lt;code&gt;enp0s3&lt;/code&gt; pasa a estado "up" (durante el inicio del equipo). Y sirve para poder comunicarnos con los otros dispositivos de la red local, incluyendo la gateway correspondiente. Se puede leer como: "Todo trafico saliente dirigido a una de las IPs del rango 192.168.1.0/24 envialo por la interfaz &lt;code&gt;enp0s3&lt;/code&gt; usando la IP de origen &lt;code&gt;192.168.1.13&lt;/code&gt; (la IP local de nuestro equipo)". Es importante notar que este ruteo es el que permite usar dispositivos en nuestra red local como impresoras, a pesar de estar conectados a la VPN. Ojo: esto es lo que provoca que el trafico local no sea considerado por los ruteos &lt;code&gt;0.0.0.0/1&lt;/code&gt; y &lt;code&gt;128.0.0.0/1&lt;/code&gt; del VPN, sino que se mantenga por fuera del túnel. Recordemos el orden de prioridad: &lt;code&gt;/1&lt;/code&gt; menos prioridad que &lt;code&gt;/24&lt;/code&gt;. Nota: este ruteo, aunque es generado por el Kernel, es parte configurado gracias a DHCP. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;¿Que es es DHCP?. En resumen es el método que usa nuestro equipo, cuando se inicia, para coordinar con nuestro router como integrarse a la red local y acceder a internet. Mas específicamente el protocolo DHCP ayuda a coordinar: la red local, su gateway y la IP que deberá tener cada dispositivo dentro de dicha red. Y, dependiendo de la configuración, también configura el servidor DNS que nuestro equipo usara para resolver hostnames (luego hablaremos mas de esto y como se relaciona a &lt;em&gt;DNS Leak&lt;/em&gt;). &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Los demás ruteos ya los mencionamos en su momento, pero ahora cobran mas sentido sabiendo las reglas de prioridad de la tabla y como funcionan:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;184.75.223.237 via 192.168.1.1 dev enp0s3&lt;/code&gt;: Un ruteo de alta prioridad porque especifica una sola IP (&lt;code&gt;184.75.223.23&lt;/code&gt;), en este caso la del servidor VPN. Este trafico debe ser enviado por &lt;code&gt;enp0s3&lt;/code&gt; para evitar problemas de recursividad. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;10.10.238.0/24 dev tun0 proto kernel scope link src 10.10.238.249&lt;/code&gt;: Ruteo que explica que cualquier trafico a &lt;code&gt;10.10.238.0/24&lt;/code&gt; (red del túnel), debe usar la interfaz &lt;code&gt;tun0&lt;/code&gt; con la IP origen &lt;code&gt;10.10.238.249&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;0.0.0.0/1 via 10.10.238.1 dev tun0&lt;/code&gt; y &lt;code&gt;128.0.0.0/1 via 10.10.238.1 dev tun0&lt;/code&gt;: Dos reglas de ruteo, que en combinación, ayudan a hacer &lt;em&gt;match&lt;/em&gt; con todos los paquetes (a excepción que otro ruteo de la misma tabla tenga &lt;em&gt;match&lt;/em&gt;) para que sea enviado por &lt;code&gt;tun0&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Antes de finalizar esta sección, quiero que reflexionemos en algo. Aunque esta modalidad de VPN se denomina "Full Tunnel", o sea, todo el trafico se va por la VPN... la verdad es que no y lo podemos ver. Si el trafico va a la red local (&lt;code&gt;192.168.1.0/24&lt;/code&gt;), no sale por &lt;code&gt;tun0&lt;/code&gt;. Si el trafico va específicamente a &lt;code&gt;184.75.223.237&lt;/code&gt; (servidor VPN), tampoco usa &lt;code&gt;tun0&lt;/code&gt;. Y, aunque no lo vimos en detalle, también están varias reglas de &lt;em&gt;localhost&lt;/em&gt; y &lt;em&gt;multicast&lt;/em&gt; que queda fuera del túnel (tabla &lt;code&gt;local&lt;/code&gt;). Por tanto, realmente no existe nada como un "Full Tunnel", de alguna manera, siempre ha sido un "Split Tunnel" con reglas de división basadas en IPs. &lt;/p&gt;

&lt;p&gt;Nosotros ahora, simplemente, tomaremos el control del networking y configuraremos un "Split Tunnel" para dividir el trafico dada nuestras necesidades.&lt;/p&gt;




&lt;h2&gt;
  
  
  Sobre el DNS y DNS Leak con OpenVPN
&lt;/h2&gt;

&lt;p&gt;Ahora nos iremos por una tangente, nada que ver con el Split Tunnel, pero extremadamente importante si deseas que OpenVPN realice su trabajo correctamente.&lt;/p&gt;

&lt;p&gt;Hablemos de DNS, Linux, OpenVPN y DNS Leak&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Que es el DNS y su gran dilema en Linux?
&lt;/h3&gt;

&lt;p&gt;Este tema es como un iceberg. Ni siquiera se como abordar la explicación... partamos desde lo básico. Nuestro sistema operativo cada vez que debe usar una dirección web, ejemplo: google.com, debe "resolver" dicho domino (o hostname) a una (o varias) IPs. Para lograr esto, el sistema operativo se comunica con un servidor de resolución de DNS. Existen miles en el mundo (y su propia estructura y funcionamiento es bien interesante, pero fuera del alcance de este artículo). Estos servidores DNS tienen tablas enormes donde están todos los dominios y su/s IPs correspondientes.&lt;/p&gt;

&lt;p&gt;¿Pero cual servidor usa nuestro sistema operativo cuando debe resolver un hostname?... bueno... el servidor DNS esta en internet... por tanto también tiene una IP, así que nuestro sistema operativo debe saber esa IP y tenerla guardada en algún lugar... ¿no?&lt;/p&gt;

&lt;p&gt;Nota: claramente el servidor DNS no puede tener un dominio, ejemplo "super-server-dns.org"; porque ese dominio debería también resolverse de alguna manera. Así que los servidores DNS solo se identifican con IP, no con hostname. &lt;/p&gt;

&lt;p&gt;La cosa es que a través de los años de evolución de: Linux, su Kernel y las diversas distribuciones; se ha generado una confusión HORRIBLE!. Hoy en día es sumamente confuso saber donde esta configurado el DNS en Linux y que mecanismos se usan para definir y leer ese valor. Si no me creen, miren &lt;a href="https://tailscale.com/blog/sisyphean-dns-client-linux" rel="noopener noreferrer"&gt;este maravilloso post&lt;/a&gt; de Tailscale donde un pobre hombre ha tratado de explicarlo. No pretendo darle sentido.&lt;/p&gt;

&lt;p&gt;En resumen, existen muchas piezas en el sistema que se mueven y coordinan para configurar el DNS. Y también, luego, para rescatar dicha configuración cada vez que se necesite resolver un hostname. Esas piezas y mecanismos dependerán de su distribución de Linux, versión y paquetes instalados. &lt;/p&gt;

&lt;p&gt;En NixOS, por defecto, el principal lugar donde debemos observar para saber a que servidor DNS estamos apuntando es: &lt;code&gt;/etc/resolv.conf&lt;/code&gt;. Si hacemos &lt;code&gt;cat /etc/resolv.conf&lt;/code&gt; veremos la IP del servidor DNS que nuestro sistema va a usar cada vez que trate de resolver un hostname. Existen 2 servicios que tienen un control sobre este archivo: &lt;code&gt;networkmanager&lt;/code&gt; y &lt;code&gt;resolvconf&lt;/code&gt;. Si desean editar y controlar su DNS, se deben usar directamente estos servicios para editar las configuraciones o recurrir a programa que se integre con esta arquitectura (como es el caso de OpenVPN que veremos a continuación).&lt;/p&gt;

&lt;h3&gt;
  
  
  DNS y OpenVPN
&lt;/h3&gt;

&lt;p&gt;Nosotros esperaríamos que al usar un Full Tunnel nuestras actividades quedaran ocultadas ante ojos del ISP (proveedor de internet) ¿no?. Pues, podemos tener un túnel perfectamente funcionando con OpenVPN y aun así, el ISP ver perfectamente a donde nos estamos conectando. ¿Como? Sucede cuando el DNS de nuestro sistema operativo esta configurado para usar un servidor DNS que se encuentra fuera del dominio de conexiones que OpenVPN esta canalizando por el túnel. Esto se denomina &lt;strong&gt;DNS Leak&lt;/strong&gt; y es mas común de lo que piensas. &lt;/p&gt;

&lt;p&gt;Realicemos algunas pruebas. &lt;/p&gt;

&lt;p&gt;Con su OpenVPN encendido (con configuraciones automáticas para lograr un Full Tunnel) podemos entrar a la web &lt;a href="https://ipleak.net/" rel="noopener noreferrer"&gt;ipleak.net&lt;/a&gt;. Podrán ver que su IP publica corresponde al servidor remoto VPN donde estemos conectado. Pero un poco mas abajo, en "DNS Addresses", claramente información relacionada a ustedes. Este es un indicador que su sistema esta consultado la resolución de hostnames a la infraestructura de su ISP. DNS Leak detectado. &lt;/p&gt;

&lt;p&gt;Si revisan que IP de servidor DNS esta usando su sistema con: &lt;code&gt;cat /etc/resolv.conf&lt;/code&gt; seguramente verán la IP de su gateway de la red local. O sea, su router. Esto quiere decir que su equipo, cada vez que resuelve un dominio, consulta a su router por la IP de la pagina web. Luego, el router, consulta siguiendo una serie de procesos a diversos servidores del ISP. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;La IP encontrada en &lt;code&gt;/etc/resolv.conf&lt;/code&gt; es configurada automáticamente por su NetworkManager cuando el sistema de DHCP asigna la IP local a su interfaz física.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Nosotros NO queremos bajo ninguna motivo usar un DNS que pertenezca a la ISP. ¿que soluciones tenemos? Existen 2 alternativas relativamente simple de aplicar:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Configurar, mediante su NetworkManager, un DNS publico con buena reputación como: &lt;code&gt;1.1.1.1&lt;/code&gt;, &lt;code&gt;8.8.8.8&lt;/code&gt; o &lt;code&gt;9.9.9.9&lt;/code&gt;. Luego de hacer esto las resoluciones de hostname pasaran, por el interior del túnel, hasta dichos servidores DNS. El ISP ya no tendrá la posibilidad de ver a donde están accediendo. En NixOS es posible ajustar estos DNS mediante el &lt;code&gt;configuration.nix&lt;/code&gt;. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Configurar OpenVPN para que &lt;em&gt;setee&lt;/em&gt;, en nuestro sistema, el servidor DNS que nuestro propio proveedor de VPN tiene. En mi caso, AirVPN ofrece a todos sus usuarios un servidor DNS interno mantenido por ellos. &lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Nosotros usaremos la opción 2, el DNS del proveedor VPN.&lt;/p&gt;

&lt;p&gt;Activarlo es muy sencillo en NixOS, solo debemos añadir &lt;code&gt;updateResolvConf = true&lt;/code&gt; a la configuración de OpenVPN en &lt;code&gt;configuration.nix&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
services.openvpn = {
  servers = {
    airVPN = {
      ...
      updateResolvConf = true;
      ...
    };
  };
};
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nota: Al activar &lt;code&gt;updateResolvConf&lt;/code&gt;, que por defecto esta desactivada, NixOS usara la técnica de &lt;em&gt;update-resolv-conf&lt;/em&gt; para automáticamente ajustar el valor de &lt;code&gt;/etc/resolv.conf&lt;/code&gt; al DNS indicado en las instrucciones PUSH que OpenVPN ha recibido desde el servidor VPN.&lt;/p&gt;

&lt;p&gt;Ahora creamos una nueva generación de NixOS y reiniciamos el sistema. &lt;/p&gt;

&lt;p&gt;Si volvemos a acceder a &lt;a href="https://ipleak.net/" rel="noopener noreferrer"&gt;ipleak.net&lt;/a&gt; veremos que no solo nuestra IP publica corresponde a la del servidor VPN, sino que también el servidor DNS. &lt;strong&gt;De esta manera hemos logrado evitar el DNS Leak.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;También podemos verificar usando &lt;code&gt;cat /etc/resolv.conf&lt;/code&gt; que ahora esta la IP correspondiente a la gateway de &lt;code&gt;tun0&lt;/code&gt;. Generalmente es la IP de la gateway del túnel donde reside el servidor DNS (Ojo, puede que en otros proveedores de VPN sea distinto)&lt;/p&gt;

&lt;p&gt;Si tienen dudas de cual es la IP del servidor DNS que su proveedor VPN tiene, la forma mas segura de averiguarlo es entrar log de OpenVPN (&lt;code&gt;journalctl -b | grep "openvpn"&lt;/code&gt;) y buscar las instrucciones PUSH. Generalmente la IP del servidor VPN esta en un argumento llamado &lt;code&gt;dhcp-option&lt;/code&gt;.   &lt;/p&gt;

&lt;p&gt;Nota: Quiero mencionar que, por defecto, todas las consultas DNS &lt;strong&gt;no&lt;/strong&gt; están cifradas. Si las consultas no usan un túnel, el contenido puede ser fácilmente analizado por el ISP para saber a que dominios se están conectado. Esto incluso si usan &lt;code&gt;1.1.1.1&lt;/code&gt; o &lt;code&gt;8.8.8.8&lt;/code&gt;. Existen tecnologías para evitar esto como &lt;a href="https://www.cloudflare.com/learning/dns/dns-over-tls/" rel="noopener noreferrer"&gt;DoT, DoH&lt;/a&gt; y &lt;a href="https://www.dnscrypt.org/" rel="noopener noreferrer"&gt;DNSCrypt&lt;/a&gt;. Por tanto siempre es prioritario asegurar que todas sus resoluciones DNS usen el túnel, de esta manera estarán cifradas y serán ilegibles por el ISP.  &lt;/p&gt;

&lt;h4&gt;
  
  
  Si no usas NixOS
&lt;/h4&gt;

&lt;p&gt;Si no usan NixOS, puede que en su sistema se encuentren con el DNS correctamente configurado desde un principio. En caso contrario, dependerá de su distribución la forma de solucionar el DNS Leak. La mejor manera de afrontarlo es asegurar que OpenVPN este usando la implementación &lt;code&gt;update-resolv-conf&lt;/code&gt; o &lt;code&gt;update-systemd-resolved&lt;/code&gt;. Puede leer mas del tema &lt;a href="https://wiki.archlinux.org/title/OpenVPN#DNS" rel="noopener noreferrer"&gt;aquí&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Configurando nuestro Split Tunnel
&lt;/h2&gt;

&lt;p&gt;"Split Tunnel" es la capacidad de enviar trafico por dentro o fuera del túnel de VPN usando una serie de reglas/ruteos que lo dividan. Esto se puede lograr de diversas maneras. Entre ellas podemos encontrar dos métodos que no requieren el uso de paquetes adicionales a los ya incluidos en la mayoría de las distribuciones de Linux. El primero, y mas sencillo, es usando exclusivamente &lt;code&gt;iproute2&lt;/code&gt;, el paquete de herramientas predeterminado para la gestión de redes. Y el segundo método es usando una combinación de &lt;code&gt;iptables/nftables&lt;/code&gt; (el firewall) y &lt;code&gt;iproute2&lt;/code&gt;. Aquí dejo una comparación de los dos métodos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;iproute2&lt;/code&gt;: Es comparativamente fácil de implementar. Solo nos permite usar reglas básicas para dividir el trafico, tales como reglas basadas en: IP de destino/origen, protocolo, puerto y usuario dueño del proceso que genera el trafico.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;iptables/nftables&lt;/code&gt; + &lt;code&gt;iproute2&lt;/code&gt;: Es mas complejo de configurar, ya que debemos coordinar las reglas y tablas de ruteo mas las reglas del propio firewall. Permite una división mucho mas exacta, basada no solo en lo anteriormente mencionado, sino también en: MACs, grupos de usuario, marcas de paquetes, procesos, tamaño de paquete, enrutamiento de forwarding...y otras cosas mas. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nosotros nos enfocaremos &lt;strong&gt;solo&lt;/strong&gt; en el método de &lt;code&gt;iproute2&lt;/code&gt;, ya que sin dominar esto, es peligroso pensar en también querer usar &lt;code&gt;iptables/nftables&lt;/code&gt;. De esta manera, nosotros editaremos nuestras tablas de enrutamiento y las reglas que las dominan y no tocaremos nada relacionado al firewall. &lt;/p&gt;

&lt;p&gt;Nuestro objetivo sera dividir el trafico &lt;strong&gt;basado en usuarios&lt;/strong&gt;. Si el trafico es generado por el usuario &lt;code&gt;root&lt;/code&gt; o &lt;code&gt;nixos&lt;/code&gt; (mi usuario normal), se enviara por &lt;strong&gt;fuera&lt;/strong&gt; del túnel. Si el trafico es generado por el usuario &lt;code&gt;vpn_user&lt;/code&gt;, se enviara por &lt;strong&gt;dentro&lt;/strong&gt; del túnel.&lt;/p&gt;

&lt;p&gt;Antes de comenzar dos puntos muy importantes:&lt;/p&gt;

&lt;p&gt;1) Recordar que en todo este artículo estoy &lt;strong&gt;omitiendo&lt;/strong&gt; el uso de IPv6 porque, sinceramente, aun no lo domino completamente. Así que las próximas configuraciones solo permitirán el uso del Split Tunnel con IPv4. &lt;/p&gt;

&lt;p&gt;2) Ya que no tocaremos el firewall, vamos a asumir que las reglas actuales de su &lt;code&gt;iptables/nftables&lt;/code&gt; permiten todo el trafico de salida (y respuestas a dicho trafico) &lt;strong&gt;sin&lt;/strong&gt; restricciones de de interfaz, protocolos o IPs de origen/destino. Esto es importante ya que puede que ustedes digan: "no me funciona nada de lo que dice este artículo" y resulta que todo el tiempo ha sido su firewall ejecutando bloqueos. ¿Como saber si mi firewall afectará el Split Tunnel? Bueno, si puedes usar OpenVPN en modo "normal", o sea, con la configuración automática que revisamos el capitulo anterior; quiere decir que todo esta bien y no deberían tener problema tampoco al configurar el Split Tunnel.&lt;/p&gt;

&lt;h3&gt;
  
  
  Desactivando las manipulaciones automatices de OpenVPN
&lt;/h3&gt;

&lt;p&gt;El primer paso sera cambiar la configuración de OpenVPN para que durante su proceso de inicio &lt;strong&gt;no&lt;/strong&gt; manipule nuestras tablas/reglas de ruteo. Ni que tampoco encienda la interfaz virtual &lt;code&gt;tun0&lt;/code&gt;. Ojo, que la cree, pero que no la configure ni encienda. &lt;/p&gt;

&lt;p&gt;Para lograr esto debemos añadir 2 instrucciones a nuestro &lt;code&gt;.ovpn&lt;/code&gt;:&lt;br&gt;
-&lt;code&gt;ifconfig-noexec&lt;/code&gt;: Provocará que el sistema no asigne IP ni encienda la interfaz virtual &lt;code&gt;tun0&lt;/code&gt;. Solo la va a crear y la dejara apagada.&lt;br&gt;
-&lt;code&gt;route-noexec&lt;/code&gt;: Con esto evitaremos que OpenVPN manipule las tablas de ruteo y las reglas asociadas.&lt;/p&gt;

&lt;p&gt;Normalmente deberíamos añadir estas dos instrucciones al &lt;code&gt;.ovpn&lt;/code&gt;, pero en NixOS podemos añadirlas directamente en &lt;code&gt;configuration.nix&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
services.openvpn = {
  servers = {
    airVPN = {
      config = "config /etc/nixos/airvpn.ovpn \n ifconfig-noexec \n route-noexec";
      updateResolvConf = true;
    };
  };
};
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Luego de: guardar las configuraciones, crear una nueva generación de NixOS y reiniciar el OS; veremos que efectivamente OpenVPN inicia, pero sin activar &lt;code&gt;tun0&lt;/code&gt; y tampoco modificando nuestros ruteos. Podemos comprobarlo usando: &lt;code&gt;ip addr&lt;/code&gt;, &lt;code&gt;ip rule&lt;/code&gt; y &lt;code&gt;ip route&lt;/code&gt;. De hecho, en la tabla de ruteo &lt;em&gt;main&lt;/em&gt;, solo veremos los 2 ruteos por defecto que &lt;code&gt;enp0s3&lt;/code&gt; necesita para funcionar. &lt;/p&gt;

&lt;p&gt;Lo otro que necesitaremos es crear el usuario: "vpn_user". Todo el trafico generado por &lt;strong&gt;este&lt;/strong&gt; usuario usara el túnel de OpenVPN. Trafico generado por otros usuarios, como &lt;code&gt;root&lt;/code&gt; o &lt;code&gt;nixos&lt;/code&gt; no usaran el túnel. Yo he creado este usuario al "modo" NixOS, pero ustedes pueden hacerlo como corresponda en su distribución. Lo importante es tener claro el &lt;strong&gt;UID que tendrá este usuario&lt;/strong&gt;. En mi caso usare el &lt;strong&gt;UID 1100&lt;/strong&gt;. Así ha quedado mi &lt;code&gt;configuration.nix&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
users.users = {
  nixos = {
    isNormalUser = true;
    description = "nixos";
    extraGroups = [ "networkmanager" "wheel" ];
  };
  vpn_user = {
    isSystemUser = true;
    group = "vpn_user_g";
    uid = 1100;
  };
};
users.groups.vpn_user_g = {};
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nota 1: En mi caso he creado a &lt;code&gt;vpn_user&lt;/code&gt; como un usuario de sistema, aunque esto no es obligatorio (no tendrá shell ni carpeta personal). Por requisito de NixOS también he tenido que crear un grupo de usuario asociado a &lt;code&gt;vpn_user&lt;/code&gt;, este grupo lo he llamado &lt;code&gt;vpn_user_g&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Nota 2: También pueden ver en esta configuración la existencia del usuario &lt;code&gt;nixos&lt;/code&gt;, el cual es el usuario normal. Ojo, el usuario &lt;code&gt;root&lt;/code&gt; también existe, aunque no esta presente en ninguna parte del &lt;code&gt;configuration.nix&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Para ver todos los usuarios y su correspondiente UID podemos usar: &lt;code&gt;awk -F: '{ print $1, $3 }' /etc/passwd&lt;/code&gt;. Seguramente verán bastante mas usuarios de los esperados... la mayoría son del sistema de Linux y los diversos servicios que estén presente en el sistema. Los importantes a identificar en el listado son: el usuario normal que estén usando, en mi caso &lt;code&gt;nixos&lt;/code&gt; con UID 1000, el usuario &lt;code&gt;vpn_user&lt;/code&gt;, que acabamos de crear, con UID 1100 y el usuario &lt;code&gt;root&lt;/code&gt; con UID 0. &lt;/p&gt;

&lt;p&gt;Con esto listo podemos ponernos a configurar manualmente el networking.&lt;/p&gt;

&lt;h3&gt;
  
  
  Comandos de configuración
&lt;/h3&gt;

&lt;p&gt;Es &lt;strong&gt;MUY&lt;/strong&gt; importante destacar que el &lt;strong&gt;orden&lt;/strong&gt; de uso de los comandos influye. Esto se debe a que ciertas cosas no puedan ser ejecutadas antes que otras. Y por otro lado, las reglas de ruteo tienen prioridades y ordenes de ejecución. Así que mucho cuidado con el orden.&lt;/p&gt;

&lt;p&gt;Antes de empezar con los comandos necesitamos tener claro lo siguientes valores:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;uid_range&lt;/code&gt; El rango de UID de usuarios que su trafico sera enviado por la VPN. En mi caso es "1100-1100" (si, es obligatorio que sea un rango; en caso de ser solo un usuario pueden iniciar y terminar el rango con el mismo UID).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;openvpn_peer_ip&lt;/code&gt; La IP publica de servidor remoto de VPN. En mi caso es: &lt;code&gt;184.75.223.237&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tun0_host&lt;/code&gt; La IP que el servidor VPN a asignado a nuestra interfaz &lt;code&gt;tun0&lt;/code&gt;. En mi caso es: &lt;code&gt;10.10.238.249&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tun0_gateway&lt;/code&gt; La IP de la gateway de la red del túnel. En mi caso: &lt;code&gt;10.10.238.1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tun0_dns&lt;/code&gt; La IP del DNS del servidor VPN. Generalmente tiene exactamente el mismo valor que &lt;code&gt;tun0_gateway&lt;/code&gt;. En mi caso: &lt;code&gt;10.10.238.1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tun0_network&lt;/code&gt; El rango de la red que usa &lt;code&gt;tun0&lt;/code&gt; con la mascara incorporada en formato CIDR. En mi caso: &lt;code&gt;10.10.238.0/24&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;enp0s3_network&lt;/code&gt; El rango de la red local que usa &lt;code&gt;enp0s3&lt;/code&gt; con la mascara incorporada en formato CIDR. En mi caso: &lt;code&gt;192.168.1.0/24&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cada vez que OpenVPN inicia, estos valores podrían cambiar. ¿Como los obtengo?. Lo mas fácil es usar: &lt;code&gt;journalctl -b | grep 'openvpn'&lt;/code&gt; y leer los logs en búsqueda de cada valor. El mejor lugar para buscar es la sección PUSH. &lt;/p&gt;

&lt;p&gt;En caso del valor de &lt;code&gt;enp0s3_network&lt;/code&gt;, una forma fácil de obtenerlo es con &lt;code&gt;ip addr show enp0s3&lt;/code&gt;, luego tomar el valor &lt;code&gt;inet&lt;/code&gt; (IP host del nuestro equipo) y cambiar el ultimo octeto por un &lt;code&gt;.0&lt;/code&gt;. Ej: &lt;code&gt;192.168.1.13/24&lt;/code&gt; -&amp;gt; &lt;code&gt;192.168.1.0/24&lt;/code&gt;. Nota: si su interfaz física no se llama &lt;code&gt;enp0s3&lt;/code&gt;, recuerden cambiar al nombre correspondiente. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Claramente realizar los pasos anteriores de manera manual es lento y complicado. Luego de esta explicación del paso a paso, lo automatizaremos todo en un script. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Bien, con estas variables definidas ejecutaremos un total de &lt;strong&gt;9&lt;/strong&gt; comandos de &lt;code&gt;iproute2&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;1) &lt;code&gt;ip addr add &amp;lt;tun0_host&amp;gt; dev tun0&lt;/code&gt;: Le asignamos a la interfaz &lt;code&gt;tun0&lt;/code&gt; la IP host indicada por el PUSH de OpenVPN.&lt;/p&gt;

&lt;p&gt;2) &lt;code&gt;ip link set tun0 up&lt;/code&gt;: Pasamos la interfaz &lt;code&gt;tun0&lt;/code&gt; a estado "activa".&lt;/p&gt;

&lt;p&gt;3) &lt;code&gt;ip route add &amp;lt;tun0_network&amp;gt; dev tun0 scope link src &amp;lt;tun0_host&amp;gt; table 200&lt;/code&gt;: Esto enviara por la interfaz &lt;code&gt;tun0&lt;/code&gt;, con IP de origen &lt;code&gt;10.10.238.249&lt;/code&gt;, todo trafico dirigido a &lt;code&gt;10.10.238.0/24&lt;/code&gt;. Pero OJO, esta regla no la estamos añadiendo a la tabla &lt;em&gt;main&lt;/em&gt; (tabla de ruteo por defecto), &lt;strong&gt;sino a la tabla "200"&lt;/strong&gt; (este numero lo he seleccionado de manera aleatoria y sirve como identificado, pueden usar otro si desean).&lt;/p&gt;

&lt;p&gt;4) &lt;code&gt;ip route add default via &amp;lt;tun0_gateway&amp;gt; dev tun0 src &amp;lt;tun0_host&amp;gt; table 200&lt;/code&gt;: Enviamos todo el trafico, si no hay otro ruteo en la misma tabla que realice &lt;em&gt;match&lt;/em&gt;, a la la gateway &lt;code&gt;10.10.238.1&lt;/code&gt; mediante la interfaz &lt;code&gt;tun0&lt;/code&gt; usando como IP de origen &lt;code&gt;10.10.238.249&lt;/code&gt;. Y OJO, nuevamente, esto también &lt;strong&gt;lo hemos añadido a la tabla "200"&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;5) &lt;code&gt;ip rule add from all uidrange &amp;lt;uid_range&amp;gt; lookup 200&lt;/code&gt;: Creamos nuestra primera regla. Donde todo el trafico generado por el rango de usuarios 1100-1100 deberá dirigirse a ver &lt;strong&gt;la tabla de ruteo "200"&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Ahora tomaremos una pausa de usar comandos y examinaremos como están nuestras tablas de ruteo y reglas. Usemos &lt;code&gt;ip rule&lt;/code&gt;, &lt;code&gt;ip route show table 200&lt;/code&gt; y &lt;code&gt;ip route&lt;/code&gt;. Veamos como va nuestro networking:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ip rule&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0:  from all lookup local
32765:  from all uidrange 1100-1100 lookup 200
32766:  from all lookup main
32767:  from all lookup default
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cuando el sistema necesite enviar un paquete por red lo primero que revisara son las reglas. Como pueden ver ahora (a diferencia de cuando OpenVPN se auto-configura como Full Tunnel) es que existe una nueva regla. Y esta posicionada &lt;strong&gt;antes&lt;/strong&gt; de &lt;em&gt;main&lt;/em&gt;. Cualquier paquete emitido por el rango de usuarios 1100-1100 deberá a ir a ver la tabla de ruteo "200".&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ip route&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;default via 192.168.1.1 dev enp0s3 proto dhcp src 192.168.1.13 metric 100 
192.168.1.0/24 dev enp0s3 proto kernel scope link src 192.168.1.13 metric 100 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La tabla &lt;em&gt;main&lt;/em&gt; no ha sufrido ningún cambio. Todo lo que llegue a esta tabla usara la interfaz &lt;code&gt;enp0s3&lt;/code&gt; ya sea para salir a internet por la gateway &lt;code&gt;192.168.1.1&lt;/code&gt; o para ir a algún otro destino en la red local &lt;code&gt;192.168.1.0/24&lt;/code&gt;. Siempre usando como IP de origen &lt;code&gt;192.168.1.13&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ip route show table 200&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;default via 10.10.238.1 dev tun0 src 10.10.238.249 
10.10.238.0/24 dev tun0 scope link src 10.10.238.249
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finalmente nuestra nueva tabla de ruteo "200", creada durante el comando 3 y 4. Como pueden ver es muy similar a la tabla &lt;em&gt;main&lt;/em&gt;. Cualquier paquete que llegue a esta tabla usara la interfaz &lt;code&gt;tun0&lt;/code&gt;, ya sea para salir a internet por la gateway &lt;code&gt;10.10.238.1&lt;/code&gt; o para ir a algún otro destino de la red &lt;code&gt;10.10.238.0/24&lt;/code&gt;. Siempre usando como IP de origen &lt;code&gt;10.10.238.249&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Si ahora reflexionamos sobre estas reglas y tablas de ruteo podemos tratar de inferir que pasará con los paquetes de datos en diversas condiciones:&lt;/p&gt;

&lt;p&gt;-¿Si un paquete va a &lt;em&gt;localhost&lt;/em&gt; o &lt;em&gt;broadcast&lt;/em&gt;? -&amp;gt; Se usa la tabla de ruteo "local".&lt;br&gt;
-¿Si un paquete fue generado por UID 1100? -&amp;gt; La segunda regla hace &lt;em&gt;match&lt;/em&gt; y se aplicar la tabla de ruteo "200", donde se especifica el uso de la interfaz &lt;code&gt;tun0&lt;/code&gt;.&lt;br&gt;
-¿Si un paquete no coincide con la primera y segunda regla? -&amp;gt; Se usa la tabla de ruteo &lt;em&gt;main&lt;/em&gt;, y por ende, la interfaz &lt;code&gt;enp0s3&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Genial! &lt;/p&gt;

&lt;p&gt;Pero lamentablemente &lt;strong&gt;no&lt;/strong&gt; hemos terminado. Dada la configuración anterior, existen 4 escenarios donde nuestro networking va a fallar. Veamos cada uno de estos casos "especiales" y como abordarlos:&lt;/p&gt;

&lt;p&gt;6) &lt;code&gt;ip rule add from &amp;lt;tun0_network&amp;gt; lookup 200&lt;/code&gt;: En Linux existe algo llamado &lt;a href="https://support.luminex.be/portal/en/kb/articles/linux-reverse-path-filtering-and-multicast-packet-drops-on-embedded-devices#Introduction" rel="noopener noreferrer"&gt;rpfilter&lt;/a&gt;. Este es un mecanismo que se asegura que no recibamos ataques de &lt;em&gt;sniffing&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;Este tipo de ataques se basa alterar los paquetes entrantes al equipo para acceder a zonas de la red que no deberían y "mapear" posibles puntos de ataque. Con &lt;em&gt;rpfilter&lt;/em&gt; el sistema se asegura que todas las respuestas a paquetes que entren por una interfaz &lt;code&gt;X&lt;/code&gt;, usen la misma interfaz &lt;code&gt;X&lt;/code&gt; para salir. De esta manera, al menos que una configuración de networking diga lo contrario, se mantienen aisladas las redes a las cuales esta conectado nuestro sistema (evitando el &lt;em&gt;sniffing&lt;/em&gt;). El &lt;em&gt;rpfilter&lt;/em&gt; esta implementado a nivel Kernel generalmente. En caso de NixOS el &lt;em&gt;rpfilter&lt;/em&gt; esta presente como reglas del firewall &lt;code&gt;iptables&lt;/code&gt; (específicamente en la tabla &lt;em&gt;mangle chain nixos-fw-rpfilter&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;Resulta que el &lt;em&gt;rpfilter&lt;/em&gt; bloqueara los paquetes que entren a &lt;code&gt;tun0&lt;/code&gt;, ya que al verificar la interfaz de salida (respuesta) encontrara a &lt;code&gt;enp0s3&lt;/code&gt;. Esto provoca que &lt;em&gt;rpfilter&lt;/em&gt; piense que se tratan paquetes que están tratando de hacer &lt;em&gt;sniffing&lt;/em&gt;. ¿Pero porque sucede esto? Porque solo el usuario 1100 tiene las reglas para usar &lt;code&gt;tun0&lt;/code&gt; y el &lt;em&gt;rpfilter&lt;/em&gt; es administrado por &lt;code&gt;root&lt;/code&gt; (UID 0). Por tanto, es imposible que el &lt;em&gt;rpfilter&lt;/em&gt;  realice correctamente su trabajo... no puede ni acceder a &lt;code&gt;tun0&lt;/code&gt; para ver si los paquetes entrantes también salen por ahí. &lt;/p&gt;

&lt;p&gt;Con esta regla que hemos añadido estamos ayudando &lt;em&gt;rpfilter&lt;/em&gt;. Básicamente se lee como: "si algo entra por &lt;code&gt;10.10.238.0/24&lt;/code&gt;, usa la tabla de ruteo 200 para ver como responder", o sea, "si entra por &lt;code&gt;tun0&lt;/code&gt;, sale por &lt;code&gt;tun0&lt;/code&gt;, independiente del usuario que este manipulando el paquete de datos". &lt;/p&gt;

&lt;p&gt;7) &lt;code&gt;ip rule add to &amp;lt;openvpn_peer_ip&amp;gt; lookup main&lt;/code&gt;: ¿Que pasa si el usuario 1100 intenta comunicarse con la IP publica del servidor VPN?. Pues como la regla &lt;code&gt;uidrange 1100-1100 lookup 200&lt;/code&gt; esta antes que &lt;code&gt;lookup main&lt;/code&gt;, el sistema va a insistir que el usuario 1100 use la tabla "200". Y esto no tiene sentido... porque no podemos alcanzar la IP publica del servidor VPN (&lt;code&gt;184.75.223.237&lt;/code&gt;) desde el interior de túnel. Entonces, esta regla la anteponemos a &lt;code&gt;uidrange 1100-1100 lookup 200&lt;/code&gt; para asegurarnos que, independiente del usuario, todo paquete dirigido a la IP publica del servidor VPN (&lt;code&gt;184.75.223.237&lt;/code&gt;) debe usar la tabla &lt;em&gt;main&lt;/em&gt;, o sea, interfaz &lt;code&gt;enp0s3&lt;/code&gt;. Comprendo que esta regla puede ser algo extraña, pero recuerden: desde el interior del túnel, por recursividad, no se puede llegar a la IP publica del servidor VPN. &lt;/p&gt;

&lt;p&gt;8) &lt;code&gt;ip rule add to &amp;lt;enp0s3_network&amp;gt; lookup main&lt;/code&gt;: Esta regla tiene un fin parecido a la anterior. ¿Que pasa si el usuario 1100 quiere comunicarse con un dispositivo de la red local... por ejemplo una impresora?... pues la regla &lt;code&gt;uidrange 1100-1100 lookup 200&lt;/code&gt; lo va a obligar a usar la interfaz &lt;code&gt;tun0&lt;/code&gt;. Pero claramente desde el túnel es imposible llegar a nuestra impresora. Esta regla la anteponemos a &lt;code&gt;uidrange 1100-1100 lookup 200&lt;/code&gt;, para obligar que cualquier trafico, independiente del usuario, que se apunte a algún dispositivo de la red &lt;code&gt;192.168.1.0/24&lt;/code&gt;, use la tabla &lt;em&gt;main&lt;/em&gt; y por ende la interfaz &lt;code&gt;enp0s3&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;9) &lt;code&gt;ip rule add to &amp;lt;tun0_dns&amp;gt; lookup 200&lt;/code&gt;: Esta ultima regla es para que el DNS funcione correctamente en modo Split Tunnel. Resulta que el sistema operativo no tiene una funcionalidad por defecto de tener algo como "Split DNS" (para eso debemos usar otras herramientas como &lt;a href="https://unbound.docs.nlnetlabs.nl/en/latest/" rel="noopener noreferrer"&gt;Unbound&lt;/a&gt;). Por tanto, tenemos que definir un solo DNS para todo el sistema, independiente del usuario que este requiriendo resolver un hostname. Si no añadimos esta regla, solo el usuario &lt;code&gt;vpn_user&lt;/code&gt; podrá acceder a usar el DNS que se ha definido en &lt;code&gt;/etc/resolv.conf&lt;/code&gt; (automáticamente durante el inicio de de OpenVPN). Si otro usuario, como &lt;code&gt;root&lt;/code&gt; o &lt;code&gt;nixos&lt;/code&gt; intentan resolver un hostname, trataran de usar &lt;code&gt;10.10.238.1&lt;/code&gt; pero, dadas las reglas, van a ser dirigidos a la tabla &lt;em&gt;main&lt;/em&gt;; lugar por el cual es imposible llegar a &lt;code&gt;10.10.238.1&lt;/code&gt; de &lt;code&gt;tun0&lt;/code&gt;. Con esta novena regla nos aseguramos que, independiente del usuario, cualquier parte del sistema que requiera resolver un hostname, pueda usar la tabla "200" para llegar al servidor DNS que ofrece el proveedor VPN. &lt;/p&gt;

&lt;p&gt;Nota: En caso que usen un DNS como &lt;code&gt;1.1.1.1&lt;/code&gt; o &lt;code&gt;8.8.8.8&lt;/code&gt; deberán configurar esta regla con dicho valor para hacer las consultas a esos servidores DNS usando el túnel. En caso contrario las resoluciones ocuparan la interfaz &lt;code&gt;enp0s3&lt;/code&gt; y el ISP podrá detectar a que dominós se esta conectado (para evitar esto ultimo pueden investigar sobre el uso de DoT o DoH &lt;a href="https://www.cloudflare.com/learning/dns/dns-over-tls/" rel="noopener noreferrer"&gt;aqui&lt;/a&gt;). &lt;/p&gt;

&lt;p&gt;Si volvemos a usar &lt;code&gt;ip rule&lt;/code&gt;, &lt;code&gt;ip route&lt;/code&gt; y &lt;code&gt;ip route show table 200&lt;/code&gt; deberíamos ver:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ip rule&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0:  from all lookup local
32761:  from all to 192.168.1.0/24 lookup main
32762:  from all to 184.75.223.237 lookup main
32763:  from 10.10.238.0/24 lookup 200
32764:  from all to 10.10.238.1 lookup 200
32765:  from all uidrange 1100-1100 lookup 200
32766:  from all lookup main
32767:  from all lookup default
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Ojo, miren la importancia del orden de cada regla&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;ip route&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;default via 192.168.1.1 dev enp0s3 proto dhcp src 192.168.1.13 metric 100 
192.168.1.0/24 dev enp0s3 proto kernel scope link src 192.168.1.13 metric 100
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;ip route show table 200&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;default via 10.10.238.1 dev tun0 src 10.10.238.249 
10.10.238.0/24 dev tun0 scope link src 10.10.238.249 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Realizando pruebas
&lt;/h3&gt;

&lt;p&gt;Una vez usemos las 9 instrucciones deberíamos tener nuestro Split Tunnel funcionando. Vamos a realizar algunas pruebas: &lt;/p&gt;

&lt;p&gt;Si hacemos con nuestro usuario &lt;code&gt;nixos&lt;/code&gt; (normal):&lt;/p&gt;

&lt;p&gt;&lt;code&gt;curl https://ipv4.ipleak.net/json/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Deberíamos ver como respuesta nuestra IP publica, muestra nuestro IPS y el país donde residimos... o sea, &lt;strong&gt;no&lt;/strong&gt; esta usando la VPN.&lt;/p&gt;

&lt;p&gt;Y lo mismo para el usuario &lt;code&gt;root&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sudo curl https://ipv4.ipleak.net/json/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Deberíamos ver que el túnel &lt;strong&gt;no&lt;/strong&gt; se usa.&lt;/p&gt;

&lt;p&gt;PERO si usamos nuestro usuario &lt;code&gt;vpn_user&lt;/code&gt;, con UID 1100:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sudo -u vpn_user curl https://ipv4.ipleak.net/json/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Magia! Dicha solicitud web esta saliendo por el túnel. Deberíamos ver una IP que no se puede asociar a nosotros a igual que una IPS y país distinto. &lt;/p&gt;

&lt;h4&gt;
  
  
  Pruebas de DNS
&lt;/h4&gt;

&lt;p&gt;También podemos realizar pruebas para asegurar que no tenemos DNS Leak. Existe un método usando la terminal y pueden encontrar los detalles &lt;a href="https://airvpn.org/forums/topic/14737-api/" rel="noopener noreferrer"&gt;aqui&lt;/a&gt;. Lo primero que deberán hacer es &lt;a href="https://pinetools.com/es/generador-cadenas-aleatorias" rel="noopener noreferrer"&gt;generar&lt;/a&gt; una cadena de 40 caracteres aleatorios, esta sera la "session". Luego deberán hacer un &lt;code&gt;curl&lt;/code&gt; a la siguiente URL usando dicha "session". Deben hacer varios &lt;code&gt;curl&lt;/code&gt; consecutivos usando la misma "session", pero en cada una de ellas cambiar el valor de "random".&lt;/p&gt;

&lt;p&gt;&lt;code&gt;curl https://[session]-[random].ipleak.net/dnsdetection/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Las respuestas que acumulen de cada &lt;code&gt;curl&lt;/code&gt; empezarán a formar un "mapeo" de los servidores DNS que se están usando. Luego tiene que tomar dichas IPs de respuesta e investigar mediante &lt;em&gt;reverse IP lookup&lt;/em&gt; (&lt;a href="https://dnschecker.org/reverse-dns.php" rel="noopener noreferrer"&gt;link1&lt;/a&gt;, &lt;a href="https://mxtoolbox.com/ReverseLookup.aspx" rel="noopener noreferrer"&gt;link2&lt;/a&gt;, &lt;a href="https://hackertarget.com/reverse-dns-lookup/" rel="noopener noreferrer"&gt;link3&lt;/a&gt;) a que servidores corresponden. &lt;/p&gt;

&lt;p&gt;Si su DNS esta correcto deberían ver que el servidor DNS usado no puede ser asociado a ustedes geográficamente. &lt;/p&gt;

&lt;p&gt;Luego, generando una nueva "session", repitan el proceso para los otros usuarios: &lt;code&gt;sudo curl...&lt;/code&gt;,  &lt;code&gt;sudo -u vpn_user curl...&lt;/code&gt;; el resultado debería ser siempre el mismo.&lt;/p&gt;

&lt;p&gt;Si el DNS que detectan es geograficamente cercano a ustedes, algo no esta funcionando bien y tienen DNS Leak.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Split Tunnel basado en usuarios y sin DNS Leak funcionando :)&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Automatizando el proceso
&lt;/h2&gt;

&lt;p&gt;Claramente ejecutar 9 comandos y ademas tener que leer los logs de OpenVPN para configurar el Split Tunnel es... lento, fácil de cometer errores... no gracias. Bueno, podemos automatizar esto.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Kromtar/OpenVPN_SplitTunnel_NixOS" rel="noopener noreferrer"&gt;Aquí pueden encontrar un script&lt;/a&gt; que automatiza el proceso. Yo lo he guardado en &lt;code&gt;/etc/nixos/vpn_custom_script.sh&lt;/code&gt;. Y debe ser integrado haciendo estos cambios en su &lt;code&gt;configuration.nix&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
services.openvpn = {
  servers = {
    airVPN = {
      config = "config /etc/nixos/airvpn.ovpn \n route-noexec \n ifconfig-noexec";
      updateResolvConf = true;
      up = ''
        UID_RANGE="1100-1100"
        CUSTOM_SCRIPT_MODE="up"
        ${builtins.readFile /etc/nixos/vpn_custom_script.sh}
      '';
      down = ''
        UID_RANGE="1100-1100"
        CUSTOM_SCRIPT_MODE="down"
        ${builtins.readFile /etc/nixos/vpn_custom_script.sh}
      '';
    };
  };
};
systemd.services.openvpn-airVPN.path = [ pkgs.gawk pkgs.ipcalc ];
... 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La integración de OpenVPN en NixOS nos da el parámetro declarativo &lt;a href="https://search.nixos.org/options?channel=25.05&amp;amp;show=services.openvpn.servers.%3Cname%3E.up&amp;amp;from=0&amp;amp;size=50&amp;amp;sort=relevance&amp;amp;type=packages&amp;amp;query=services.openvpn." rel="noopener noreferrer"&gt;up&lt;/a&gt; y &lt;a href="https://search.nixos.org/options?channel=25.05&amp;amp;show=services.openvpn.servers.%3Cname%3E.down&amp;amp;from=0&amp;amp;size=50&amp;amp;sort=relevance&amp;amp;type=packages&amp;amp;query=services.openvpn." rel="noopener noreferrer"&gt;down&lt;/a&gt;. La &lt;strong&gt;cadena de texto&lt;/strong&gt; pasada a estos parámetros será "incrustada" en los scripts del ciclo de vida del servicio de OpenVPN. Lo indicado en &lt;code&gt;up&lt;/code&gt; se ejecutará luego que OpenVPN termine de iniciar. Lo indicado en &lt;code&gt;down&lt;/code&gt; luego que el servicio se detenga. Estos son lugares perfectos para añadir funcionalidades que estén relacionadas en manipular la red. &lt;/p&gt;

&lt;p&gt;Nuestro &lt;code&gt;vpn_custom_script.sh&lt;/code&gt;, dependiendo del valor &lt;code&gt;CUSTOM_SCRIPT_MODE&lt;/code&gt;, aplica o revierte las manipulaciones de red. El único valor que tenemos que definir manualmente es el rango de UID de usuarios en &lt;code&gt;UID_RANGE&lt;/code&gt;. Estos son los usuarios cuyo trafico sera dirigido por dentro del túnel. &lt;/p&gt;

&lt;p&gt;Nota 1: Usamos &lt;code&gt;builtins.readFile&lt;/code&gt; para leer el contenido del &lt;code&gt;.sh&lt;/code&gt; y pasarlo como cadena de caracteres a &lt;code&gt;up&lt;/code&gt; y &lt;code&gt;down&lt;/code&gt;. Esto ya que dichos parámetros no esperan un &lt;em&gt;path&lt;/em&gt; a un script, sino, literalmente una cadena de texto que sera incrustada a los &lt;code&gt;.sh&lt;/code&gt; de OpenVPN. Pueden ver &lt;a href="https://github.com/NixOS/nixpkgs/blob/nixos-25.05/nixos/modules/services/networking/openvpn.nix" rel="noopener noreferrer"&gt;aquí&lt;/a&gt; para mas información. &lt;/p&gt;

&lt;p&gt;Nota 2: En &lt;code&gt;systemd.services.openvpn-airVPN.path&lt;/code&gt; hemos añadido, al estilo NixOS, los paquetes que son usados al interior de &lt;code&gt;vpn_custom_script.sh&lt;/code&gt;: &lt;a href="https://search.nixos.org/packages?channel=25.05&amp;amp;show=gawk&amp;amp;from=0&amp;amp;size=50&amp;amp;sort=relevance&amp;amp;type=packages&amp;amp;query=awk" rel="noopener noreferrer"&gt;gawk&lt;/a&gt; y &lt;a href="https://search.nixos.org/packages?channel=25.05&amp;amp;show=ipcalc&amp;amp;from=0&amp;amp;size=50&amp;amp;sort=relevance&amp;amp;type=packages&amp;amp;query=ipcalc" rel="noopener noreferrer"&gt;ipcalc&lt;/a&gt;. Sin esta referencia, NixOS no podrá encontrar los &lt;em&gt;path&lt;/em&gt; a los binarios necesarios. &lt;/p&gt;

&lt;p&gt;Nota 3: Puede que te extrañe, que al interior de &lt;code&gt;vpn_custom_script.sh&lt;/code&gt;, existen algunas variables como &lt;code&gt;$ifconfig_netmask&lt;/code&gt; que parecieran ser usadas "de la nada" sin ser nunca declaradas. Realmente el valor de estas variables corresponde a variables de entorno que OpenVPN usa en su proceso. Por tanto, como el contenido de &lt;code&gt;vpn_custom_script.sh&lt;/code&gt; esta siendo "incrustado" a los &lt;code&gt;.sh&lt;/code&gt; propios de OpenVPN, podemos aprovechar de acceder a sus variables de entorno. Lugar donde, por fortuna, están los principales parámetros de red de la VPN. Puedes ver mas &lt;a href="https://github.com/NixOS/nixpkgs/blob/nixos-25.05/nixos/modules/services/networking/openvpn.nix" rel="noopener noreferrer"&gt;aquí&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Si no tienes NixOS
&lt;/h3&gt;

&lt;p&gt;Como he dicho al inicio, este artículo esta pensado en NixOS. Así que si usas otra distribución de Linux te tocará idear como automatizar el proceso para tu ambiente. Espero que el script te pueda servir de inspiración para encontrar la mejor solución a tu caso. &lt;/p&gt;

&lt;p&gt;El mayor desafió es encontrar el valor de las IPs y redes involucradas en la VPN. Para eso tienes 2 opciones. 1) De alguna manera acceder a las variables de entorno que maneja de OpenVPN (como lo hace mi script) o 2) usar &lt;code&gt;journalctl -b | grep 'openvpn'&lt;/code&gt; para obtener y procesar el texto de los logs de OpenVPN. Generalmente OpenVPN permite añadir al &lt;code&gt;.ovpn&lt;/code&gt; &lt;em&gt;paths&lt;/em&gt; a scripts que deben ser ejecutados durante su proceso de inicio (&lt;em&gt;up&lt;/em&gt;) y cierre (&lt;em&gt;down&lt;/em&gt;). Es aquí el mejor lugar para que ustedes realicen la referencia a los scripts que vayan a usar en su proceso de automatización. Relacionado a esto, les recomiendo leer sobre &lt;em&gt;script-security&lt;/em&gt; de OpenVPN. También, como ultimo consejo, no olviden tener, al igual que un script de &lt;em&gt;seteo&lt;/em&gt;, un script para revertir todas las reglas y ruteos cuando OpenVPN se apaga o reinicia. Si no hacen esto, podrían llegar a corromper su networking. &lt;/p&gt;




&lt;h2&gt;
  
  
  Bonus: la regla inversa, que todos los usuarios, menos uno, usen el túnel
&lt;/h2&gt;

&lt;p&gt;He decidido añadir este bonus donde explico, rápidamente, como lograr la "negación" de nuestro Split Tunnel. Que todos los usuarios, menos uno, usen OpenVPN.&lt;/p&gt;

&lt;p&gt;Para esto deben reemplazar las reglas de ruteo para usar los rangos de esta manera. Supongamos que queremos mantener el trafico del usuario UID 1100 &lt;strong&gt;fuera&lt;/strong&gt; del túnel.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ip rule add from all uidrange 0-1099 lookup 200&lt;/code&gt;&lt;br&gt;
&lt;code&gt;ip rule add from all uidrange 1101-65535 lookup 200&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Nota: Verifiquen en su distribución cual es el máximo valor UID que puede existir. En NixOS es 65535. &lt;/p&gt;

&lt;p&gt;Luego deberán hacer solo un cambio mas. Tiene que ver con el &lt;code&gt;rpfilter&lt;/code&gt;. Debemos tener una regla que asegure que todo el trafico que llega por &lt;code&gt;enp0s3&lt;/code&gt; salga por &lt;code&gt;enp0s3&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;ip rule add from 192.168.1.0/24 lookup main&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Esto se necesita ya que ahora &lt;code&gt;root&lt;/code&gt; (usuario dueño de &lt;code&gt;rpfilter&lt;/code&gt;) siempre estará usando el &lt;code&gt;tun0&lt;/code&gt; y provocará que cuando se encuentre con trafico del usuario 1100, y lo analice para ver si hay &lt;em&gt;sniffing&lt;/em&gt;, no pueda usar la interfaz &lt;code&gt;enp0s3&lt;/code&gt; para ver la salida del mismo. Con esta regla lo solucionamos. &lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusión
&lt;/h2&gt;

&lt;p&gt;Espero que este artículo los ayudará a comprender mejor cómo funciona el networking que gestiona OpenVPN y como lograr tener un Split Tunnel. Los invito a leer más de mis artículos, donde hablo generalmente en profundidad de seguridad, NixOS y Home Servers.&lt;/p&gt;

&lt;p&gt;Sin nada más que añadir, que tengan un lindo día experimentando :)  &lt;/p&gt;

</description>
      <category>spanish</category>
      <category>openvpn</category>
      <category>nixos</category>
      <category>networking</category>
    </item>
    <item>
      <title>Desbloqueo remoto LUKS, una solución innovadora - NixOS</title>
      <dc:creator>Federico Jensen</dc:creator>
      <pubDate>Thu, 22 May 2025 02:27:48 +0000</pubDate>
      <link>https://dev.to/federico_jensen/desbloqueo-remoto-luks-una-solucion-innovadora-nixos-1g25</link>
      <guid>https://dev.to/federico_jensen/desbloqueo-remoto-luks-una-solucion-innovadora-nixos-1g25</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Ninguna IA ha estado involucrada en la creación de este articulo.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  En este articulo veremos:
&lt;/h2&gt;

&lt;p&gt;Como lograr &lt;strong&gt;desbloquear remotamente&lt;/strong&gt; nuestro &lt;a href="https://nixos.org/" rel="noopener noreferrer"&gt;NixOS&lt;/a&gt; que use &lt;a href="https://gitlab.com/cryptsetup/cryptsetup" rel="noopener noreferrer"&gt;LUKS&lt;/a&gt; como medida de cifrado completo. Esto será posible ya que, durante el Boot, nuestro OS solicitará a un "dispositivo remoto autorizado", por ejemplo nuestro celular, la clave LUKS. Como intermediario de comunicación usaremos &lt;a href="https://ntfy.sh/" rel="noopener noreferrer"&gt;Ntfy&lt;/a&gt; y todo el intercambio de información estará cifrado con múltiples capas de seguridad. Finalmente, y como algo opcional, abordaremos la integración de &lt;a href="https://airvpn.org/" rel="noopener noreferrer"&gt;AirVPN (OpenVPN)&lt;/a&gt; como una VPN que se usara durante el Boot para asegurar la comunicación. También abordaremos detalles respecto a posibles DNS leak del proceso.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Esta solución nace desde la imposibilidad, en circunstancias normales, de desbloquear un servidor NixOS que tenga LUKS de alguna forma que no requiera la presencia física de un humano con dicha maquina.&lt;/strong&gt; En mi caso tengo un HomeLab que, físicamente, se encuentra en un lugar remoto y donde no tengo acceso habitual. Luego de cortes energéticos o reinicios de emergencia, era para mi un fastidio tener que ir físicamente a introducir la clave LUKS para que mi servidor iniciara nuevamente a su funcionamiento habitual. Buscando soluciones a esto, solo encontré el proyecto &lt;a href="https://github.com/latchset/clevis" rel="noopener noreferrer"&gt;Clevis&lt;/a&gt;-&lt;a href="https://github.com/latchset/tang" rel="noopener noreferrer"&gt;Tang&lt;/a&gt;, un servidor de autentificación LUKS, que podría ayudar con mi problema. Pero sus características técnicas no se adecuaron a mis necesidades; requiriendo modificaciones profundas del proyecto para poder adaptarlo a mis circunstancias. Tales como: una funcionalidad asíncrona del sistema, la capacidad manual de introducir la clave LUKS, la autorización por parte de dispositivos específicos y la funcionalidad de usar un celular como "terminal remoto". Con ello, nace esta idea. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;La propuesta que presento es estable y puede ser implementada con confianza. La lógica de seguridad que usaremos es resiliente a diversos vectores de ataque, tales como: Men-in-the-middle, fuerza bruta, intervención/secuestro/inyección de paquetes de datos y suplantación de identidad. A pesar de esto, es aun una obra en progreso y muchas mejoras pueden ser realizadas.&lt;/p&gt;

&lt;p&gt;Este articulo también es una invitación a, exactamente, mejorar esta propuesta y añadir nuevas funcionalidades. &lt;/p&gt;

&lt;p&gt;A continuación podrán encontrar dos &lt;strong&gt;videos tutoriales&lt;/strong&gt; relacionados a este articulo. El primero es una introducción y el segundo toda la guiá de implementación. Los códigos que usamos (aunque son pocos) los pueden encontrar aquí: &lt;a href="https://github.com/Kromtar/RemoteLuksUnlockNixOs" rel="noopener noreferrer"&gt;-GitHub-&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Video Introducción:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://odysee.com/@Federico_Jensen:7/desbloqueo-remoto-luks-nixos-intro" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthumbnails.odycdn.com%2Fcard%2Fs%3A1280%3A720%2Fquality%3A85%2Fplain%2Fhttps%3A%2F%2Fthumbs.odycdn.com%2Fd72591f8c8227034dae74a3cd6ceb397.webp" height="auto" class="m-0"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://odysee.com/@Federico_Jensen:7/desbloqueo-remoto-luks-nixos-intro" rel="noopener noreferrer" class="c-link"&gt;
            Desbloqueo remoto LUKS - NixOS - Introducción
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Video introductorio sobre una implementación para desbloquear, de manera remota, un NixOS protegido mediante LUKS.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fodysee.com%2Fpublic%2Ffavicon_128.png"&gt;
          odysee.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Video Implementación:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://odysee.com/@Federico_Jensen:7/desbloqueo_remoto_luks-nixos-implementacion" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthumbnails.odycdn.com%2Fcard%2Fs%3A1280%3A720%2Fquality%3A85%2Fplain%2Fhttps%3A%2F%2Fthumbs.odycdn.com%2Faf7662619e353511e9e7c044c8a27fb1.webp" height="auto" class="m-0"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://odysee.com/@Federico_Jensen:7/desbloqueo_remoto_luks-nixos-implementacion" rel="noopener noreferrer" class="c-link"&gt;
            Desbloqueo remoto LUKS - NixOS - Implementación
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Video donde vemos, en profundidad, la implementación de un sistema para desbloquear remotamente un NixOS con LUKS.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fodysee.com%2Fpublic%2Ffavicon_128.png"&gt;
          odysee.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Requisitos
&lt;/h2&gt;

&lt;p&gt;1- El requisito mas importante es que nuestro &lt;a href="https://nixos.org/" rel="noopener noreferrer"&gt;NixOS&lt;/a&gt; tenga conectividad a internet durante Stage1 del proceso de Boot. Claramente, si nuestro sistema no tiene red, sera imposible realizar un proceso de descifrado remoto. En &lt;a href="https://dev.to/federico_jensen/red-y-ssh-en-stage1-boot-initrd-de-nixos-parte-1-28o4"&gt;este articulo&lt;/a&gt; pueden encontrar una guiá completa de como lograr esto.&lt;/p&gt;

&lt;p&gt;1.1- Opcionalmente: tener habilitado en la Stage1, del proceso de Boot, un servidor SSH. Lo anterior, para facilitar el &lt;em&gt;debugeo&lt;/em&gt; ante posibles errores en el proceso de implementación. &lt;a href="https://dev.to/federico_jensen/red-y-ssh-en-stage1-boot-initrd-de-nixos-parte-1-28o4"&gt;En el articulo&lt;/a&gt; donde explico como tener internet en Stage1, también explico como habilitar un servidor SSH para estos propósitos. Nuevamente, esto es solo opcional y algo útil de tener habilitado en caso de encontrarnos con errores inesperados durante el Boot. &lt;/p&gt;


&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/federico_jensen/red-y-ssh-en-stage1-boot-initrd-de-nixos-parte-1-28o4" class="crayons-story__hidden-navigation-link"&gt;Red y SSH en Stage1 (boot - initrd) de NixOS - Parte 1&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/federico_jensen" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2986200%2F2cd0eeba-f0ca-49b4-b9ba-44af10bcb14e.png" alt="federico_jensen profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/federico_jensen" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Federico Jensen
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Federico Jensen
                
              
              &lt;div id="story-author-preview-content-2375422" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/federico_jensen" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2986200%2F2cd0eeba-f0ca-49b4-b9ba-44af10bcb14e.png" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Federico Jensen&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/federico_jensen/red-y-ssh-en-stage1-boot-initrd-de-nixos-parte-1-28o4" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Apr 4 '25&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/federico_jensen/red-y-ssh-en-stage1-boot-initrd-de-nixos-parte-1-28o4" id="article-link-2375422"&gt;
          Red y SSH en Stage1 (boot - initrd) de NixOS - Parte 1
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/spanish"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;spanish&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/nixos"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;nixos&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/linux"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;linux&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
            &lt;a href="https://dev.to/federico_jensen/red-y-ssh-en-stage1-boot-initrd-de-nixos-parte-1-28o4#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              &lt;span class="hidden s:inline"&gt;Add Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            13 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


&lt;p&gt;2- Estar dispuestos en usar &lt;a href="https://ntfy.sh/" rel="noopener noreferrer"&gt;Ntfy&lt;/a&gt; como nuestro "intermediario" para enviar y recibir mensajes entre el NixOS y el "dispositivo remoto" desde donde desbloquearemos la unidad LUKS. Ntfy ofrece canales de comunicación con funcionalidades pub/sub gratuitos y de alta disponibilidad. El gran "pero" es que los canales son públicos. A pesar de ello, el sistema propuesto usa diferentes métodos criptográficos donde esto &lt;strong&gt;no afecta la seguridad de la solución&lt;/strong&gt;. Esta guiá usa exclusivamente Ntfy, aunque los invito a tomar la iniciativa y hacer implementación para otros intermediarios de comunicación como: Plugins para Discord, sistemas basados en Email, conexiones directas/privadas entre NixOS y otro servidor... la imaginación es el limite.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4vu1irxsg1y0wdovscxl.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4vu1irxsg1y0wdovscxl.jpg" alt="Ntfy logo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;3- En caso de seguir la parte final de este articulo: "Implementación de una VPN para el proceso de desbloqueo remoto (opcional)", estar dispuestos a pagar por los servicios de &lt;a href="https://airvpn.org/" rel="noopener noreferrer"&gt;AirVPN&lt;/a&gt; como proveedor de VPN. Como alternativa, también pueden usar cualquier servidor/proveedor de VPN que sea compatible con el cliente de OpenVPN. Vuelvo a repetir, esto es &lt;strong&gt;opcional&lt;/strong&gt;... yo uso AirVPN en este articulo porque consdiero que es el mejor servicio de VPN actualmente. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdlpxbkhs1vez44dbrmvg.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdlpxbkhs1vez44dbrmvg.webp" alt="AirVPN logo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Por ultimo, hacer un recordatorio que lo expuesto en este articulo es focalizado en NixOS. Aunque no me cabe duda que puede servir de inspiración para realizar una implementación similar en otras distribuciones de Linux.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkxgap4a219ntpktbvrjz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkxgap4a219ntpktbvrjz.png" alt="NixOS logo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Certificados CA TLS
&lt;/h2&gt;

&lt;p&gt;Como parte del proceso para habilitar una forma de desbloqueo remoto de LUKS, nuestro NixOS deberá comunicase con los servidores de Ntfy mediante HTTPS. Lamentablemente durante el Boot del sistema operativo, por defecto, no se encuentran disponibles los &lt;a href="https://es.wikipedia.org/wiki/Autoridad_de_certificaci%C3%B3n" rel="noopener noreferrer"&gt;Certificados CA TLS&lt;/a&gt; para resolver el protocolo HTTPS. Nuestra primera configuración sera añadir estos certificados al proceso de Boot.&lt;/p&gt;

&lt;p&gt;Para esto, en nuestro archivo de configuración &lt;code&gt;/etc/nixos/hardware-configuration.nix&lt;/code&gt; añadiremos unas declaraciones. Específicamente en la sección &lt;code&gt;boot.initrd.systemd.contents&lt;/code&gt;. Esta delcaracion nos permite listar ficheros que deben ser considerados para ser "montados" en el &lt;a href="https://www.kernel.org/doc/html/v4.17/admin-guide/initrd.html" rel="noopener noreferrer"&gt;Ram-Disk/initrd&lt;/a&gt; (sistema de archivos temporal, montado en RAM, usado durante el proceso de Boot de Linux).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;boot = {
  ...
  initrd = {
    ...
    systemd = {
      ...
      contents = {      
        "/etc/ssl/certs/ca-certificates.crt".source = builtins.toFile "ca-certificates.crt" (builtins.readFile "/etc/ssl/certs/ca-certificates.crt");
        "/etc/ssl/certs/ca-bundle.crt".source = builtins.toFile "ca-bundle.crt" (builtins.readFile "/etc/ssl/certs/ca-bundle.crt");
      };
    };
  };
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Nota 1:&lt;/strong&gt; Es buen momento para verificar que boot.initrd.systemd.enable tenga un valor de true. O sea, que estemos usando SystemD para administrar los servicios del proceso de Boot. De todos modos, esto ya deberia estar activado si cumpimos con el requisito de tener internet durante Stage1, ya que es necesario para configurar las interfaces de red correctamente.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nota 2:&lt;/strong&gt; La sintaxis que usamos dentro de &lt;code&gt;contents&lt;/code&gt; para "copiar" los ficheros &lt;code&gt;.crt&lt;/code&gt; al listado de los que deben estar presentes en el proceso de Boot puede parecer algo confuso. El uso de &lt;code&gt;builtins.toFile&lt;/code&gt; y b&lt;code&gt;uiltins.readFile&lt;/code&gt; como métodos auxiliares (&lt;a href="https://nix.dev/manual/nix/2.25/language/builtins" rel="noopener noreferrer"&gt;parte del lenguaje de Nix&lt;/a&gt; se debe a que los &lt;code&gt;.crt&lt;/code&gt; realmente son &lt;em&gt;symlinks&lt;/em&gt;. Para que &lt;code&gt;contents&lt;/code&gt; pueda copiar el contenido de los &lt;code&gt;.crt&lt;/code&gt; correctamente debemos usar estos métodos auxiliares para leer el contenido, traspasarlos a un archivo temporal y luego copiar el contenido de dicho archivo a los que deberán estar disponibles durante el Boot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Clave criptográfica RSA
&lt;/h2&gt;

&lt;p&gt;Ahora debemos generar un par de &lt;a href="https://es.wikipedia.org/wiki/RSA" rel="noopener noreferrer"&gt;claves publico-privada RSA&lt;/a&gt;. Estas servirán para que solo un "dispositivo remoto" autorizado pueda "darle sentido" a los mensajes que están involucrados en descifrar la unidad LUKS de NixOS y que transitaran por Ntfy. La parte privada, de la clave, quedará en el dispositivo remoto y la parte publica la dejaremos en nuestro NixOS.&lt;/p&gt;

&lt;p&gt;Para generar las claves podemos usar &lt;a href="https://www.openssl.org/" rel="noopener noreferrer"&gt;OpenSSL&lt;/a&gt;. Es MUY importante que la calve RSA generada tenga una longitud de &lt;strong&gt;4096bits&lt;/strong&gt;. Para generar la clave privada podemos usar el comando:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;openssl genpkey -algorithm RSA -out private_key.pem -pkeyopt rsa_keygen_bits:4096&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Luego, para generar la parte publica, de dicha clave privada, podemos usar el comando:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;openssl rsa -in private_key.pem -pubout -out public_key.pem&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy88cf620c9xjl1ac12xw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy88cf620c9xjl1ac12xw.png" alt="Creando claves RSA"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;En caso de usar Windows, deberán instalar primero OpenSSL. La forma mas fácil es ejecutando un &lt;em&gt;Power Shell&lt;/em&gt; en modo administrador y luego usando el comando &lt;code&gt;choco install openssl&lt;/code&gt;. Luego de reiniciar la terminal, ya podrán usar los comandos anteriores en Windows para generar la clave.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;La clave privada la dejaremos en el equipo remoto... mas delante la utilizaremos. Ahora nos debemos enfocar en la clave publica. Esta la deberemos dejar en &lt;code&gt;/etc/nixos/&lt;/code&gt; de nuestro NixOS. En mi caso he llamado al archivo que contiene la clave publica &lt;code&gt;public_key.pem&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nota 1:&lt;/strong&gt; La implementación que propongo en este articulo esta preparada para admitir solo un par de claves. Por tanto, si deseamos tener múltiples dispositivos, cada uno con claves distintas (lo recomendado), deberemos entra a programa dicha funcionalidad.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nota 2:&lt;/strong&gt; La necesidad de tener que usar una clave de 4096bits se debe a que, internamente, la implementación que configuremos usara otras claves criptográficas en "modo onion" (capas). Y por longitud de mensajes, debemos hacer que estas sean de 4096bits, en caso contrario las otras "capas" del cifrado superaran el "espacio" permitido. &lt;/p&gt;

&lt;p&gt;Con nuestra clave publica ya en &lt;code&gt;/etc/nixos/public_key.pem&lt;/code&gt;, ahora deberemos disponibilizar ese &lt;code&gt;.pem&lt;/code&gt; en el proceso de Boot (similar a como disponibilizamos los &lt;code&gt;.crt&lt;/code&gt; anteriormente).&lt;/p&gt;

&lt;p&gt;Para esto en nuestro &lt;code&gt;hardware-configuration.nix&lt;/code&gt; usaremos la declaración &lt;code&gt;boot.initrd.secrets&lt;/code&gt; de esta manera:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;boot = {
  ...
  initrd = {
    ...
    secrets = {
      ...
      "/etc/nixos/public_key.pem" = "/etc/nixos/public_key.pem";
    };
  };
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Nota:&lt;/strong&gt; La razón de usar &lt;code&gt;boot.initrd.secrets&lt;/code&gt; para esto y no &lt;code&gt;boot.initrd.systemd.contents&lt;/code&gt; se debe a que, dada las buenas practicas de NixOS, se recomienda el uso de &lt;code&gt;secrets&lt;/code&gt; para... eso... claves; y &lt;code&gt;contents&lt;/code&gt; para ficheros de otra índole.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creando nuestro canal en Ntfy
&lt;/h2&gt;

&lt;p&gt;Crear un canal de Ntfy es extremadamente sencillo. Simplemente debemos ir a la pagina web de &lt;a href="https://ntfy.sh" rel="noopener noreferrer"&gt;Ntfy&lt;/a&gt; (&lt;a href="https://ntfy.sh" rel="noopener noreferrer"&gt;https://ntfy.sh&lt;/a&gt;) y luego añadir en la URL un &lt;code&gt;"/"&lt;/code&gt; continuado de una cadena alfanumérica de caracteres (&lt;code&gt;"-"&lt;/code&gt; y &lt;code&gt;"_"&lt;/code&gt; tambien estan permitidos). Esta "cadena" sera la ID del canal. La idea es que esta "cadena" sea algo aleatorio. Por ejemplo: &lt;code&gt;"UGaCGId_S4w-7rYxtg"&lt;/code&gt;. Ahora cualquiera que acceda a &lt;code&gt;https://ntfy.sh/UGaCGId_S4w-7rYxtg&lt;/code&gt; podrá usar dicho canal para enviar o recibir notificaciones (sistema pub/sub). &lt;/p&gt;

&lt;p&gt;Lo ideal es usar un &lt;a href="https://www.gigacalculator.com/randomizers/random-string-generator.php" rel="noopener noreferrer"&gt;genrador&lt;/a&gt; aleatorio para crear la ID que usaremos para el canal. La longitud máxima de caracteres para la ID es de 64... así que recomiendo usar dicha cantidad. Recordemos guardar la ID que usaremos, ya que la vamos a necesitar en futuras configuraciones.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv55njuzje9et77t3uuz7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv55njuzje9et77t3uuz7.png" alt="Creando canal en Ntfy"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Quiero aprovechar nuevamente de recordar, que aunque el canal de Ntfy es publico, o sea, cualquiera que tenga la ID puede escribir y leer mensajes en dicho canal; nuestra implementación es segura. Esto ya que los mensajes que intercambiaremos entre NixOS y el "dispositivo remoto" estarán cifrados con múltiples capas de seguridad. Estos resguardos nos protegen diversos ataques como: intercepción de paquetes, reutilización de paquetes, análisis de patrones, fuerza bruta, man-in-the-middle y/o suplantación de identidad entre otros posibles vectores. En el Anexo de este articulo pueden leer un poco mas sobre estas medidas de seguridad.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Donde sucede la magia: CustomDecrypt.sh
&lt;/h2&gt;

&lt;p&gt;El Script &lt;em&gt;CustomDecrypt.sh&lt;/em&gt; es el cual realiza toda la "magia". Este Script se iniciara durante Stage1 del proceso de Boot y sera el encargado de todo el proceso de comunicación con Ntfy y posterior desbloqueo de la unidad LUKS. Este Script en su interior realiza varias otras funciones, como:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Comprobar el estado de las unidades de almacenamiento y la precedencia de particiones aseguradas con LUKS.&lt;/li&gt;
&lt;li&gt;Usar la clave publica (correspondiente a la clave privada del "dispositivo remoto") para asegurar los mensajes.&lt;/li&gt;
&lt;li&gt;La generación de claves RSA efímeras axilares para lograr una comunicación de con cifrado de múltiples capas.
&lt;/li&gt;
&lt;li&gt;Enviar la solicitud de la clave LUKS a Ntfy (para que el "dispositivo remoto" reciba una notificación de la necesidad de digitar la clave LUKS).&lt;/li&gt;
&lt;li&gt;Gestionar la "escucha" de respuestas desde Ntfy de mensajes. &lt;/li&gt;
&lt;li&gt;Considerar varios aspectos de integridad y seguridad del proceso de comunicación. &lt;/li&gt;
&lt;li&gt;Desbloquear las unidades LUKS una vez se tenga una clave valida. &lt;/li&gt;
&lt;li&gt;Soportar algunos procesos extra que deben ser considerados en caso de estar usando OpenVPN. &lt;/li&gt;
&lt;li&gt;Considerar algunos escenarios limites en el cual se puede encontrar el proceso de Boot y/o el Script que podrían generar problemas en la secuencia de inicio y/o seguridad. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhw5i70watyrec86j2vhc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhw5i70watyrec86j2vhc.png" alt="Código del CustomDecrypt.sh"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Como pueden ver... son bastantes cosas...&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Como sea, el contenido de &lt;em&gt;CustomDecrypt.sh&lt;/em&gt; lo pueden &lt;a href="https://github.com/Kromtar/RemoteLuksUnlockNixOs/blob/main/CustomDecrypt.sh" rel="noopener noreferrer"&gt;encontrar aquí&lt;/a&gt;. Quiero destacar que el Script es una "obra en progreso", por tanto, no pretende ser perfecto. Poco a poco lo he tenido que ir modificando para ir considerando nuevos escenarios. Los invito a seguir contribuyendo.  &lt;/p&gt;

&lt;p&gt;Una vez descarguen el archivo, lo deben dejar en &lt;code&gt;/etc/nixos/&lt;/code&gt;. Tener cuidado en que el nombre del fichero debe ser &lt;em&gt;CustomDecrypt.sh&lt;/em&gt; para que funcione correctamente con lo que realizaremos a continuación.&lt;/p&gt;

&lt;p&gt;Ahora, como ya hemos realizado anteriormente, debemos disponibilizar &lt;em&gt;CustomDecrypt.sh&lt;/em&gt; para que este presente durante el proceso de Boot. Para esto en &lt;code&gt;boot.initrd.systemd.contents&lt;/code&gt; debemos agregar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
contents = {
  ...
  "/etc/nixos/CustomDecrypt.sh".source = "${/etc/nixos/CustomDecrypt.sh}";
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Nota:&lt;/strong&gt; Podrán notar que en este caso la sintaxis es distinta a la usada con los &lt;code&gt;.crt&lt;/code&gt;. Esto se debe a que &lt;em&gt;CustomDecrypt.sh&lt;/em&gt; es, efectivamente, un fichero. Mientras que los &lt;code&gt;.crt&lt;/code&gt; son &lt;em&gt;symlinks&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Con el archivo ya disponible en Boot, ahora crearemos un servicio para que ejecute este Script en el momento exacto. Para esto usaremos la declaración &lt;code&gt;boot.initrd.systemd.services&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;boot = {
  ...
  initrd = {
    ...
    systemd = {
      ...
      services = {
        ...
        CustomDecrypt = {
          enable = true;
          wants = [ "initrd-nixos-copy-secrets.service" ];
          after = [ "initrd-nixos-copy-secrets.service" ];
          before = [ "systemd-ask-password-console.service" ];
          wantedBy = [ "systemd-ask-password-console.service" ];
          unitConfig = { 
            Description = "CustomDecrypt";
            DefaultDependencies = false;
          };
          serviceConfig = {
            Type = "forking";
            ExecStart="${pkgs.bash}/bin/sh -c 'sh /etc/nixos/CustomDecrypt.sh \"https://ntfy.sh/UGaCGId_S4w-7rYxtg\" \"/etc/nixos/public_key.pem\" &amp;amp;'";
            TimeoutStopSec = "3700s";
          };
        };
      };
    };
  };
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Es importante notar que en &lt;code&gt;ExecStart&lt;/code&gt; pasamos dos parámetros a &lt;em&gt;CustomDecrypt.sh&lt;/em&gt;. El primer parámetro es el canal de Ntfy que usaremos, tengan cuidado de usar https y de indicar correctamente &lt;strong&gt;la ID que corresponda a su canal&lt;/strong&gt;. El segundo parámetro es el &lt;em&gt;path&lt;/em&gt; a la clave publica &lt;code&gt;.pem&lt;/code&gt; (par correspondiente a la clave privada que dejamos en nuestro "dispositivo remoto"). &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nota 1:&lt;/strong&gt; Usamos &lt;code&gt;wants&lt;/code&gt; y &lt;code&gt;after&lt;/code&gt; para ejecutar &lt;em&gt;CustomDecrypt.sh&lt;/em&gt; luego que el proceso de copia de secretos de NixOS esta listo. Y usamos &lt;code&gt;before&lt;/code&gt; y &lt;code&gt;wantedBy&lt;/code&gt; para iniciar el Script antes de que NixOS pregunte, por el terminal, por la clave LUKS.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nota 2:&lt;/strong&gt; El servicio se ejecuta como &lt;em&gt;forking&lt;/em&gt;. De esta manera &lt;em&gt;CustomDecrypt.sh&lt;/em&gt; quedara en &lt;em&gt;background&lt;/em&gt; mientras maneja las comunicaciones de enviado/recepción de mensajes con Ntfy y todos los otros procesos involucrados en el descifrado de LUKS. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nota 3:&lt;/strong&gt; El &lt;code&gt;TimeoutStopSec&lt;/code&gt; de 3700s indica el tiempo máximo que &lt;em&gt;CustomDecrypt.sh&lt;/em&gt; esperara una respuesta remota con la clave LUKS (es un poco mas que una hora). Luego de este tiempo el servicio de &lt;em&gt;CustomDecrypt.sh&lt;/em&gt; terminara, haciendo imposible procesar respuesta remotas con la clave. Esto podrá parecer extraño e incomodo desde el punto de vista del usuario, pero luego veremos que tiene sentido... paciencia. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;CustomDecrypt.sh&lt;/em&gt; recurre al uso de varios comandos como: &lt;code&gt;ip&lt;/code&gt;, &lt;code&gt;curl&lt;/code&gt; y &lt;code&gt;sed&lt;/code&gt; (entre otros) para su funcionamiento. Normalmente estos comandos están integrados en el OS, pero resulta que en el proceso de Boot no. Esto se debe a que el proceso de Boot trata de cargar las mínimas dependencias necesarias para poder funcionar. &lt;/p&gt;

&lt;p&gt;Por tanto, deberemos indicar en nuestro &lt;code&gt;hardware-configuration.nix&lt;/code&gt; que deseamos usar una serie de paquetes "extras" durante el Boot. Esto lo podemos hacer usando la declaración &lt;code&gt;boot.initrd.systemd.initrdBin&lt;/code&gt;. Incluiremos, usando la &lt;a href="https://search.nixos.org/packages" rel="noopener noreferrer"&gt;nomenclatura de NixOS para paquetes&lt;/a&gt;, los siguientes paquetes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;libuuid&lt;/code&gt;: Para el uso de &lt;code&gt;lsblk&lt;/code&gt; y poder listar unidades de almacenamiento.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;gnugrep&lt;/code&gt;: Para el uso de &lt;code&gt;grep&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;cryptsetup&lt;/code&gt;: Para poder manejar particiones que tengan LUKS.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;openssl&lt;/code&gt;: Para crear y manipular claves RSA.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;curl&lt;/code&gt;: Para comunicarnos con HTTPS con Ntfy.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;iproute2&lt;/code&gt;: Para el uso del comando &lt;code&gt;ip&lt;/code&gt; y validar algunas cosas relacionas a la red.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;gnused&lt;/code&gt;: Para el uso de &lt;code&gt;sed&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Para esto añadimos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;boot = {
  ...
  initrd = {
    ...
    systemd = {
      ...
      initrdBin = [ pkgs.libuuid pkgs.gnugrep pkgs.cryptsetup pkgs.openssl pkgs.curl pkgs.iproute2 pkgs.gnused ];
    };
  };
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Nota:&lt;/strong&gt; Si tienen la necesidad de añadir mas paquetes, simplemente los listan en este arreglo.&lt;/p&gt;

&lt;p&gt;Con todo esto estamos listos para crear una nueva generación de NixOS:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sudo nixos-rebuild switch&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvjl24bw5ifkx8k6wl606.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvjl24bw5ifkx8k6wl606.png" alt="Primera prueba"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Y luego reiniciamos. Si todo va bien, deberíamos ver que durante el proceso de Boot, nos llega a nuestro canal de Ntfy un mensaje. &lt;/p&gt;

&lt;h2&gt;
  
  
  Preparando el dispositivo remoto
&lt;/h2&gt;

&lt;p&gt;Ahora que tenemos listo nuestro NixOS, nos toca ocuparnos del "dispositivo remoto", o sea, el dispositivo desde el cual digitaremos la clave LUKS. &lt;/p&gt;

&lt;p&gt;En teoría nuestro "dispositivo remoto" puede ser cualquier cosa que tenga la capacidad de leer/enviar mensajes con Ntfy usando HTTPS y que pueda manipular claves de tipo RSA. O sea, este "dispositivo remoto" podría ser una aplicación de celular, un servidor con una rutina CRON o una plataforma web que hemos programado para este uso especifico... la imaginación es el limite. &lt;/p&gt;

&lt;p&gt;En este articulo, nuestro "dispositivo remoto" sera un Windows donde ejecutaremos un Script Python. El Script lo pueden &lt;a href="https://github.com/Kromtar/RemoteLuksUnlockNixOs/blob/main/remote_script.py" rel="noopener noreferrer"&gt;encontrar aquí&lt;/a&gt;. Es algo un poco "burdo" y "aburrido"... pero mas que suficiente en términos de funcionalidad practica. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;De antemano, me quiero disculpar con lo básico y poco profesional del Script Python. Se que se puede ser mejorado mucho, pero la verdad, es que no he puesto mucho esfuerzo en esta parte del proyecto. Lo importante, es que funciona.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;El Script para funcionar necesita del paquete &lt;a href="https://pypi.org/project/requests/" rel="noopener noreferrer"&gt;requests&lt;/a&gt; y &lt;a href="https://pypi.org/project/pycryptodome/" rel="noopener noreferrer"&gt;pycryptodome&lt;/a&gt;, los cules pueden instalar con &lt;code&gt;pip install requests pycryptodome&lt;/code&gt;. También este Script necesita de dos configuraciones:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;En la variable &lt;code&gt;TOPIC&lt;/code&gt;, dejar la ID del canal de Ntfy que estemos usando.&lt;/li&gt;
&lt;li&gt;En la variable &lt;code&gt;PRIVATE_KEY_PATH&lt;/code&gt; el Path a la clave privada que hemos generado al inicio del guía. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Hora de probar todo:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Usaremos Python para ejecutar el Script. Mientras tengamos activo el Script de Python, vamos a reiniciar NixOS. Durante el proceso de Boot se enviara un mensaje de NixOS a Ntfy, el Script de Python va a reaccionar a dicho mensaje. Luego veremos que el Script de Python nos solicitará introducir la clave LUKS. Luego de digitarla y apretar enter, un nuevo mensaje sera enviado desde el Script de Python a Ntfy. &lt;em&gt;CustomDecrypt.sh&lt;/em&gt;, que corre en NixOS, reaccionara a dicha respuesta y la analizará. Si todo va bien, luego de unos &lt;strong&gt;10 a 15 segundos&lt;/strong&gt; la unidad LUKS terminara de descifrarse y veremos como el proceso de Boot continuara y terminara de forma normal.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjzslddx67jswr4rknp4y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjzslddx67jswr4rknp4y.png" alt="Prueba completa usando Script de Python"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffg7d7vo2w510pr41ue26.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffg7d7vo2w510pr41ue26.png" alt="Prueba completa usando Script de Python, clave aceptada"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Y con eso ya estamos listos ! &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;El Script de Python no necesariamente lo tenemos que tener previamente activo antes que NixOS se reinicie. Si deseamos, podemos primero reiniciar NixOS y luego podemos iniciar el Script de Python. El Script debería poder "recuperar" el ultimo mensaje enviado a Ntfy (el enviado por NixOS), para usarlo en el proceso de solicitar la calve LUKS.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Recordemos que el &lt;code&gt;TimeoutStopSec&lt;/code&gt; de &lt;em&gt;CustomDecrypt.sh&lt;/em&gt; es de 3700 segundos (un poquito mas de 1 hora), por tanto ese sera el plazo de tiempo que tenemos para digitar la clave LUKS desde el momento en que se reinicia NixOS. &lt;/p&gt;

&lt;h3&gt;
  
  
  Móvil Android como "dispositivo remoto"
&lt;/h3&gt;

&lt;p&gt;Es fácil tener como "dispositivo remoto" nuestro celular Android. Solo debemos instalar la aplicación &lt;a href="https://pydroid.app/" rel="noopener noreferrer"&gt;Pydroid 3&lt;/a&gt;. Esta app nos permite ejecutar scripts Python en el celular. Basta que copiemos la clave privada &lt;code&gt;.pem&lt;/code&gt; y el Script &lt;code&gt;.py&lt;/code&gt; a nuestro celular. Y luego usando Pydroid 3 ejecutar el Script. El uso del Script sera exactamente el mismo que en Windows. Recuerda instalar las dependencias de &lt;code&gt;requests&lt;/code&gt; y &lt;code&gt;pycryptodome&lt;/code&gt; en Pydroid 3.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Claramente seria mas elegante con una aplicación dedicada y nativa de celular... en vez de usar un Script de Python. Pero eso ya se los dejo a ustedes para que lo creen. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;También pueden instalar la &lt;a href="https://docs.ntfy.sh/#step-1-get-the-app" rel="noopener noreferrer"&gt;aplicación móvil oficial de Ntfy&lt;/a&gt;. Luego de instalarla pueden "subscribirse" al canal de comunicaciones usando su ID. De esta manera recibirán notificaciones en su celular cuando mensajes lleguen al canal. Esta es una buena manera de enterarse de forma oportuna si nuestro NixOS esta solicitando la clave LUKS. Luego podremos usar el Script de Python desde Pydroid 3 para digitar la clave LUKS, o acercarnos a nuestro computador de escritorio y usar el Script desde ahí.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;En caso de iOS supongo que existe algo similar a Pydroid 3... pero la verdad no he probado. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Implementado un Watchdog en Stage1 del Boot
&lt;/h2&gt;

&lt;p&gt;Hay un aspecto que aun debemos considerar en nuestra implementacion. Y es el uso de un &lt;em&gt;Watchdog&lt;/em&gt; que se encargue de reiniciar el sistema operativo, de forma completa, en caso que dentro un periodo de tiempo determinado, no se desbloquee la unidad LUKS de forma exitosa. Esto lo hacemos por varias razones:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Siempre esta la posibilidad que durante el Boot algo falle. Por ejemplo que, luego de un corte energético, la arquitectura de red aun no esta totalmente restablecida. O que existe alguna falla en el arranque de Stage1 relacionada al &lt;em&gt;hardware&lt;/em&gt;. Un reinicio siempre es la mejor opción para "purgar" y cargar todo limpiamente.&lt;/li&gt;
&lt;li&gt;Nuestro &lt;em&gt;CustomDecrypt.sh&lt;/em&gt; solo acepta claves LUKS durante 3700 segundos (&lt;code&gt;TimeoutStopSec&lt;/code&gt;) desde el momento que iniciar. Si ese tiempo ya ha transcurrido, no hay forma de reiniciar &lt;code&gt;CustomDrcrypt.sh&lt;/code&gt;. Nuestro equipo quedara sin poder terminar el Boot. Reiniciar es la única opción.&lt;/li&gt;
&lt;li&gt;Esto también ayuda a que &lt;em&gt;CustomDecrypt.sh&lt;/em&gt; genere nuevamente las claves RSA efímeras (de uso internas). Esto ayuda que los mensajes enviados por Ntfy siempre estén en un constante ciclo de "renovación criptográfica", haciendo que no exista tiempo suficiente para hacer ataques mas sofisticados. Mejor dicho, es buena practica permitir al sistema de &lt;em&gt;CustomDecrypt.sh&lt;/em&gt; renovar sus claves efímeras de forma habitual... como por ejemplo cada 1 hora. &lt;/li&gt;
&lt;li&gt;
&lt;em&gt;CustomDecrypt.sh&lt;/em&gt; solo acepta 1 vez una contraseña remota LUKS. Si esta es digitada de forma incorrecta, &lt;em&gt;CustomDecrypt.sh&lt;/em&gt; no acepta reintentos. Y estos es apropósito. Es para evitar ataques de fuerza bruta desde el dispositivo remoto. Con el reinicio permitimos que &lt;em&gt;CustomDecrypt.sh&lt;/em&gt; solicite nuevamente la clave, dandonos la opcion de tener "reintentos" de manera controlada y segura. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Para implementar nuestro &lt;em&gt;Watchdog&lt;/em&gt; sera tan simple como agregar un nuevo servicio a nuestro &lt;code&gt;hardware-configuration.nix&lt;/code&gt;. En la sección &lt;code&gt;boot.initrd.systemd.services&lt;/code&gt; agregamos, junto a nuestro Script de &lt;em&gt;CustomDecrypt&lt;/em&gt;, el nuevo servicio de &lt;em&gt;CustomWatchdog&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;services = {
  ...
  CustomWatchdog = {
    enable = true;
    after = [ "timer.target" ];
    requiredBy = [ "initrd.target" ];
    unitConfig = { 
      Description = "CustomWatchdog";
      DefaultDependencies = false;
    };
    serviceConfig = {
      Type = "forking";
      ExecStart="${pkgs.bash}/bin/sh -c 'sleep 3600 &amp;amp;&amp;amp; reboot -f &amp;amp;'";
      TimeoutStopSec = "3700s";
    };
  };
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lo mas importante en este servicio es el valor de &lt;strong&gt;3600 segundos&lt;/strong&gt; (1 hora) que tiene asignado el comando &lt;code&gt;sleep&lt;/code&gt; (localizado en la instrucción de ejecución &lt;code&gt;ExecStart&lt;/code&gt;). Este sera el tiempo que &lt;em&gt;CustomWatchdog&lt;/em&gt; esperara antes de &lt;strong&gt;reiniciar&lt;/strong&gt; el sistema operativo.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nota 1:&lt;/strong&gt; Usamos &lt;code&gt;after&lt;/code&gt; y &lt;code&gt;requiredBy&lt;/code&gt; para ejecutar &lt;em&gt;CustomWatchdog&lt;/em&gt; lo antes posible en la cadena de procesos de Stage1 del Boot.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nota 2:&lt;/strong&gt; &lt;em&gt;CustomWatchdog&lt;/em&gt; se ejecuta en modo &lt;em&gt;forking&lt;/em&gt;, ya que estará constantemente en &lt;em&gt;background&lt;/em&gt; esperando ejecutar el reinicio (en caso que el proceso de Boot no logre superar la etapa de LUKS correctamente).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nota 3:&lt;/strong&gt; Usamos &lt;code&gt;reboot&lt;/code&gt; con la flag &lt;code&gt;-f&lt;/code&gt; (force) para asegurarnos que el sistema se reinicie, a pesar de que otros procesos lo bloqueen. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nota 4:&lt;/strong&gt; El &lt;code&gt;TimeoutStopSec&lt;/code&gt; es muy importante. Pueden notar que tiene un valor un poco mayor al usado en el &lt;code&gt;sleep&lt;/code&gt;. Este &lt;code&gt;TimeoutStopSec&lt;/code&gt; es esencial para que &lt;em&gt;SystemD&lt;/em&gt; no "crea" que &lt;em&gt;CustomWatchdog&lt;/em&gt; esta "pegado" y termine el proceso antes de tiempo. Esto puede suceder, porque en algunas ocasiones, &lt;em&gt;SystemD&lt;/em&gt; no sabe interpretar correctamente los &lt;code&gt;sleep&lt;/code&gt; prolongados y "cree" que el servicio esta fallando por alguna razón y que esta "pegado" sin hacer nada.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;En caso que deseemos ajustar los tiempos, deberemos ser cuidadosos. El &lt;code&gt;TimeoutStopSec&lt;/code&gt; de &lt;em&gt;CustomDecrypt&lt;/em&gt; y de &lt;em&gt;CustomWatchdog&lt;/em&gt; siempre deben tener un valor ligeramente mayor al usado en el &lt;code&gt;sleep&lt;/code&gt; de &lt;em&gt;CustomWatchdog&lt;/em&gt;. Esto es importante para no entrar en condiciones de carrera. Por tanto, si queremos por ejemplo, reiniciar nuestro equipo cada 6 horas, deberemos dejar en el &lt;code&gt;sleep&lt;/code&gt; de &lt;em&gt;CustomWatchdog&lt;/em&gt; con un valor de 21600 (segundos en 6 horas); y en &lt;code&gt;TimeoutStopSec&lt;/code&gt;de &lt;em&gt;CustomDecrypt&lt;/em&gt; como &lt;em&gt;CustomWatchdog&lt;/em&gt;, un valor un poco mayor, por ejemplo "21700s".&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Con esto listo, podemos crear una nueva generación de NixOS &lt;code&gt;sudo nixos-rebuild switch&lt;/code&gt; y luego reiniciar nuestro sistema. Es un poco difícil "probar" si nuestro &lt;em&gt;Watchdog&lt;/em&gt; funciona... ya que deberemos esperar 1 hora. Pero si quieren pueden reducir el valor de los &lt;code&gt;TimeoutStopSec&lt;/code&gt; y &lt;code&gt;sleep&lt;/code&gt; a algo como 10 minutos para hacer una prueba completa.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusión, primera parte, sistema de desbloqueo remoto
&lt;/h2&gt;

&lt;p&gt;Listo, ya tenemos nuestro sistema de desbloqueo remoto LUKS completo, usando Ntfy como intermediario para los mensajes. Yupi! &lt;/p&gt;

&lt;p&gt;Ahora inicia la segunda parte, totalmente opcional, de este articulo. Y esto es la implementación de OpenVPN, con el proveedor AirVPN, durante el proceso de Boot. Esto nos ayudara a anonimizar el trafico de red entre NixOS y Ntfy. Posteriormente vamos a abordar algunos temas relacionados a &lt;a href="https://es.wikipedia.org/wiki/Filtraci%C3%B3n_DNS" rel="noopener noreferrer"&gt;&lt;em&gt;DNS leak&lt;/em&gt;&lt;/a&gt; para dejar todo perfectamente ajustado y anónimo. &lt;/p&gt;

&lt;h2&gt;
  
  
  Opcional: Implementación de VPN, con OpenVPN, en Stage1 del proceso de Boot
&lt;/h2&gt;

&lt;p&gt;La razón por la cual yo deseo implementar una VPN durante el proceso de Boot, es que mi HomeLab se ejecuta siempre usando una VPN. Por tanto, es contraproducente, que durante el proceso de Boot me comunique con internet (en este caso con Ntfy) y que dicha conexión no pase por un túnel. Con esta implementación logro, realmente, que desde el inicio de OS, todo el trafico pase por la VPN... incluso durante el Boot. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Como he comentado en un inicio, yo usaré &lt;a href="https://airvpn.org/" rel="noopener noreferrer"&gt;AirVPN&lt;/a&gt; como proveedor de VPN (de pago). Es mi servicio de VPN favorito (y por mucho). La política y respaldo que tiene la empresa de AirVPN es muy difícil de cuestionar. Y técnicamente son geniales. Si... soy un poco de "Fanboy". En un internet lleno de VPNs que son estafas y "trampas de tontos"... creadas específicamente para obtener dinero; AirVPN aparece como una opción "real" de lo que debe ser una VPN. Bueno, como sea. El punto es que usaré AirVPN, pero ustedes pueden usar cualquier proveedor que les permita usar OpenVPN como cliente (o sea, que el proveedor les de la posibilidad de genera un archivo &lt;code&gt;.ovpn&lt;/code&gt; de conexión). Incluso pueden crear su propio servidor VPN usando algún servicio cloud u otro servidor que tengan disponible. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Creando el archivo &lt;em&gt;.ovpn&lt;/em&gt; en AirVPN
&lt;/h3&gt;

&lt;p&gt;Lo primero que haremos es crear nuestro &lt;code&gt;.ovpn&lt;/code&gt;. Este es el archivo que tiene las credenciales para que el cliente OpenVPN pueda conectarse al servidor VPN.&lt;/p&gt;

&lt;p&gt;Lo primero sera entrar a la web de AirVPN y crear un "&lt;code&gt;Device&lt;/code&gt;" en el panel de "&lt;em&gt;Client Area&lt;/em&gt;". Los &lt;code&gt;Device&lt;/code&gt; permiten diferenciar distintos equipos que usen la misma cuenta de AirVPN. Por ejemplo, yo tengo un &lt;em&gt;Device&lt;/em&gt; para mi celular, otro para mi notebook y ahora voy a crear uno para este proyecto. Yo le he puesto como nombre "NIX".&lt;/p&gt;

&lt;p&gt;Con el &lt;em&gt;Device&lt;/em&gt; ya creado, ahora vamos al panel de "&lt;code&gt;Config Generator&lt;/code&gt;", que encontraran también en la &lt;em&gt;Client Area&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;En &lt;em&gt;Config Generator&lt;/em&gt; vamos a activar la opción &lt;strong&gt;&lt;em&gt;Advanced&lt;/em&gt;&lt;/strong&gt;. Luego vamos a seleccionar el OS, o sea, Linux. Posteriormente el protocolo de conexión que usaremos. Yo generalmente uso "&lt;em&gt;OpenVPN TCP 443&lt;/em&gt;". Y en la sección &lt;em&gt;Advance&lt;/em&gt; vamos a marcar "&lt;em&gt;Resolved hosts&lt;/em&gt;". Luego bajaremos y vamos a seleccionar el &lt;em&gt;Device&lt;/em&gt; al cual vamos asignar este &lt;code&gt;.ovpn&lt;/code&gt;, en mi caso "NIX". Finalmente vamos a seleccionar el servidor al cual nos conectaremos. Yo generalmente uso "&lt;em&gt;Global&lt;/em&gt;". Al final de la pagina pueden darle a "&lt;em&gt;Generate&lt;/em&gt;" para iniciar la descarga de su &lt;code&gt;.ovpn&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nota:&lt;/strong&gt; La opción &lt;em&gt;Resolved hosts&lt;/em&gt; nos sirve para que el &lt;code&gt;.ovpn&lt;/code&gt; generado tenga definido el punto de acceso del servidor VPN con una dirección IP y no con un &lt;em&gt;hostname&lt;/em&gt;. Esto lo necesitamos ya que durante Boot veremos que existen algunos problemas en la resolución de &lt;em&gt;hostnames&lt;/em&gt; de manera consistente. Por tanto es mejor usar directamente la IP del servidor VPN.&lt;/p&gt;

&lt;p&gt;Luego deberán copiar el &lt;code&gt;.ovpn&lt;/code&gt; y dejarlo en &lt;code&gt;/etc/nixos/&lt;/code&gt; de su NixOS. Yo he usado como nombre para el archivo &lt;code&gt;airvpn.ovpn&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Antes de continuar, no olvidemos que debemos disponibilizar dicho archivo para que este presente durante el Boot. Para esto en &lt;code&gt;boot.initrd.secrets&lt;/code&gt; de nuestro &lt;code&gt;hardware-configuration.nix&lt;/code&gt; añadimos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;secrets = {
  ...
  "/etc/nixos/airvpn.ovpn" = "/etc/nixos/airvpn.ovpn";
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Configurando OpenVPN
&lt;/h3&gt;

&lt;p&gt;Ahora vamos a indicar al sistema que permita el uso del &lt;a href="https://search.nixos.org/packages?channel=24.11&amp;amp;show=openvpn&amp;amp;from=0&amp;amp;size=50&amp;amp;sort=relevance&amp;amp;type=packages&amp;amp;query=OpenVPN" rel="noopener noreferrer"&gt;paquete de OpenVPN&lt;/a&gt; en el Boot. Para esto vamos a añadir al arreglo &lt;code&gt;boot.initrd.systemd.initBin&lt;/code&gt; el paquete &lt;code&gt;pkgs.openvpn&lt;/code&gt;, o sea, nuestro &lt;code&gt;initBin&lt;/code&gt; quedara así:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;initrdBin = [ pkgs.openvpn pkgs.libuuid pkgs.gnugrep pkgs.cryptsetup pkgs.openssl pkgs.curl pkgs.iproute2 pkgs.gnused ];
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Posteriormente deberemos habilitar unos "&lt;a href="https://nixos.wiki/wiki/Linux_kernel" rel="noopener noreferrer"&gt;Módulos de Kernel&lt;/a&gt;" al proceso de Boot, para que el sistema tenga la capacidad de crear adaptadores de red de &lt;a href="https://en.wikipedia.org/wiki/TUN/TAP" rel="noopener noreferrer"&gt;tipo túnel&lt;/a&gt;. En el arreglo de la declaración &lt;code&gt;boot.initrd.availableKernelModules&lt;/code&gt; añadiremos &lt;code&gt;tun&lt;/code&gt; y &lt;code&gt;tap&lt;/code&gt;. Deberá quedar así:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;boot.initrd.availableKernelModules = ["tun" "tap" ...&amp;lt;otros módulos&amp;gt;... ];
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lo único que nos falta es crear el servicio que se encargará de iniciar OpenVPN en el momento correcto. Para esto añadiremos un servicio mas a &lt;code&gt;boot.initrd.systemd.services&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;services = {
  ...
  Openvpn = {
    enable = true;
    wants = [ "network.target" "initrd-nixos-copy-secrets.service" ];
    after = [ "network.target" "initrd-nixos-copy-secrets.service" ];
    before = [ "CustomDecrypt.service" ];
    wantedBy = [ "CustomDecrypt.service" ];
    unitConfig = {
      Description = "OpenVPN";
      DefaultDependencies = false;
    };
    serviceConfig = {
      Type = "forking";
      ExecStart = "${pkgs.bash}/bin/sh -c 'openvpn --daemon --config /etc/nixos/airvpn.ovpn'";
    };
  };
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Es muy importante prestar atención en el nombre del servicio: "&lt;strong&gt;Openvpn&lt;/strong&gt;", ya que influye en un comportamiento de &lt;code&gt;CustomDecrypt.sh&lt;/code&gt; que explicare mas adelante.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nota 1:&lt;/strong&gt; Usamos &lt;code&gt;wants&lt;/code&gt; y &lt;code&gt;after&lt;/code&gt; para iniciar Openvpn luego de tener el sistema de network básico listo y luego de tener los secretos disponibles. Usamos &lt;code&gt;before&lt;/code&gt; y &lt;code&gt;wantedBy&lt;/code&gt; para indicar que Openvpn inicie antes que el servicio de &lt;code&gt;CustomDecrypt&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nota 2:&lt;/strong&gt; El Script inicia en modo &lt;em&gt;forking&lt;/em&gt;, ya que el cliente de OpenVPN operara como un &lt;em&gt;deamon&lt;/em&gt; durante el proceso de Boot.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nota 3:&lt;/strong&gt; En el comando de ejecución de &lt;code&gt;ExecStart&lt;/code&gt; pasamos en &lt;code&gt;--config&lt;/code&gt; el path al archivo de configuración &lt;code&gt;.ovpn&lt;/code&gt; que hemos generado en AirVPN.&lt;/p&gt;

&lt;p&gt;Con esto listo ya se iniciará de forma automática OpenVPN durante el Boot y se creará un túnel a los servidores de AirVPN. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feg7pbioixq64z6yp9fdm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feg7pbioixq64z6yp9fdm.png" alt="Tunel creado en AirVPN"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Aprovecho de mencionar que &lt;code&gt;CustomDecrypt.sh&lt;/code&gt; en su interior tiene una rutina donde, si detecta que un servicio llamado "Openvpn" (ojo, con "O" mayúscula, igual que el nombre usado en &lt;code&gt;boot.initrd.systemd.services.Openvpn&lt;/code&gt;) activo, procurara que el túnel esta activo antes de proseguir con la comunicación con Ntfy. Este es un resguardo para que no se genere comunicación &lt;em&gt;https&lt;/em&gt; con el servidor antes que el VPN este listo. En caso que el servicio de Openvpn lo llamarán de forma distinta, pueden cambiar el nombre en la variable &lt;code&gt;OPENVPN_SERVICE_NAME&lt;/code&gt; localizada al inicio de &lt;code&gt;CustomDecrypt.sh&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Una &lt;em&gt;feature&lt;/em&gt; que me gustaría añadir en un futuro es la capacidad de tener distintos &lt;code&gt;.ovpn&lt;/code&gt; (apuntando a distintos servidores). Y si uno falla, OpenVPN pase a usar otro .ovpn. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Arreglando bug que provoca DNS leak
&lt;/h3&gt;

&lt;p&gt;El talón de Aquiles de los VPN es cuando nuestro OS no resuelve los &lt;em&gt;hostname&lt;/em&gt; (&lt;a href="https://en.wikipedia.org/wiki/Hostname" rel="noopener noreferrer"&gt;nombres de dominio&lt;/a&gt;) usando un DNS "seguro". Esto se denomina &lt;a href="https://es.wikipedia.org/wiki/Filtraci%C3%B3n_DNS" rel="noopener noreferrer"&gt;DNS leak&lt;/a&gt;, donde el ISP puede analizar nuestro trafico usando la resolución de DNS. En este segmento nos aseguraremos que los DNS se usen de forma apropiada y no provoquen este problema que potencialmente des-anonimice nuestro trafico. &lt;/p&gt;

&lt;p&gt;Generalmente cuando usamos una VPN, se usa un servidor DNS interno a dicha VPN para resolver &lt;em&gt;hostname&lt;/em&gt;. Ese es el caso típico también con el servicio de AirVPN... ellos tienen servidores DNS que podemos usar una vez tengamos el túnel activo. Esta configuración de "selección de DNS" casi casi casi siempre es automática. Pero por alguna razón... en NixOS... específicamente en el sistema de red usado en Boot... no sucede. &lt;/p&gt;

&lt;p&gt;Esto quiere decir, que aunque estemos conectados al VPN y tengamos el túnel activo, no siempre se usará el DNS de AirVPN. Resulta que si tenemos un DNS configurado a nivel interfaz física, este valor "sobrescribirá" al indicado por OpenVPN al configurar el túnel. Esto, en palabras simples, nos generará un catastrófico DNS leak.&lt;/p&gt;

&lt;p&gt;Por suerte solucionarlo es sencillo. Deberemos ir a nuestro &lt;code&gt;hardware-configuration.nix&lt;/code&gt; a la declaración &lt;code&gt;boot.initrd.systemd.network&lt;/code&gt; y luego identificar la interfaz que usamos para conectarnos a internet. En mi caso es la llamada &lt;code&gt;enp0s3&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Ahora, la forma de solucionar el problema depende de como se configura su interfaz:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;La interfaz es configurada de forma estática (&lt;strong&gt;sin DHCP&lt;/strong&gt;):&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;En este caso deberían ver algo como:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;enp0s3 = {
  enable = true;
  name = "enp0s3";
  address = [ "192.168.4.152/24" ];
  gateway = [ "192.168.4.1" ];
  dns = [ "8.8.8.8" ]; 
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La solución consiste en &lt;strong&gt;remover&lt;/strong&gt; la definición de DNS. O sea, dejarlo así:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;enp0s3 = {
  enable = true;
  name = "enp0s3";
  address = [ "192.168.4.152/24" ];
  gateway = [ "192.168.4.1" ];
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;La interfaz es configurada usando DHCP:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;En este caso deberían ver algo como:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;enp0s3 = {
  enable = true;
  name = "enp0s3";
  DHCP = "yes";
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La solución consiste en añadir las siguientes declaraciones:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;enp0s3 = {
  enable = true;
  name = "enp0s3";
  DHCP = "yes";
  dhcpV4Config = {
    UseDNS = false;
  };
  dhcpV6Config = {
    UseDNS = false;
  };
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Con esto le indicamos a DHCP que solo configure de forma automática el &lt;code&gt;address&lt;/code&gt; y &lt;code&gt;gateway&lt;/code&gt; de la interfaz y que no defina ningún DNS. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Independiente del modo en que resuelvan la configuración esto solucionara el echo que, una vez conectados al VPN, se use efectivamente el DNS del VPN. &lt;/p&gt;

&lt;h3&gt;
  
  
  Otros problemas que pueden causar DNS leak
&lt;/h3&gt;

&lt;p&gt;Resulta que existe otro "problema", que puede surgir, dada la solución que implementamos en el paso anterior. El escenario de este "problema" es el siguiente:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Nuestras interfaces no tienen asignado un DNS (ni manualmente ni por DHCP).&lt;/li&gt;
&lt;li&gt;Por alguna razón la conexión a la VPN falla de forma catastrófica.&lt;/li&gt;
&lt;li&gt;Por otra razón, totalmente anómala, nuestro sistema operativo intenta resolver un &lt;em&gt;hostname&lt;/em&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;¿Que pasará? Pues resulta que el servicio que se encarga de administrar la resolución de DNS del sistema operativo, llamado &lt;a href="https://wiki.archlinux.org/title/Systemd-resolved" rel="noopener noreferrer"&gt;resolved&lt;/a&gt;, usara unos DNS denominados "&lt;em&gt;FallbackDNS&lt;/em&gt;". Este es uno (o varios) DNS de emergencia que son usados en caso que no se puedan localizar a nivel interfaz (ni a nivel VPN). Si esto llega a suceder, puede que nuestro sistema intente resolver el hostname de "ntfy.sh" usando estos DNS de emergencia provocando un DNS leak.&lt;/p&gt;

&lt;p&gt;Para solucionar esto podemos añadir una definición en &lt;code&gt;configuration.nix&lt;/code&gt;. Específicamente en &lt;code&gt;services.resolved&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;services.resolved = {
  fallbackDns = [];
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Con esto, ya no existirán &lt;code&gt;fallbackDns&lt;/code&gt; que puedan ser usados. Nuestro sistema operativo quedara sin opciones de resolver hostname sin querer.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Esto claramente provoca un "restricción colateral". Si no estamos conectados a la VPN, no podemos resolver hostname. Pero dentro del contexto de la solución de "desbloqueo remoto", no debería haber ninguna razón lógica por la cual desearíamos hacer esto sin antes estar conectados a la VPN. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Ultimo ajuste a resolveD
&lt;/h3&gt;

&lt;p&gt;Finalmente, ya que estamos en &lt;code&gt;configuration.nix&lt;/code&gt; podemos aprovechar de hacer una ultima cosa en &lt;code&gt;services.resolved&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;services.resolved = {
  fallbackDns = [];
  extraConfig = ''
    MulticastDNS=no
    LLMNR=no
    DNSSEC=yes
  '';
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Estas 3 opciones nos ayudan a terminar de configurar unos detalles finales. &lt;code&gt;MulticastDNS&lt;/code&gt; y &lt;code&gt;LLMNR&lt;/code&gt; son unos protocolos para que el sistema operativo encuentre dispositivos en la red local (como impresoras o carpetas compartidas). Personalmente no me gusta que mi sistema emita paquetes "porque si" a la red (aunque sea local). Con eso desactivamos esos protocolos. &lt;code&gt;DNSSEC&lt;/code&gt; nos ayuda a que la resolución de DNS se realice con los parámetros de seguridad de &lt;a href="https://en.wikipedia.org/wiki/Domain_Name_System_Security_Extensions" rel="noopener noreferrer"&gt;DNSSEC&lt;/a&gt;. El servidor DNS privado de AirVPN soporta DNSSEC, así que de esta manera nos aseguramos que las consultas sean realizadas de manera segura.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nota:&lt;/strong&gt; Me gustaría mencionar que &lt;code&gt;CustomDecrypt.sh&lt;/code&gt;, en su interior, tiene una parte de código que se encarga de sobre escribir, automáticamente, el valor de &lt;code&gt;fallbackDns&lt;/code&gt; en caso que OpenVPN se este usando. El valor de &lt;code&gt;fallbackDns&lt;/code&gt; queda configurado con la misma IP que la &lt;em&gt;gateway&lt;/em&gt; del túnel generado con AirVPN. Esta es la IP que AirVPN &lt;a href="https://airvpn.org/specs/" rel="noopener noreferrer"&gt;recomienda usar&lt;/a&gt; en caso de querer configurar manualmente el uso del DNS privado de ellos. El motivo de reescribir el valor de &lt;code&gt;fallbackDns&lt;/code&gt; es simplemente para asegurarnos que &lt;code&gt;resolved&lt;/code&gt; use correctamente el DNS. Es una prevención extra, a lo que ya es una serie de bugs y comportamientos particulares. &lt;strong&gt;Si no desean que&lt;/strong&gt; &lt;code&gt;CustomDecrypt.sh&lt;/code&gt; toque el &lt;code&gt;fallbackDns&lt;/code&gt; pueden desactivar esta configuración pasando el valor de la variable &lt;code&gt;FORCE_FALLBACK_DNS_VPN&lt;/code&gt; (localizada al inicio de &lt;code&gt;CustomDecrypt.sh&lt;/code&gt;) a &lt;code&gt;0&lt;/code&gt;. Esto puede que sea necesario en caso que usen otro proveedor de VPN (donde la configuración manual para el uso del DNS privado sea distinta).&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusión
&lt;/h2&gt;

&lt;p&gt;Y con esto ya tenemos un sistema que nos permite desbloquear de forma remota nuestra unidad LUKS, durante el Boot, de forma segura y anomia. Usando como intermediario Ntfy hemos logrado crear un sistema de notificaciones y mensajes asíncronos, así que podemos usar un celular como nuestro dispositivo remoto autorizado. Ademas, la implementación de seguridad interna que usa &lt;code&gt;CustomDecrypt.sh&lt;/code&gt; para gestionar los mensajes, nos protegen de múltiples vectores de ataque, haciendo que el uso de canales públicos de comunicación no sea un problema.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;No olviden, en su Stage1, desactivar el servidor SSH... ya no lo van a necesitar. También recomiendo ejecutar &lt;code&gt;sudo nix-collect-garbage -d&lt;/code&gt; para limpiar el cache :)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Nuevamente los invito a seguir mejorando esta propuesta. Creo que una gran contribución seria hacer que el sistema funcione de forma modular, permitiendo cambiar que el canal de comunicación sea Discord, Slack, un sistema basado en intercambio de emails firmados o incluso un comunicación directa entre servidores.&lt;/p&gt;

&lt;p&gt;En los próximos días subiré un articulo donde explicaré, detalladamente, la lógica detrás de las decisiones de seguridad que usa &lt;code&gt;CustomDecrypt.sh&lt;/code&gt;. Puede ser una lectura interesante si te apasiona la seguridad.&lt;/p&gt;

&lt;p&gt;Un saludo a todos! &lt;/p&gt;

</description>
      <category>nixos</category>
      <category>spanish</category>
      <category>luks</category>
      <category>linux</category>
    </item>
    <item>
      <title>Red (wifi) y SSH en Stage1 (boot - initrd) de NixOS - Parte 2</title>
      <dc:creator>Federico Jensen</dc:creator>
      <pubDate>Sun, 06 Apr 2025 22:40:17 +0000</pubDate>
      <link>https://dev.to/federico_jensen/red-wifi-y-ssh-en-stage1-boot-initrd-de-nixos-parte-2-4j9m</link>
      <guid>https://dev.to/federico_jensen/red-wifi-y-ssh-en-stage1-boot-initrd-de-nixos-parte-2-4j9m</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Ninguna IA ha estado involucrada en la creación de este articulo &lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Contexto
&lt;/h2&gt;

&lt;p&gt;Esta es la Parte 2 del articulo "Red y SSH en Stage1 (boot - initrd) de NixOS". &lt;a href="https://dev.to/federico_jensen/red-y-ssh-en-stage1-boot-initrd-de-nixos-parte-1-28o4"&gt;La Parte 1 puede ser encontrada aquí&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Esta guiá forma parte de un compendio de clases/tutoriales para crear y gestionar un HomeLab usando NixOS.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Este articulo posee un video asociado donde se pueden encontrar mas detalles y el paso a paso:&lt;/strong&gt;&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://odysee.com/red_y_ssh_en_stage1_de_nixos_parte_2:e9b2314212614ec5fe9f4a86d4ac1b29863cccb2" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthumbnails.odycdn.com%2Fcard%2Fs%3A1280%3A720%2Fquality%3A85%2Fplain%2Fhttps%3A%2F%2Fthumbs.odycdn.com%2F54187ee24a50b3e5c96ad67904da1327.webp" height="auto" class="m-0"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://odysee.com/red_y_ssh_en_stage1_de_nixos_parte_2:e9b2314212614ec5fe9f4a86d4ac1b29863cccb2" rel="noopener noreferrer" class="c-link"&gt;
            Red y SSH en Stage1 de NixOS - Parte 2
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Guiá donde habilitamos conexión a la red y un servidor SSH en la Stage1 (init ram disk) en NixOS.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fodysee.com%2Fpublic%2Ffavicon_128.png"&gt;
          odysee.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;





&lt;h2&gt;
  
  
  Introducción
&lt;/h2&gt;

&lt;p&gt;En esta segunda parte veremos como activar una interfaz inalámbrica (WiFi) durante la Stage1 del proceso de boot de NixOS. Exploraremos los desafíos de identificar e instalar drivers, de escanear redes wifi durante Stage1 y de automatizar el proceso de conexión durante el boot. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;En esta segunda parte estoy asumiendo que ustedes poseen acceso por SSH a Stage1 usando una interfaz Ethernet.&lt;/strong&gt; Si aun no han logrado configurar esto, puede ver la &lt;a href="https://dev.to/federico_jensen/red-y-ssh-en-stage1-boot-initrd-de-nixos-parte-1-28o4"&gt;primera parte del articulo&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;El Plan:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Verificando el funcionamiento normal de WiFi en NixOS &lt;/li&gt;
&lt;li&gt;Activar drivers de interfaz inalámbrica en Stage1&lt;/li&gt;
&lt;li&gt;Validar escaneo y conexión de redes WiFi en Stage1&lt;/li&gt;
&lt;li&gt;Automatizar el proceso de conexión a WiFi en Stage1 y probar el acceso remoto usando SSH&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;Si... si comparan con lo expuesto en la &lt;a href="https://dev.to/federico_jensen/red-y-ssh-en-stage1-boot-initrd-de-nixos-parte-1-28o4"&gt;Parte 1&lt;/a&gt;, he cambiado un poco los puntos de "El Plan" de la Parte 2 &amp;gt;.&amp;lt; &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Vamos a ello!&lt;/p&gt;




&lt;h2&gt;
  
  
  1) Verificando el funcionamiento normal de WiFi en NixOS
&lt;/h2&gt;

&lt;p&gt;Lo primero sera validar que nuestro NixOS pueda usar el adaptador WiFi de forma normal. Con esto me refiero a poder: ir a su interfaz de &lt;em&gt;NetworkManager&lt;/em&gt;, escanear las redes WiFi, seleccionar una y conectarnos correctamente luego de indicar la contraseña asociada. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm4vl9bdqol3bjb9efstl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm4vl9bdqol3bjb9efstl.png" alt="NetworkManager y selección de red WiFi"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Si podemos hacer esto de forma normal, te invito a &lt;strong&gt;continuar&lt;/strong&gt; con la siguiente sección de este artículo.&lt;/p&gt;

&lt;p&gt;En caso que tengas conectado un adaptador inalámbrico, pero no lo puedas usar en su NixOS, quiere decir que faltan los drivers. A continuación exploraremos como instalar un adaptador WiFi. &lt;/p&gt;

&lt;h3&gt;
  
  
  1.1) Instalando drivers de interfaz inalámbrica en NixOS
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;He querido incluir este paso porque, en mis experimentaciones, he estado usando un dongle USB WiFi que, efectivamente, ha requerido una instalación de drivers manual... espero que este segmento le sea útil a alguien que este en una situación similar.  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Nuestro objetivo es buscar el &lt;strong&gt;nombre&lt;/strong&gt; del dispositivo inalámbrico. Con esto me refiero al modelo del hardware. Para esto, lo mejor es usar las herramientas &lt;code&gt;pciutils&lt;/code&gt; y/o &lt;code&gt;usbutils&lt;/code&gt;. Si vienen de la &lt;a href="https://dev.to/federico_jensen/red-y-ssh-en-stage1-boot-initrd-de-nixos-parte-1-28o4"&gt;Parte 1&lt;/a&gt; del articulo, estas herramientas ya las deberían tener en: &lt;code&gt;/etc/nixos/configuration.nix&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Usando los comandos de &lt;code&gt;lsusb -v&lt;/code&gt; y &lt;code&gt;lspci -k&lt;/code&gt; podemos listar el hardware conectado por el &lt;em&gt;bus&lt;/em&gt; USB y PCI a nuestro equipo. Una de estas dos opciones serán de utilidad para ustedes, ya que los adaptadores WiFi generalmente usan uno de estos dos &lt;em&gt;bus&lt;/em&gt; de comunicación. En mi caso, como tengo un dongle USB, con &lt;code&gt;lsusb -v&lt;/code&gt; he podido encontrar el nombre de mi dispositivo. Es: "Realtek RTL8188EUS". &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fej5rm7dmv1i0kzfyv4zc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fej5rm7dmv1i0kzfyv4zc.png" alt="Dispositivo dongle WiFi"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Si su adaptador inalámbrico usa el &lt;em&gt;bus&lt;/em&gt; PCI (por ejemplo si es una tarjeta pci-express) pueden usar &lt;code&gt;lspci -k&lt;/code&gt; para localizar el nombre.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Usando este nombre debemos entregarnos a Google...y buscar... Nuestro objetivo ahora es encontrar el nombre del driver relacionado a este dispositivo. Luego de un poco de búsqueda, para mi dongle Realtek he encontrado que el driver correspondiente se llama "rtl8xxxu" y es parte de un paquete de drivers de llamado: "rtl8188eus-aircrack".&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Claramente en su caso esto sera distinto, lamentablemente no existe una manera sistemática para encontrar el driver correcto... pero no tengan duda que alguien en internet ya ha pasado por lo mismo que ustedes. Con algo de investigación encontraran el nombre del driver.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ahora nos toca incluir este driver en nuestro NixOS. Para esto en &lt;code&gt;/etc/nixos/hardware-configuration.nix&lt;/code&gt; vamos a añadir:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;boot.extraModulePackages = with config.boot.kernelPackages; [
  rtl8188eus-aircrack
];
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Nota:&lt;/strong&gt; Estoy usando &lt;em&gt;extraModulePackages _ y no _availableKernelModules&lt;/em&gt; porque, en específico, este es un driver externo a los empaquetados con NixOS. &lt;/p&gt;

&lt;p&gt;Ahora nos toca crear una nueva generación de NixOS con &lt;code&gt;sudo nixos-rebuild switch&lt;/code&gt; y luego reiniciar el sistema. Luego del reinicio ya deberían poder usar su adaptador WiFi de forma normal en nuestro NixOS.&lt;/p&gt;




&lt;h2&gt;
  
  
  2) Activar drivers de interfaz inalámbrica en Stage1
&lt;/h2&gt;

&lt;p&gt;Primero partiremos identificando el nombre de la interfaz inalámbrica. Usando &lt;code&gt;ip link&lt;/code&gt; podemos listar los adaptadores del sistema. En mi caso se llama "wlp0s11u1" (desde ahora los ejemplos usaran este nombre para el adaptador, no olviden usar el de su interfaz).&lt;/p&gt;

&lt;p&gt;Con esta información ahora veremos cual es el estado de la interfaz durante Stage1. Vamos a reiniciar nuestro sistema y conectarnos por SSH a Stage1 (de la forma expuesta en la &lt;a href="https://dev.to/federico_jensen/red-y-ssh-en-stage1-boot-initrd-de-nixos-parte-1-28o4"&gt;Parte 1&lt;/a&gt; del artículo). Una vez en Stage1 usaremos &lt;code&gt;ip link&lt;/code&gt; para ver cuales adaptadores están siendo detectados en esta etapa del boot. Lo mas seguro es que &lt;strong&gt;no&lt;/strong&gt; vean su interfaz inalámbrica... y esto es lo normal. En el extraño caso que &lt;strong&gt;si&lt;/strong&gt; vean su interfaz inalámbrica listada, pueden continuar con la siguiente sección del artículo.&lt;/p&gt;

&lt;p&gt;Bien, entonces ahora lo que debemos lograr es habilitar en Stage1 los mismos drivers que en Stage2 se están usando para el WiFi. La mejor forma para lograr esto es &lt;strong&gt;realizar una comparativa&lt;/strong&gt; entre los drivers cargados en Stage1 y Stage2. Y luego deducir (con ayuda de Google si es necesario) cual es exactamente el que "nos esta faltando" en Stage1 "pero que si esta" en Stage2.&lt;/p&gt;

&lt;p&gt;Para esto primero vamos a ir a nuestra Stage2 (escritorio de toda la vida) y usaremos los comandos &lt;code&gt;lsmod&lt;/code&gt; y &lt;code&gt;modinfo &amp;lt;nombre modulo&amp;gt;&lt;/code&gt; para listar y ver el detalle de los driveres cargados. Estamos buscando uno que tenga relación con la interfaz inalámbrica.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fksmm2urzga8fcqtjkkov.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fksmm2urzga8fcqtjkkov.png" alt="Módulos cargados en Stage2 relacionados a rtl8xxxu"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Dado el nombre de mi adaptador he logrado encontrar, usando &lt;code&gt;lsmod&lt;/code&gt;, un modulo llamado "rtl8xxxu". Luego usando &lt;code&gt;modinfo rtl8xxxu&lt;/code&gt; he podido ver que efectivamente se relaciona a la interfaz inalámbrica.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;He aprovechado también de regresar por SSH a mi Stage1 para usar el mismo comando (&lt;code&gt;lsmod&lt;/code&gt;) y confirmar que, efectivamente, "rtl8xxxu" no esta en Stage1.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Entonces, en teoría, si logramos cargar "rtl8xxxu" en Stage1 vamos a poder usar la interfaz inalámbrica. &lt;/p&gt;

&lt;p&gt;Con esta información vamos a añadir "rtl8xxxu" al parámetro &lt;em&gt;availableKernelModules&lt;/em&gt; en nuestro &lt;code&gt;/etc/nixos/hardware-configuration.nix&lt;/code&gt;. Con esto habilitamos el uso del driver en Stage1:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;boot.initrd.availableKernelModules = ["rtl8xxxu" … ];
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En algunos casos puede ser necesario usar la opción &lt;em&gt;enableRedistributableFirmware&lt;/em&gt;. Específicamente esto puede ser necesario si el driver que están cargando en &lt;em&gt;availableKernelModules&lt;/em&gt; no es parte por defecto del sistema y ha sido instalado desde una fuente externa.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;hardware.enableRedistributableFirmware = true;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Luego, creamos una nueva generación de NixOS y reiniciamos. De regreso a Stage1 por SSH he volvemos a usar &lt;code&gt;ip link&lt;/code&gt; y ahora si veremos la interfaz listada! :)&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Nota extra: En un momento use el driver "8188eu", el cual parecía ser el correspondiente a mi dongle WiFi. Pero, por alguna razón, eso solo funcionaba en Stage2 y no en Stage1. Por otro lado, el "rtl8xxxu" funciona en ambos contextos. La moraleja es que puede ser necesario un &lt;strong&gt;poco de prueba y error&lt;/strong&gt; hasta lograr dar con el driver correcto.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  3) Validar escaneo y conexión de redes WiFi en Stage1
&lt;/h2&gt;

&lt;p&gt;Una vez que sabemos que en Stage1 la interfaz inalámbrica es detectada, toca usarla. En una primera instancia realizaremos algunas pruebas de conexión de forma manual. Y luego, en la siguiente sección del artículo, lo automatizaremos. &lt;/p&gt;

&lt;p&gt;La primera prueba sera confirmar que la interfaz puede escanear redes en Stage1.&lt;/p&gt;

&lt;p&gt;En primer lugar vamos a instalar unas herramientas que nos facilitaran el debugeo. En &lt;code&gt;/etc/nixos/configuration.nix&lt;/code&gt; añadiéremos los paquetes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://search.nixos.org/packages?channel=24.11&amp;amp;show=iw&amp;amp;from=0&amp;amp;size=50&amp;amp;sort=relevance&amp;amp;type=packages&amp;amp;query=iw" rel="noopener noreferrer"&gt;iw&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://search.nixos.org/packages?channel=24.11&amp;amp;show=wirelesstools&amp;amp;from=0&amp;amp;size=50&amp;amp;sort=relevance&amp;amp;type=packages&amp;amp;query=wirelesstools" rel="noopener noreferrer"&gt;wirelesstools&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;También vamos a querer estas herramientas en Stage1, así que las añadiremos al parámetro &lt;em&gt;initrdBin&lt;/em&gt; de nuestro &lt;code&gt;/etc/nixos/hardware-configuration.nix&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;boot.initrd.systemd.initrdBin = [ pkgs.iw pkgs.wirelesstools … ];
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aprovechando que estamos en &lt;code&gt;hardware-configuration.nix&lt;/code&gt; también activaremos la interfaz inalámbrica de Stage1 en la sección &lt;code&gt;network.networks&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
wlp0s11u1 = {
  enable = true;
  name = "wlp0s11u1";
  DHCP = "yes";
}; 
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Nota 1:&lt;/strong&gt; Recuerda usar el nombre de tu interfaz. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nota 2:&lt;/strong&gt; Por ahora usaremos DHCP para que la IP, Gateway y DNS se configuren automáticamente desde nuestro router.&lt;/p&gt;

&lt;p&gt;Bien, con esto listo vamos a crear una nueva generación de NixOS. &lt;/p&gt;

&lt;h3&gt;
  
  
  3.1) Probando el escaneo de redes
&lt;/h3&gt;

&lt;p&gt;Primero realizaremos una prueba en Stage2 (escritorio típico). Usando los comandos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ip link&lt;/code&gt; Deberíamos identificar la disponibilidad e la interfaz inalámbrica.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;iw dev&lt;/code&gt; y/o &lt;code&gt;iwconfig&lt;/code&gt; Deberíamos poder ver detalles de la interfaz inalámbrica.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;iw &amp;lt;nombre interfaz&amp;gt; scan&lt;/code&gt; y/o &lt;code&gt;iwlist &amp;lt;nombre interfaz&amp;gt; scan&lt;/code&gt; Deberíamos ver las redes WiFi disponibles.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Una vez comprobado que todo se ve "normal" en Stage2, vamos a repetir este proceso en Stage1. Si todo va bien, también deberíamos ser capaces de ver las señales WiFi disponibles. &lt;/p&gt;

&lt;p&gt;Nos conectamos por SSH a Stage1 y usamos los mismos comandos: &lt;code&gt;ip link&lt;/code&gt;, &lt;code&gt;iw dev&lt;/code&gt; y &lt;code&gt;iw &amp;lt;nombre interfaz&amp;gt; scan&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Con esto podemos confirmar que la interfaz inalámbrica en Stage1 es capaz de escanear redes. Genial !&lt;/p&gt;

&lt;h3&gt;
  
  
  3.2) Creado un &lt;em&gt;supplicant&lt;/em&gt; con las configuraciones de red inalámbrica
&lt;/h3&gt;

&lt;p&gt;Ahora que sabemos que podemos escanear redes en Stage1, debemos prepararnos para conectarnos a una. Para esto deberemos crear un archivo de configuración (denominado "wpa_passphrase") que posee en su interior el nombre de la red WiFi (SSID) y contraseña asociada.&lt;/p&gt;

&lt;p&gt;Para generar el archivo de configuración podemos usar el siguiente comando en Stage2:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;wpa_passphrase "SSID" "CONTRASEÑA" | sudo tee /etc/nixos/wpa_supplicant.conf&lt;/code&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Recuerda indicar correctamente el nombre de tu señal (SSID) y la contraseña.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;El archivo generado sera guardado en &lt;code&gt;/etc/nixos/wpa_supplicant.conf&lt;/code&gt;. Este archivo de configuración lo vamos a necesitar en Stage1. Así que usaremos &lt;em&gt;secrets&lt;/em&gt; para crear una "copia" que si este disponible en el &lt;em&gt;ram disk&lt;/em&gt; del boot (esto ya lo vimos en la &lt;a href="https://dev.to/federico_jensen/red-y-ssh-en-stage1-boot-initrd-de-nixos-parte-1-28o4"&gt;Parte 1&lt;/a&gt; de este articulo). Para esto, añadiremos el fichero &lt;code&gt;/etc/nixos/wpa_supplicant.conf&lt;/code&gt; a la lista de &lt;em&gt;secrets&lt;/em&gt; de &lt;code&gt;/etc/nixos/hardware-configuration.nix&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
secrets = {
  ...
  "/etc/nixos/wpa_supplicant.conf" = "/etc/nixos/wpa_supplicant.conf";
};
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En &lt;code&gt;hardware-configuration.nix&lt;/code&gt; aprovecharemos de añadir el &lt;a href="https://search.nixos.org/packages?channel=24.11&amp;amp;show=wpa_supplicant&amp;amp;from=0&amp;amp;size=50&amp;amp;sort=relevance&amp;amp;type=packages&amp;amp;query=wpa_supplicant" rel="noopener noreferrer"&gt;wpa_supplicant&lt;/a&gt; paquete a &lt;em&gt;initrdBin&lt;/em&gt; para que pueda ser usado en Stage1. Este paquete es el responsable de hacer que el archivo de configuración, que hemos generado, pueda ser usado como parte del proceso de selección y autorización de una red WiFi:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;boot.initrd.systemd.initrdBin = [ pkgs.wpa_supplicant … ];
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Por ultimo, también añadiremos en &lt;code&gt;hardware-configuration.nix&lt;/code&gt; 4 módulos a &lt;em&gt;availableKernelModules&lt;/em&gt; necesarios para que Stage1 puede ser capaz de manejar las redes WiFi y entender sus protocolos de seguridad:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;boot.initrd.availableKernelModules = ["ccm" "ctr" "iwlmvm" "iwlwifi" … ];
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Con todos los cambios guardados ahora nos toca crear la nueva generación de NixOS y reiniciar el sistema.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.3) Conectándonos a una red inalámbrica usando &lt;em&gt;supplicant&lt;/em&gt; en Stage1
&lt;/h3&gt;

&lt;p&gt;Finalmente vamos a conectarnos! Entraremos por SSH al Stage1 de NixOS y luego vamos a ejecutar este comando:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;wpa_supplicant -i wlp0s11u1 -c /etc/nixos/wpa_supplicant.conf -B&lt;/code&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Recuerda usar el nombre de tu interfaz&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Si todo va bien, esto iniciara un proceso en &lt;em&gt;background&lt;/em&gt; que usara la interfaz inalámbrica indicada en &lt;code&gt;-i&lt;/code&gt; para enlazarnos a la red WiFi especificada por el archivo &lt;code&gt;wpa_supplicant.conf&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Luego de esperar unos segundos podemos comprobar la conexión usando estos comandos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ip link&lt;/code&gt; Se debería ver la interfaz inalámbrica "UP".&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;iw dev&lt;/code&gt; Deberíamos ver una serie de información que indica el estado de la conexión WiFi. &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;iw dev NOMBRE_INTERFAZ_WIFI link&lt;/code&gt; Deberíamos ver un mensaje donde se confirma que existe conectividad WiFi.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ip addr&lt;/code&gt; Tendríamos que ver la IP que ha sido asignada a la interfaz gracias a DHCP.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feofapgy0sb9ki5sevu9f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feofapgy0sb9ki5sevu9f.png" alt="Conexión manual a WiFi en Stage1"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Si todo va bien ya tenemos WiFi en nuestra Stage1&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Por ultimo, si deseamos, podemos desactivar DHCP y asignar de manera estática los parámetros de IP (address), Gateway y DNS a nuestra interfaz. Esto se puede realizar de la misma manera en la cual lo logramos en la &lt;a href="https://dev.to/federico_jensen/red-y-ssh-en-stage1-boot-initrd-de-nixos-parte-1-28o4"&gt;Parte 1&lt;/a&gt; de este articulo con la interfaz Ethernet. Para esto modificamos en &lt;code&gt;/etc/nixos/hardware-configuration.nix&lt;/code&gt; algunas cosas:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
wlp0s11u1 = {
  enable = true;
  name = "wlp0s11u1";
  #DHCP = "yes"; #Comentamos para desactivar DHCP
  #Añadimos los parámetros de forma manual
  address = [ "192.168.4.151/24" ];
  gateway = [ "192.168.4.1" ];
  dns = [ "8.8.8.8" ]; 
};
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Para saber que &lt;em&gt;address&lt;/em&gt; y &lt;em&gt;gateway&lt;/em&gt; digitar, podemos usar los comandos &lt;code&gt;ip route&lt;/code&gt; y &lt;code&gt;ip link&lt;/code&gt; para averiguar cual IP y Gateway son los que usa nuestro sistema de forma automática. Luego copiamos esos valores. Recuerda usar el nombre de tu interfaz inalámbrica. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Con esto sera mas fácil usar SSH, ya que nos aseguramos de tener siempre la misma IP. &lt;/p&gt;




&lt;h2&gt;
  
  
  4) Automatizar el proceso de conexión a WiFi en Stage1 y probar el acceso remoto usando SSH
&lt;/h2&gt;

&lt;p&gt;En esta etapa final buscamos crear un &lt;em&gt;script&lt;/em&gt; que realice el proceso de conexión a la red WiFi durante Stage1 de manera automática. &lt;/p&gt;

&lt;p&gt;Para esto añadiremos el siguiente &lt;code&gt;script&lt;/code&gt; a &lt;code&gt;/etc/nixos/hardware-configuration.nix&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
services = {
  ...
  ConnectWifi = {
    enable = true;
    wants = [ "systemd-udev-settle.service" "network.target" "initrd-nixos-copy-secrets.service" ];
    after = [ "systemd-udev-settle.service" "network.target" "initrd-nixos-copy-secrets.service" ];
    before = [ "systemd-ask-password-console.service" ];
    wantedBy = [ "systemd-ask-password-console.service" ];
    unitConfig = {
      Description = "ConnectWifi";
      DefaultDependencies = false;
   };
   serviceConfig = {
     Type = "forking";
     ExecStart="${pkgs.bash}/bin/sh -c 'wpa_supplicant -i wlp0s11u1 -c /etc/nixos/wpa_supplicant.conf -B || true'";
   };
 };
...
};
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Recuerda cambiar en &lt;code&gt;-i&lt;/code&gt; el nombre de la interfaz inalámbrica a la tuya.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Nota 1:&lt;/strong&gt; Este &lt;em&gt;script&lt;/em&gt; se va a ejecutar luego que el hardware (&lt;em&gt;systemd-udev-settle.service&lt;/em&gt;), secretos (&lt;em&gt;initrd-nixos-copy-secrets.service&lt;/em&gt;) y base de sistema de red (&lt;em&gt;network.target&lt;/em&gt;) estén disponibles. Y antes de que LUKS pida la clave (&lt;em&gt;systemd-ask-password-console.service&lt;/em&gt;). O sea, antes de Stage2.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nota 1.1:&lt;/strong&gt; En caso de no usar LUKS y estar usando el &lt;em&gt;script&lt;/em&gt; "force-pause-script" (mencionado en la &lt;a href="https://dev.to/federico_jensen/red-y-ssh-en-stage1-boot-initrd-de-nixos-parte-1-28o4"&gt;Parte 1&lt;/a&gt; del artículo) para pausar Stage1; deberás cambiar: &lt;em&gt;systemd-ask-password-console.service&lt;/em&gt; por &lt;em&gt;force-pause-script.service&lt;/em&gt; en &lt;code&gt;before&lt;/code&gt; y &lt;code&gt;wantedBy&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nota 2:&lt;/strong&gt; El &lt;em&gt;script&lt;/em&gt; corre en modo &lt;em&gt;forking&lt;/em&gt; y con &lt;em&gt;wpa_supplicant&lt;/em&gt; en &lt;em&gt;background&lt;/em&gt; (&lt;code&gt;-B&lt;/code&gt;) para no interrumpir otros procesos de Stage1. El &lt;code&gt;|| true&lt;/code&gt; se usa para evitar que &lt;em&gt;systemd&lt;/em&gt; piense que &lt;em&gt;wpa_supplicant&lt;/em&gt; "falló" mientras realiza re-intentos para lograr conectividad WiFi (algo normal en el protocolo de conexión WiFi).&lt;/p&gt;

&lt;p&gt;Luego que generemos la nueva generación de NixOS y reiniciemos el sistema, podemos volver a confirmar que la conexión WiFi está bien usando SSH. De hecho, podemos conectarnos por SSH directamente usando la IP que hemos fijado al adaptador inalámbrico.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SSH por WiFi en Stage1 !!!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft8nm4wofcpv97tjuqlec.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft8nm4wofcpv97tjuqlec.png" alt="Conexión automática a WiFi en Stage1"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Si deseamos, podemos desactivar la interfaz Ethernet y solo usar WiFi. También puede ser buen momento para remover herramientas que solo utilizamos durante el proceso de configuración tales como: &lt;code&gt;iw&lt;/code&gt;, &lt;code&gt;wirelesstools&lt;/code&gt;, &lt;code&gt;pciutils&lt;/code&gt; y &lt;code&gt;usbutils&lt;/code&gt;. Un &lt;code&gt;sudo nix-collect-garbage -d&lt;/code&gt; también puede ser útil para limpiar nuestro cache.&lt;/p&gt;

&lt;p&gt;Finalmente un recordatorio: Solo usar SSH en Stage1 a modo de debugger... no es muy recomendado tener SSH en dicha etapa del boot.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusión
&lt;/h2&gt;

&lt;p&gt;Espero que este articulo de dos partes fuera de su utilidad para lograr tener Red y SSH en Stage1 de NixOS&lt;/p&gt;

&lt;p&gt;Nuevamente quiero agradecer al &lt;a href="https://blog.decent.id/post/nixos-systemd-initrd/" rel="noopener noreferrer"&gt;blog de Spencer Balogh&lt;/a&gt; por su guiá indispensable en comprender como funciona el networking de Stage1. &lt;/p&gt;

&lt;p&gt;Otras fuentes de información que he usado:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://discourse.nixos.org/t/wireless-connection-within-initrd/38317" rel="noopener noreferrer"&gt;Wireless connection within initrd&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Como comente en un inicio, esta guiá nace como un pre-requisito para la implementación de un sistema de desbloquear remoto y seguro de particiones LUKS durante el proceso de boot.&lt;/p&gt;

&lt;p&gt;Salu2 :) &lt;/p&gt;

</description>
      <category>spanish</category>
      <category>nixos</category>
      <category>linux</category>
    </item>
    <item>
      <title>Red y SSH en Stage1 (boot - initrd) de NixOS - Parte 1</title>
      <dc:creator>Federico Jensen</dc:creator>
      <pubDate>Fri, 04 Apr 2025 16:34:23 +0000</pubDate>
      <link>https://dev.to/federico_jensen/red-y-ssh-en-stage1-boot-initrd-de-nixos-parte-1-28o4</link>
      <guid>https://dev.to/federico_jensen/red-y-ssh-en-stage1-boot-initrd-de-nixos-parte-1-28o4</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Ninguna IA ha estado involucrada en la creacion de este articulo &lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Contexto
&lt;/h2&gt;

&lt;p&gt;En la siguiente guía veremos cómo configurar las interfaces de redes para poder tener conexión a internet durante la Stage1 (&lt;em&gt;init ram disk&lt;/em&gt; o &lt;em&gt;initrm&lt;/em&gt;) de &lt;a href="https://nixos.org/" rel="noopener noreferrer"&gt;NixOS&lt;/a&gt;. Más específicamente, en esta primera parte de la articulo veremos como configurar la interfaz Ethernet. Y luego nos conectaremos, de forma remota, con SSH a la Stage1. En la segunda parte del articulo veremos como lograr lo mismo usando una interfaz inalámbrica (algo que supone algunos otros desafíos).&lt;/p&gt;

&lt;p&gt;¿Porque querer tener Red en Stage1?... bueno, esta guiá realmente es parte de un pre-requisito de un proyecto mas grande. Una implementación para lograr descifrar, de forma remota y segura, particiones cifradas con &lt;a href="https://www.cyberciti.biz/security/howto-linux-hard-disk-encryption-with-luks-cryptsetup-command/" rel="noopener noreferrer"&gt;LUKS&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Esta guiá forma parte de un compendio de clases/tutoriales para crear y gestionar un HomeLab usando NixOS.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Este articulo posee un video asociado donde se pueden encontrar mas detalles y el paso a paso:&lt;/strong&gt;&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://odysee.com/@Federico_Jensen:7/red_y_ssh_en_stage1_de_nixos_parte_1" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthumbnails.odycdn.com%2Fcard%2Fs%3A1280%3A720%2Fquality%3A85%2Fplain%2Fhttps%3A%2F%2Fthumbs.odycdn.com%2F06c7bc2bcb429dd7300ac1ba4c3ef2d9.webp" height="auto" class="m-0"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://odysee.com/@Federico_Jensen:7/red_y_ssh_en_stage1_de_nixos_parte_1" rel="noopener noreferrer" class="c-link"&gt;
            Red y SSH en Stage1 de NixOS - Parte 1
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Guiá donde habilitamos conexión a la red y un servidor SSH en la Stage1 (init ram disk) en NixOS.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fodysee.com%2Fpublic%2Ffavicon_128.png"&gt;
          odysee.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;





&lt;h2&gt;
  
  
  Introducción
&lt;/h2&gt;

&lt;p&gt;La Stage1 de NixOS es una rutina de procesos, dentro del boot, que suceden antes que el sistema operativo esté totalmente cargado. Durante esta etapa se carga el Kernel, se detectan y configuran los distintos elementos del hardware y se montan los sistemas de archivos. Todo este proceso sucede “en memoria”, o sea, usando la RAM como espacio de almacenamiento. Esto hace que sea efímero... se destruye una vez se alcanza la Stage2 (momento donde realmente los procesos, de lo que será nuestro OS, inician). Debido a que Stage1 tiene una función muy específica: "preparar el hardware y sistemas de archivos para Stage2", esta etapa carga solo el mínimo de elementos necesarios para lograr su objetivo... Stage1 es una especie de "pre-linux mínimo auxiliar y efímero". Por ello, intervenir y dotar esta etapa de funcionalidades, como conectividad a internet o un servidor SSH, puede ser no trivial. Por suerte NixOS ya posee algunas configuraciones que nos ayudaran. Este desafió es una buena oportunidad para aprender mas de los proceso de boot, NixOS y linux en general. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;El Plan:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Parte 1 (este post)&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Lograr “pausar” el arranque del sistema al final de Stage1 (y antes que Stage2) para poder debugear nuestro trabajo de forma mas cómoda. &lt;/li&gt;
&lt;li&gt;Lograr tener red en Stage1 mediante una interfaz Ethernet.&lt;/li&gt;
&lt;li&gt;Implementar un servidor SSH en Stage1 para poder conectarnos desde un equipo remoto (mediante Ethernet) para poder interactuar con los procesos y sistema de archivo de &lt;em&gt;initrm&lt;/em&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Parte 2 (...el la &lt;a href="https://dev.to/federico_jensen/red-wifi-y-ssh-en-stage1-boot-initrd-de-nixos-parte-2-4j9m"&gt;Parte 2&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Instalar, si es necesario, los drivers del adaptador inalámbrico para poder que sea detectado y cargado en Stage1.&lt;/li&gt;
&lt;li&gt;Validar que en Stage1 podemos escanear redes y conectarnos a ellas de manera segura.&lt;/li&gt;
&lt;li&gt;Automatizar el proceso de conexión a WiFi en Stage1 y probar el acceso remoto usando SSH. &lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  1) “Pausar” el arranque en Stage1
&lt;/h2&gt;

&lt;p&gt;Si tu NixOS esta cifrado con LUKS la "pausa" en Stage1 ya esta activa; no debes hacer nada. El momento, durante el boot, cuando se pregunta al usuario por la clave LUKS, es exactamente la frontera entre el Stage1 y Stage2.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Recordemos que LUKS es una manera de tener cifrado nuestro OS de forma completa. Es una opción que solo puede ser activada durante la instalación del OS y es muy recomendado usarla si la privacidad/seguridad son de tu interés.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Por lo tanto ya estas listo con el paso 1 si estas usando LUKS.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbv7wswizhemckgusbgo1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbv7wswizhemckgusbgo1.png" alt="Pausa de Stage1"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;En caso que estés siguiendo esta guiá pero no estés usando LUKS, no temas, existe una forma "manual" de detener el proceso de boot entre Stage1 y Stage2. Para esto debemos usar un &lt;em&gt;script&lt;/em&gt;, el cual llamaremos "force-pause-script", que se inicie al final de Stage1 y pause el proceso de boot hasta que nosotros lo indiquemos.&lt;/p&gt;

&lt;p&gt;Puedes añadir este &lt;em&gt;script&lt;/em&gt; a tu &lt;code&gt;/etc/nixos/hardware-configuration.conf&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;boot.initrd.systemd = {
  enable = true;
  services.force-pause-script = {
    enable = true;
    after = [ "basic.target" ];
    before = [ "default.target" ];
    wantedBy = [ "default.target" ];
    unitConfig = { 
      Description = "ForcePause";
      DefaultDependencies = false; 
    };
    serviceConfig = {
      Type = "oneshot";
      ExecStart = "${pkgs.bash}/bin/sh -c 'read'";
      StandardInput = "tty";
    };
  };
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Nota:&lt;/strong&gt; Quiero aclarar que esta guiá esta pensada para quienes usen LUKS principalmente. Por lo tanto, usar el &lt;em&gt;script&lt;/em&gt; anterior puede implicar que debas cambiar algunas cosas mencionadas más adelante. Específicamente deberás cambiar donde uso &lt;code&gt;systemd-ask-password-console.service&lt;/code&gt;, ya que tu sistema no tendrá este servicio. &lt;/p&gt;

&lt;p&gt;Esto pausará tu boot durante Stage1, para continuar con el proceso de boot presiona cualquier tecla.&lt;/p&gt;




&lt;h2&gt;
  
  
  2) Activando la interfaz Ethernet en Stage1
&lt;/h2&gt;

&lt;p&gt;Lo primero que necesitamos es identificar el nombre de nuestra interfaz Ethernet. Podemos usar el comando &lt;code&gt;ip link&lt;/code&gt; para listar las interfaces disponibles. En mi caso la interfaz Ethernet tiene por nombre “enp0s3” (usare este nombre durante la guiá a modo de ejemplo). &lt;/p&gt;

&lt;p&gt;Ahora podemos añadir lo siguiente en nuestro &lt;code&gt;/etc/nixos/hardware-configuration.nix&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;boot = {
  initrd = {
    systemd = {
      enable = true;
      network = {
        enable = true;
        networks = {
          enp0s3 = {
            enable = true;
            name = "enp0s3";
            DHCP = "yes";
          };
        };
      };
    };
  };
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Recuerda usar reemplazar el nombre de tu interfaz Ethernet como corresponda.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Nota 1:&lt;/strong&gt; Durante Stage1 pueden ver que usaremos “systemd”. Esto quiere decir que un “systemd” (independiente al normalmente usado en Stage2) estará encargado de gestionar los procesos de arranque de &lt;em&gt;init ram disk&lt;/em&gt;. Es importante mencionar que el uso de &lt;em&gt;systemd&lt;/em&gt; en &lt;em&gt;initrd&lt;/em&gt; aun es experimental en NixOS; a pesar de esto, según mi experiencia funciona de forma estable. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nota 2:&lt;/strong&gt; Vamos a usar &lt;a href="https://www.redeszone.net/tutoriales/internet/que-es-protocolo-dhcp/" rel="noopener noreferrer"&gt;DHCP&lt;/a&gt; para asignar IP, Gateway y DNS a nuestra interfaz Ethernet. Luego lo cambiaremos a una definición estática para facilitar el proceso de conexión por SSH.&lt;/p&gt;

&lt;p&gt;En teoría, con esto, ya deberíamos tener red en Stage1.&lt;/p&gt;

&lt;p&gt;En Stage1 se usará la interfaz Ethernet para iniciar una conexión a la red. Comprobar si esto está funcionando de manera correcta puede ser algo mas complejo. Una opción puede ser revisar los dispositivos conectados en las opciones de nuestro router. Otra manera podría ser usar una herramienta para analizar la red local y detectar los dispsitivios participantes. &lt;/p&gt;

&lt;p&gt;Nosotros vamos a optar poder añadir un &lt;em&gt;script&lt;/em&gt; a Stage1 que imprimirá en el log de boot los detalles de nuestra conectividad. Luego vamos a revisar dicho log para asegurarnos que todo este bien. &lt;/p&gt;

&lt;p&gt;El &lt;em&gt;script&lt;/em&gt; lo vamos a guardar en &lt;code&gt;/etc/nixos/hardware-configuration.nix&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;boot = {
  initrd = {
    systemd = {
      ...
      initrdBin = [ pkgs.iproute2 ];
      services = {
        CustomScript = {
          enable = true;
          wants = [ "systemd-udev-settle.service" ];
          after = [ "systemd-udev-settle.service" ];
          before = [ "systemd-ask-password-console.service" ];
          wantedBy =  [ "systemd-ask-password-console.service" ];
          unitConfig = { 
            Description = "CustomScript"; 
            DefaultDependencies = false;
          };
          serviceConfig = {
            Type = "oneshot";
            ExecStart="${pkgs.bash}/bin/sh -c 'sleep 5 &amp;amp;&amp;amp; ip addr'";
          }; 
        };
      };
      ...
    };
  };
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Nota 1:&lt;/strong&gt; En Stage1 muchos comandos no están disponibles. Debemos usar &lt;code&gt;initrdBin&lt;/code&gt; para especificar los paquetes que queremos incluir en Stage1. Vamos a incluir &lt;em&gt;iproute2&lt;/em&gt; para poder usar el comando &lt;em&gt;ip&lt;/em&gt; en el &lt;em&gt;script&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nota 2:&lt;/strong&gt; El &lt;em&gt;script&lt;/em&gt; se ejecutará antes que se nos solicite la clave LUKS en Stage1 y dejará el output de "ip addr" en el log. El &lt;em&gt;sleep&lt;/em&gt; es para dar tiempo a que la interfaz este totalmente configurada. Las opciones de &lt;em&gt;wants&lt;/em&gt;, &lt;em&gt;after&lt;/em&gt;, &lt;em&gt;before&lt;/em&gt; y &lt;em&gt;wantedBy&lt;/em&gt; nos ayudan a que el &lt;em&gt;script&lt;/em&gt; se ejecute el la secuencia y momento preciso. Específicamente esperar &lt;em&gt;systemd-udev-settle.service&lt;/em&gt; nos asegura que el hardware esté disponible. Y &lt;em&gt;systemd-ask-password-console.service&lt;/em&gt; a ejecutar el &lt;em&gt;script&lt;/em&gt; antes que se pregunte por la contraseña LUKS (momento en que Stage1 queda “pausado”).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nota 2.1:&lt;/strong&gt; Si no estas usando LUKS y estas usando el &lt;em&gt;script&lt;/em&gt; "force-pause-script" (indicando al inicio del post), cambia &lt;em&gt;systemd-ask-password-console.service&lt;/em&gt; por &lt;em&gt;force-pause-script.service&lt;/em&gt; tanto en &lt;em&gt;before&lt;/em&gt; como &lt;em&gt;wantedBy&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nota 4:&lt;/strong&gt; En caso que experimentes con &lt;em&gt;scripts&lt;/em&gt; de &lt;em&gt;systemd&lt;/em&gt; puede ser algo difícil saber sus "estados" y "orden de ejecución". Aquí te dejo algunos comandos (entre muchos otros) que pueden ser de utilidad para debugear:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;systemctl list-units&lt;/code&gt;&lt;br&gt;
&lt;code&gt;systemctl status &amp;lt;nombre-del-servicio/target&amp;gt;&lt;/code&gt;&lt;br&gt;
&lt;code&gt;systemctl list-dependencies --all &amp;lt;nombre-del-servicio&amp;gt;&lt;/code&gt;&lt;br&gt;
&lt;code&gt;systemctl list-dependencies --reverse &amp;lt;nombre-del-servicio&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Con esto listo, ahora vamos a reiniciar el sistema… pasar por el proceso de boot… esperar unos segundos… introducir la clave LUKS… y volver a nuestro escritorio de NixOS.  &lt;/p&gt;

&lt;p&gt;Una vez en el escritorio usaremos el comando &lt;code&gt;journalctl -b&lt;/code&gt; para ver el log de nuestro último proceso de boot.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lo que queremos saber, es si por defecto, se ha encontrado y encendido la interfaz Ethernet&lt;/strong&gt; ("enp0s3" en mi caso). Buscando en log del boot, deberemos encontrar el output de “ip addr”. Si todo va bien deberemos ver la interfaz Ethernet listada en dicho output. No solo eso, sino que también debería tener una IP asignada. Si esto es así, podemos seguir con el siguiente paso; configurar el servidor SSH.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft98n1buu0vbdir6bi8ja.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft98n1buu0vbdir6bi8ja.png" alt="Interfaces de red en el log de boot"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;En caso que &lt;strong&gt;no&lt;/strong&gt; se encuentre la interfaz Ethernet en Stage1... tenemos un problema. Un problema de drivers. Para solucionar esto deberemos recorrer una tangente:&lt;/p&gt;
&lt;h3&gt;
  
  
  2.1) Buscando y cargando drivers Ethernet en Stage1 de NixOS
&lt;/h3&gt;

&lt;p&gt;Si en Stage1 &lt;strong&gt;no&lt;/strong&gt; vemos la interfaz Ethernet, pero en Stage2 (escritorio de toda la vida) &lt;strong&gt;si&lt;/strong&gt; tenemos conexión... tenemos un indicativo que el driver relacionado no esta siendo "cargado completamente" durante Stage1. &lt;/p&gt;

&lt;p&gt;Para solucionar esto deberemos hacer un poco de investigación. Objetivo: averiguar el nombre del driver de Ethernet que "si" esta presente en Stage2 pero que "no" esta cargado en Stage1. Para esto podemos hacer uso de un par de herramientas. Instalaremos en &lt;code&gt;/etc/nixos/configuration.nix&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://search.nixos.org/packages?channel=24.11&amp;amp;show=pciutils&amp;amp;from=0&amp;amp;size=50&amp;amp;sort=relevance&amp;amp;type=packages&amp;amp;query=pciutils" rel="noopener noreferrer"&gt;pciutils&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://search.nixos.org/packages?channel=24.11&amp;amp;show=usbutils&amp;amp;from=0&amp;amp;size=50&amp;amp;sort=relevance&amp;amp;type=packages&amp;amp;query=usbutils" rel="noopener noreferrer"&gt;usbutils&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cada una de estas herramientas nos ayudarán a listar y averiguar mas del hardware que use el &lt;em&gt;bus&lt;/em&gt; PCI o USB. En mi caso, se que mi interfaz Ethernet usa el bus PCI, así que usare &lt;em&gt;pciutils&lt;/em&gt;. Pero puede que ustedes necesiten usar &lt;em&gt;usbutils&lt;/em&gt; si su interfaz usa USB. Una vez instaladas esta herramientas en NixOS:&lt;/p&gt;

&lt;p&gt;Usando los comandos &lt;code&gt;lspci -k&lt;/code&gt; o &lt;code&gt;lsusb -t&lt;/code&gt; vamos a tratar de buscar nuestro adaptador Ethernet. Lo que estamos buscando es el &lt;strong&gt;nombre&lt;/strong&gt; del “modulo”/“kernel” o “module”/“driver” relacionado al adaptador de red. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn8t2r147zq4mhrrlzc68.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn8t2r147zq4mhrrlzc68.png" alt="Lista de dispositivos PCI y sus modulos"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Leyendo el output de &lt;code&gt;lspci -k&lt;/code&gt; yo he podido identificar claramente que el "kernel module" usado para mi interfaz de red se llama: "e1000". Dicho driver lo debemos incluir para que sea totalmente cargado en Stage1. &lt;/p&gt;

&lt;p&gt;Para esto, debemos añadir el nombre del driver al listado de &lt;em&gt;availableKernelModules&lt;/em&gt; definido en &lt;code&gt;/etc/nixos/hardware-configuration.nix&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;boot.initrd.availableKernelModules = [ "e1000" … ];
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Luego de: construir nuestra nueva generación de NixOS, reiniciar el sistema y regresar a nuestro escritorio... entraremos nuevamente al log del boot con &lt;code&gt;journalctl -b&lt;/code&gt;. Si examinamos nuevamente el output de “ip addr”, deberíamos ver que ahora efectivamente esta listada la interfaz Ethernet (enp0s3 en mi caso).... y más aun... también deberíamos tener una IP asignada.&lt;/p&gt;

&lt;p&gt;Si por alguna razón no funciona, seguramente el nombre de nuestro driver esta incorrecto. En este caso el mejor aliado es Google. Buscando un poco deberíamos ser capaces de encontrar cual es el driver indicado para nuestra interfaz Ethernet.&lt;/p&gt;




&lt;h2&gt;
  
  
  3) Configurando SSH en Stage1
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Nota previa:&lt;/strong&gt; Durante todo el proceso hasta el momento (y lo que continúa) puede que nuestra partición boot (donde se almacenan todos los cambios relacionados a Stage1) se quede sin espacio. Para liberar el caché podemos usar el comando: &lt;code&gt;sudo nix-collect-garbage -d&lt;/code&gt; (ojo, tiene que ir con &lt;em&gt;sudo&lt;/em&gt; para que limpie correctamente). Generalmente la partición boot es bastante pequeña, así que termina siendo habitual limpiar el cache cada unas 5 a 10 generaciones de NixOS.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Es aconsejable usar &lt;code&gt;sudo nix-collect-garbage -d&lt;/code&gt; &lt;strong&gt;antes&lt;/strong&gt; de un &lt;code&gt;sudo nixos-rebuild switch&lt;/code&gt; y &lt;strong&gt;no&lt;/strong&gt; después. Limpiar el caché borra las generaciones anteriores del OS, usando los comandos en este orden nos aseguramos de siempre mantener “la versión previa” disponible (algo que puede ser necesario en caso de “romper” el OS). &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Bien, ahora que tenemos Stage1 con red, vamos a querer conectarnos por SSH para poder ejecutar comandos y debuggear directamente Stage1. &lt;/p&gt;

&lt;p&gt;Lo primero que vamos a necesitar es generar una dupla de claves privada-pública. En nuestro equipo remoto (desde donde nos vamos a conectar a Stage1) vamos a generar la dupla de claves RSA. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;En Windows podemos usar PuttyGen y en linux &lt;code&gt;ssh-keygen&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;La clave pública generada la dejamos en nuestro NixOs en el fichero &lt;code&gt;/etc/nixos/authorized_keys&lt;/code&gt;. Si tienes dudas sobre como debe ser el formato de las claves guardadas en &lt;code&gt;authorized_keys&lt;/code&gt;, puedes leer &lt;a href="https://www.ibm.com/docs/en/zos/3.1.0?topic=daemon-format-authorized-keys-file" rel="noopener noreferrer"&gt;esto&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Debido a un bug, al cual no quiero entrar a explicar, vamos a tener que generar una “key de host”; sin esto el servidor SSH no va a iniciar. Para esto en nuestro NixOS ejecutamos: &lt;code&gt;ssh-keygen -t rsa -N "" -f /etc/nixos/host_key&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Ahora ya tenemos los archivos con las credenciales necesarias listas y guardadas. Pero debemos recordar algo. Stage1 es un "espacio aislado" y se ejecuta en la ram durante el boot. O sea, Stage1 no tiene acceso directo a estas credenciales que hemos guardado en &lt;code&gt;/etc/nixos&lt;/code&gt;. Debemos primero indicar a NixOS que genere una "copia" de estos "secretos" desde el sistema de archivos del usuario al espacio que puede ser accedido durante &lt;em&gt;intird&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;Para esto podemos usar &lt;em&gt;secrets&lt;/em&gt; en nuestro &lt;code&gt;/etc/nixos/hardware-configuration.nix&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;boot = {
  initrd = {
    ...
    secrets = {
      "/etc/nixos/authorized_keys" = "/etc/nixos/authorized_keys";
      "/etc/nixos/host_key" = "/etc/nixos/host_key";
    };
    ...
  };
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Con esto estaremos copiando los ficheros de directorio &lt;code&gt;/etc/nixos/&lt;/code&gt; del sistema de ficheros del usuario, a un directorio exactamente con el mismo nombre &lt;code&gt;/etc/nixos/&lt;/code&gt;... pero que se montará en el &lt;em&gt;ram disk&lt;/em&gt; durante Stage1&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Nota 1:&lt;/strong&gt; NixOS maneja los secretos en la Stage1 de una manera en la cual no se borran al crear una nueva generación de OS. Por lo tanto, siempre que cambiemos los secretos es buena practica usar: &lt;code&gt;sudo nix-collect-garbage -d&lt;/code&gt; para eliminar/sobre-escribir las credenciales previas.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nota 2:&lt;/strong&gt; Con &lt;em&gt;secrets&lt;/em&gt; hay  tener cuidado de usar comillas (“”) al referenciar los &lt;em&gt;paths&lt;/em&gt;. Esto es importante para que las credenciales se almacenen de forma segura.&lt;/p&gt;

&lt;p&gt;Ahora activaremos el SSH en &lt;code&gt;/etc/nixos/hardware-configuration.nix&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;boot = {
  initrd = {
    ...
    network = {
      ssh = {
        enable = true;
        port = 2222;
        authorizedKeyFiles = [ "/etc/nixos/authorized_keys" ];
        hostKeys = [ "/etc/nixos/host_key" ];
      };
    };
    ...
  };
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Los archivos referenciados en &lt;em&gt;authorizedKeyFiles&lt;/em&gt; y &lt;em&gt;hostKeys&lt;/em&gt; seran buscados en el sistema de archivos de &lt;em&gt;ram disk&lt;/em&gt; del Stage1. Gracias al uso de &lt;em&gt;secrets&lt;/em&gt; estos estarán disponibles en dicho lugar. &lt;/p&gt;

&lt;p&gt;Ojo: Las definiciones de &lt;code&gt;ssh&lt;/code&gt; van dentro del segmento &lt;code&gt;boot.initrd.network&lt;/code&gt; &lt;strong&gt;no&lt;/strong&gt; &lt;code&gt;boot.initrd.systemd.network&lt;/code&gt;... es fácil confundirse entre ellos. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Y listo, ya deberíamos tener configurado nuestro servidor SSH en Stage1.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;Pero... aprovechando que estamos en &lt;code&gt;hardware-configuration.nix&lt;/code&gt; podemos:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Desactivar el &lt;em&gt;CustomScript&lt;/em&gt; que usamos durante la primera etapa de este proceso... ahora que vamos a tener acceso por SSH no necesitamos mas dicho &lt;em&gt;script&lt;/em&gt;. &lt;/li&gt;
&lt;li&gt;Desactivar el DHCP de la interfaz Ethernet y asignar manualmente los parámetros de: IP (address), Gateway y DNS. Aunque varia de router a router, puede que cada vez que estemos iniciando NixOS se este asginando una IP distinta a la interfaz Ethernet. Esto puede ser algo molesto si usamos SSH. Lo mejor es fijar dichos valores. Para lograr esto debemos desactivar DHCP en &lt;code&gt;hardware-configuration.nix&lt;/code&gt; (segmento de &lt;em&gt;networks&lt;/em&gt;):
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
systemd = {
...
  network = {
    enable = true;
    networks = {
      ...
      enp0s3 = {
        enable = true;
        name = "enp0s3";
        #DHCP = "yes" #Comentamos DHCP para desactivarlo
        #Asignamos los valores manualmente
        address = [ "192.168.1.20/24" ];
        gateway = [ "192.168.1.1" ];
        dns = [ "8.8.8.8" ];
      };
      ...
    };
  };
  ...
};
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Recuerda usar el nombre de tu interfaz Ethernet. La &lt;em&gt;address&lt;/em&gt; y &lt;em&gt;gateway&lt;/em&gt; dependerán de tu red local. Puedes usar los comandos: &lt;code&gt;ip route&lt;/code&gt; y &lt;code&gt;ip addr&lt;/code&gt; para saber que IP y Gateway tienes asignada y usar dichos valores en la configuración. Para el DNS puedes usar el de Google (8.8.8.8) a prueba... 1.1.1.1 también puede ser una alternativa. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Bien! Finalmente vamos a crear una nueva generación de NixOS con todos estos cambios y reiniciar el sistema.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;Si todo va bien, cuando Stage1 se detenga para pedirnos la clave LUKS, vamos a tener la posibilidad de acceder de forma remota usando SSH. Recuerda usar la IP del NixOS que acabamos de configurar y puerto (2222) correcto. También recuerda usar la llave privada correspondiente a la llave publica que usamos para configurar el servidor SSH. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;El usuario de Stage1 por defecto es: &lt;strong&gt;root&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Filfzmogyklba4napmit7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Filfzmogyklba4napmit7.png" alt="Conexión SSH a Stage1"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nota:&lt;/strong&gt; Recuerda que el propósito del SSH en Stage1 es meramente para debugear. Una vez tengas el Stage1 funcionando como quieras, es 100% recomendable desactivar el servidor y eliminar las credenciales asociadas.&lt;/p&gt;




&lt;h2&gt;
  
  
  bonus) Solucionando bug de red Stage1 -&amp;gt; Stage2
&lt;/h2&gt;

&lt;p&gt;Puede que durante, o al finalizar esta guiá, se percataran de un extraño error. Cuando usamos network en Stage1, el NetworkManager de Stage2 se vuelve algo "tonto" y no se conecta automáticamente a las redes cuando se nos presenta el escritorio del OS. Al parece esto se debe a que determinadas configuraciones de redes son pasadas de Stage1 a Stage2 y el sistema no "refresca" correctamente la asignación de IP. &lt;/p&gt;

&lt;p&gt;La manera mas fácil de solucionar esto es apagar y encender el NetworkManager cuando estemos en el escritorio de NixOS. Pero claramente es bastante incomodo tener que hacer esto en cada inicio.  &lt;/p&gt;

&lt;p&gt;Aquí presento un &lt;em&gt;script&lt;/em&gt; (muy "bruto") que automáticamente realiza el proceso anterior. Para implementarlo en vamos a nuestro &lt;code&gt;/etc/nixos/configuration.nix&lt;/code&gt; y añadimos el servicio:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;systemd.services.reset-network = {
  enable = true;
  description = "Reinicia NetworkManager para evitar configuraciones duplicadas";
  wants = [ "network-manager.service" ];
  after = [ "network-manager.service" ];
  wantedBy = [ "multi-user.target" ];
  serviceConfig = {
    ExecStart = "${pkgs.bash}/bin/sh -c 'until systemctl is-active --quiet NetworkManager; do sleep 1; done &amp;amp;&amp;amp; nmcli networking off &amp;amp;&amp;amp; sleep 5 &amp;amp;&amp;amp; nmcli networking on'";
    Type = "oneshot";
    RemainAfterExit = true;
    Environment = "PATH=${pkgs.networkmanager}/bin:${pkgs.bash}/bin:${pkgs.coreutils}/bin:${pkgs.systemd}/bin:$PATH";
  };
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;El &lt;em&gt;script&lt;/em&gt; espera que el servicio de NetworkManager este "activo", para luego desactivarlo y volver a encenderlo. Esto limpia "sea lo que sea" que provoca el error. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;También puede ser necesario agregar en &lt;code&gt;/etc/nixos/hardware-configuration.nix&lt;/code&gt; esto:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;boot.initrd.network.flushBeforeStage2 = false;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Esta declaración "originalmente" se supone que funcionaba, exactamente, para solucionar el bug que estamos comentando. Como dice el nombre: "network flush before stage2". Pero por alguna razón al usarlo en conjunto a &lt;em&gt;boot.initrd.systemd&lt;/em&gt; no funciona. Por tanto lo mejor es dejarlo apagado para que no rompa nada. &lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Final primera parte
&lt;/h2&gt;

&lt;p&gt;Espero que esta guiá los ayudara a obtener conexión a red durante el Stage1 de NixOS y/o a implementar un servidor SSH para poder debugear este segmento del proceso de boot.&lt;/p&gt;

&lt;p&gt;Quiero agradecer al &lt;a href="https://blog.decent.id/post/nixos-systemd-initrd/" rel="noopener noreferrer"&gt;blog de Spencer Balogh&lt;/a&gt; por su guiá indispensable en comprender como funciona el networking de Stage1. &lt;/p&gt;

&lt;p&gt;Como comente en un inicio, esta guiá nace como un pre-requisito para la implementación de un sistema de desbloquear remoto y seguro de particiones LUKS durante el proceso de boot.&lt;/p&gt;

&lt;p&gt;En la &lt;a href="https://dev.to/federico_jensen/red-wifi-y-ssh-en-stage1-boot-initrd-de-nixos-parte-2-4j9m"&gt;Parte 2&lt;/a&gt; de esta guiá veremos como lograr obtener red durante Stage1 pero usando una interfaz inalámbrica WiFi. Esto añade desafíos relacionados a drivers, protocolos de seguridad WiFi y uso de credenciales inalámbricas.&lt;/p&gt;

&lt;p&gt;:) &lt;/p&gt;

</description>
      <category>spanish</category>
      <category>nixos</category>
      <category>linux</category>
    </item>
  </channel>
</rss>
