🎯 TL;DR

En este post documento la arquitectura y el despliegue desde cero de un servidor web estático ultraseguro utilizando OpenBSD sobre Proxmox VE. La configuración aborda la optimización del hardware virtual (controladores VirtIO SCSI, CPU AES-NI), la reducción de la superficie de ataque del sistema base, la delegación auditable de privilegios con doas, el filtrado de red estricto con PF y la puesta en marcha del servidor web nativo httpd operando en un entorno chroot.

Competencias aplicadas: Administración de sistemas, OpenBSD, Proxmox, seguridad perimetral, web servers.


☕ El Contexto

A veces, las mejores arquitecturas nacen a las 5 de la madrugada. Mi objetivo era simple: levantar un servidor web para alojar este blog y poder dormir tranquilo por las noches sabiendo que es (casi) inexpugnable. Elegí OpenBSD.

Lo que no esperaba era que mi primer intento fuera un desastre de rendimiento. OpenBSD tiene una función de seguridad llamada KARL que reorganiza internamente su núcleo en cada reinicio para que sea mucho más difícil de atacar. Al usar un disco virtual antiguo, ese proceso de escritura fue tan lento que el servidor tardaba 15 minutos solo en arrancar.

¿La solución? Destruir la máquina virtual sin piedad, aprender la lección de I/O, subirle la RAM a 2 GB, meterle VirtIO SCSI y volver a empezar. El resultado es la bestia que vas a ver a continuación.


🥩 La “Chicha” Técnica

🛠️ Paso 1: La Obra — Creación de la VM en Proxmox

Para comenzar con la instalación, necesitamos el archivo ISO de OpenBSD. Yo usaré el netinstall: un archivo de unos pocos MB con lo suficiente para arrancar, particionar el disco y configurar el sistema. No contiene los sets (paquetes base), que se descargan obligatoriamente frescos desde internet.

Para no duplicar la carga de la red local pasando la ISO de mi PC al servidor, usé la utilidad de descarga de Proxmox. Dentro de Proxmox, vamos a local > Imágenes ISO > Descargar desde URL y pegamos el link:

https://cdn.openbsd.org/pub/OpenBSD/7.8/amd64/cd78.iso

Descargar desde URL en Proxmox

Descargar desde URL en Proxmox

A continuación, creamos la máquina virtual con esta parametrización de alto rendimiento:

Parámetro Valor
General VM ID 105, Nombre web-openbsd
OS Type Other — crucial para que Proxmox no intente “ayudar” con drivers de Linux que rompen BSD
System SCSI Controller: VirtIO SCSI single (la clave del rendimiento de disco). BIOS: SeaBIOS
Disks Bus: SCSI (cambiado de IDE). Tamaño: 16 GB
CPU 2 Cores, Type x86-64-v2-AES — expone las instrucciones AES por hardware para que LibreSSL vuele
Memory 2048 MB — necesarios para que KARL (aleatorización del núcleo) trabaje en RAM sin paginar
Network Modelo Intel E1000 — el driver em de OpenBSD es una roca aquí

Resumen de creación de VM


🛠️ Paso 2: El Interrogatorio — La Instalación de OpenBSD

Arrancamos la máquina, abrimos la consola y vamos a hacer un speedrun de la instalación. Cuando veas el prompt de bienvenida, pulsa I (Install) y sigue este guion:

Teclado y Hostname

  • Keyboard layout: es
  • System hostname: web-openbsd

Red

  • Network interface: em0
  • IPv4 address: 192.168.1.105 (para que coincida con la configuración de nuestra red).
  • Netmask: 255.255.255.0 (para indicarle dónde empieza la calle).
  • IPv6 address: none
  • Default route: 192.168.1.1 (o la IP de tu router).
  • DNS domain name: alextty.cc (podrías dejarlo por defecto y sería funcional, pero my.domain queda feo).
  • DNS nameservers: 1.1.1.1 9.9.9.9 (evitamos el punto de fallo único. Si cae Cloudflare, seguimos funcionando con Quad9).

Seguridad y Usuario

  • Password for root account: (la que tú elijas).
  • Start sshd(8) by default? yes
  • Do you expect to run the X Window System? no (bloatware fuera).
  • Setup a user? alex
  • Allow root ssh login? no (paranoia por bandera).

Discos (La magia SCSI)

  • Available disks: Verás que sale sd0 (¡nuestro VirtIO rindiendo!).
  • Root disk? sd0
  • Use (W)hole disk MBR, (E)dit or (O)penBSD area? whole (o M para MBR si te lo pregunta).
  • Layout? auto

El layout de particiones auto de OpenBSD

La genialidad del particionado auto es que OpenBSD crea subparticiones separadas para /tmp, /var, /usr, etc. Si un atacante satura el servidor, solo llenará un chroot y el sistema no colapsará. Dejamos que instale los sets por http desde cdn.openbsd.org.

Descargando los sets al 100% y CONGRATULATIONS


🛠️ Paso 3: Auditoría y Parcheo — Blindando el búnker

Tras reiniciar, entramos como root y ejecutamos la prueba de fuego: top.

El comando top mostrando el consumo de RAM

El sistema base, con sus demonios funcionando, apenas consume entre 25–40 MB de memoria activa. Una eficiencia demencial.

Delegación de privilegios con doas

Le damos permisos al usuario raso (alex) para no tener que loguearnos como root nunca más:

echo "permit persist alex as root" > /etc/doas.conf

Actualización del sistema

syspatch    # parches del sistema base
fw_update   # firmware (sí, aunque estemos en una VM)

🧱 Configuración del firewall con PF

PF (Packet Filter) es la joya de la corona de OpenBSD y viene activado de fábrica. El problema es que /etc/pf.conf por defecto es bastante permisivo.

Para que este servidor sea un búnker real, aplicamos la regla de oro: Default Deny — bloquear todo y abrir solo lo estrictamente necesario. Permitiremos únicamente la salida a internet y la entrada por SSH (puerto 22) y HTTP (puerto 80):

cat << 'EOF' > /etc/pf.conf
# --- MACROS ---
ext_if="em0"

# --- OPCIONES GLOBALES ---
set skip on lo

# --- POLÍTICA POR DEFECTO ---
block return all

# --- REGLAS DE SALIDA (OUT) ---
pass out all

# --- REGLAS DE ENTRADA (IN) ---
pass in on $ext_if inet proto icmp all
pass in on $ext_if inet proto tcp to port { 22, 80 }
EOF

Recargamos las reglas en caliente y verificamos el estado del firewall:

doas pfctl -f /etc/pf.conf
doas pfctl -si

🌐 Paso 4: El Servidor Web — Puesta en marcha de httpd

El servidor httpd de OpenBSD es una obra maestra del minimalismo. No necesitas instalar Nginx o Apache; ya viene integrado en el sistema base. Por seguridad, se ejecuta encerrado (chroot) en /var/www/, sin poder ver nada fuera de ese directorio.

Creamos su configuración para que escuche en el puerto 80:

cat << 'EOF' > /etc/httpd.conf
server "default" {
    listen on * port 80
    root "/htdocs"
}
EOF

Lo habilitamos en el arranque y lo encendemos en caliente:

rcctl enable httpd
rcctl start httpd

Finalmente, plantamos nuestra bandera creando un index.html:

echo "<h1>Búnker 105 Operativo</h1><p>Son más de las 5 de la madrugada y el servidor está sirviendo tráfico. Sysadmin de guardia.</p>" > /var/www/htdocs/index.html

El navegador mostrando Búnker 105 Operativo