📋 Contexto
La documentación es uno de los activos más valiosos (y descuidados) en equipos de ingeniería. Wiki interna obsoleta, Google Docs dispersos, README.md desactualizados, conocimiento tribal que solo existe en la cabeza de seniors.
Recientemente implementé Docusaurus, un generador de sitios estáticos open source creado por Meta (Facebook), para centralizar la documentación de un equipo de ingeniería. Este post documenta el proceso, problemas encontrados, y cómo podrías usar Docusaurus en tu contexto (empresa o home lab).
🎯 ¿Qué es Docusaurus?
Docusaurus es un framework de React que convierte archivos Markdown/MDX en un sitio web de documentación profesional.
Características Principales
- Markdown/MDX: Escribe en Markdown, con soporte para componentes React
- Versionado: Documenta múltiples versiones de tu software/APIs
- Search: Búsqueda full-text integrada (Algolia DocSearch gratis)
- Dark mode: Built-in, sin configuración adicional
- i18n: Internacionalización nativa
- Blog integrado: Para changelogs, release notes, tutoriales
- SEO-friendly: Static site generation (SSG)
¿Por Qué Docusaurus vs Otras Opciones?
| Herramienta | Pros | Contras |
|---|---|---|
| Docusaurus | Moderno, completo, mantenido por Meta | Requiere Node.js, build process |
| MkDocs | Simple, Python-based | Menos features, UI básica |
| Confluence | Enterprise, mucho features | Caro, pesado, requiere Jira |
| Notion | UI moderna, colaborativo | Vendor lock-in, no code-friendly |
| GitHub Wiki | Gratis, integrado con repos | UI pobre, features limitados |
🛠️ Implementación: Setup Inicial
Prerequisitos
# Node.js 18+ (recomiendo 20 LTS)
node --version
# npm o yarn
npm --version
# Git (para versionado)
git --version
Paso 1: Crear Proyecto Docusaurus
# Crear proyecto nuevo
npx create-docusaurus@latest my-docs classic
cd my-docs
# Estructura generada:
my-docs/
├── docs/ # Documentación principal
│ └── intro.md
├── blog/ # Blog (opcional)
│ └── welcome.md
├── src/
│ ├── components/ # Componentes React custom
│ ├── css/ # Estilos custom
│ └── pages/ # Páginas adicionales
├── static/ # Assets estáticos (imágenes)
├── docusaurus.config.js # Configuración principal
└── sidebars.js # Estructura del menú lateral
Paso 2: Configuración Básica
Editar docusaurus.config.js:
// docusaurus.config.js
module.exports = {
title: 'Engineering Docs',
tagline: 'Internal documentation for the engineering team',
url: 'https://docs.mycompany.internal',
baseUrl: '/',
// Opciones de deployment
organizationName: 'mycompany',
projectName: 'eng-docs',
// Theme config
themeConfig: {
navbar: {
title: 'Engineering Docs',
logo: {
alt: 'Logo',
src: 'img/logo.svg',
},
items: [
{
type: 'doc',
docId: 'intro',
position: 'left',
label: 'Documentation',
},
{to: '/blog', label: 'Changelog', position: 'left'},
{
href: 'https://github.com/myorg/docs',
label: 'GitHub',
position: 'right',
},
],
},
// Dark mode (ya viene incluido)
colorMode: {
defaultMode: 'dark',
disableSwitch: false,
respectPrefersColorScheme: true,
},
// Footer
footer: {
style: 'dark',
links: [
{
title: 'Docs',
items: [
{label: 'Getting Started', to: '/docs/intro'},
{label: 'Architecture', to: '/docs/architecture'},
],
},
{
title: 'Community',
items: [
{label: 'Slack', href: 'https://myteam.slack.com'},
{label: 'GitHub', href: 'https://github.com/myorg'},
],
},
],
copyright: `Copyright © ${new Date().getFullYear()} Engineering Team`,
},
},
presets: [
[
'classic',
{
docs: {
sidebarPath: require.resolve('./sidebars.js'),
editUrl: 'https://github.com/myorg/docs/edit/main/',
},
blog: {
showReadingTime: true,
editUrl: 'https://github.com/myorg/docs/edit/main/',
},
theme: {
customCss: require.resolve('./src/css/custom.css'),
},
},
],
],
};
Paso 3: Desarrollo Local
# Iniciar servidor de desarrollo
npm run start
# Abre automáticamente: http://localhost:3000
# Hot reload: Guarda cambios y se reflejan automáticamente
📁 Estructura de Documentación
Organización Sugerida
docs/
├── getting-started/
│ ├── intro.md
│ ├── installation.md
│ └── quickstart.md
├── architecture/
│ ├── overview.md
│ ├── services.md
│ └── data-flow.md
├── apis/
│ ├── rest-api.md
│ ├── authentication.md
│ └── examples.md
├── deployment/
│ ├── docker.md
│ ├── kubernetes.md
│ └── ci-cd.md
├── runbooks/
│ ├── incident-response.md
│ ├── maintenance.md
│ └── troubleshooting.md
└── best-practices/
├── coding-standards.md
├── security.md
└── testing.md
🐛 Problemas Comunes y Soluciones
1. Build Falla con "Out of Memory"
Síntoma: npm run build termina con error FATAL ERROR: Reached heap limit
Causa: Documentación muy grande (100+ páginas) excede memoria de Node.js por defecto.
Solución:
# Aumentar memoria de Node.js
NODE_OPTIONS="--max-old-space-size=4096" npm run build
# O agregar a package.json:
{
"scripts": {
"build": "NODE_OPTIONS='--max-old-space-size=4096' docusaurus build"
}
}
2. Search No Funciona (Algolia)
Síntoma: Barra de búsqueda no encuentra nada.
Causa: Algolia DocSearch requiere aplicar y ser aprobado (puede tardar semanas).
Solución: Usar búsqueda local mientras esperas:
# Instalar plugin de búsqueda local
npm install @easyops-cn/docusaurus-search-local
# docusaurus.config.js
themes: [
[
'@easyops-cn/docusaurus-search-local',
{
hashed: true,
language: ['en', 'es'],
},
],
],
3. Imágenes Rotas Después del Build
Síntoma: Imágenes se ven en dev pero no en producción.
Causa: Rutas relativas incorrectas o imágenes no en /static.
Solución:
# Imágenes en /static/img/
static/
└── img/
└── architecture.png
# En Markdown, usar:

