Levantando un búnker web: Arquitectura e Instalación de OpenBSD en Proxmox
🎯 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


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í |

🛠️ 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, peromy.domainqueda 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(oMpara MBR si te lo pregunta). - Layout?
auto

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.

🛠️ Paso 3: Auditoría y Parcheo — Blindando el búnker
Tras reiniciar, entramos como root y ejecutamos la prueba de fuego: top.

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
