Uso de OpenBSD para hospedaje de página web
By B.E. Alejandro • 4 minutes read •
Contexto y motivación
Decidí migrar el hospedaje de mi página web a OpenBSD como un ejercicio deliberado de control, simplicidad y seguridad.
No fue una decisión basada en rendimiento, escalabilidad comercial ni automatización extrema, sino en comprensión total del sistema.
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.
El objetivo era claro: un servidor auditable, predecible y mínimo.
Infraestructura y VM
El servidor corre en una máquina virtual alquilada (VPS) de bajo costo, suficiente para contenido estático y servicios mínimos.
Características generales de la VM:
- 1 vCPU
- 1–2 GB de RAM
- Almacenamiento SSD
- IP pública dedicada
- Acceso root inicial para bootstrap
El proveedor no es relevante: OpenBSD no depende de features del host. El sistema se mantiene portable y reproducible.
Elección del stack
El stack fue elegido conscientemente para reducir superficie de ataque:
- Sistema operativo: OpenBSD
- Servidor web: httpd (nativo)
- HTTPS: acme-client (Let’s Encrypt)
- Generador estático: Zola
- Tema: Duckquill (modificado)
- Repositorio: Git + Codeberg
- Acceso remoto: SSH con YubiKey (OpenPGP)
- Servicio oculto: Tor (mirror .onion)
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.
Migración a OpenBSD
La migración incluyó:
- Instalación limpia de OpenBSD
- Configuración manual de red y DNS
- Creación explícita de usuarios
- Uso exclusivo de doas (sin sudo)
- Servicios deshabilitados por defecto
Separación clara entre: sistema (/etc), contenido (/var/www), claves (/etc/ssl, /etc/acme). Nada se dejó “por default” sin entenderlo.
Servidor web con httpd
El servidor web se configuró usando httpd nativo, sin módulos externos.
Configuración base simplificada:
server "nezzontli.xyz" {
listen on * port 80
root "/htdocs"
location "/.well-known/acme-challenge/*" {
root "/acme"
request strip 2
}
}
server "nezzontli.xyz" {
listen on * tls port 443
root "/htdocs"
tls {
certificate "/etc/ssl/nezzontli.xyz.fullchain.pem"
key "/etc/ssl/private/nezzontli.xyz.key"
}
}
HTTPS con acme-client
OpenBSD incluye acme-client en base, lo que elimina dependencias externas.
Flujo real:
- Configurar httpd solo en HTTP
- Resolver DNS correctamente (A records apuntando a la VM)
- Ejecutar:
doas acme-client -v nezzontli.xyz - Verificar creación de certificados en /etc/ssl
- Habilitar TLS en httpd
- Reiniciar servicio
No se usan scripts externos. La renovación se maneja vía cron del sistema.
Problemas encontrados (y soluciones)
1. Error 404 en ACME challenge
Causa: httpd no estaba sirviendo correctamente /var/www/acme.
Solución:
2. DNS no propagado
Durante el primer intento, el dominio resolvía a múltiples IPs antiguas: dig nezzontli.xyz +short
Solución: Esperar propagación completa y eliminar registros conflictivos.
3. Confusión con DNSSEC
DNSSEC no es requisito para Let’s Encrypt HTTP-01. DNSSEC es independiente de TLS. No se activó en esta etapa.
Generación del sitio con Zola
El sitio es 100% estático.
Flujo básico:
No hay generación en runtime. No hay escritura desde el servidor web.
Mirror Tor (.onion)
Se configuró un Hidden Service de Tor como mirror del sitio.
/etc/tor/torrc:
HiddenServiceDir /var/tor/hidden_service/
HiddenServicePort 80 127.0.0.1:80
httpd escucha solo en localhost para Tor:
server "*" {
listen on 127.0.0.1 port 80
root "/tor"
}
Build específico para Tor:
Integración Tor Browser (Onion-Location):
Automatización del despliegue
Script único para clearnet + Tor:
#!/bin/sh
ONION_URL="http://<onion>.onion"
Instalado en: /usr/local/bin/update-site
Control de acceso: SSH + YubiKey
Acceso remoto sin contraseñas persistentes:
- Clave OpenPGP en YubiKey
- PIN + touch físico
- gpg-agent como SSH agent
- ssh-ed25519
La clave privada nunca toca el disco.
Control de versiones y firmas
Repositorio alojado en Codeberg:
- Git puro
- Commits firmados
- Modelo de confianza por defecto
- Sin CI obligatorio
El servidor no compila desde hooks remotos: el despliegue es consciente y manual.
Estructura del proyecto
site/
├── config.toml
├── content/
├── templates/
├── static/
├── public/
└── scripts/
En servidor:
/var/www/
├── htdocs/
├── tor/
└── acme/
Qué falta por hacer
Pendientes reales:
- Hardening adicional de httpd
- Documentar bootstrap completo desde cero
- Monitoreo mínimo (sin agentes invasivos)
- Publicar configs como referencia reproducible
- Auditoría de headers de seguridad
Idea central
Este proyecto no busca conveniencia ni velocidad de desarrollo.
Busca:
- Comprensión
- Control
- Auditabilidad
- Reducción de estados implícitos
OpenBSD no acelera el trabajo. Elimina errores silenciosos. Ese es el valor.