<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="es">
    <title>Nezzontli - Server</title>
    <subtitle>Bitácora personal de Alejandro B.E.: tecnología, física, sistemas resilientes y fotografía analógica.</subtitle>
    <link rel="self" type="application/atom+xml" href="https://nezzontli.xyz/es/tags/server/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://nezzontli.xyz"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2026-07-16T00:00:00+00:00</updated>
    <id>https://nezzontli.xyz/es/tags/server/atom.xml</id>
    <entry xml:lang="es">
        <title>Servidor personal: Debian + Docker, no FreeBSD</title>
        <published>2026-07-16T00:00:00+00:00</published>
        <updated>2026-07-16T00:00:00+00:00</updated>
        
        <author>
          <name>
            B.E. Alejandro
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://nezzontli.xyz/es/blog/servidor/"/>
        <id>https://nezzontli.xyz/es/blog/servidor/</id>
        
        <content type="html" xml:base="https://nezzontli.xyz/es/blog/servidor/">&lt;h2 id=&quot;contexto&quot;&gt;Contexto&lt;&#x2F;h2&gt;
&lt;p&gt;Este post reemplaza una entrada anterior que describía el plan original: FreeBSD, jails, bastilleBSD. Ese plan no se ejecutó así. Lo que terminó corriendo en la máquina reusada (hostname &lt;code&gt;pcale&lt;&#x2F;code&gt;) es &lt;strong&gt;Debian 13 (Trixie)&lt;&#x2F;strong&gt; con todo containerizado en &lt;strong&gt;Docker&lt;&#x2F;strong&gt;, un stack por servicio en &lt;code&gt;docker-compose.yml&lt;&#x2F;code&gt; separados, sin hypervisor ni jails.&lt;&#x2F;p&gt;
&lt;p&gt;La razón del cambio fue práctica: Docker Compose me da aislamiento por servicio sin la curva de aprendizaje adicional de jails&#x2F;bhyve, y el ecosistema de imágenes ya resueltas (linuxserver, imágenes oficiales) redujo tiempo de instalación a casi cero comparado con compilar todo desde ports.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;infraestructura-base&quot;&gt;Infraestructura base&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;SO:&lt;&#x2F;strong&gt; Debian 13 (Trixie), kernel 6.12.x&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Actualizaciones:&lt;&#x2F;strong&gt; &lt;code&gt;unattended-upgrades&lt;&#x2F;code&gt; para parches de seguridad automáticos&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Todo lo demás vive en contenedores&lt;&#x2F;strong&gt; — cada servicio tiene su propio &lt;code&gt;docker-compose.yml&lt;&#x2F;code&gt; bajo &lt;code&gt;&#x2F;home&#x2F;ale&#x2F;&amp;lt;servicio&amp;gt;&#x2F;&lt;&#x2F;code&gt;, así config, volúmenes y upgrades quedan aislados por app&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;acceso-y-red&quot;&gt;Acceso y red&lt;&#x2F;h2&gt;
&lt;p&gt;No hay puertos abiertos al público en el router. El acceso normal es vía &lt;strong&gt;Tailscale&lt;&#x2F;strong&gt;: cada servicio interno se publica con un hostname propio y HTTPS real usando Tailscale Services:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;tailscale&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; serve&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;service&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-option z-shell&quot;&gt;=&lt;&#x2F;span&gt;svc:&lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;nombre&lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-terminator z-file-descriptor z-shell&quot;&gt;-&lt;&#x2F;span&gt;-bg&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;https&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-option z-shell&quot;&gt;=&lt;&#x2F;span&gt;443 http:&#x2F;&#x2F;localhost:&lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;puerto&lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;tailscale&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; serve&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;service&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-option z-shell&quot;&gt;=&lt;&#x2F;span&gt;svc:&lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;nombre&lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-terminator z-file-descriptor z-shell&quot;&gt;-&lt;&#x2F;span&gt;-bg&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;http&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-option z-shell&quot;&gt;=&lt;&#x2F;span&gt;80 http:&#x2F;&#x2F;localhost:&lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;puerto&lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Esto da URLs como &lt;code&gt;https:&#x2F;&#x2F;nextcloud.tail32b955.ts.net&lt;&#x2F;code&gt;, con certificado válido, sin recordar puertos. Un par de servicios sí salen a internet público, pero vía &lt;strong&gt;Cloudflare Tunnel&lt;&#x2F;strong&gt; (&lt;code&gt;cloudflared&lt;&#x2F;code&gt;, conexión saliente únicamente, nada expuesto en el router) — el caso principal es PeerTube en &lt;code&gt;tube.richard69.lat&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Perímetro:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;SSH solo con clave, llave de seguridad física (YubiKey), &lt;code&gt;X11Forwarding&lt;&#x2F;code&gt; desactivado&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;ufw&lt;&#x2F;code&gt; en default-deny, la mayoría de servicios restringidos a LAN (&lt;code&gt;192.168.68.0&#x2F;24&lt;&#x2F;code&gt;) + Tailscale (&lt;code&gt;100.0.0.0&#x2F;8&lt;&#x2F;code&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;fail2ban&lt;&#x2F;code&gt; en el jail de SSH (maxretry 3, ban 24h)&lt;&#x2F;li&gt;
&lt;li&gt;Vaultwarden llegó a tener un hostname público en el tunnel; se sacó por completo y ahora es Tailscale-only&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;servicios-corriendo&quot;&gt;Servicios corriendo&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;strong&gt;Nube y datos personales&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Nextcloud&lt;&#x2F;strong&gt; — almacenamiento personal, también sirve como fuente de la biblioteca de Calibre-web (apunta directo a &lt;code&gt;Documents&#x2F;Libros&lt;&#x2F;code&gt; sin duplicar archivos)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Immich&lt;&#x2F;strong&gt; — fotos&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Vaultwarden&lt;&#x2F;strong&gt; — gestor de contraseñas (servidor compatible con Bitwarden), solo por Tailscale&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Calibre-web&lt;&#x2F;strong&gt; — lector&#x2F;biblioteca de ebooks&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;Media&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Jellyfin&lt;&#x2F;strong&gt; — servidor de medios (películas, series, música)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;qBittorrent + Radarr + Sonarr + Prowlarr&lt;&#x2F;strong&gt; — el stack *arr completo: indexers → búsqueda → descarga → importación, aterrizando directo en la biblioteca de Jellyfin, que se refresca sola al importar&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Navidrome&lt;&#x2F;strong&gt; — streaming de música&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;spotiflac&lt;&#x2F;strong&gt;, &lt;strong&gt;AudioMuse AI&lt;&#x2F;strong&gt; — utilidades de música&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;PeerTube&lt;&#x2F;strong&gt; — instancia propia y federada de video (&lt;code&gt;tube.richard69.lat&lt;&#x2F;code&gt;), con una imagen parcheada a mano (ver abajo)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Todo el lado de descargas (qBittorrent, Radarr, Sonarr, Prowlarr, spotiflac) corre con &lt;code&gt;network_mode: container:mullvad-exit-vpn&lt;&#x2F;code&gt;, compartiendo el namespace de red de un único contenedor &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;qdm12&#x2F;gluetun&quot;&gt;gluetun&lt;&#x2F;a&gt;, así ese tráfico —y solo ese— sale por un exit de Mullvad vía WireGuard.&lt;&#x2F;p&gt;
&lt;p&gt;Un extra que armé sobre esto: un script que convierte un canal de PeerTube seguido en una biblioteca de Jellyfin de archivos &lt;code&gt;.strm&lt;&#x2F;code&gt; (punteros a la URL del HLS del video original). Jellyfin los reproduce en directo desde la instancia origen sin que el archivo toque el disco del servidor.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Utilidades&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Glance&lt;&#x2F;strong&gt; — dashboard único: bookmarks, RSS, clima, chequeos de salud de cada servicio, buscador&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;4get&lt;&#x2F;strong&gt; — metabuscador privado, también el buscador embebido en Glance&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;ntfy&lt;&#x2F;strong&gt; — notificaciones push self-hosted (alertas del servidor, watchdog de la VPN, etc.)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Uptime Kuma &#x2F; Beszel&lt;&#x2F;strong&gt; — monitoreo, con umbrales de alerta mandando a ntfy&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Prosody&lt;&#x2F;strong&gt; — mensajería XMPP&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Forgejo&lt;&#x2F;strong&gt; — Git self-hosted (donde vive este mismo blog)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;problemas-encontrados-y-soluciones&quot;&gt;Problemas encontrados (y soluciones)&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;network_mode: container:X&lt;&#x2F;code&gt; no se re-resuelve solo.&lt;&#x2F;strong&gt; Docker fija esa referencia a un &lt;em&gt;container ID&lt;&#x2F;em&gt; en el momento de crear el contenedor. Si gluetun se recrea (&lt;code&gt;docker compose up --force-recreate&lt;&#x2F;code&gt;, o cualquier reinicio del stack), todo lo que comparte su netns (qBittorrent, Radarr, Sonarr, Prowlarr, spotiflac) queda apuntando a un namespace huérfano. El síntoma es engañoso: el contenedor se ve &lt;code&gt;Up (healthy)&lt;&#x2F;code&gt; y su proceso interno escucha bien desde adentro, pero nada llega desde afuera. Fix: force-recreate de cada contenedor afectado, no alcanza con &lt;code&gt;docker restart&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;*&lt;em&gt;La ruta de descarga de un &lt;em&gt;arr no puede ser su propia root folder.&lt;&#x2F;em&gt;&lt;&#x2F;em&gt; Si la categoría de qBittorrent apunta al mismo path que el root folder de Radarr&#x2F;Sonarr, la app no puede distinguir “todavía bajando” de “ya importado” y tira &lt;code&gt;DownloadClientRootFolderCheck&lt;&#x2F;code&gt;. Solución: carpetas de staging separadas (&lt;code&gt;&#x2F;media&#x2F;downloads&#x2F;movies&lt;&#x2F;code&gt;, &lt;code&gt;&#x2F;media&#x2F;downloads&#x2F;shows&lt;&#x2F;code&gt;), Radarr&#x2F;Sonarr importan por hardlink desde ahí al root folder real.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;ntfy en iOS necesita un &lt;code&gt;base-url&lt;&#x2F;code&gt; alcanzable.&lt;&#x2F;strong&gt; iOS no puede recibir contenido completo en el push directamente (limitación de APNs) — el teléfono hace polling al &lt;code&gt;base-url&lt;&#x2F;code&gt; del propio servidor después de recibir un push genérico de “new message”. Si ese &lt;code&gt;base-url&lt;&#x2F;code&gt; apunta a un dominio muerto, la notificación queda vacía sin ningún error visible en ningún lado.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;PeerTube solo acepta thumbnails remotos en JPEG.&lt;&#x2F;strong&gt; El validador de videos federados de PeerTube rechaza en silencio cualquier video cuyo thumbnail remoto sea PNG o WebP. Lo resolví con un parche chico horneado en una imagen Docker custom — hay que reconstruirla (no solo &lt;code&gt;docker compose pull&lt;&#x2F;code&gt;) en cada actualización de PeerTube o el parche desaparece sin avisar.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;que-falta-por-hacer&quot;&gt;Qué falta por hacer&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;Cloudflare Access delante de Uptime Kuma si algún día se tunelea al público&lt;&#x2F;li&gt;
&lt;li&gt;Reglas de &lt;code&gt;ufw&lt;&#x2F;code&gt; para un par de servicios más nuevos (4get, AudioMuse) que hoy solo responden desde localhost&lt;&#x2F;li&gt;
&lt;li&gt;Un manual real de recuperación ante desastres — por ahora ese conocimiento vive en mis notas, no en un documento&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;idea-central&quot;&gt;Idea central&lt;&#x2F;h2&gt;
&lt;p&gt;El objetivo cambió de “aprender FreeBSD a fondo” a “tener servicios propios corriendo de forma confiable, con el mínimo de superficie expuesta al público”. Docker Compose y Tailscale resultaron el camino más corto ahí. FreeBSD y jails siguen siendo un proyecto que me interesa, pero para otro momento — ver el post de &lt;a href=&quot;https:&#x2F;&#x2F;nezzontli.xyz&#x2F;blog&#x2F;web&#x2F;&quot;&gt;OpenBSD&lt;&#x2F;a&gt; para la versión de “control total” aplicada a algo más chico (el hospedaje de este mismo sitio).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;referencias&quot;&gt;Referencias&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;tailscale.com&#x2F;kb&#x2F;&quot;&gt;Documentación de Tailscale&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;qdm12&#x2F;gluetun&quot;&gt;gluetun&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;glanceapp&#x2F;glance&quot;&gt;Glance&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;wiki.servarr.com&#x2F;&quot;&gt;Servarr Wiki&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.joinpeertube.org&#x2F;&quot;&gt;Documentación de PeerTube&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    <entry xml:lang="es">
        <title>Uso de OpenBSD para hospedaje de página web</title>
        <published>2026-02-03T00:00:00+00:00</published>
        <updated>2026-02-03T00:00:00+00:00</updated>
        
        <author>
          <name>
            B.E. Alejandro
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://nezzontli.xyz/es/blog/web/"/>
        <id>https://nezzontli.xyz/es/blog/web/</id>
        
        <content type="html" xml:base="https://nezzontli.xyz/es/blog/web/">&lt;h2 id=&quot;contexto-y-motivacion&quot;&gt;Contexto y motivación&lt;&#x2F;h2&gt;
&lt;p&gt;Decidí migrar el hospedaje de mi página web a OpenBSD como un ejercicio deliberado de control, simplicidad y seguridad.&lt;br &#x2F;&gt;
No fue una decisión basada en rendimiento, escalabilidad comercial ni automatización extrema, sino en comprensión total del sistema.&lt;&#x2F;p&gt;
&lt;p&gt;OpenBSD obliga a entender cada archivo de configuración, cada servicio activo y cada permiso. No oculta complejidad: la expone. Ese fue el motivo central de esta migración.&lt;&#x2F;p&gt;
&lt;p&gt;El objetivo era claro: un servidor auditable, predecible y mínimo.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;infraestructura-y-vm&quot;&gt;Infraestructura y VM&lt;&#x2F;h2&gt;
&lt;p&gt;El servidor corre en una máquina virtual alquilada (VPS) de bajo costo, suficiente para contenido estático y servicios mínimos.&lt;&#x2F;p&gt;
&lt;p&gt;Características generales de la VM:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;1 vCPU&lt;&#x2F;li&gt;
&lt;li&gt;1–2 GB de RAM&lt;&#x2F;li&gt;
&lt;li&gt;Almacenamiento SSD&lt;&#x2F;li&gt;
&lt;li&gt;IP pública dedicada&lt;&#x2F;li&gt;
&lt;li&gt;Acceso root inicial para bootstrap&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;El proveedor no es relevante: OpenBSD no depende de features del host. El sistema se mantiene portable y reproducible.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;eleccion-del-stack&quot;&gt;Elección del stack&lt;&#x2F;h2&gt;
&lt;p&gt;El stack fue elegido conscientemente para reducir superficie de ataque:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Sistema operativo: OpenBSD&lt;&#x2F;li&gt;
&lt;li&gt;Servidor web: httpd (nativo)&lt;&#x2F;li&gt;
&lt;li&gt;HTTPS: acme-client (Let’s Encrypt)&lt;&#x2F;li&gt;
&lt;li&gt;Generador estático: Zola&lt;&#x2F;li&gt;
&lt;li&gt;Tema: Duckquill (modificado)&lt;&#x2F;li&gt;
&lt;li&gt;Repositorio: Git + GitHub&lt;&#x2F;li&gt;
&lt;li&gt;Acceso remoto: SSH con YubiKey (OpenPGP)&lt;&#x2F;li&gt;
&lt;li&gt;Servicio oculto: Tor (mirror .onion)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;No hay nginx, no hay docker, no hay paneles web, no hay Node en producción. Solo binarios del sistema base y archivos de texto.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;migracion-a-openbsd&quot;&gt;Migración a OpenBSD&lt;&#x2F;h2&gt;
&lt;p&gt;La migración incluyó:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Instalación limpia de OpenBSD&lt;&#x2F;li&gt;
&lt;li&gt;Configuración manual de red y DNS&lt;&#x2F;li&gt;
&lt;li&gt;Creación explícita de usuarios&lt;&#x2F;li&gt;
&lt;li&gt;Uso exclusivo de doas (sin sudo)&lt;&#x2F;li&gt;
&lt;li&gt;Servicios deshabilitados por defecto&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Separación clara entre: sistema (&#x2F;etc), contenido (&#x2F;var&#x2F;www), claves (&#x2F;etc&#x2F;ssl, &#x2F;etc&#x2F;acme). Nada se dejó “por default” sin entenderlo.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;servidor-web-con-httpd&quot;&gt;Servidor web con httpd&lt;&#x2F;h2&gt;
&lt;p&gt;El servidor web se configuró usando httpd nativo, sin módulos externos.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Configuración base simplificada:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;server &amp;quot;nezzontli.xyz&amp;quot; {
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    listen on * port 80
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    root &amp;quot;&#x2F;htdocs&amp;quot;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    location &amp;quot;&#x2F;.well-known&#x2F;acme-challenge&#x2F;*&amp;quot; {
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;        root &amp;quot;&#x2F;acme&amp;quot;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;        request strip 2
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    }
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;server &amp;quot;nezzontli.xyz&amp;quot; {
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    listen on * tls port 443
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    root &amp;quot;&#x2F;htdocs&amp;quot;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    tls {
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;        certificate &amp;quot;&#x2F;etc&#x2F;ssl&#x2F;nezzontli.xyz.fullchain.pem&amp;quot;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;        key &amp;quot;&#x2F;etc&#x2F;ssl&#x2F;private&#x2F;nezzontli.xyz.key&amp;quot;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    }
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;https-con-acme-client&quot;&gt;HTTPS con acme-client&lt;&#x2F;h2&gt;
&lt;p&gt;OpenBSD incluye acme-client en base, lo que elimina dependencias externas.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Flujo real:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Configurar httpd solo en HTTP&lt;&#x2F;li&gt;
&lt;li&gt;Resolver DNS correctamente (A records apuntando a la VM)&lt;&#x2F;li&gt;
&lt;li&gt;Ejecutar: &lt;code&gt;doas acme-client -v nezzontli.xyz&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Verificar creación de certificados en &#x2F;etc&#x2F;ssl&lt;&#x2F;li&gt;
&lt;li&gt;Habilitar TLS en httpd&lt;&#x2F;li&gt;
&lt;li&gt;Reiniciar servicio&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;No se usan scripts externos. La renovación se maneja vía cron del sistema.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;problemas-encontrados-y-soluciones&quot;&gt;Problemas encontrados (y soluciones)&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;1-error-404-en-acme-challenge&quot;&gt;1. Error 404 en ACME challenge&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;strong&gt;Causa:&lt;&#x2F;strong&gt; httpd no estaba sirviendo correctamente &#x2F;var&#x2F;www&#x2F;acme.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Solución:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;doas&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; mkdir&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;p&lt;&#x2F;span&gt; &#x2F;var&#x2F;www&#x2F;acme&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;doas&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; chown&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;R&lt;&#x2F;span&gt; web:web &#x2F;var&#x2F;www&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;2-dns-no-propagado&quot;&gt;2. DNS no propagado&lt;&#x2F;h3&gt;
&lt;p&gt;Durante el primer intento, el dominio resolvía a múltiples IPs antiguas: &lt;code&gt;dig nezzontli.xyz +short&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Solución:&lt;&#x2F;strong&gt; Esperar propagación completa y eliminar registros conflictivos.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;3-confusion-con-dnssec&quot;&gt;3. Confusión con DNSSEC&lt;&#x2F;h3&gt;
&lt;p&gt;DNSSEC no es requisito para Let’s Encrypt HTTP-01. DNSSEC es independiente de TLS. No se activó en esta etapa.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;generacion-del-sitio-con-zola&quot;&gt;Generación del sitio con Zola&lt;&#x2F;h2&gt;
&lt;p&gt;El sitio es 100% estático.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Flujo básico:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;zola&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; build&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;doas&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; rsync&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;a&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;delete&lt;&#x2F;span&gt; public&#x2F; &#x2F;var&#x2F;www&#x2F;htdocs&#x2F;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;No hay generación en runtime. No hay escritura desde el servidor web.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;mirror-tor-onion&quot;&gt;Mirror Tor (.onion)&lt;&#x2F;h2&gt;
&lt;p&gt;Se configuró un Hidden Service de Tor como mirror del sitio.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;&#x2F;etc&#x2F;tor&#x2F;torrc:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;HiddenServiceDir &#x2F;var&#x2F;tor&#x2F;hidden_service&#x2F;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;HiddenServicePort 80 127.0.0.1:80
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;httpd escucha solo en localhost para Tor:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;server &amp;quot;*&amp;quot; {
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    listen on 127.0.0.1 port 80
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    root &amp;quot;&#x2F;tor&amp;quot;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;Build específico para Tor:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;zola&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; build&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;base-url&lt;&#x2F;span&gt; http:&#x2F;&#x2F;&lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;onion&lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;.onion&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;doas&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; rsync&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;a&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;delete&lt;&#x2F;span&gt; public&#x2F; &#x2F;var&#x2F;www&#x2F;tor&#x2F;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;Integración Tor Browser (Onion-Location):&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;html&quot; class=&quot;language-html z-code&quot;&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;&lt;span class=&quot;z-text z-html z-basic&quot;&gt;&lt;span class=&quot;z-meta z-tag z-inline z-any z-html&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-begin z-html&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-inline z-any z-html&quot;&gt;meta&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-attribute-with-value z-html&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name z-html&quot;&gt;http-equiv&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-html&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-html&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-html&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;onion-location&lt;span class=&quot;z-punctuation z-definition z-string z-end z-html&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-attribute-with-value z-html&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name z-html&quot;&gt;content&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value z-html&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-html&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-html&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;http:&#x2F;&#x2F;&amp;lt;onion&amp;gt;.onion&lt;span class=&quot;z-punctuation z-definition z-string z-end z-html&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-end z-html&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;automatizacion-del-despliegue&quot;&gt;Automatización del despliegue&lt;&#x2F;h2&gt;
&lt;p&gt;Script único para clearnet + Tor:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;!&#x2F;bin&#x2F;sh&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-support z-function z-set z-shell&quot;&gt;set&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt;-&lt;&#x2F;span&gt;e&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-assignment z-shell&quot;&gt;ONION_URL&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-shell&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-unquoted z-shell&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;http:&#x2F;&#x2F;&amp;lt;onion&amp;gt;.onion&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;git&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; pull&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;zola&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; build&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;doas&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; rsync&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;a&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;delete&lt;&#x2F;span&gt; public&#x2F; &#x2F;var&#x2F;www&#x2F;htdocs&#x2F;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;zola&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; build&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;base-url&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;ONION_URL&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;doas&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; rsync&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;a&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;delete&lt;&#x2F;span&gt; public&#x2F; &#x2F;var&#x2F;www&#x2F;tor&#x2F;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Instalado en: &lt;code&gt;&#x2F;usr&#x2F;local&#x2F;bin&#x2F;update-site&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;control-de-acceso-ssh-yubikey&quot;&gt;Control de acceso: SSH + YubiKey&lt;&#x2F;h2&gt;
&lt;p&gt;Acceso remoto sin contraseñas persistentes:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Clave OpenPGP en YubiKey&lt;&#x2F;li&gt;
&lt;li&gt;PIN + touch físico&lt;&#x2F;li&gt;
&lt;li&gt;gpg-agent como SSH agent&lt;&#x2F;li&gt;
&lt;li&gt;ssh-ed25519&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;La clave privada nunca toca el disco.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;control-de-versiones-y-firmas&quot;&gt;Control de versiones y firmas&lt;&#x2F;h2&gt;
&lt;p&gt;Repositorio alojado en GitHub:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Git puro&lt;&#x2F;li&gt;
&lt;li&gt;Commits firmados&lt;&#x2F;li&gt;
&lt;li&gt;Modelo de confianza por defecto&lt;&#x2F;li&gt;
&lt;li&gt;Sin CI obligatorio&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;El servidor no compila desde hooks remotos: el despliegue es consciente y manual.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;estructura-del-proyecto&quot;&gt;Estructura del proyecto&lt;&#x2F;h2&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;site&#x2F;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;├── config.toml
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;├── content&#x2F;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;├── templates&#x2F;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;├── static&#x2F;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;├── public&#x2F;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;└── scripts&#x2F;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;En servidor:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;&#x2F;var&#x2F;www&#x2F;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;├── htdocs&#x2F;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;├── tor&#x2F;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;└── acme&#x2F;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;que-falta-por-hacer&quot;&gt;Qué falta por hacer&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;strong&gt;Pendientes reales:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Hardening adicional de httpd&lt;&#x2F;li&gt;
&lt;li&gt;Documentar bootstrap completo desde cero&lt;&#x2F;li&gt;
&lt;li&gt;Monitoreo mínimo (sin agentes invasivos)&lt;&#x2F;li&gt;
&lt;li&gt;Publicar configs como referencia reproducible&lt;&#x2F;li&gt;
&lt;li&gt;Auditoría de headers de seguridad&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;idea-central&quot;&gt;Idea central&lt;&#x2F;h2&gt;
&lt;p&gt;Este proyecto no busca conveniencia ni velocidad de desarrollo.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Busca:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Comprensión&lt;&#x2F;li&gt;
&lt;li&gt;Control&lt;&#x2F;li&gt;
&lt;li&gt;Auditabilidad&lt;&#x2F;li&gt;
&lt;li&gt;Reducción de estados implícitos&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;OpenBSD no acelera el trabajo. Elimina errores silenciosos. Ese es el valor.&lt;&#x2F;p&gt;
</content>
        
    </entry>
</feed>
