Meta
Colofón
Cómo está construido este sitio, qué decisiones tiene detrás y por qué. Si un portafolio de infraestructura no explica su propia infraestructura, algo falla.
Arquitectura
Un único contenedor Node que sirve tanto el sitio público como el panel de administración. Sin framework de frontend, sin paso de compilación y sin CDN de terceros: el HTML sale ya renderizado del servidor y el navegador sólo recibe lo que va a usar.
navegador
│ HTTPS
▼
reverse proxy (Caddy/Traefik) ── TLS automático
│ HTTP en loopback
▼
contenedor forgekloud (Node 26, usuario sin privilegios, FS de sólo lectura)
├── Fastify ── rutas públicas + /admin
├── SQLite (WAL) ── volumen persistente
└── /uploads ── imágenes validadas por bytesDecisiones y por qué
SQLite en vez de Postgres. Un solo escritor, lecturas concurrentes y un respaldo que consiste en copiar un fichero. Postgres aquí sería un servicio más que mantener, actualizar y monitorizar sin ganar nada.
Sin build step. El CSS y el JavaScript se sirven tal cual se escriben. No hay
bundler que actualizar ni node_modules de 400 MB en la imagen final.
Markdown sin HTML crudo. El renderizador tiene html: false, así que no
existe vector de XSS almacenado ni hace falta un sanitizador.
Páginas editables sin desplegar. El contenido de estas páginas vive en SQLite como una lista ordenada de bloques, no en el código. Cambiar una cifra o añadir una sección no exige tocar un fichero ni reiniciar el contenedor.
Resaltado de sintaxis en servidor. Un tokenizador propio de ~150 líneas cubre bash, YAML, HCL, Dockerfile, JSON, SQL y algunos más. El cliente recibe HTML ya coloreado: cero JavaScript de resaltado.
Seguridad
- Sesión en JWT HS256 firmado, en cookie
httpOnly+SameSite=Strict+Secure. - Contraseña con scrypt (KDF de memoria dura), nunca en texto plano.
- Token CSRF derivado del identificador de sesión en todo formulario que escribe.
- Rate limiting en el login: 5 intentos por ventana de 15 minutos.
- Subidas validadas por magic bytes, no por extensión ni por el
Content-Typeque declare el cliente. SVG está excluido a propósito. - El contenido de los bloques se valida contra un esquema al guardar y se escapa al renderizar: lo que se escribe en el panel nunca llega crudo al navegador.
- Cabeceras:
Content-Security-Policysinunsafe-inline,X-Content-Type-Options,Referrer-PolicyyX-Frame-Options. - Contenedor con
no-new-privileges, sistema de ficheros de sólo lectura y usuario no root.
Diseño
Sistema propio construido a partir de patrones observados en sitios de infraestructura y observabilidad, no copiado de ninguno: rampa de superficies neutra-cálida, un único acento (ámbar de forja) contrapesado con un frío para datos, monoespaciada reservada a telemetría y código, y retícula bento asimétrica. Tipografías Space Grotesk, IBM Plex Sans e IBM Plex Mono, autoalojadas.
Rendimiento
Sin JavaScript de terceros, sin fuentes remotas y sin peticiones fuera del propio dominio. El sitio se lee y se navega entero con JavaScript desactivado; el JS sólo añade el menú móvil, la animación del terminal y el botón de copiar código.