<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Solución on gvisoc.com</title>
    <link>https://gvisoc.com/tags/soluci%C3%B3n/</link>
    <description>Recent content in Solución on gvisoc.com</description>
    <image>
      <title>gvisoc.com</title>
      <url>https://gvisoc.com/images/site-umina-gs.jpg</url>
      <link>https://gvisoc.com/images/site-umina-gs.jpg</link>
    </image>
    <generator>Hugo -- 0.151.0</generator>
    <language>es-ES</language>
    <managingEditor>gabriel@gvisoc.com (Gabriel Viso Carrera)</managingEditor>
    <webMaster>gabriel@gvisoc.com (Gabriel Viso Carrera)</webMaster>
    <copyright>Gabriel Viso Carrera</copyright>
    <lastBuildDate>Sun, 07 Sep 2025 07:49:35 +0000</lastBuildDate>
    <atom:link href="https://gvisoc.com/tags/soluci%C3%B3n/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Reenviar tráfico TCP y UDP por la red con iptables</title>
      <link>https://gvisoc.com/posts/iptables-router/</link>
      <pubDate>Sun, 07 Sep 2025 07:49:35 +0000</pubDate><author>gabriel@gvisoc.com (Gabriel Viso Carrera)</author>
      <guid>https://gvisoc.com/posts/iptables-router/</guid>
      <description>Este método permite encaminar tráfico UDP y TCP a través de la red cuando no se necesita proxy, o cuando las soluciones basadas en proxies fallan.</description>
      <content:encoded><![CDATA[<p>Este es el tercer artículo de la serie que empezó con &ldquo;<a href="https://gvisoc.com/posts/cambios-xmpp/">Cambios en mi red de la mano de XMPP</a>.&rdquo;</p>
<h2 id="el-problema">El problema</h2>
<p>En aquel artículo, casi al final de todo, comentaba que hacía falta aplicar una solución para que el tráfico XMPP del resto de puertos (5000, 5222,&hellip; todos los que no son el 80 ó el 443) fuese reenviado desde el VPS a mi servidor en casa.</p>
<p>Probé algunas cosas con la configuración de NGINX y su módulo <code>streams</code>, pero no funcionó, así que voy a describir aquí cómo acabé usando las capacidades de filtrado de paquetes de Linux (el núcleo mismo) a través de <a href="https://www.netfilter.org/projects/iptables/index.html">iptables (en inglés)</a>.</p>
<p>Mi solución está basada y adaptada a partir de lo explicado en este <a href="https://ryanwelch.me/blog/port-forward-with-tailscale/">artículo (en inglés)</a> de <a href="https://ryanwelch.me">Ryan Welch</a>.</p>
<figure class="ma0 w-75">
    <img loading="lazy" src="/images/20250910-solution.png"
         alt="El diagrama que representa lo que queremos conseguir y acabamos de detallar."/> <figcaption>
            <p>El objetivo</p>
        </figcaption>
</figure>

<p>Al final del artículo, en cualquier caso, dejaré las configuraciones que intenté aplicar en NGINX para procesar tráfico TCP y UDP en general. Quizá lo necesitemos más adelante, o a lo mejor decides probarlo y comentarme qué es lo que hice mal.</p>
<h2 id="solución">Solución</h2>
<p>Como comentaba antes, Linux (NO GNU/Linux, sino &ldquo;Linux&rdquo; sin más, el núcleo) tiene funcionalidades de filtrado de paquetes de red incluidas, que podemos configurar para nuestros propios fines.</p>
<p>Para configurar la redirección de tráfico en el VPS, entramos por SSH y habilitaremos <em>IP forwarding</em> en el núcleo:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="go">sudo sysctl -w net.ipv4.ip_forward=1
</span></span></span></code></pre></div><p>Esto puede que se aplique entre arranques, o no, dependiendo de tu distribución. Para asegurarte, edita el fichero <code>/etc/sysctl.conf</code> y descomenta la línea <code>net.ipv4.ip_forward=1</code>.</p>
<p>Tras ello, ya podrás redirigir puertos y rangos de puertos con instrucciones como la siguiente:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="go">iptables -A PREROUTING -t nat -p tcp -i eth0 --dport 5222 -j DNAT --to-destination &lt;IP Destino&gt;:5222
</span></span></span><span class="line"><span class="cl"><span class="go">iptables -A POSTROUTING -t nat -p tcp -d &lt;IP Destino&gt; --dport 5222 -j MASQUERADE
</span></span></span></code></pre></div><p>Y, para rangos de puertos:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="go">iptables -A PREROUTING -t nat -p udp -i eth0 -m multiport --dports 49152:65535 -j DNAT --to-destination &lt;IP Destino&gt;:49152-65535
</span></span></span><span class="line"><span class="cl"><span class="go">iptables -A POSTROUTING -t nat -p udp -d &lt;IP Destini&gt; -m multiport --dports 49152:65535 -j MASQUERADE
</span></span></span></code></pre></div><p>Vas a tener que cambiar los puertos del ejemplo por los tuyos propios, así como poner tu propia dirección IP de destino en lugar del texto <code>&lt;IP Destino&gt;</code>.</p>
<p>Para el caso de XMPP hay que añadir todas las reglas de renvío correspondientes a sus puertos, cambiando el texto <code>&lt;IP Destino&gt;</code> por la dirección IP del servidor de casa, <em>patata</em> en el <a href="https://gvisoc.com/posts/vps-servidor-casero/">artículo previo de la serie</a>, y teniendo en cuenta que la dirección que tenemos que configurar es la de <em>patata</em> en Tailscale.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="go">iptables -A PREROUTING -t nat -p tcp -i eth0 --dport 5222 -j DNAT --to-destination &lt;IP Destino&gt;:5222
</span></span></span><span class="line"><span class="cl"><span class="go">iptables -A POSTROUTING -t nat -p tcp -d &lt;IP Destino&gt; --dport 5222 -j MASQUERADE
</span></span></span><span class="line"><span class="cl"><span class="go">iptables -A PREROUTING -t nat -p tcp -i eth0 --dport 5269 -j DNAT --to-destination &lt;IP Destino&gt;:5269
</span></span></span><span class="line"><span class="cl"><span class="go">iptables -A POSTROUTING -t nat -p tcp -d &lt;IP Destino&gt; --dport 5269 -j MASQUERADE
</span></span></span><span class="line"><span class="cl"><span class="go">iptables -A PREROUTING -t nat -p tcp -i eth0 --dport 5000 -j DNAT --to-destination &lt;IP Destino&gt;:5000
</span></span></span><span class="line"><span class="cl"><span class="go">iptables -A POSTROUTING -t nat -p tcp -d &lt;IP Destino&gt; --dport 5000 -j MASQUERADE
</span></span></span><span class="line"><span class="cl"><span class="go">iptables -A PREROUTING -t nat -p tcp -i eth0 --dport 3478 -j DNAT --to-destination &lt;IP Destino&gt;:3478
</span></span></span><span class="line"><span class="cl"><span class="go">iptables -A POSTROUTING -t nat -p tcp -d &lt;IP Destino&gt; --dport 3478 -j MASQUERADE
</span></span></span><span class="line"><span class="cl"><span class="go">iptables -A PREROUTING -t nat -p tcp -i eth0 --dport 3479 -j DNAT --to-destination &lt;IP Destino&gt;:3479
</span></span></span><span class="line"><span class="cl"><span class="go">iptables -A POSTROUTING -t nat -p tcp -d &lt;IP Destino&gt; --dport 3479 -j MASQUERADE
</span></span></span><span class="line"><span class="cl"><span class="go">iptables -A PREROUTING -t nat -p udp -i eth0 --dport 3478 -j DNAT --to-destination &lt;IP Destino&gt;:3478
</span></span></span><span class="line"><span class="cl"><span class="go">iptables -A POSTROUTING -t nat -p udp -d &lt;IP Destino&gt; --dport 3478 -j MASQUERADE
</span></span></span><span class="line"><span class="cl"><span class="go">iptables -A PREROUTING -t nat -p udp -i eth0 --dport 3479 -j DNAT --to-destination &lt;IP Destino&gt;:3479
</span></span></span><span class="line"><span class="cl"><span class="go">iptables -A POSTROUTING -t nat -p udp -d &lt;IP Destino&gt; --dport 3479 -j MASQUERADE
</span></span></span><span class="line"><span class="cl"><span class="go">iptables -A PREROUTING -t nat -p tcp -i eth0 --dport 5349 -j DNAT --to-destination &lt;IP Destino&gt;:5349
</span></span></span><span class="line"><span class="cl"><span class="go">iptables -A POSTROUTING -t nat -p tcp -d &lt;IP Destino&gt; --dport 5349 -j MASQUERADE
</span></span></span><span class="line"><span class="cl"><span class="go">iptables -A PREROUTING -t nat -p tcp -i eth0 --dport 5350 -j DNAT --to-destination &lt;IP Destino&gt;:5350
</span></span></span><span class="line"><span class="cl"><span class="go">iptables -A POSTROUTING -t nat -p tcp -d &lt;IP Destino&gt; --dport 5350 -j MASQUERADE
</span></span></span><span class="line"><span class="cl"><span class="go">iptables -A PREROUTING -t nat -p udp -i eth0 --dport 5349 -j DNAT --to-destination &lt;IP Destino&gt;:5349
</span></span></span><span class="line"><span class="cl"><span class="go">iptables -A POSTROUTING -t nat -p udp -d &lt;IP Destino&gt; --dport 5349 -j MASQUERADE
</span></span></span><span class="line"><span class="cl"><span class="go">iptables -A PREROUTING -t nat -p udp -i eth0 --dport 5350 -j DNAT --to-destination &lt;IP Destino&gt;:5350
</span></span></span><span class="line"><span class="cl"><span class="go">iptables -A POSTROUTING -t nat -p udp -d &lt;IP Destino&gt; --dport 5350 -j MASQUERADE
</span></span></span><span class="line"><span class="cl"><span class="go">iptables -A PREROUTING -t nat -p udp -i eth0 -m multiport --dports 49152:65535 -j DNAT --to-destination &lt;IP Destino&gt;:49152-65535
</span></span></span><span class="line"><span class="cl"><span class="go">iptables -A POSTROUTING -t nat -p udp -d &lt;IP Destino&gt; -m multiport --dports 49152:65535 -j MASQUERADE
</span></span></span></code></pre></div><p>Prueba que todo funciona y graba las reglas de iptables con <code>sudo iptables-save &gt; /etc/iptables/rules.v4</code>, de tal forma que se apliquen cada vez que reinicies el VPS.</p>
<p>En <a href="https://ryanwelch.me/blog/port-forward-with-tailscale/">su artículo</a>, Ryan comentaba otras configuraciones adicionales para temas tales como control de congestión. Consulta ese artículo para saber más, y aplica todo aquello que te sea de utilidad.</p>
<h2 id="nginx-con-tráfico-tcp-y-udp-genérico">NGINX con tráfico TCP y UDP genérico</h2>
<blockquote>
<p>Esta parte del artículo no está del todo probada, porque no me acabó de funcionar para la instalación del servidor XMPP <a href="http://snikket.org">Snikket</a>. Sin embargo, de acuerdo a su documentación, ésta es la forma en la que se configura NGINX para tráfico que no es Web.</p></blockquote>
<p>Instala <code>libnginx-mod-stream</code> para habilitar el soporte a proxies inversos TCP y UDP.</p>
<p>Modifica <code>/etc/nginx/nginx.conf</code> para añadir un bloque <em>stream</em>:</p>
<pre tabindex="0"><code class="language-conf" data-lang="conf">stream {
        include /etc/nginx/streams-enabled/*;
}
</code></pre><p>Tras ello, crea los directorios correspondientes siguiendo el mismo esquema existente para las webs: <code>sudo mkdir -p /etc/nginx/streams-available /etc/nginx/streams-enabled</code></p>
<p>Crea un fichero <code>/etc/nginx/streams-available/tcpudpservice.example.com.conf</code> con reglas como las siguientes:</p>
<pre tabindex="0"><code class="language-conf" data-lang="conf"># Puerto TCP (tráfico no HTTP):
server {
        listen 5222;
        proxy_pass &lt;IP Destino&gt;:5222;
}

# ...

# Puerto UDP:
server {
        listen 3478 udp;
        proxy_pass &lt;IP Destino&gt;:3478;
}

# ...

# Se aceptan rangos, también. En este caso, fíjate
# en el uso de $server_port en la sentencia proxy_pass.

server {
        listen 49152-65535 udp;
        proxy_pass &lt;IP Destino&gt;:$server_port;
}
</code></pre><p>En caso de definir rangos de puertos muy grande, como los que propone Snikket para conversaciones de audio y vídeo por XMPP en instalaciones con muchos usuarios, NGINX devolverá un error al tener demasiados ficheros abiertos. La configuración de Snikket espera poder tener hasta 16384 conexiones UDP abiertas al mismo tiempo.</p>
<p>Si queremos resolver esto en lugar de reducir el rango de puertos UDP, hay que aumentar el parámetro <code>LimitNOFILE</code> de NGINX. Para eso, ejecuta <code>sudo systemctl edit nginx.service</code>; esto abrirá un fichero de extensión de la definición del servicio</p>
<p>Escribe lo siguiente y graba los cambios:</p>
<pre tabindex="0"><code class="language-unit" data-lang="unit">[Service]
LimitNOFILE=65535
</code></pre><p>Tras ello, en el preámbulo de <code>/etc/nginx/nginx.conf</code> (fuera de cualquier bloque <code>http</code>, <code>events</code> o <code>stream</code>), añade la línea  <code>worker_rlimit_nofile</code> con un valor menor a 65535 (30000 funciona para Snikket), e incrementa el valor de <code>worker_connections</code> dentro de <code>events</code>:</p>
<pre tabindex="0"><code class="language-conf" data-lang="conf">...
include /etc/nginx/modules-enabled/*.conf;

worker_rlimit_nofile 30000;

events {
        # worker_connections 768;
        # 3 veces 8192 será suficiente
        worker_connections 24576;
        # multi_accept on;
}

...
</code></pre><p>Como dije antes, esta configuración no me sirvió para XMPP, pero puede ser útil para otros casos de uso.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Exponer servicios alojados en casa usando un VPS y Tailscale</title>
      <link>https://gvisoc.com/posts/vps-servidor-casero/</link>
      <pubDate>Fri, 05 Sep 2025 05:40:00 +1000</pubDate><author>gabriel@gvisoc.com (Gabriel Viso Carrera)</author>
      <guid>https://gvisoc.com/posts/vps-servidor-casero/</guid>
      <description>Una forma fácil de exponer servicios en tu red casera sin necesidad de abrir puertos ni contratar direcciones IP estáticas con tu operador de acceso a internet.</description>
      <content:encoded><![CDATA[<h2 id="problema">Problema</h2>
<p>Este texto detalla los pasos a seguir para conectar un proxy inverso (<a href="https://nginx.org">NGINX</a>) instalado en un servidor A, y dar acceso a servicios web instalados en otra máquina diferente, un servidor B. Si la máquinas están en ubicaciones o redes diferentes, la conectividad la podremos resolver mediante varias alternativas, como una VPN.</p>
<p>En mi caso concreto, esto sirve para instalar NGINX en un VPS, y usarlo para exponer mis servicios alojados en un servidor que tengo en casa, &ldquo;barcas&rdquo;. Para conectar las dos máquinas y que NGINX pueda redirigir el tráfico a esos servicios, he usado <a href="https://tailscale.com">Tailscale</a>.</p>
<figure class="ma0 w-75">
    <img loading="lazy" src="/images/20250905-solution.png"
         alt="Un diagrama que representa lo que queremos conseguir y que acabamos de explicar"/> <figcaption>
            <p>El objetivo</p>
        </figcaption>
</figure>

<p>Este artículo continúa la serie que empezó con &ldquo;<a href="/posts/cambios-xmpp/">Cambios en mi red de la mano de XMPP</a>&rdquo;. Si te preguntas por qué querríamos hacer esto, o qué valor tiene esta configuración, visita ese enlace.</p>
<h2 id="solución">Solución</h2>
<p>Para llevar a cabo esta solución necesitarás:</p>
<ol>
<li>Un servidor VPS contratado con tu servicio de alojamiento de confianza, al que poder acceder por SSH.</li>
<li>Un servidor en tu casa, con al menos un servicio aceptando conexiones HTTP. Por ejemplo, en el puerto 5000 (<code>0.0.0.0:5000</code>). A este servidor lo llamaremos <em>patata</em> en el resto del artículo, por claridad.</li>
<li>Una cuenta gratuita en <a href="https://tailscale.com">Tailscale</a>. En general, valdría con cualquier otro proveedor de VPN, pero es preferible que esté basada en <a href="https://es.wikipedia.org/wiki/WireGuard">WireGuard</a>, porque ofrece un mejor rendimiento que <a href="https://es.wikipedia.org/wiki/OpenVPN">OpenVPN</a>.</li>
<li>Opcionalmente, o para que esto tenga sentido, un dominio con sus registros de DNS apuntando al VPS que mencionamos en el punto 1.</li>
</ol>
<p>En las instrucciones de este artículo supondré que ambos servidores (el VPS y <em>patata</em>) tienen instalada una Ubuntu LTS Server (por ejemplo, la 24.04).</p>
<p>Si no hay problemas, en 20 minutos deberías tenerlo todo listo.</p>
<h3 id="servidor-en-casa">Servidor en casa</h3>
<p>Nos conectaremos a <em>patata</em>, donde está nuestro servicio web esperando peticiones en el puerto 5000.</p>
<p><a href="https://tailscale.com/download">Instalamos Tailscale</a> y autenticamos a <em>patata</em> en nuestra cuenta. Esto asociará una dirección IP dentro de la VPN a <em>patata</em>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">#</span> Las órdenes para instalar tailscale no las reproduzco 
</span></span><span class="line"><span class="cl"><span class="gp">#</span> porque podrían cambiar en cualquier momento.
</span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="go">sudo tailscale up
</span></span></span><span class="line"><span class="cl"><span class="go"></span><span class="gp">#</span> Seguimos las instrucciones por pantalla
</span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="gp">#</span> Habilitamos Tailscale como servicio de sistema permanentemente
</span></span><span class="line"><span class="cl"><span class="go">sudo systemctl enable tailscaled --now
</span></span></span><span class="line"><span class="cl"><span class="go"></span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="gp">#</span> Obtenemos la IP de esta máquina en la tailnet y la anotamos.
</span></span><span class="line"><span class="cl"><span class="go">tailscale ip -4
</span></span></span><span class="line"><span class="cl"><span class="go">100.85.67.22
</span></span></span></code></pre></div><p>En el panel de control de Tailscale podremos ver su nombre local, además de la IP devuelta por la última orden.</p>
<p>También podremos configurar la máquina para que no haya que re-introducirla en la red, desactivando la expiración de la clave usada para autenticar la máquina en Tailscale.</p>
<figure class="ma0 w-10">
    <img loading="lazy" src="/images/20250905-keyexpiry.png"
         alt="Un menú contextual del panel de control de Tailscale para desactivar la expiración de las claves"/> <figcaption>
            <p>Opción relevante para desactivar la expiración de las claves</p>
        </figcaption>
</figure>

<p>Opcionalmente, podemos activar el &ldquo;MagicDNS&rdquo; para podernos referir a ambas máquinas mediante un nombre, en lugar de mediante una dirección IP, sin tener que configurar nada localmente en las máquinas.</p>
<figure class="ma0 w-75">
    <img loading="lazy" src="/images/20250905-magicdns.png"
         alt="Opciones de &#34;MagicDNS&#34; en el panel de control de Tailscale, descrita como &#34;Automatically register domain names for devices in your tailnet. This lets you to use a machine’s name instead of its IP address.&#34;. En la imagen ya se encuentra activado."/> <figcaption>
            <p>Opciones de &ldquo;MagicDNS&rdquo; en el panel de control de Tailscale. En el ejemplo ya se encuentra activado.</p>
        </figcaption>
</figure>

<p>Una vez la máquina está en Tailscale, debemos <strong>abrir el puerto 5000 en el cortafuegos de <em>patata</em></strong>, si es que no lo habíamos hecho ya, para que pueda recibir peticiones desde el VPS por dicho puerto.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="go">sudo iptables -A INPUT -p tcp -m tcp --dport 5000 -j ACCEPT
</span></span></span></code></pre></div><p>A este respecto:</p>
<ol>
<li>Si no tienes <code>iptables-persistent</code> instalado, es el momento de instalarlo para poder grabar las reglas de cortafuegos de tal forma que se apliquen con cada reinicio de la máquina.</li>
</ol>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="go">sudo apt install iptables-persistent 
</span></span></span><span class="line"><span class="cl"><span class="go">sudo iptables-save &gt; /etc/iptables/rules.v4
</span></span></span></code></pre></div><ol start="2">
<li>Personalmente, abro los puertos en todos los interfaces y no sólo en el de Tailscale.
<ul>
<li>Al no tener que abrir ese puerto en el router, no estoy haciendo nada que me deje demasiado expuesto.</li>
<li>Al hacerlo así, no necesito acceder por Tailscale a <em>patata</em> cuando, estando en casa, necesito hacer alguna prueba.</li>
<li>Cada caso es distinto: decide qué hacer tú mismo con tu cortafuegos dependiendo de lo crítico que sea el servicio que estás configurando, y lo sensibles que sean los datos que gestiona.</li>
</ul>
</li>
</ol>
<h3 id="vps">VPS</h3>
<p>En segundo lugar, nos conectamos al VPS por medio de SSH e instalamos un proxy inverso. Aunque no vayamos a tener más de un servicio escuchando en los puertos 80 y 443, configurar y entender un proxy inverso es más fácil que configurar y entender reglas de reenvío de tráfico y DNAT en un cortafuegos como iptables.</p>
<p>En mi caso, suelo usar NGINX.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="go">sudo apt update &amp;&amp; sudo apt install nginx
</span></span></span></code></pre></div><p><a href="https://tailscale.com/download">Instalamos Tailscale</a> y repetimos los mismos pasos al respecto que en el caso de <em>patata</em>. Anotamos la dirección IP de el VPS en &ldquo;la tailnet&rdquo;, por ejemplo <code>100.85.77.36</code>.</p>
<p>Obtenemos un certificado de Let&rsquo;s Encrypt para nuestro dominio, con CertBot. Para esto:</p>
<ul>
<li>Debemos configur previamente los registros DNS de nuestro dominio, <code>ejemplo.com</code>, para que apunten a la IP pública (no a su IP en Tailscale) del VPS en el que estamos trabajando.</li>
<li>Es posible tengamos que parar NGINX para esto (<code>sudo systemctl stop nginx</code>), dependiendo de nuestros proveedores de dominio y los plugins de CertBot disponibles para interactuar con él.</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="go">sudo certbot certonly --standalone -d ejemplo.com
</span></span></span><span class="line"><span class="cl"><span class="go">...
</span></span></span><span class="line"><span class="cl"><span class="go">...
</span></span></span><span class="line"><span class="cl"><span class="go">Successfully received certificate.
</span></span></span><span class="line"><span class="cl"><span class="go">Certificate saved at: /etc/letsencrypt/live/ejemplo.com/fullchain.pem;
</span></span></span><span class="line"><span class="cl"><span class="go">Key is saved at:      /etc/letsencrypt/live/ejemplo.com/privkey.pem;
</span></span></span><span class="line"><span class="cl"><span class="go">...
</span></span></span><span class="line"><span class="cl"><span class="go">...
</span></span></span></code></pre></div><p>Configuramos el servicio en el proxy inverso, poniendo en la sentencia <code>proxy_pass</code> la IP de nuestro servidor <em>patata</em> en Tailscale. Para ello, en <code>/etc/nginx/sites-available/</code> creamos un fichero de configuración, por ejemplo <code>ejemplo.com.conf</code> para una web <code>https://ejemplo.com</code>.</p>
<pre tabindex="0"><code class="language-conf" data-lang="conf">upstream ejemploweb {
        # Sustituye [IP o nombre de máquina] por el valor de tu &#39;patata&#39;
        # **en Tailscale**.
        # 100.85.67.22 en el texto del artículo.
        server [IP o nombre de máquina]:5000;
        keepalive 64;
}

server {
        server_name ejemplo.com;
        listen 80;

        location / {
                return 301 https://$host$request_uri;
        }
}

server {
        server_name ejemplo.com;
        listen 443 ssl http2;

        # Other SSL stuff goes here
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_ciphers HIGH:!MEDIUM:!LOW:!aNULL:!NULL:!SHA;
        ssl_prefer_server_ciphers on;
        ssl_session_cache shared:SSL:10m;
        ssl_session_tickets off;

        ssl_certificate     /etc/letsencrypt/live/ejemplo.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/ejemplo.com/privkey.pem;

        location / {
                # The final `/` is important.
                proxy_pass http://ejemploweb/;
                add_header X-Frame-Options SAMEORIGIN;
                add_header X-XSS-Protection &#34;1; mode=block&#34;;
                proxy_redirect off;
                proxy_buffering off;
                proxy_set_header Host $host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Forwarded-Proto $scheme;
                proxy_set_header X-Forwarded-Port $server_port;
                proxy_read_timeout 90;
        }
}
</code></pre><p>Creamos un enlace simbólico a este fichero en <code>/etc/nginx/sites-enabled</code>, probamos la configuración de NGINX y, si todo va bien, la recargamos.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="go">cd /etc/nginx/sites-enabled/
</span></span></span><span class="line"><span class="cl"><span class="go">sudo ln -s ../sites-available/ejemplo.com.conf
</span></span></span><span class="line"><span class="cl"><span class="go">sudo nginx -t
</span></span></span><span class="line"><span class="cl"><span class="go">nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
</span></span></span><span class="line"><span class="cl"><span class="go">nginx: configuration file /etc/nginx/nginx.conf test is successful
</span></span></span><span class="line"><span class="cl"><span class="go"></span><span class="gp">#</span> Si hemos detenido el servicio de NGINX para obtener el certificado, 
</span></span><span class="line"><span class="cl"><span class="gp">#</span> lo arrancamos<span class="p">;</span> si no:
</span></span><span class="line"><span class="cl"><span class="go">sudo systemctl reload nginx
</span></span></span></code></pre></div><p>En este punto, deberíamos poder interactuar con nuestro servicio en <em>patata</em> desde <code>https://ejemplo.com</code>.</p>
<h2 id="posibles-errores-que-te-puedes-encontrar">Posibles errores que te puedes encontrar</h2>
<ul>
<li><strong>El navegador no muestra nada, el servicio no contesta</strong>. Si hay actividad en los logs de NGINX en el VPS (<code>sudo tail -f /var/log/nginx/access.log</code>), y la petición se abandona tras un tiempo (<em>timeout</em>), hay varias posibles causas que me he encontrado con mi limitada experiencia. En <em>patata</em>:
<ul>
<li>El servicio al que quieremos acceder a través de NGINX no está funcionando, y tenemos que arrancarlo,</li>
<li>o el servicio está expuesto en el puerto 5000 de un interfaz de red específico, en lugar de <code>0.0.0.0</code> (que significa <code>todos los interfaces de red</code> de <em>patata</em>), y que no es el de Tailscale; por ejemplo, en <code>127.0.0.1</code>,</li>
<li>o hemos hecho algo mal con el cortafuegos y la petición se está rechazando de esta forma.</li>
</ul>
</li>
<li><strong>La configuración de NGINX es correcta</strong> (<code>sudo nginx -t</code> dice que 👍)<strong>, pero NGINX no arranca</strong> o se muere al recargar la configuración. La causa más frecuente es que NGINX no se puede comunicar con <em>patata</em>, al que estaríamos apuntando con la sentencia <code>proxy_pass</code>, porque no lo encuentra.
<ul>
<li>O bien hemos cometido un error al configurar el <code>proxy_pass</code>,</li>
<li>o bien NGINX ha intentado establecer contacto con <em>patata</em> antes de que Tailscale estableciese el túnel, por ejemplo si esto ocurre tras reiniciar el VPS,</li>
<li>o bien el servicio de Tailscale se ha parado en alguna de las dos máquinas.</li>
<li>Esta causa se confirma con el mensaje <code>host not found in upstream</code> en la salida de <code>sudo systemctl status nginx</code>:</li>
</ul>
</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="go">nginx.service - A high performance web server and a reverse proxy server
</span></span></span><span class="line"><span class="cl"><span class="go">     Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; preset: enabled)
</span></span></span><span class="line"><span class="cl"><span class="go">    Drop-In: /etc/systemd/system/nginx.service.d
</span></span></span><span class="line"><span class="cl"><span class="go">             └─override.conf
</span></span></span><span class="line"><span class="cl"><span class="go">     Active: active (running) since Fri 2025-08-29 11:05:51 UTC; 3 days ago
</span></span></span><span class="line"><span class="cl"><span class="go">       Docs: man:nginx(8)
</span></span></span><span class="line"><span class="cl"><span class="go">    Process: 1154 ExecStartPre=/usr/sbin/nginx -t -q -g daemon on; master_process on; (code=exited, status=0/SUCCESS)
</span></span></span><span class="line"><span class="cl"><span class="go">    Process: 1156 ExecStart=/usr/sbin/nginx -g daemon on; master_process on; (code=exited, status=0/SUCCESS)
</span></span></span><span class="line"><span class="cl"><span class="go">    Process: 58676 ExecReload=/usr/sbin/nginx -g daemon on; master_process on; -s reload (code=exited, status=1/FAILURE)
</span></span></span><span class="line"><span class="cl"><span class="go">   Main PID: 1157 (nginx)
</span></span></span><span class="line"><span class="cl"><span class="go">      Tasks: 3 (limit: 1110)
</span></span></span><span class="line"><span class="cl"><span class="go">     Memory: 46.9M (peak: 200.2M)
</span></span></span><span class="line"><span class="cl"><span class="go">        CPU: 29min 57.349s
</span></span></span><span class="line"><span class="cl"><span class="go">     CGroup: /system.slice/nginx.service
</span></span></span><span class="line"><span class="cl"><span class="go">             ├─1157 &#34;nginx: master process /usr/sbin/nginx -g daemon on; master_process on;&#34;
</span></span></span><span class="line"><span class="cl"><span class="go">             ├─1158 &#34;nginx: worker process&#34;
</span></span></span><span class="line"><span class="cl"><span class="go">             └─1159 &#34;nginx: cache manager process&#34;
</span></span></span><span class="line"><span class="cl"><span class="go"></span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err"></span><span class="go">...
</span></span></span><span class="line"><span class="cl"><span class="go">Sep 02 05:32:49 vps-hostingprovider nginx[58676]: 2025/09/02 05:32:49 [emerg] 58676#58676: host not found in upstream &#34;100.85.77.22&#34; in /etc/nginx/sites-enabled/ejemlo.com.conf&gt;
</span></span></span><span class="line"><span class="cl"><span class="go">Sep 02 05:32:49 vps-hostingprovider systemd[1]: nginx.service: Control process exited, code=exited, status=1/FAILURE
</span></span></span><span class="line"><span class="cl"><span class="go">Sep 02 05:32:49 vps-hostingprovider systemd[1]: Reload failed for nginx.service - A high performance web server and a reverse proxy server.
</span></span></span><span class="line"><span class="cl"><span class="go">lines 1-28/28 (END)
</span></span></span></code></pre></div><ul>
<li><strong>Recibimos un código de estado HTTP 502</strong>. Esto quiere decir que, si bien NGINX está funcionando correctamente, el servicio al que nos conectamos (expuesto en el puerto 5000 de <em>patata</em>), está devolviendo errores.
<ul>
<li>Si haces una prueba local en <em>patata</em> y el servicio funciona, casi seguro que se trata de un tema de <strong>proxies de confianza</strong>. Describir el problema en detalle excede los objetivos de este artículo, pero en resumen se trata de que tienes que especificar en la configuración de ese servicio, en <em>patata</em>, que NGINX está instalado en una máquina diferente, el VPS, y configurar la dirección del VPS en Tailscale como proxy de confianza. <strong>Consulta los logs del servicio</strong> para confirmar esta hipótesis.</li>
<li>Esto no es un problema, es una característica de seguridad bastante interesante.</li>
<li>Por ejemplo, esto me pasó con mis instancias de Mastodon y de Nextcloud. En ambos casos, la documentación contenía las soluciones: <a href="https://docs.joinmastodon.org/admin/config/#trusted_proxy_ip">Mastodon &ndash; trusted proxies</a>, <a href="https://docs.nextcloud.com/server/latest/admin_manual/configuration_server/reverse_proxy_configuration.html#defining-trusted-proxies">Nextcloud &ndash; trusted proxies</a></li>
<li>Depende de cómo esté implementado el servicio que estamos intentando arreglar, puede ser que acepte un proxy de confianza tanto como nombre de máquina o como direccion IP, o sólo como IP. Ármate de paciencia y si no te funciona con el nombre de la máquina no te desesperes.</li>
</ul>
</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>Cambios en mi red de la mano de XMPP</title>
      <link>https://gvisoc.com/posts/cambios-xmpp/</link>
      <pubDate>Sun, 31 Aug 2025 00:49:35 +0000</pubDate><author>gabriel@gvisoc.com (Gabriel Viso Carrera)</author>
      <guid>https://gvisoc.com/posts/cambios-xmpp/</guid>
      <description>Hace unos días me recomendaron Snikket como servidor XMPP sencillo de instalar y mantener, y a raíz de ello he cambiado la forma de exponer mis servicios a internet.</description>
      <content:encoded><![CDATA[<p><strong>Hace unos días me recomendaron <a href="https://snikket.org">Snikket</a> como una opción sencilla para montar un servidor XMPP<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>, y me lancé por el terraplén</strong> de cabeza. A mitad del descenso, me encontré un montón de problemas interesantísimos que resolver, que iré desgranando paso a paso en los próximos artículos.</p>
<p>En éste os voy a contar cuáles son esos problemas, por qué surgen, por qué los quiero resolver y cómo los he resuelto, pero desde un punto de vista de diseño por el momento. No vas a encontrar instrucciones de terminal para resolver todo esto, sino el contexto necesario para saber qué estoy intentando resolver; las instrucciones detalladas vendrán en los siguientes artículos.</p>
<p>Hasta ahora, todos mis servicios alojados bajo mi impresora eran servicios Web, es decir, basados en comunicaciones a través de los puertos 80 y 443 (HTTP y HTTPs). Estos puertos eran suficientes para comunicar todos mis servicios con mis dispositivos o con mi navegador, o con otros servidores en el caso de mi instancia de Mastodon. Para poder atender a tantos servicios tras los mismos puertos, uso <a href="https://nginx.org/">NGINX</a> como <a href="https://es.wikipedia.org/wiki/Proxy_inverso">proxy inverso</a>:</p>
<figure class="ma0 w-75">
    <img loading="lazy" src="/images/20250901-before.png"
         alt="Un diagrama donde se ve la conectividad entre cloudflare y un servidor llamado barcas, que contiene NGINX y una serie de servicios ejecutados en Docker"/> <figcaption>
            <p>&ldquo;Barcas&rdquo; es el nombre de mi servidor.</p>
        </figcaption>
</figure>

<p>A diferencia de mis otros servicios, <strong>XMPP usa más puertos TCP y UDP que el 80 y el 443</strong>: 5000, 5222, 5269,&hellip; En el caso de Snikket como, supongo, toda otra serie de alternativas, los puertos 80 y 443 también se usan para proporcionar un panel de control Web y poder administrar usuarios y salas de chat.</p>
<p>Sobre el papel, la configuración para instalar Snikket sería la siguiente:</p>
<ul>
<li>Configurar los puertos 80 y 443 en NGINX para poder usar el panel de control de usuarios y conversaciones de Snikket.</li>
<li>Configurar acceso directo a todo el resto de los puertos de Snikket: 5222, 5269,&hellip; ésta es la <a href="https://snikket.org/service/help/advanced/firewall/">lista completa</a> (en inglés). Como no son puertos compartidos entre varios servicios, no hace falta configurarlos en un proxy inverso.</li>
<li>Configurar las DNS de mi servicio de XMPP en mi proveedor de dominios, que es <a href="https://www.cloudflare.com/">Cloudflare</a>.</li>
</ul>
<p>Esta configuración, que a priori tendría buena pinta, se resume en esta figura:</p>
<figure class="ma0 w-75">
    <img loading="lazy" src="/images/20250902-snikketsimple.png"
         alt="Un diagrama donde se ve la conectividad entre cloudflare y un servidor llamado barcas, que contiene NGINX y una serie de servicios ejecutados en Docker."/> <figcaption>
            <p>Esta configuración, aunque parece que tiene sentido, no funciona. Cloudflare sólo ofrece funciones de proxy para los puertos 80 y 443 en su cuenta gratuita, por lo que el tráfico del resto de puertos de Snikket es descartado.</p>
        </figcaption>
</figure>

<p><strong>Sin embargo, esto tiene un problema que no es evidente, y la configuración de arriba no funciona</strong> sin más. Las características de seguridad de Cloudflare que están disponibles para las cuentas gratuitas en forma de &ldquo;el proxy de Cloudflare&rdquo; sólo soportan los puertos 80 y 443. Con el proxy de Cloudflare activado, todo el tráfico que no es web (80 y 443) se descartaba, por lo que ninguno de los puertos que entran en juego en las conversaciones de XMPP llegaba a mi servidor.</p>
<p>Desactivando el proxy de Cloudflare para la configuración de los subdominios de Snikket todo funciona, pero queda así:</p>
<figure class="ma0 w-75">
    <img loading="lazy" src="/images/20250902-snikketactual.png"
         alt="Un diagrama donde se ve la conectividad entre cloudflare y un servidor llamado barcas, que contiene NGINX y una serie de servicios ejecutados en Docker."/> <figcaption>
            <p>Esta configuración, aunque funciona, supone un riesgo. Al desactivar la función de proxy, la dirección IP de mi casa (por donde se entra a &ldquo;barcas&rdquo;) queda expuesta a todo internet. Un ataque de denegación de servicio distribuido que afecte a mi proveedor de servicios de acceso a internet puede dejar sin internet a toda la casa, cosa que no nos gusta.</p>
        </figcaption>
</figure>

<p><strong>Desactivar el proxy de Cloudflare no es ideal, porque expone la IP del servidor</strong> al resto de internet. Mi servidor está en casa, por lo que un ataque de denegación de servicio que, por puro azar, incluyese la dirección IP que mi operador de acceso a internet me asigna, tiraría por tierra toda mi red doméstica. Eso nos impediría trabajar o estudiar desde casa y, probablemente, me traería problemas con mi proveedor de servicio.</p>
<p>Una alternativa a esto es contratar un servidor barato en cualquier proveedor de alojamiento en la nube (un <a href="https://es.wikipedia.org/wiki/Servidor_virtual_privado">VPS</a>) y mover toda mi configuración de NGINX a él, conectando este servidor en la nube con el servidor de mi casa mediante una VPN (la cuenta gratuita de <a href="https://tailscale.com">Tailscale</a> funciona muy bien y es más que suficiente).</p>
<ul>
<li>El proveedor de alojamiento en la nube protegería mi servidor porque la IP expuesta sería la suya, no la de mi casa, y este tipo de empresas protegen su infraestructura ante ataques, por lo menos a un nivel de red. Tras los puertos XMPP no hay contenido, sino un servicio de mensajería que además cifra el tráfico, así que no hay problema por perder la capa de seguridad y anti-<em>bots</em> que proporciona Cloudflare para estos puertos.</li>
<li>Conectar el VPS a mi servidor a través de una VPN es perfecto para este caso, porque oculta la dirección IP de mi red doméstica ahorrándome configurarla en el panel de control de DNS, y también el tener que abrir puertos en mi router. Además, para todo el tráfico que iría entre la VPS y mi servidor, se aplicaría una capa de cifrado que lo protegería en caso de que, de por sí, no estuviese ya cifrado.</li>
</ul>
<figure class="ma0 w-75">
    <img loading="lazy" src="/images/20250902-snikketvps.png"
         alt="Un diagrama donde se ve la conectividad entre cloudflare, un VPS que contiene NGINX, y entre éste y un servidor llamado barcas usando Tailscale. Barcas que contiene una serie de servicios ejecutados en Docker."/> <figcaption>
            <p>Esta configuración funciona y resuelve el problema de la configuración anterior, pero requiere encontrar una solución para redirigir el tráfico de todos los puertos diferentes a 80 y 443 a &ldquo;barcas&rdquo;.</p>
        </figcaption>
</figure>

<p>¿Por qué mover sólo la configuración de NGINX y no todos los servicios? Por una cuestión de recursos y precio: para ejecutar NGINX y una serie de reglas de cortafuegos, los requisitos que necesitamos son mínimos. Con un servidor que tenga 1 GB de RAM y con una CPU es más que suficiente, y eso cuesta entre 3 y 6€ al mes. Si muevo todo<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup> necesitaría entre 8 y 16 GB de RAM, mucho más almacenamiento potencia de CPU, una solución de copias de seguridad,&hellip; Con todo ello me estaría moviendo en un rango de unos 40€, o más, al mes. Teniendo un servidor en casa donde ejecutar los servicios, moverlo todo a la VPS acarrea un coste innecesario en mi caso.</p>
<p>Así pues, parece que contratar una VPS sencilla para tener NGINX configurado allí, y conectarla al servidor de casa mediante Tailscale, resolvería mis problemas a un coste muy bajo (3 a 6€ al mes).</p>
<p>La única complicación adicional de este método es que tenemos que tener algún mecanismo para redirigir el tráfico de los puertos de XMPP (varios puertos como el 5222, 5269,&hellip; en TCP y UDP) desde el VPS hacia nuestro servidor (en casa o donde fuere). Al final lo he resuelto configurando el VPS para que haga <em>IP forwarding</em> y luego he configurado una serie de reglas DNAT<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup> en su cortafuegos.</p>
<p>En próximos artículos veremos más en detalle la configuración de todos los elementos.</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p><em><a href="https://es.wikipedia.org/wiki/Extensible_Messaging_and_Presence_Protocol">Extensible Messaging and Presence Protocol</a></em> &ndash; Protocolo Extensible de Mensajería y Presencia. XMPP es un protocolo que comunica comunidades de usuarios a través de sus servidores, creando conversaciones entre pares de usuarios, o salas para conversaciones en grupo. Google Talks fue el ejemplo más popular de aplicación de XMPP. Una ventaja de XMPP es que es un protocolo federado, es decir: aunque yo me conecte a un servidor donde sólo esté yo, puedo establecer contacto con cualquier otro usuario de cualquier otro servicio que utilice XMPP en el planeta. Los nombres de usuario en XMPP tienen el mismo formato que un correo electrónico, y los servidores se comunican entre ellos cuando sus usuarios lo necesitan.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>Aunque en este artículo hablo casi exclusivamente de Snikket, en mi servidor de casa tengo muchos otros servicios: Mastodon, Castopod, algún que otro blog, Linkwarden, FreshRSS, Actual Budget, Forgejo y Nextcloud.&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p><em>Destination <a href="https://es.wikipedia.org/wiki/Traducci%C3%B3n_de_direcciones_de_red">NAT</a></em>. Traducción de direcciones de destino de red.&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded>
    </item>
    <item>
      <title>Cuando la captura de pantalla de OBS se rompe en Wayland</title>
      <link>https://gvisoc.com/posts/solucionar-captura-obs-rota-wayland/</link>
      <pubDate>Mon, 21 Apr 2025 20:09:27 +0000</pubDate><author>gabriel@gvisoc.com (Gabriel Viso Carrera)</author>
      <guid>https://gvisoc.com/posts/solucionar-captura-obs-rota-wayland/</guid>
      <description>Qué hacer si en OBS (en Linux) deja de aparecer la opción de capturar la pantalla de tu ordenador.</description>
      <content:encoded><![CDATA[<p><a href="https://gvisoc.com/posts/linux-en-directo/">A veces grabo vídeos</a> usando <a href="https://obsproject.com/es">OBS</a>. Salvo contadísimas excepciones grabo usando un PC con Fedora, que es una distribución de Linux que usa <a href="https://es.wikipedia.org/wiki/Wayland_%28protocolo%29">Wayland</a> como protocolo de pantalla.</p>
<p>En ocasiones, algo pasa y la opción correspondiente para grabar el escritorio del ordenador desaparece. No sé si OBS está traducido al Español, o si lo está, si está bien traducido; en Inglés la opción que desaparece es &ldquo;<em>Screen Capture (PipeWire)</em>&rdquo;:</p>
<figure>
    <img loading="lazy" src="/images/20250421-obspipewire.png"
         alt="Captura de pantalla de OBS que muestra un menú emergente con la opción &amp;quot;Screen Capture (PipeWire)&amp;quot; resaltada."/> <figcaption>
            <p>OBS mostrando la opción a recuperar</p>
        </figcaption>
</figure>

<p>En mi caso este problema se debió a que los recursos correspondientes a la funcionalidad de Wayland para compartir pantalla se quedaron bloqueados en algún estado inconsistente.</p>
<p>Tras mucho trastear, acabé por recuperar la funcionalidad perdida borrando el contenido de los directorios <code>~/.cache</code> y <code>~/.local/state/</code>:</p>
<pre><code>rm -rf ~/.cache/*
rm -rf ~/.local/state/*
</code></pre>
<p>No creo que esta solución sirva a todo el mundo, porque Wayland está aún en fase de desarrollo y pueden estar fallando muchas más cosas. Las pistas que me sirvieron para probar estas cosas fueron las siguientes:</p>
<ul>
<li>Esta característica funcionaba, no mucho tiempo atrás.</li>
<li>Creando un usuario nuevo, ese usuario tiene la opción disponible.</li>
</ul>
<p>Esto quiere decir que OBS y Wayland están bien instalados y funcionan en el ordenador, por lo que todo apuntaba a ficheros temporales.</p>
]]></content:encoded>
    </item>
    <item>
      <title>KMail: responder por encima del texto citado</title>
      <link>https://gvisoc.com/posts/kmail-responder-por-encima-del-texto-citado/</link>
      <pubDate>Tue, 10 Dec 2024 23:51:40 +0000</pubDate><author>gabriel@gvisoc.com (Gabriel Viso Carrera)</author>
      <guid>https://gvisoc.com/posts/kmail-responder-por-encima-del-texto-citado/</guid>
      <description>Cómo configurar KMail para que tu respuesta salga por encima del texto del correo al que respondes.</description>
      <content:encoded><![CDATA[<p>Si usas <a href="https://apps.kde.org/kmail2/">KMail</a>, el cliente de correo electrónico de <a href="https://kde.org/">KDE</a>, verás que hay una opción sumamente básica que falta: poder responder mensajes <em>encima</em> del texto del correo al que estás contestando. Por más que busques, no encontrarás esa opción.</p>
<p>Para poder colocar la respuesta automáticamente por encima del texto al que respondes, deberás <strong>editar las plantillas por defecto del editor</strong>. Para eso, en <em>Settings</em> → <em>Composer</em> → *Standard Templates, *o sus equivalentes en español, deberás cambiar todas las plantillas de respuesta para que el comando <code>%CURSOR</code> aparezca por encima del comando <code>%QUOTE</code>.</p>
<p>Por ejemplo, la plantilla de responder a todos pasaría de ésto:</p>
<pre><code>%REM=&quot;Default reply all template&quot;%-
On %ODATE %OTIMELONG %OFROMNAME wrote:
%QUOTE
%CURSOR
</code></pre>
<p>A ésto:</p>
<pre><code>%REM=&quot;Default reply all template&quot;%-
%CURSOR

On %ODATE %OTIMELONG %OFROMNAME wrote:
%QUOTE
</code></pre>
<p>Deberás cambiarlas todas. Y para más inri, si usas KMail como un plugin de <a href="https://apps.kde.org/kontact/">Kontact</a>, probablemente debas cambiar estas plantillas en ambas aplicaciones; por alguna razón no hablan entre ellas muy bien. En cualquier caso, ese cambio funciona una vez ambos escenarios reconocen el cambio.</p>
<p>Siendo esta aplicación parte de KDE, entorno de escritorio famoso por la ingente cantidad de opciones que ofrece, que falte algo tan básico es casi un síntoma de la falta de diseñadores de producto colaborando con proyectos de software libre que, por otro lado y desde cualquier punto de vista, son fantásticos.</p>
<p>Aún así, no hace falta buscar muy a fondo en internet para encontrar <a href="https://www.reddit.com/r/kde/comments/jh3ctl/comment/ga3tmr3/">respuestas</a> como la que sigue:</p>
<blockquote>
<p><em>No tiene nada de malo que la comunidad de KDE <em>eduque</em> a usuarios como tú en conceptos avanzados de los clientes de correo electrónico [como las plantillas].
&hellip;
&hellip; entender cómo funcionan las plantillas de texto no es mucho pedir para un usuario de KDE/Plasma. Siempre puedes instalar Thunderbird si piensas diferente.</em></p></blockquote>
<p><strong>Y así es como el software libre pierde usuarios: con respuestas pedantes</strong> que piensan que forzarte a perder el tiempo con algo tan <em>de nicho</em> como un lenguaje de marcado específico de un editor de plantillas de mensajes correo electrónico es más razonable que mejorar un producto con una opción en forma de una casilla de verificación. <strong>Una triste casilla de verificación</strong>.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Linux en directo</title>
      <link>https://gvisoc.com/posts/linux-en-directo/</link>
      <pubDate>Sat, 30 Nov 2024 21:47:45 +0000</pubDate><author>gabriel@gvisoc.com (Gabriel Viso Carrera)</author>
      <guid>https://gvisoc.com/posts/linux-en-directo/</guid>
      <description>&lt;p&gt;Empezar con Linux no es un paso &lt;em&gt;trivial&lt;/em&gt; para todo el mundo. Pese a que las cosas son mucho más sencillas que en 1998, o, sin irnos tan allá, que en 2010, hay muchas preguntas que hacerse al respecto.&lt;/p&gt;
&lt;p&gt;El pasado viernes 29 de noviembre estuve instalando Linux en arranque dual con Windows 11, en través de &lt;a href=&#34;https://www.twitch.tv/gvis0c&#34;&gt;twitch&lt;/a&gt;. Y me ha gustado el resultado, tanto que es muy posible que haga muchos más vídeos de ahora en adelante, tanto en directo como &amp;ldquo;producidos&amp;rdquo;.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Empezar con Linux no es un paso <em>trivial</em> para todo el mundo. Pese a que las cosas son mucho más sencillas que en 1998, o, sin irnos tan allá, que en 2010, hay muchas preguntas que hacerse al respecto.</p>
<p>El pasado viernes 29 de noviembre estuve instalando Linux en arranque dual con Windows 11, en través de <a href="https://www.twitch.tv/gvis0c">twitch</a>. Y me ha gustado el resultado, tanto que es muy posible que haga muchos más vídeos de ahora en adelante, tanto en directo como &ldquo;producidos&rdquo;.</p>
<p>El resultado está disponible en PeerTube, en mi cuenta de <a href="https://veedeo.org/a/gvisoc/">veedeo.org</a>, próximamente en YouTube, y lo puedes ver aquí mismo:</p>
<div style="position: relative; padding-bottom: 56.25%; margin-bottom: 1rem; height: 0; overflow: hidden;">
<iframe sandbox="allow-scripts allow-popups" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;"
    src="https://veedeo.org/videos/embed/h5hYmcWPtyDXPmydDu8kFZ?title=0&warningTitle=0&peertubeLink=0" allowfullscreen>
</iframe>
</div>

<p>También he creado, por fin, <a href="https://www.patreon.com/gabrielviso">una cuenta de Patreon</a> para que, quien quiera, pueda apoyar este blog, <a href="https://podcast.gvisoc.com/@sobrelamarcha">el podcast</a> y <a href="https://veedeo.org/a/gvisoc/">los vídeos que iré creando</a> a medida que el tiempo y el material disponible me lo permitan.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Solucionando Problemas de Compatibilidad del Certificado de la FNMT</title>
      <link>https://gvisoc.com/posts/solucionando-problemas-pkcs12/</link>
      <pubDate>Tue, 10 Sep 2024 21:34:34 +0000</pubDate><author>gabriel@gvisoc.com (Gabriel Viso Carrera)</author>
      <guid>https://gvisoc.com/posts/solucionando-problemas-pkcs12/</guid>
      <description>Si tienes un certificado almacenado en un fichero .p12, probablemente no lo puedas importar en un navegador sin realizar algunos cambios primero.</description>
      <content:encoded><![CDATA[<p>Hace unos pocos días tuve que renovar mi certificado digital de la Fábrica Nacional de Moneda y Timbre (España). Como hacía menos de 5 años que me había identificado personalmente en el Consulado Español en Sydney, no tuve que hacer gran cosa y pude realizar todo el proceso en Fedora, siguiendo las instrucciones correspondientes.</p>
<p>Sin embargo, el fichero de copia de seguridad del certificado (formato PKCS #12, de extensión <code>.p12</code>) que generan las herramientas oficiales usa una versión de los algoritmos de cifrado que está considerada obsoleta. Esto genera un fichero aparentemente inservible, imposible de usar en la mayoría de navegadores modernos, como Firefox en mi caso.</p>
<figure>
    <img loading="lazy" src="/images/20240910-errorpkcs12.png"
         alt="Un cuadro de diálogo de error proporcionado por Firefox, en este caso funcionando en Fedora. Dice textualmente &amp;quot;Failed to decode the file. Either is not in PKCS #12 format, has been corrupted, or the password you entered was incorrect&amp;quot;. Tiene un botón &amp;quot;OK&amp;quot;."/> <figcaption>
            <p>&ldquo;Fallo al decodificar el fichero. O bien no está en formato PKCS #12, o está corrupto, o la contraseña proporcionada es incorrecta&rdquo; es el error proporcionado por Firefox al intentar importar el certificado desde el fichero <code>.p12</code> generado por las herramientas de la FNMT.</p>
        </figcaption>
</figure>

<p>Esto te puede estar afectando ya mismo aunque no uses Linux, y aunque no hayas renovado nada.</p>
<ul>
<li>El problema se debe a un cambio en los estándares de seguridad de los navegadores, que busca elevar el nivel de seguridad de este tipo de cosas. Si tienes esta copia de seguridad almacenada en tus archivos y quieres importarla en un navegador moderno, meses o años después de haberla generado, probablemente tengas este problema.</li>
<li>Al ser algo relacionado con la seguridad de forma general, el problema no debería estar limitado a Firefox ni a Linux, y puede estar pasando ahora o en un futuro cercano con Safari, Chrome o Edge en Windows o en macOS.</li>
</ul>
<p>Los siguientes comandos en GNU/Linux producen un fichero <code>certificado.p12</code> que podrás importar en tu navegador. Antes de empezar, algunas notas:</p>
<ul>
<li>
<p><code>VISO_CARRERA_GABRIEL___[NIF].p12</code> es el archivo de certificado con problemas, así que tendrás que usar el nombre de tu propio fichero.</p>
</li>
<li>
<p>Los ficheros <code>.p12</code> están protegidos con contraseña. Necesitarás introducir una contraseña para operar con el fichero <code>.p12</code> con problemas, y fijar una nueva contraseña en el fichero <code>.p12</code> resultado del proceso. Esto no está representado en los comandos siguientes.</p>
<p>openssl pkcs12 -legacy -in VISO_CARRERA_GABRIEL___[NIF].p12 -clcerts -nokeys -out certificado.crt
openssl pkcs12 -legacy -in VISO_CARRERA_GABRIEL___[NIF].p12 -nocerts -out cifrado.key
openssl rsa -in cifrado.key -out privado.key
openssl pkcs12 -export -in certificado.crt -inkey privado.key -out certificado.p12</p>
</li>
</ul>
<p>Un comando por línea.</p>
<p>Una vez hecho esto, <code>certificado.p12</code> podrá ser importado en tus navegadores, sin problema alguno.</p>
<p>Este proceso no me lo he inventado yo, ni lo he descubierto por mi mismo; lo he encontrado en <a href="https://discussion.fedoraproject.org/t/importing-pfx-pkcs12-certificate-fails-on-fedora-but-succeeds-on-windows-11/120349/4">esta respuesta en el foro de la comunidad de Fedora</a>.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Actualiza tu Máquina Virtual de Windows 10 a Windows 11 en VirtualBox</title>
      <link>https://gvisoc.com/posts/actualiza-tu-maquina-virtual-de-windows-10-a-windows-11-en-virtualbox/</link>
      <pubDate>Mon, 15 Jul 2024 23:52:31 +0000</pubDate><author>gabriel@gvisoc.com (Gabriel Viso Carrera)</author>
      <guid>https://gvisoc.com/posts/actualiza-tu-maquina-virtual-de-windows-10-a-windows-11-en-virtualbox/</guid>
      <description>Es hora de ver cómo actualizar tu máquina virtual de Windows 10 a Windows 11, antes de perder el soporte de Microsoft.</description>
      <content:encoded><![CDATA[<p><a href="https://learn.microsoft.com/es-es/lifecycle/products/windows-10-home-and-pro"><strong>En Octubre de 2025 Windows 10 pierde su soporte</strong></a><strong>, y no recibirá más actualizaciones</strong>.</p>
<p><strong>Si usas GNU/Linux en tu día a día pero tienes Windows en una máquina virtual por si las moscas, esto también es un problema</strong> aunque no uses Windows más que una o dos veces al año. Por ejemplo, si usas Windows para entrar en la típica página de la administración porque no has sido capaz de configurar un navegador de forma que funcione correctamente, vas a tener que tener un sistema compatible pero actualizado. No quieres usar un sistema desactualizado, sin parches, etc., para cosas tan sensibles como tu declaración de la renta o gestionar cosas con la Seguridad Social. <strong>Aunque creas que te da igual, no te da igual, y no quieres hacerlo</strong>.</p>
<blockquote>
<p><strong>Para poder llevar a cabo este proceso tu ordenador físico tiene que cumplir con los requisitos de hardware de Windows 11</strong> en términos de microprocesador, módulo de seguridad TPM, y demás. La virtualización es un proceso que comparte dispositivos reales de la máquina física entre distintos sistemas operativos: uno anfitrión, que es el que está instalado sobre la máquina física, y los distintos sistemas operativos huéspedes, instalados en las máquinas virtuales.</p>
<p>Aunque pudiese haber productos que, además de virtualización, tuviesen capadidades de <em>emulación</em> para exponer un chip TPM realizado por software, o para que Windows 11 percibiese un microprocesador de una serie más moderna que el tuyo, VirtualBox no es uno de ellos.</p>
<p>Por lo tanto, <strong>utilizar VirtualBox no te va a servir para instalar Windows 11 en un PC que no esté soportado</strong>.</p></blockquote>
<p>Al igual que actualizar un ordenador a Windows 11, actualizar una máquina virtual tiene sus curvas, sus terraplenes y sus trucos: si cambiamos el <em>hardware virtual</em> de nuestra máquina virtual, nuestra licencia de Windows 10 no será válida, y tendremos que comprar una licencia de Windows 11. No podemos crear otra máquina virtual, instalar Windows 11 y usarlo, porque no tendremos licencia de Windows para ese hardware. Incluso si creamos la máquina virtual con los mismos <em>identificadores de hardware</em>, sospecho que al no haber cambiado de Windows 10 a Windows 11 de forma controlada podríamos tener algún problema de licencia porque la licencia vinculada a esos identificadores de hardware es de Windows 10.</p>
<p>Por si fuera poco, VirtualBox no se caracteriza por ofrecer una experiencia de virtualización de Windows 11 adecuada, ni por facilitar la actualización desde Windows 10:</p>
<ol>
<li>Hasta hace relativamente pocos telediarios, las máquinas virtuales de VirtualBox tenían una definición equivalente a un PC de hace 20 años, y no exagero: BIOS, esquema de particiones MBR, nada que se parezca a un chip TPM es ofrecido a la máquina virtual, el arranque seguro es ciencia-ficción y la EFI &ldquo;<em>sólo es válida para sistemas operativos especiales</em>&rdquo;.</li>
<li>Por las razones arriba expuestas, estas máquinas no soportan Windows 11. Para usar Windows 11 en estas máquinas debías usar <a href="https://blogs.oracle.com/virtualization/post/install-microsoft-windows-11-on-virtualbox">el proceso existente para decirle a Windows que no comprobase sus requisitos de hardware</a>. Esto cae en un terreno gris donde Microsoft no termina de posicionarse, pero siempre ha barajado no permitir que dichos PC recibiesen actualizaciones.</li>
<li>En <strong>VirtualBox 7</strong>, como quien dice, anteayer, Oracle por fin implementó todas las características que requiere Windows 11 de forma nativa y <a href="https://windowsreport.com/virtualbox-7-windows-11/">ya permite definir una máquina virtual con EFI, arranque seguro, TPM 2.0</a> y todas esas otras características.</li>
<li>En una máquina virtual existente, activar esas características permitiría, en teoría, ejecutar el proceso de actualización a Windows 11 sin perder la licencia ni tener que hacer arcanos de terminal ni editar ficheros a mano.</li>
<li>Sin embargo, <strong>activar la EFI, TPM y arranque seguro en nuestra máquina virtual existente la dejará aparentemente inservible, porque no arrancará</strong>.</li>
</ol>
<p><strong>No es un problema tan descabellado</strong>, tiene su sentido, la causa del problema es trivial y, por suerte, <strong>tiene fácil solución</strong>. El problema es que la máquina no encuentra el sistema operativo: el disco donde está Windows 10 es un disco formateado con un esquema de particiones MBR, típico de la época de los PC con BIOS, mientras que los PC con EFI espera discos formateados con esquema de particiones GPT.</p>
<p>Así pues, <strong>para poder activar la EFI hay que</strong> <a href="https://www.windowscentral.com/how-convert-mbr-disk-gpt-move-bios-uefi-windows-10"><strong>convertir la tabla de particiones de un disco desde MBR a GPT</strong></a>. Para ello y como se discute en el enlace anterior, Microsoft proporciona un programa llamado <code>mbr2gpt.exe</code>. Afortunadamente, todas las instalaciones de Windows 10 que conserven su partición de recuperación lo tienen disponible, y las instalaciones hechas en VirtualBox no son una excepción. Además, y por si las moscas, ese programa está incluido en todas las imágenes de DVD o de memoria USB que usaríamos para reparar, actualizar o restaurar el sistema.</p>
<p>Esto es lo que hay que hacer específicamente en Virtual Box:</p>
<ul>
<li>
<p>Actualiza tu instalación de Windows 10 hasta la última actualización disponible.</p>
</li>
<li>
<p><strong>Realiza una copia de seguridad de tus ficheros</strong>, por si la conversión desde MBR a GPT fallase por alguna razón y debieras reinstalar Windows 10.</p>
</li>
<li>
<p><strong>Recuerda: tu licencia está vinculada a Windows 10</strong>. Hasta que no tengas un sistema actualizado a Windows 11 y con Windows 11 activado, <em>creo que</em> no puedes formatear e instalar Windows 11 desde cero.</p>
</li>
<li>
<p>Descarga el programa de creación de medios de instalación de Microsoft para crear dos medios de instalación en formato ISO: <code>Windows 10.iso</code> y <code>Windows 11.iso</code>.</p>
</li>
<li>
<p>Reinicia tu sistema operativo en modo recuperación pulsando la tecla de mayúsculas mientras pinchas en el botón <strong>Reiniciar</strong> de Windows 10</p>
</li>
<li>
<p>Alternativamente, utiliza cualquiera de las ISO que acabas de descargar para reparar el sistema.</p>
</li>
</ul>
<p><img alt="La imagen muestra la pantalla de bienvenida de Windows 11 que aparece al arrancar desde la ISO que hemos descargado. Abajo a la izquierda, vemos una opción para reparar el sistema, que nos llevará a las mismas pantallas y opciones que ofrece la partición de recuperación de Windows 10." loading="lazy" src="/images/20240715-isorepair.png">La ISO de Windows 11 ofrece opciones para reparar el sistema, igual que la partición de recuperación de Windows 10.</p>
<ul>
<li>
<p>En este entorno, abre un intérprete de comandos (<em>Troubleshoot</em> &gt; <em>Advanced Options</em> &gt; <em>Command Prompt</em> o algo como <em>Solución de Problemas</em> &gt; <em>Opciones Avanzadas</em> &gt; <em>Intérprete de Comandos</em>) y ejecuta los comandos siguientes:</p>
<p>mbr32gpt /validate</p>
</li>
</ul>
<p>Comando para validar tu unidad de disco. Si todo va bien, la salida del programa terminará con <code>MBR2GPT: Validation completed successfully.</code></p>
<pre><code>mbr2gpt /convert
</code></pre>
<p>Comando para convertir tu unidad de disco desde MBR a GPT. Si todo va bien, la salida del programa terminará con <code>MBR2GPT: Conversion completed successfullyMBR2GPT: Update WinRE config fileMBR2GPT: Before the new system can boot properly you need to switch the firmware to boot to UEFI mode!</code></p>
<p><img loading="lazy" src="/images/20240715-recovery.png"></p>
<p><img loading="lazy" src="/images/20240715-recovery2.png"></p>
<p><img loading="lazy" src="/images/20240715-recovery3.png"></p>
<p><img loading="lazy" src="/images/20240715-cmd.png"></p>
<p><img loading="lazy" src="/images/20240715-cmd2.png"></p>
<p>Diferentes pantallas del proceso explicado en los puntos anteriores, donde podemos ver el aspecto del proceso de recuperación y la salida de los comandos.</p>
<ul>
<li><strong>Apaga la máquina virtual de forma ordenada</strong> y, en VirtualBox, cambia la configuración para que EFI, Arranque Seguro (<em>Secure Boot</em>), el chip TMP 2.0 y la aceleración de gráficos en 3D estén activadas en el siguiente arranque.</li>
</ul>
<p><img alt="La imagen muestra la pantalla de opciones de la máquina virtual de Windows 10, en Virtual Box, en la pestaña &quot;System&quot;, donde deberemos seleccionar &quot;Enable EFI (special OSes only)&quot; y &quot;Enable Secure Boot&quot;" loading="lazy" src="/images/20240715-uefitpm.png">Activando las opciones EFI y Secure Boot.<img alt="En la imagen vemos otra de las pestañas de opciones de la máquina virtual de Windows 10 en VirtualBox, &quot;Display&quot;, donde deberemos activar &quot;Extended features: Enable 3D Acceleration&quot;. También dotaremos a la máquina virtual de suficiente memoria de vídeo, en &quot;Video Memory&quot;, desplazando el selector hasta el máximo de 256 MB." loading="lazy" src="/images/20240715-3daccel.png">Activando la aceleración 3D, y dotando a la máquina de suficiente memoria de vídeo (256 MB, que es el máximo)</p>
<ul>
<li><strong>Arranca la máquina virtual</strong>. El sistema debería arrancar perfectamente y funcionar como si nada.</li>
<li>Actualiza Windows 10 una vez más.</li>
</ul>
<p>Windows seguirá diciendo que tu sistema no es compatible con Windows 11, y sólo obtendrás actualizaciones de Windows 10. Esto no es cierto gracias a los cambios que hemos llevado a cabo en la máquina: mi sospecha es que el programa de compatibilidad que Microsoft ha escrito tiene una base de datos de fabricantes reconocidos que no está preparado para máquinas virtuales. Pero esto no es un problema, porque tenemos una ISO de Windows 11 y podremos iniciar el proceso pese a todo.</p>
<ul>
<li><strong>Monta la ISO de Windows 11 en la unidad de DVD que tiene tu máquina virtual</strong>.</li>
<li><strong>Ábrela con el Explorador de Ficheros</strong> y ejecuta el programa <code>setup.exe</code>.</li>
</ul>
<p><img alt="Imagen de una ventana del Explorador de Ficheros de Windows 10, mostrando los contenidos de un DVD. El DVD se llama &quot;ESD-ISO&quot; y es el resultado de montar la imagen de DVD de Windows 11 en Virtual Box. En el panel derecho de la ventana se muestran varias carpetas y ficheros, y está seleccionado &quot;setup.exe&quot;." loading="lazy" src="/images/20240715-win11-setup.png">Programa de instalación de Windows 11, en el Explorador de Ficheros de Windows 10</p>
<ul>
<li>Selecciona las opciones adecuadas para conservar tus ficheros y aplicaciones (o no), y actualizar el sistema.</li>
</ul>
<p>Si todo te ha ido igual de bien que a mí, deberías tener una máquina virtual con Windows 11 donde todos los requisitos están cumplidos, la activación del sistema es correcta y está vinculada a tu cuenta de Microsoft.
<img alt="En la imagen se muestra la ventana de Virtual Box con escritorio de Windows 11. Los marcos de la ventana son los de Gnome, por lo que la máquina virtual está funcionando en Linux. Dentro de la máquina virtual hay una ventana abierta que muestra el detalle del chip TPM que le es ofrecido. Se muestran varios detalles, como el fabricante (IBM), especificaciones, y demás." loading="lazy" src="/images/20240715-win11tpmdetails.png">Detalle de la máquina virtual Windows 11 mostrando los detalles del chip TPM que le es ofrecido.
Es hora de actualizarla una última vez para recibir actualizaciones específicas de Windows 11, crear una copia de seguridad de acuerdo a tu propia estrategia, y dedicarte a cosas más productivas.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Migrar un Podcast de Spotify a Castopod</title>
      <link>https://gvisoc.com/posts/migrar-un-podcast-a-castopod/</link>
      <pubDate>Fri, 24 May 2024 12:00:05 +0000</pubDate><author>gabriel@gvisoc.com (Gabriel Viso Carrera)</author>
      <guid>https://gvisoc.com/posts/migrar-un-podcast-a-castopod/</guid>
      <description>Recuperando el control sobre las cosas que siempre debieron pertenecernos.</description>
      <content:encoded><![CDATA[<p>Empecé <a href="https://podcast.gvisoc.com/@sobrelamarcha">sobre la marcha</a> en 2017, al poco de llegar a Australia. Por aquél entonces, una red social de segmentos de 2 minutos llamada Anchor viraba su rumbo y abrazaba el podcasting como siguiente paso lógico en su estrategia. El funcionamiento era original e innovador: durante un espacio de 24 horas, los segmentos de 2 minutos y las contestaciones de tus contactos, de 1 minuto, se iban añadiendo a tu <em>emisora</em> de Anchor. Cuando terminaba el día, podías optar por publicar todo el contenido del día en un feed RSS: ya tenías tu podcast.</p>
<p>Era genial.</p>
<p>Entonces, llegó Spotify, primero como inversor, y luego comprando Anchor. Al poco tiempo, todas las características sociales y el funcionamiento que comentaba arriba, como la <em>emisora</em>, desaparecieron del producto y nos quedamos con una plataforma de podcasting solvente, y nada más.</p>
<p>No voy a dar cuenta en detalle del proceso de <a href="https://gvisoc.com/posts/enmierdificacion/">enmierdificación</a> de Spotify en este artículo, sino que me voy a limitar a decir que no estoy cómodo en esa plataforma desde hace tiempo, y he decidido <a href="https://gvisoc.com/posts/personal-y-rapido/">autoalojar en casa</a> mi propio podcast. El soporte a mi podcast me lo da ahora <a href="https://castopod.org/">Castopod</a>, una plataforma de podcasting libre y de código abierto que, además, ofrece integración con el fediverso mediante Activity Pub y soporte a múltiples características del <a href="https://podcasting2.org/">podcasting 2.0</a>, como la posibilidad de dejar comentarios desde tu propia aplicación de escucha de podcasts entre otras cosas.</p>
<p>Vamos a ver cómo se migra un podcast a Castopod. En este artículo se trata de Spotify, pero el proceso va a ser muy similar en cualquier otro caso.</p>
<h2 id="obtén-castopod">Obtén Castopod</h2>
<p>Castopod está disponible para instalar en tu propio servidor, que puede ser una VPS o una máquina sencilla conectada a internet, o puedes contratarlo en varios proveedores especializados. En <a href="https://castopod.org/">castopod.org</a> tienes acceso a información acerca de todas las opciones. Yo lo he instalado en un mini PC, en mi casa, usando Docker y NGINX como proxy inverso. Publicaré algo al respecto en lo sucesivo, pero hoy me voy a centrar en el <strong>proceso de salida de Spotify</strong>.</p>
<h3 id="opcional-obtén-tu-propio-dominio-y-si-es-posible-una-cdn">Opcional: obtén tu propio dominio y, si es posible, una CDN</h3>
<p>Si lo vas a instalar en tu casa, vas a necesitar un dominio. Si lo usas ofrecido por alguno de los proveedores, probablemente puedas usar un subdominio proporcionado por ellos.</p>
<p>En cualquier caso, como un podcast sirve archivos de cierto peso, es buena idea contratar un servicio que te ofrezca una red de distribución de contenidos (CDN) con presencia en múltiples geografías: actuará de caché, relajando los requisitos de ancho de banda de tu proveedor, y además acelerará el acceso a tu podcast desde geografías lejanas. Personalmente, uso la cuenta gratuita de Cloudflare para los dos asuntos: dominio y CDN.</p>
<h2 id="importa-tu-podcast-en-castopod">Importa tu Podcast en Castopod</h2>
<p>Una vez Castopod está funcionando en tu servidor, es hora de importar tu podcast en Castopod. Esto se hace indicando la dirección del feed RSS a Castopod en su panel de control, así como el nombre de usuario en el fediverso, la categoría y el idioma del contenido.</p>
<figure class="ma0 w-75">
    <img loading="lazy" src="/images/20240524-castopodimport.png"
         alt="Formulario de importación de un podcast en Castopod. Permite introducir la dirección del feed, indicar el idioma, la categoría y el nombre de usuario de la cuenta en el fediverso."/> <figcaption>
            <p>Formulario de importación de un podcast en Castopod.</p>
        </figcaption>
</figure>

<p>![)Formulario de importación de un podcast en Castopod
Es importante tener en cuenta que Castopod va a reinterpretar todo el feed y a validarlo. Uno de los problemas que tuve derivados de este aspecto es que, si a alguno de tus episodios le faltan las notas (el contenido del campo <code>&lt;description /&gt;</code>), el proceso va a fallar, tendrás que corregir el episodio en concreto, esperar a que Spotify republique tu feed, y reanudar el proceso donde se interrumpió. En mi caso, llevó unos cuantos intentos:</p>
<figure class="ma0 w-75">
    <img loading="lazy" src="/images/20240524-castopodimportlog.png"
         alt="Pantalla de Castopod que muestra diferentes intentos de importar sobre la marcha en mi nuevo servidor. Podemos contar 8 intentos fallidos, seguidos de tres exitosos para sincronizar metadatos editados y publicaciones posteriores al proceso original de importación"/> <figcaption>
            <p>Distintos intentos fallidos antes de completar la importación de sobre la marcha.</p>
        </figcaption>
</figure>

<h3 id="opcional-activa-las-estadísticas-op3">Opcional: activa las estadísticas OP3</h3>
<p>Las estadísticas que ofrece Castopod por defecto son bastante buenas, pero si te interesa la iniciativa <em>Open Podcast Prefix Project</em>, <a href="https://op3.dev/">OP3</a>, es un buen momento para unirte a ella activando las estadísticas con un sólo click en el formulario de edición de tu podcast.</p>
<figure class="ma0 w-75">
    <img loading="lazy" src="/images/20240524-castopodeditpod.png"
         alt="Formulario de edición del podcast recién importado. De interés es el hecho de que para activar las estadísticas OP3, en Castopod se hace con un click."/> <figcaption>
            <p>Formulario de edición del podcast recién importado.</p>
        </figcaption>
</figure>

<h2 id="redirige-tu-antiguo-feed-al-nuevo-permanentemente">Redirige tu antiguo feed al nuevo, permanentemente</h2>
<p>Éste es el paso más sencillo, y más crítico. En Spotify para Podcasters, en el panel de edición de tu podcast, encontrarás un campo de texto para introducir un nuevo feed al que redirigir el antiguo. Esta redirección se implementa mediante un código de estado del protocolo HTTP, 301, que indica a los clientes, índices, buscadores y directorios de podcasting que el feed se ha mudado y nunca volverá a Spotify. En el cuerpo de la respuesta que acompaña a ese estado de redirección permanente 301 está la dirección del nuevo feed. El comportamiento esperado para clientes HTTP (cualquier aplicación o servicio que quiera acceder al feed) cuando reciben una respuesta con estado 301 es actualizar sus registros a la nueva dirección y no volver a intentar acceder a la antigua nunca más.</p>
<p>A partir de este momento, y en un tiempo indeterminado, todos tus suscriptores empezarán a recibir contenido por el feed nuevo, y si tienes la misma experiencia que yo, de una forma totalmente transparente.</p>
<blockquote>
<p>⚠️ <strong>Cuando esto pase, perderás el control de tu podcast en Spotify para Podcasters</strong></p></blockquote>
<p>Esto es algo de lo que Spotify no te avisa claramente, pero cuando Spotify perciba que el podcast ya no está bajo su control, perderás acceso a funciones de edición del mismo, e incluso a la posibilidad de borrar los datos del mismo en Spotify.</p>
<p>Aún cuando veas que esto está pasando, no borres aún tu cuenta de Spotify para Podcasters: si algún rezagado no ha recibido la instrucción de redirección y borras tu cuenta, se borra la redirección, con lo cual podrías perder oyentes. Personalmente, yo voy a borrarla pasado un mes.</p>
<blockquote>
<p>⚠️ Escoge cuidadosamente el momento de hacer esto si alojas tu nuevo podcast en tu casa.</p>
<p>En el momento en el que actives la redirección en Spotify, servicios de directorio que probablemente no sepas que estaban indexando tu feed recibirán las coordenadas del feed nuevo. Estos servicios de directorio usan procesos tipo <em>arañas</em> (mala traducción de <em>web crawlers</em>) para recorrer el feed y reindexarlo todo.</p>
<p>El cambio desde Spotify para Podcasters a Castopod es muy profundo. En términos de la propia estructura del feed, de dónde están alojados los ficheros, y del nombre de los mismos, el efecto es que todos estos procesos perciben tu podcast como una <em>reedición</em> completa. Como decimos en España, <em>a este feed no lo reconoce ni su padre</em>. Esto hace que todos estos actores invaliden todos los datos previos y lo recorran todo de nuevo, descargando todos y cada uno de tus episodios, metadatos, imágenes&hellip; todo. Y en este momento, aunque tengas CDN, su caché todavía está vacía, por lo que todas las peticiones van a ir directas a tu casa.</p>
<p>Estos servicios tienen una capacidad de cómputo y de red inmensamente mayor que la de tu casa, por lo que todos* ataquen tu feed a la vez*, tu conexión a internet va a experimentar un pico de tráfico de subida muy significativo, que puede afectar a tu conectividad, especialmente si hay alguien trabajando desde casa.</p>
<p>Por eso, mejor hazlo por la noche. No seas como yo 😅</p></blockquote>
<h2 id="solicita-el-traspaso-de-tu-podcast-a-tu-propiedad-en-los-distintos-directorios-que-te-interesen">Solicita el traspaso de tu Podcast a tu propiedad en los distintos directorios (que te interesen)</h2>
<p>Esto es importante.</p>
<p>Me voy a centrar en Apple Podcasts, pero es fácil entender que esto deberías hacerlo allá en donde te interese tener presencia, en tu caso particular.</p>
<p>Acabas de redirigir tu feed a Castopod, tu conexión a internet en casa las ha pasado canutas, y has tenido que dar explicaciones a tu mujer e hijos de por qué internet iba como una patata, pero todo ha vuelto a su cauce normal, todo funciona y los primeros oyentes que sabían que ibas a cambiar esto te felicitan, te dicen que las descargas van más lentas&hellip;</p>
<p>Sin embargo, los directorios de podcasting como Apple Podcasts no te tienen registrado como el autor o el responsable del mismo a la hora de enviarte alertas y avisos con respecto a tu podcast. Situaciones en las que te podrías ver involucrado y que te interesaría resolver con Apple, como una potencial violación de los Términos y Condiciones de su servicios de directorio, no te serán notificadas.</p>
<p>Por otro lado, tampoco tienes control sobre tu podcast en Spotify para Podcasters, que es a donde Apple enviaría este tipo de mensajes en caso de conflicto. Spotify te ha dado la patada en cuanto la redirección se ha vuelto efectiva.</p>
<p>Estás en tierra de nadie.</p>
<p>Es hora de ponerse en contacto con Apple Podcasts Connect y solicitar que te den control sobre tu podcast.</p>
<p>Para eso, ármate con tu fluidez en el idioma de Shakespeare, porque creo que el formulario no se ofrece en Español, y haz lo siguiente (efectivo en Mayo de 2024):</p>
<ol>
<li>
<p>Entra en <a href="https://podcastsconnect.apple.com">Apple Podcasts Connect</a>, o regístrate si no tienes cuenta.</p>
</li>
<li>
<p>Abajo de todo, selecciona &ldquo;<em>Contact Us</em>&rdquo;</p>
</li>
<li>
<p>En el formulario que aparece, rellena tus datos y selecciona como tema de consulta &ldquo;<em>Missing Podcast(s)</em>&rdquo; dentro de &ldquo;<em>Content Management</em>&rdquo;. Tendrás que introducir los siguientes datos:</p>
</li>
<li>
<p>El título del podcast (&quot;<em><strong>Podamigos del cocido</strong></em>&quot;)</p>
</li>
<li>
<p>El <em>id</em> del podcast. Entiendo que se trata de los números al final en la URL del podcast en Apple Podcasts: &ldquo;<strong>id817487481</strong>&rdquo;.</p>
</li>
<li>
<p>La URL completa a la página del podcast en Apple Podcasts.</p>
</li>
<li>
<p>La URL del nuevo feed.</p>
</li>
<li>
<p>En el cuerpo del mensaje, indica que has migrado tu podcast desde Spotify a otro hosting, indica también la del anterior por si acaso el operador que te atienda todavía tiene el antiguo feed en sus cachés, y pide instrucciones como te gustaría que te las pidiesen a ti.</p>
</li>
</ol>
<p>Este fue el mensaje enviado, nada fuera de lo común:</p>
<blockquote>
<p>Good afternoon.</p>
<p>I am writing as the author of the show &ldquo;sobre la marcha&rdquo;, which was previously hosted on Spotify for Podcasters. I recently re-hosted the show on my own hosting server, and I would like to claim ownership and be able to manage it under my Apple Podcasts Connect dashboard. I hope this is the right method / channel to request so.</p>
<p>Looking forward to hearing from you,</p>
<p>~Gabriel Viso Carrera</p>
<p>PS – before today, the show&rsquo;s feed was &ldquo;<a href="https://anchor.fm/s/dd4f78/podcast/rss%22">https://anchor.fm/s/dd4f78/podcast/rss"</a>. As part of the migration, it has been placed a 301 permanent redirection to the feed I filled in this form; please take it into consideration of you see that the redirection hasn&rsquo;t been followed in your systems yet. Please note that no further episodes will be appearing in such feed.</p></blockquote>
<p>Te enviarán un correo en un plazo de un par de días, pidiéndote más datos (como el ID de tu cuenta en Apple Podcasts Connect), y dándote un código numérico que deberás introducir en algún campo del feed. Por ejemplo, mí me dieron como opciones el campo de <code>&lt;copyright /&gt;</code>, <code>&lt;keyword /&gt;</code> o <code>&lt;verification /&gt;</code>.</p>
<p>En negrita los aspectos clave que nos piden en esta respuesta de ejemplo, que es lo que me contestaron a mí con algunas cosas cambiadas.</p>
<blockquote>
<p>Hello Gabriel,</p>
<p>Thanks for reaching out to us. I hope you&rsquo;re doing well.</p>
<p>To get access to the show in Apple Podcasts Connect, we can transfer the ownership of it to your account.</p>
<p>To transfer ownership, <strong>enter the six-digit authorization code “381234” in the verification, keyword, or copyright fields of your RSS feed</strong>.</p>
<p>You can update the six-digit authorization code on your hosting provider’s platform or edit the metadata tags in your RSS feed. If you need assistance with this update, contact your hosting provider. We’ll review your request after we receive your reply.</p>
<p>When you reply, <strong>tell us where you entered the authorization code so we can find it <strong>and</strong> include the Account ID of your Apple Podcasts Connect account</strong>.</p>
<p>You can locate the Account ID on the <a href="https://podcastsconnect.apple.com/account/details">Details pane</a> in the Account section in Apple Podcasts Connect.</p>
<p>Example Account ID: 12a345bc6-d7ef-8901-2ghi-j3k4lm56n7o8</p>
<p>If you have additional questions related to this request, please reference case number 384791872432.</p>
<p>Best regards,</p>
<p>Mary Jane
Apple Inc.</p></blockquote>
<p>El feed que genera Castopod no tiene campo <code>&lt;verification /&gt;</code>, pero como añadir campos a medida es sencillísimo, es la solución ideal porque nadie recibirá ese cambio de forma visible. Ve al panel de control de edición de tu podcast, y abajo de todo encontrarás un campo donde poder poner el campo extra:</p>
<figure class="ma0 w-75">
    <img loading="lazy" src="/images/20240524-castopodeditpodverification.png"
         alt="Captura de pantalla del panel de edición del podcast, mostrando el campo donde podemos introducir el código de verificación. Este lugar es &#34;Advanced Parameters&#34;; y debemos introducir el campo con las etiquetas XML incluidas, por ejemplo &amp;lt;verification&amp;gt;381234&amp;lt;/verification&amp;gt;"/> <figcaption>
            <p>Captura de pantalla del panel de edición del podcast, mostrando el campo donde podemos introducir el código de verificación.</p>
        </figcaption>
</figure>

<p>Salva los cambios en tu podcast, verifica que en unos segundos, el feed tiene el mencionado campo dentro del objeto <code>&lt;channel /&gt;</code>, y contesta a Apple con los datos que te han solicitado, que incluyen dónde pueden encontrar el valor en cuestión.</p>
<blockquote>
<p>Good morning, Mary Jane.</p>
<p>Thanks for your prompt reply. As requested:My Podcasts Connect Account ID is <strong>12a345bc6-d7ef-8901-2ghi-j3k4lm56n7o8</strong>.I&rsquo;ve just included the code you provided in the tag of my feed, inside the &lt;channel /&gt; element:</p>
<p>&lt;rss version=&ldquo;2.0&rdquo;&gt;
&lt;channel&gt;
&hellip;
**        &lt;verification&gt;381234&lt;/verification&gt;**
&hellip;
&lt;/channel&gt;
&lt;/rss&gt;</p>
<p>Thank you for your help and kind regards,
~Gabriel</p></blockquote>
<p>Cuando recibas la confirmación y al cabo de un tiempo prudencial que te indicarán, deberías poder controlar tu relación con el directorio de Apple Podcasts tú mismo.</p>
<figure class="ma0 w-75">
    <img loading="lazy" src="/images/20240524-applepodconnect.png"
         alt="Captura de pantalla de mi panel de control de Apple Podcasts Connect mostrando mi podcast &#34;sobre la marcha&#34;"/> <figcaption>
            <p>Captura de pantalla de mi panel de control de Apple Podcasts Connect mostrando mi podcast &ldquo;sobre la marcha&rdquo;</p>
        </figcaption>
</figure>

<h2 id="no-tengas-prisa-en-borrar-cosas">No tengas prisa en borrar cosas</h2>
<p>En realidad ya está, pero es importante que no corras a Spotify y a tu feed a borrar cosas y deshacer cambios, porque puedes revertir el proceso sin querer.</p>
<ol>
<li>Como comentaba en el apartado de la redirección permamente, no tengas demasiada prisa en borrar tu cuenta de Spotify, porque podrías perder oyentes.</li>
<li>Aún cuando ya tengas tu podcast en Apple Podcasts Connect, no corras a editar tu podcast en Castopod para retirar el campo de verificación. Ten en cuenta que el directorio de podcasts de Apple tienen páginas en todo el mundo, y no nos interesa que, por alguna razón, alguna versión antigua del feed se haya quedado en algún sitio y reasignen tu podcast a Spotify. Deja ese campo de verificación en tu feed el tiempo que te parezca oportuno.</li>
</ol>
<h2 id="pues-ya-estaría">Pues ya estaría</h2>
<p>Hasta aquí mi experiencia. Espero que te resulte útil e interesante.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Copias de Seguridad con Pika Backup</title>
      <link>https://gvisoc.com/posts/copias-de-seguridad-pika-backup/</link>
      <pubDate>Mon, 06 May 2024 10:28:43 +0000</pubDate><author>gabriel@gvisoc.com (Gabriel Viso Carrera)</author>
      <guid>https://gvisoc.com/posts/copias-de-seguridad-pika-backup/</guid>
      <description>Abandono Déjà Dup después de años de servicio.</description>
      <content:encoded><![CDATA[<p>Estoy moviendo todas mis copias de seguridad, desde Déjà Dup a Pika Backup.</p>
<p><a href="https://apps.gnome.org/PikaBackup/">Pika Backup</a> es una solución de copias de seguridad para GNU/Linux que, sin dejar de ser extremadamente sencilla de utilizar, proporciona características muy interesantes y es muy eficiente. Está basado en <a href="https://borgbackup.readthedocs.io/en/stable/">Borg Backup</a>, un sistema que crea copias de seguridad comprimidas, cifradas, y que además detecta y elimina duplicados en la copia de seguridad.</p>
<figure class="ma0 w-75">
    <img loading="lazy" src="/images/20240506-pikabackupmulti.png"
         alt="La imagen muestra la vista principal de Pika Backup. Muestra dos configuraciones de copia de seguridad, una a un disco duro USB sin programar, y otra, programada para ejecutarse periódicamente, a una ubicación remota."/> <figcaption>
            <p>Pika Backup con dos tareas de copia de seguridad configuradas; una en un directorio remoto, y otra en un disco duro externo</p>
        </figcaption>
</figure>

<p>Las características de Pika Backup que me han convencido han sido las siguientes:</p>
<ul>
<li>
<p><strong>Permite realizar copias de seguridad a discos USB y a cualquier directorio remoto, y soporta Borg en el lado del servidor</strong>:</p>
</li>
<li>
<p>Directorio &ldquo;tonto&rdquo;: cualquier directorio en donde tengas acceso local (por ejemplo, servicios tipo Drop Box o One Drive), y a localizaciones remotas &ldquo;tradicionales&rdquo; como servidores de ficheros FTP, o carpetas compartidas en red.</p>
</li>
<li>
<p>En sí, esto ya es muy potente y versátil.</p>
</li>
<li>
<p>Servicio remoto con soporte para <a href="https://borgbackup.readthedocs.io/en/stable/">Borg Backup</a>, si quieres mejor rendimiento. Esto no es más que un servidor donde el ejecutable <code>borg</code> esté instalado, y al que tengas acceso por <code>ssh</code>. Una Raspberry Pi con el paquete <code>borgbackup</code> instalado y un disco duro enchufado por USB es suficiente para tener copias de seguridad en red en casa, con rendimiento mejorado.</p>
</li>
<li>
<p>No hay por qué saber usar Borg; Pika Backup lo hace todo por ti, tanto en tu ordenador de trabajo como en tu servidor de copia de seguridad.</p>
</li>
<li>
<p>Más adelante os cuento por qué esto es tan ventajoso.</p>
</li>
<li>
<p><strong>Permite tener más de una tarea de copia de seguridad configuradas sobre el mismo conjunto de datos</strong>, para poder tener tu copia de seguridad en varios lugares. Por ejemplo, en un servidor en red, donde ejecutas la copia de seguridad de forma programada, y en un disco externo por USB, donde ejecutas la copia manualmente, cuando te parece bien.</p>
</li>
<li>
<p>Esto permite desarrollar una **estrategia 3:2:1 **sin salir de Pika Backup.</p>
</li>
</ul>
<blockquote>
<p>💡 Una estrategia <strong>3:2:1</strong> significa que deberíamos tener <strong>3</strong> réplicas de los datos, <strong>2</strong> de las cuales serían las copias de seguridad, ubicadas en sistemas almacenamiento diferentes, para <strong>1</strong> conjunto de datos en particular.</p></blockquote>
<p>De esa forma, siempre nos protegemos en caso de daño físico tanto a nuestra estación de trabajo como a discos de las copias, siendo extremadamente difícil que fallen las tres réplicas a la vez.</p>
<ul>
<li><strong>Es amigable para portátiles</strong>, porque detecta si el ordenador está conectado a la corriente, y si no lo está, ni siquiera intenta realizar la tarea de copia de seguridad programada.</li>
<li><strong>Proporciona filtros predefinidos</strong> para excluir de la copia de seguridad máquinas virtuales, contenedores, cachés y aplicaciones flatpak instaladas en el directorio de usuario. Esto simplifica bastante la configuración, aunque si no es suficiente, se pueden añador desde ficheros y carpetas individuales, hasta filtros basados en nombres de fichero y en expresiones regulares.</li>
<li><strong>Las copias de seguridad se pueden programar</strong> (hay reglas horarias, diarias, semanales, mensuales o anuales), <strong>y permite especificar el día y la hora 🎉</strong>. Esto parece baladí, pero si sabes que, por ejemplo, los domingos por la tarde el portátil va a estar en el escritorio con tareas de mantenimiento como actualizar el sistema, con sólo dejarlo enchufado la copia de seguridad se va a realizar automáticamente.</li>
</ul>
<figure class="ma0 w-75">
    <img loading="lazy" src="/images/20240506-pikabackupfilters.png"
         alt="Una vista de la configuración donde se pueden ver los distintos filtros que se pueden configurar en Pika Backup. Muestra filtros predeterminados, y carpetas seleccionadas manualmente."/> <figcaption>
            <p>Una vista de la configuración donde se pueden ver los distintos filtros que se pueden configurar en Pika Backup.</p>
        </figcaption>
</figure>

<p>De por sí, las funcionalidades que proporciona Pika Backup en su interfaz gráfico son ya suficientes para convencerme; <em>sobre todo</em> el hecho de poder tener todas las copias de seguridad de mi estrategia 3:2:1 en la misma aplicación. Pero donde lo remata es en el aspecto de ser un cliente de Borg, y por lo tanto soportar servidores con Borg,  para acelerar todas las operaciones de copia y restauración, y en especial <strong>la verificación</strong> de las copias de seguridad.</p>
<p>En general, <strong>hay que verificar las copias de seguridad, al menos cada cierto tiempo</strong>. Con ello nos aseguramos de que los archivos se han generado y almacenado correctamente, y que no hay nada corrupto. Y esto es un proceso que, si se hace en red, es muy costoso: Pika debería descargarse un trozo de la copia de seguridad desde el servidor de red, verificar su integridad, buscar el siguiente trozo, y así&hellip; hasta 130 GB en mi caso. He presenciado verificaciones de integridad hechas así que tardaron 20 horas. Y así es como se hace cuando Pika Backup deposita las copias de seguridad en un directorio de red, &ldquo;tonto&rdquo;, es decir, sin Borg.</p>
<p>Con Borg, la cosa cambia. El hecho de que Pika Backup esté basado en Borg Backup y, a todos los efectos, que sea un cliente de Borg, acelera el proceso de una forma drástica. Según la documentación de Borg, el proceso del lado del servidor realiza las operaciones de gestión de almacenamiento completas cuando se hace la copia de seguridad, <strong>y la verificación en sí</strong>. Esto incrementa el rendimiento sensiblemente, porque elimina el trasiego de datos por la red, y reduce el tiempo de verificación de una copia tan masiva como 130 GB <strong>de 20 horas a unos 35 minutos</strong>.</p>
<figure class="ma0 w-75">
    <img loading="lazy" src="/images/20240506-borgserve.png"
         alt="La imagen muestra un terminal de Gnome conectado al host barcas, bajo el usuario gvisoc. Dentro del terminal se puede ver la salida del comando htop, que muestra el proceso de servidor de borg realizando la verificación de integridad de la copia de seguridad, consumiendo algo menos de un 13% de CPU."/> <figcaption>
            <p>Una captura de pantalla que muestra el proceso de servidor de borg realizando la verificación de integridad de la copia de seguridad, consumiendo algo menos de un 13% de CPU.</p>
        </figcaption>
</figure>

<p>En general estoy muy contento con el cambio, ya que me permite realizar las cosas más eficientemente, utilizar mejor los recursos, y sobre todo, <strong>sobre todísimo</strong>, poder realizar todas las copias de seguridad de mi estrategia con la misma aplicación y de forma sencilla.</p>
<p>Extremadamente recomendable.</p>
<hr>
<h2 id="cómo-se-compara-pika-backup-con-déjà-dup">¿Cómo se compara Pika Backup con Déjà Dup?</h2>
<p><a href="https://flathub.org/apps/org.gnome.DejaDup">Déjà Dup</a> es una solución basada en <a href="https://duplicity.gitlab.io/">duplicity</a> que se ofrece, tradicionalmente, como parte del entorno de escritorio Gnome. Realiza copias de seguridad cifradas, incrementales, y las almacena en un formato de archivo comprimido que, independientemente de dónde almacenes estos archivos, preserva los permisos de los ficheros en tu máquina.</p>
<ul>
<li>Soporta discos externos y todo tipo de almacenamiento remoto –la lista completa se puede consultar en la documentación de <a href="https://duplicity.gitlab.io/">duplicity</a>, pero <strong>sólo soporta una única configuración para tu copia de seguridad. La copia de seguridad que configures, es única y a un sólo destino</strong>. Esto dificulta el realizar una estrategia de copias de seguridad robusta, 3:2:1, con la misma herramienta.</li>
<li>Por otro lado, el sistema de copias de seguridad no tiene parte servidora, como la tiene Borg (y la aprovecha Pika Backup al ser éste un cliente gráfico y versátil de Borg); esto quiere decir que <strong>la verificación y el almacenamiento sea <em>mucho</em> más lento</strong>.</li>
<li>No está bien pensado para portátiles, si es que han pensado en portátiles en absoluto.</li>
<li><strong>No permite escoger el día o la hora de las copias de seguridad programada</strong>. Si cuando configuras Déjà Dup las copias semanales caen en miércoles por el artículo 33, moverlas al domingo no es nada intuitivo, si es que el posible. Y, si cuando entra la copia de seguridad, te tienes que ir con tu portátil, el proceso se va a quedar por ahí medio enganchado.</li>
<li><strong>Las copias de seguridad programadas siempre se intentan realizar, estés funcionando en batería, sin red, o lo que sea</strong>. Esto consume energía y genera errores de forma innecesaria.</li>
</ul>
<p>Todo este tipo de cosas hacen que Déjà Dup se vaya quedando atrás. Si bien es igual de sencillo de usar que Pika Backup, el ritmo al que añaden el tipo de funcionalidades que  me afectan más es bastante bajo, casi diría que cae en la apatía, y estas cosas van desluciendo al producto poco a poco.</p>
<hr>
<h3 id="comentarios-previos">Comentarios previos</h3>
<p><strong>Antonio</strong>, el 8 de mayo de 2024 , <strong>comentó</strong>:</p>
<blockquote>
<p>Gabriel, estupendo artículo muy interesante para los que tenemos que hacer respaldos de los archivos regularmente. Recomiendas alguno para macOS?. Gracias</p></blockquote>
<p><strong>Gabriel Viso Carrera</strong>, el 8 de mayo de 2024, <strong>respondió</strong>:</p>
<blockquote>
<blockquote>
<p>Para macOS solo tengo experiencia con Time Machine y Super Duper. Los dos hacen bien su tarea.</p>
<p>No descarto probar Vorta, que está basado en Borg Backup, igual que Pika Backup. Si quieres echarle un vistazo ve a <a href="https://vorta.borgbase.com">https://vorta.borgbase.com</a></p></blockquote></blockquote>
]]></content:encoded>
    </item>
  </channel>
</rss>