# NO usar:
 # ❌ Relativo falla
4. Deploy en Servidor Interno Falla (CORS/404)
Síntoma: Sitio deployado da 404 en rutas o assets no cargan.
Causa: baseUrl incorrecto en config.
Solución:
// Si deploy en https://docs.company.com/
baseUrl: '/',
// Si deploy en https://company.com/docs/
baseUrl: '/docs/',
// Reconstruir después de cambiar baseUrl
npm run build
5. Nginx da 403 Forbidden en RHEL/CentOS (SELinux) ⚠️ CRÍTICO
Síntoma: Después de copiar archivos a /var/www/docs, Nginx devuelve 403 Forbidden.
Causa: SELinux (Security-Enhanced Linux) bloquea el acceso de Nginx a archivos con contexto de seguridad incorrecto. Común en RHEL, CentOS, Rocky Linux, AlmaLinux.
Diagnóstico:
# Verificar si SELinux está activo
getenforce
# Output: Enforcing (bloqueará acceso)
# Ver logs de SELinux
sudo ausearch -m avc -ts recent | grep nginx
# Verificar contexto actual de los archivos
ls -Z /var/www/docs/
# Output incorrecta: unconfined_u:object_r:user_home_t:s0
Solución:
# Opción 1: Corregir contexto de archivos (RECOMENDADO)
sudo chcon -R -t httpd_sys_content_t /var/www/docs/
# Opción 2: Usar restorecon (si tienes políticas configuradas)
sudo restorecon -Rv /var/www/docs/
# Opción 3: Permitir Nginx leer home directories (solo si es necesario)
sudo setsebool -P httpd_read_user_content 1
# Verificar que el contexto está correcto
ls -Z /var/www/docs/
# Output correcto: unconfined_u:object_r:httpd_sys_content_t:s0
- NUNCA uses
setenforce 0(deshabilitar SELinux) en producción - Siempre corrige los contextos de seguridad correctamente
- En scripts de deployment, agrega
chcondespués delscp - Si usas rsync, considera
rsync -avz --contextpara preservar contexto
🖥️ Infraestructura y Deployment
Opción 1: GitHub Pages (Más Simple)
# docusaurus.config.js
organizationName: 'myorg',
projectName: 'docs',
deploymentBranch: 'gh-pages',
# Deploy con un comando
GIT_USER= npm run deploy
# Disponible en: https://myorg.github.io/docs/
Opción 2: Docker + Nginx (Para Empresas)
# Dockerfile
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Nginx para servir estáticos
FROM nginx:alpine
COPY --from=builder /app/build /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
# docker-compose.yml
version: '3.8'
services:
docs:
build: .
ports:
- "8080:80"
restart: unless-stopped
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
Opción 3: Vercel/Netlify (Deploy Automático)
# Conectar repo GitHub a Vercel:
# 1. Import project from GitHub
# 2. Vercel detecta Docusaurus automáticamente
# 3. Deploy automático en cada push a main
#
# URL: https://my-docs.vercel.app
Opción 4: Home Lab (Self-Hosted)
Para tener tu propia documentación en home lab:
# 1. Build estático
npm run build
# Output: build/ directory
# 2. Copiar a tu servidor
scp -r build/* user@your-server:/var/www/docs/
# 3. Nginx config
server {
listen 80;
server_name docs.yourdomain.com;
root /var/www/docs;
index index.html;
location / {
try_files $uri $uri/ $uri.html /index.html;
}
}
💡 Caso de Uso Empresarial (Generalizado)
El Problema Que Resolvimos
Un equipo de ingeniería con:
- 15+ microservicios sin documentación unificada
- Confluence obsoleto (última actualización: 2 años atrás)
- README.md dispersos en múltiples repos
- Onboarding de nuevos devs: 2-3 semanas
- Preguntas repetitivas en Slack
La Solución: Sistema de Documentación Centralizado
Implementamos Docusaurus con:
- Arquitectura: Diagramas de componentes, flujo de datos
- APIs: Documentación de endpoints con ejemplos
- Runbooks: Procedimientos de incidentes, deploys
- ADRs: Architectural Decision Records (por qué tomamos cada decisión)
- Onboarding: Guía step-by-step para nuevos developers
Resultados (Después de 3 Meses)
• Onboarding time: 2-3 semanas → 3-5 días (80% reducción)
• Preguntas repetitivas en Slack: -60%
• Tiempo buscando información: -70%
• Incidentes por falta de documentación: -50%
• Satisfacción del equipo: +85%
🏠 Caso de Uso: Home Lab
¿Por Qué Docusaurus en un Home Lab?
Documentar tu home lab con Docusaurus es útil si:
- Tienes múltiples servicios y te olvidas cómo configuraste cada uno
- Experimentas con tecnologías y quieres documentar aprendizajes
- Quieres compartir tus proyectos públicamente (como yo con este blog)
- Estás preparándote para certificaciones (documentar lo que aprendes)
Estructura para Home Lab
docs/
├── services/
│ ├── n8n.md # Setup de n8n
│ ├── nginx.md # Configuración Nginx
│ ├── postgres.md # PostgreSQL configs
│ └── cloudflare.md # Cloudflare Tunnel
├── infrastructure/
│ ├── network.md # Configuración de red
│ ├── hardware.md # Specs del servidor
│ └── security.md # Firewall, fail2ban
├── procedures/
│ ├── backup.md # Procedimientos de backup
│ ├── restore.md # Cómo restaurar
│ └── updates.md # Actualizar servicios
├── troubleshooting/
│ ├── docker.md # Problemas comunes Docker
│ ├── network.md # Issues de red
│ └── performance.md # Debugging performance
└── learning/
├── certifications.md # Progreso de certificaciones
├── projects.md # Ideas de proyectos
└── resources.md # Links útiles, cursos
Ejemplo: Documentar Tu Servidor
---
id: server-specs
title: Server Hardware Specifications
sidebar_position: 1
---
# Server Hardware
## Overview
Home lab server built from Lenovo G480 (2013).
## Specifications
| Component | Details |
|-----------|---------|
| **CPU** | Intel Celeron B970 (2 cores, 2.3 GHz) |
| **RAM** | 4 GB DDR3 |
| **Storage** | 512 GB SSD |
| **Network** | Ethernet 1 Gbps |
| **Power** | 12-18W idle, 30-40W load |
## Services Running
- Docker (n8n, PostgreSQL, Nginx)
- Cloudflare Tunnel
- System monitor (sysmon_web.py)
## Known Issues
### Lid Close Suspension
**Problem:** Closing laptop lid suspends the system.
**Solution:**
\`\`\`bash
sudo nano /etc/systemd/logind.conf
# Set:
HandleLidSwitch=ignore
\`\`\`
### Temperature Management
- Summer: Keep lid open (better ventilation)
- Winter: Lid can be closed (lower temps)
- Monitor: https://mytechzone.dev/status.html
🚀 Features Avanzadas
1. Componentes React Personalizados
// src/components/APIEndpoint.js
import React from 'react';
export default function APIEndpoint({method, path, description}) {
return (
{method}
{path}
{description}
);
}
// Uso en MDX:
import APIEndpoint from '@site/src/components/APIEndpoint';
2. Versionado de Documentación
# Crear nueva versión (cuando lanzas v2.0 de tu API)
npm run docusaurus docs:version 2.0
# Estructura resultante:
docs/ # Current (v2.1 en desarrollo)
versioned_docs/
├── version-2.0/ # Docs de v2.0
└── version-1.0/ # Docs de v1.0
# Dropdown automático en UI para cambiar versiones
3. Search con Algolia (Gratis para Open Source)
# Aplicar en: https://docsearch.algolia.com/apply/
# Después de aprobación, agregar a config:
themeConfig: {
algolia: {
apiKey: 'YOUR_API_KEY',
indexName: 'my-docs',
appId: 'YOUR_APP_ID',
},
}
📊 Infraestructura Necesaria
Mínimo Viable (Para Empezar)
| Componente | Requerimiento |
|---|---|
| Servidor | 1 vCPU, 512 MB RAM (sitio estático) |
| Storage | ~50-100 MB (build output) |
| Node.js | v18+ (solo para build, no en runtime) |
| Web Server | Nginx, Apache, o cualquiera |
| SSL | Let's Encrypt (gratis) |
Setup Empresarial (Recomendado)
| Componente | Requerimiento |
|---|---|
| CI/CD | GitHub Actions, GitLab CI |
| Build Server | 2 vCPU, 4 GB RAM (para builds) |
| CDN | CloudFront, Cloudflare (opcional) |
| Authentication | OAuth, SSO (si es interno) |
| Search | Algolia DocSearch (gratis) o local |
🔄 CI/CD Pipeline
GitHub Actions (Auto-Deploy)
# .github/workflows/deploy.yml
name: Deploy Docs
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build
- name: Deploy to Server
run: |
rsync -avz --delete build/ ${{ secrets.SERVER_USER }}@${{ secrets.SERVER_HOST }}:/var/www/docs/
env:
SSH_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
- Deploy en red interna (VPN required)
- Autenticación con SSO/OAuth (ver implementación abajo ⬇️)
- NO hacer el repo público en GitHub si contiene info sensible
- Usar secrets de GitHub para credenciales
🔐 Autenticación Empresarial (Critical)
Opción 1: Nginx + OpenID Connect (OIDC)
Integración con proveedores corporativos (Okta, Azure AD, Keycloak):
# 1. Instalar módulo de autenticación
# Para Nginx Plus (comercial):
sudo apt-get install nginx-plus-module-njs nginx-plus-module-auth-spnego
# Para Nginx Open Source, usar oauth2-proxy
docker run -d \
--name oauth2-proxy \
-p 4180:4180 \
quay.io/oauth2-proxy/oauth2-proxy:latest \
--provider=oidc \
--client-id="YOUR_CLIENT_ID" \
--client-secret="YOUR_CLIENT_SECRET" \
--oidc-issuer-url="https://your-idp.company.com" \
--cookie-secret="RANDOM_SECRET_32_CHARS" \
--email-domain="company.com" \
--upstream="http://localhost:8080" \
--http-address="0.0.0.0:4180"
# 2. Configurar Nginx como reverse proxy
server {
listen 443 ssl;
server_name docs.company.internal;
ssl_certificate /etc/nginx/ssl/cert.pem;
ssl_certificate_key /etc/nginx/ssl/key.pem;
# Proxy a oauth2-proxy
location /oauth2/ {
proxy_pass http://127.0.0.1:4180;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
}
# Verificar autenticación antes de servir Docusaurus
location / {
auth_request /oauth2/auth;
error_page 401 = /oauth2/sign_in;
# Headers de usuario autenticado
auth_request_set $user $upstream_http_x_auth_request_user;
auth_request_set $email $upstream_http_x_auth_request_email;
proxy_set_header X-User $user;
proxy_set_header X-Email $email;
# Proxy a Docusaurus
root /var/www/docs;
try_files $uri $uri/ $uri.html /index.html;
}
}
Opción 2: Apache + LDAP
Para empresas con Active Directory o OpenLDAP:
# httpd.conf o site config
ServerName docs.company.internal
DocumentRoot /var/www/docs
SSLEngine on
SSLCertificateFile /etc/httpd/ssl/cert.pem
SSLCertificateKeyFile /etc/httpd/ssl/key.pem
AuthType Basic
AuthName "Company Documentation"
AuthBasicProvider ldap
# LDAP Configuration
AuthLDAPURL "ldap://ldap.company.com:389/ou=users,dc=company,dc=com?uid?sub?(objectClass=*)"
AuthLDAPBindDN "cn=readonly,dc=company,dc=com"
AuthLDAPBindPassword "BIND_PASSWORD"
# Requerir autenticación
Require valid-user
# O restringir a grupo específico
Require ldap-group cn=engineering,ou=groups,dc=company,dc=com
# Rewrite para SPA
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]
Opción 3: Cloudflare Access (Más Simple)
Si tu docs está públicamente accesible pero quieres restringir acceso:
# 1. En Cloudflare Dashboard:
# - Ir a Zero Trust → Access → Applications
# - Add application → Self-hosted
# - Domain: docs.company.com
# - Policy: Allow emails ending in @company.com
# 2. En tu servidor Docusaurus, NO necesitas cambios
# Cloudflare intercepta ANTES de llegar al origin
# 3. (Opcional) Verificar headers de Cloudflare Access en Nginx
server {
location / {
# Cloudflare Access agrega header Cf-Access-Authenticated-User-Email
if ($http_cf_access_authenticated_user_email = "") {
return 403;
}
root /var/www/docs;
try_files $uri $uri/ $uri.html /index.html;
}
}
Comparación de Métodos de Autenticación
| Método | Complejidad | Costo | Mejor Para |
|---|---|---|---|
| Nginx + OIDC | 🟡 Media | 💰 Gratis (oauth2-proxy) | Empresas con Okta/Azure AD |
| Apache + LDAP | 🟡 Media | 💰 Gratis | Empresas con Active Directory |
| Cloudflare Access | 🟢 Baja | 💰💰 $3-7/usuario/mes | Startups, equipos pequeños |
| VPN Only | 🟢 Muy baja | 💰 Gratis | Docs muy sensibles, red interna |
| Basic Auth | 🟢 Muy baja | 💰 Gratis | ❌ NO recomendado (passwords compartidos) |
💡 Best Practices
1. Docs-as-Code
- ✅ Documentación vive en Git (versionado, historial)
- ✅ Pull requests para cambios (code review de docs)
- ✅ CI/CD para deploy automático
- ✅ Linting de Markdown (vale-cli, markdownlint)
2. Organización del Contenido
- ✅ User journey primero (Getting Started → Advanced)
- ✅ Una página = Un concepto
- ✅ Evitar páginas gigantes (split en subsecciones)
- ✅ Links internos frecuentes
3. Mantenimiento Sostenible
- ✅ Asignar "doc owner" por sección
- ✅ Review trimestral (marcar páginas obsoletas)
- ✅ Incentivar contribuciones (parte del onboarding)
- ✅ Metrics: qué páginas se leen más (Analytics)
4. Seguridad y Compliance
- ✅ NO documentar passwords, API keys, secrets
- ✅ Generalizar IPs, nombres de servidores productivos
- ✅ Review de Legal/Security antes de hacer público
- ✅ Separar docs públicas vs internas
📈 Comparación: Antes vs Después
| Aspecto | Antes (Confluence) | Después (Docusaurus) |
|---|---|---|
| Búsqueda | 🟡 Lenta, resultados malos | 🟢 Instant, relevante |
| Actualización | 🔴 Manual, nadie lo hace | 🟢 PR automatizados, CI/CD |
| Versionado | 🔴 No hay, confusión | 🟢 Múltiples versiones, dropdown |
| Performance | 🟡 Lenta (server-side) | 🟢 Instant (estático + CDN) |
| Costo | 🔴 $10-50/user/mes | 🟢 $0 (self-hosted) o $10/mes (Vercel) |
| Code snippets | 🟡 Formateado malo | 🟢 Syntax highlighting perfecto |
| Mantenibilidad | 🔴 Difícil, nadie contribuye | 🟢 Fácil (Markdown), PRs naturales |
🎯 Ideas para Diferentes Contextos
1. Documentación de APIs (Equipo Backend)
docs/
├── api-reference/
│ ├── authentication.md
│ ├── users-endpoint.md
│ └── orders-endpoint.md
├── guides/
│ ├── getting-started.md
│ └── best-practices.md
└── changelog.md
2. Runbooks de SRE (Equipo Ops)
docs/
├── incidents/
│ ├── database-down.md
│ ├── high-latency.md
│ └── disk-full.md
├── maintenance/
│ ├── db-migration.md
│ └── scaling-nodes.md
└── monitoring/
├── alerts-guide.md
└── dashboards.md
3. Knowledge Base Personal (Home Lab)
docs/
├── server-setup/
│ ├── debian-installation.md
│ └── docker-compose.md
├── services/
│ ├── n8n-workflows.md
│ └── monitoring.md
├── troubleshooting/
│ └── common-issues.md
└── learning/
├── aws-notes.md
└── kubernetes-study.md
4. Portfolio + Tutoriales (Blog Técnico)
Exactamente como mi blog actual, pero con Docusaurus:
- Mejor search
- Versionado de posts
- Categorías automáticas
- Tags con páginas dedicadas
💰 Costos de Implementación
Home Lab (Self-Hosted)
Setup inicial: 4-6 horas
Costo hardware: $0 (servidor ya existe)
Costo hosting: $0 (self-hosted)
Costo dominio: $10-15/año (opcional)
Costo SSL: $0 (Let's Encrypt)
Mantenimiento: 1 hora/mes
Total año 1: ~$15 (solo dominio)
Empresarial (Hosted)
Setup inicial: 1-2 semanas (configuración, migración)
Developer time: 40-80 horas ($4,000-8,000 en salarios)
Hosting: $20-50/mes (Vercel Pro, Netlify)
Algolia Search: $0 (DocSearch gratuito para open source)
CI/CD: $0 (GitHub Actions gratis para public repos)
Total año 1: ~$500-1,000 (hosting)
vs Confluence: ~$5,000-10,000/año (10-20 usuarios)
🐛 Troubleshooting Avanzado
Problema: Hot Reload Muy Lento
Causa: Proyecto muy grande, Docusaurus recompila todo.
Solución: Fast refresh mode
# docusaurus.config.js
module.exports = {
future: {
experimental_faster: true,
},
};
Problema: Build Toma 10+ Minutos
Causa: Muchas imágenes grandes sin optimizar.
Solución: Optimizar imágenes antes del build
# Instalar plugin
npm install @docusaurus/plugin-ideal-image
# Usar en docs:
import Image from '@theme/IdealImage';
Problema: Links Rotos Después de Refactor
Solución: Usar plugin de validación
# Instalar
npm install @docusaurus/plugin-client-redirects
# Configurar redirects
plugins: [
[
'@docusaurus/plugin-client-redirects',
{
redirects: [
{
from: '/old-path',
to: '/new-path',
},
],
},
],
],
📚 Recursos Útiles
💡 Lecciones Aprendidas
- Empieza simple: No necesitas todas las features desde día 1. README básico → Docusaurus básico → Features avanzadas gradualmente.
- La migración es costosa: Copiar contenido de Confluence/Notion a Markdown toma tiempo. Considera hacerlo gradualmente.
- Documentación es iterativa: Mejor tener algo básico y funcional que esperar a que sea "perfecto".
- Ownership es crítico: Asigna responsables por sección o se vuelve obsoleta.
- Search es fundamental: Sin búsqueda buena, nadie usa la documentación.
- Docs-as-code funciona: Devs contribuyen más cuando es Markdown en Git que una wiki web.
- Performance importa: Build optimizado (< 2 min) o los devs no contribuyen.
🚀 Migración desde Otras Plataformas
Desde Confluence
# Usar herramienta de conversión
npm install -g confluence-to-markdown
confluence-to-markdown \
--space "MYSPACE" \
--user "[email protected]" \
--token "YOUR_TOKEN" \
--output ./docs
# Review manual necesario (tablas, macros custom)
Desde Notion
# Export desde Notion (Markdown & CSV)
# Settings → Export All → Markdown
# Convertir a formato Docusaurus
# Revisar frontmatter y links manualmente
Desde README.md Dispersos
# Script para consolidar READMEs de múltiples repos
#!/bin/bash
for repo in repo1 repo2 repo3; do
git clone https://github.com/myorg/$repo /tmp/$repo
cp /tmp/$repo/README.md docs/services/$repo.md
done
✅ Resultado Final
Una plataforma de documentación que:
- ✅ Es moderna y rápida (React, Static Site Generation)
- ✅ Es mantenible (Markdown, Git workflow familiar)
- ✅ Escala bien (de 10 páginas a 1000+)
- ✅ Es económica ($0-50/mes vs $5000/año Confluence)
- ✅ Tiene búsqueda excelente
- ✅ Es accesible (dark mode, responsive)
- ✅ Fomenta contribuciones (PRs como en código)
El secreto: Hacer que documentar sea TAN fácil como hacer un commit de código.
🎓 Casos de Uso Más Allá de Documentación
- Blog técnico: Como este que estás leyendo (aunque yo uso HTML puro)
- Changelog público: Release notes de tu software
- Knowledge base: FAQ, troubleshooting guides
- Tutorial site: Curso online, bootcamp interno
- API docs: Con componentes interactivos (Swagger UI integrado)
- Design system: Documentar componentes UI, guías de estilo
💭 Conclusión
Docusaurus es una solución moderna y pragmática para documentación técnica. No es perfecto (requiere conocimientos de Node.js/React), pero para equipos de ingeniería es una opción excelente que combina lo mejor de docs-as-code con una UI profesional.
Si tu equipo usa Git diariamente, implementar Docusaurus es natural. Si tu home lab tiene más de 5 servicios, Docusaurus te ayudará a no olvidar cómo configuraste todo.
Mi recomendación: Empieza pequeño. Un npx create-docusaurus, una carpeta con
5 archivos Markdown, y despliega a GitHub Pages. Después crece orgánicamente según necesites.