Million Dollar Homepage: 21 Anos Despues, lo Que una Pagina de 2005 Ensena Sobre Link Rot
Hola HaWkers, el 26 de agosto de 2026 la Million Dollar Homepage cumplio 21 anos en linea. Un estudiante de 21 anos llamado Alex Tew, de Cricklade, en Inglaterra, publico el 26 de agosto de 2005 una pagina con una cuadricula de 1000 por 1000 pixeles y vendio cada pixel por 1 dolar, en bloques minimos de 10 por 10 por 100 dolares. En enero de 2006 subasto los ultimos 1.000 pixeles en eBay: la subasta abrio el 1 de enero, cerro el 11 de enero con una puja de 38.100 dolares y llevo el total bruto a 1.037.100 dolares.
La parte que interesa a quien escribe codigo no es el dinero. Mientras escribo este articulo, milliondollarhomepage.com respondio HTTP 200. La pagina sigue ahi, en la misma URL, 21 anos despues. Y los enlaces que vendio, esos murieron. Cuantas de tus URLs de 2019 siguen respondiendo hoy? Y cuantos de los enlaces que citaste en tus ultimos diez articulos todavia llevan a algun lugar?
La pagina que vendio un millon de pixeles
El modelo era ridiculamente simple y por eso funciono. Tew necesitaba dinero para la universidad, monto una pagina con un <img> gigante de 1000 por 1000, un mapa de imagen encima y vendio espacio publicitario por pixel. Cada anunciante mandaba el arte del bloque y la URL de destino. En cinco meses, de agosto de 2005 a enero de 2006, todo cerro en 1.037.100 dolares brutos.
Tecnicamente, lo que existe ahi es el minimo posible:
- HTML estatico servido directo.
- Una imagen grande con un
<map>y cientos de elementos<area>. - Ninguna base de datos por delante, ningun framework, ningun paso de build.
Esa eleccion no fue visionaria, fue solo lo que se podia hacer en 2005. Pero es exactamente por eso que la pagina atraveso tres decadas de cambio de stack sin necesitar mantenimiento. No hay dependencia que actualizar, no hay runtime que migrar, no hay version de Node que subir. Si te gusta este tipo de arqueologia, ya escribi sobre como recrear esa estetica en el articulo de estilo retro en web design con CSS y JavaScript.
La paradoja: la pagina vive, sus enlaces murieron
Aqui esta el giro. El contenedor sobrevivio, el contenido al que apuntaba no.
En 2014, cuando la pagina tenia nueve anos, un analisis citado por el Guardian y por Gizmodo encontro 22% de los enlaces muertos, el equivalente a 221.900 pixeles. De esos, 23.200 pixeles ya nacieron rotos, porque el anunciante nunca entrego la URL de destino. O sea: cerca del 20% de los enlaces murieron a lo largo de ocho anos. En 2017, la estimacion registrada en Wikipedia ya era de aproximadamente 40% de los enlaces afectados por link rot.
Fijate en lo que paso. Alex Tew hizo su parte: mantuvo la URL viva durante dos decadas. Quienes rompieron el trato fueron los cientos de empresas que compraron pixel, cambiaron de dominio, fueron compradas, cambiaron el sitio entero o simplemente desaparecieron. La durabilidad de tu pagina no depende solo de ti. Depende de todos los que citas.
El link rot no es anecdota, es estadistica
El Pew Research Center publico el 17 de mayo de 2024 el informe "When Online Content Disappears", y los numeros son brutales:
- 38% de las paginas que existian en 2013 ya no estaban accesibles en octubre de 2023.
- 25% de todas las paginas que existieron en algun momento entre 2013 y 2023 ya habian desaparecido.
- 8% de las paginas que existian en 2023 ya habian desaparecido en el mismo ano. La descomposicion empieza rapido.
- 23% de las paginas de noticias tienen al menos un enlace roto.
- 21% de las paginas de sitios gubernamentales tambien.
- 54% de las paginas de Wikipedia tienen al menos un enlace muerto en la seccion de referencias.
Y en las redes la fecha de caducidad es aun menor: siguiendo una muestra de tuits durante tres meses, casi 1 de cada 5 dejo de ser publicamente visible. En el 60% de los casos la cuenta se volvio privada, fue suspendida o borrada; en el otro 40% el autor borro solo ese post. Para tuits en turco o arabe, mas del 40% desaparecieron en tres meses.
Traduciendo a tu blog: si publicas desde hace cinco anos, una parte relevante de tus fuentes ya es ficcion. El texto sigue afirmando algo con un enlace que ya no prueba nada.
Cool URIs don't change: la regla de 1998 que sigue vigente
En 1998, Tim Berners-Lee escribio un documento corto llamado "Cool URIs don't change", alojado en w3.org/Provider/Style/URI. La tesis cabe en una linea: despues de que creas una URI, es tu obligacion mantenerla funcionando para siempre; si el documento cambia de lugar, la URL antigua se convierte en redireccion.
Mientras escribia este articulo, probe esa direccion. Respondio HTTP 200. Veintiocho anos en la misma URL, practicando lo que predica.
La parte que la mayoria de los equipos ignora es que una URL no es un detalle de implementacion, es un contrato publico. Los errores clasicos:
- Poner la tecnologia en la URL:
/articulo.php,/posts.aspx. La tecnologia cambia, la URL queda atrapada. - Poner fecha o estado en la URL:
/2024/nuevo/producto. El ano que viene nada de eso es verdad. - Reestructurar el sitio y dejar que el 404 lo resuelva. No lo resuelve: pierdes el enlace externo, el posicionamiento y la cita.
Regla practica: URL corta, sin extension, sin estado, y todo camino antiguo se convierte en 301 permanente.
Auditando los enlaces de tu propio sitio
Basta de teoria. El primer paso es saber cuantos enlaces de tu contenido ya estan muertos. Se puede hacer con Node puro, sin instalar nada:
// scripts/check-links.mjs
// Recorre los markdown del contenido y prueba cada enlace externo.
import { readdir, readFile } from 'node:fs/promises'
import { join } from 'node:path'
const CONTENT_DIR = 'content/blog'
const CONCURRENCY = 8
const TIMEOUT_MS = 10000
async function collectLinks(dir) {
const files = await readdir(dir, { withFileTypes: true })
const found = new Map() // url -> archivos donde aparece
for (const file of files) {
if (!file.isFile() || !file.name.endsWith('.md')) continue
const raw = await readFile(join(dir, file.name), 'utf8')
// Captura solo enlaces markdown hacia http/https
const matches = raw.matchAll(/\]\((https?:\/\/[^)\s]+)\)/g)
for (const [, url] of matches) {
if (!found.has(url)) found.set(url, [])
found.get(url).push(file.name)
}
}
return found
}
async function probe(url) {
const controller = new AbortController()
const timer = setTimeout(() => controller.abort(), TIMEOUT_MS)
try {
// HEAD es mas barato, pero muchos servidores responden 405
let res = await fetch(url, { method: 'HEAD', redirect: 'follow', signal: controller.signal })
if (res.status === 405 || res.status === 501) {
res = await fetch(url, { method: 'GET', redirect: 'follow', signal: controller.signal })
}
return { url, status: res.status, ok: res.ok }
} catch (error) {
return { url, status: 0, ok: false, error: error.name }
} finally {
clearTimeout(timer)
}
}
const links = await collectLinks(CONTENT_DIR)
const queue = [...links.keys()]
const broken = []
// Pool manual de concurrencia: no tumba el servidor ajeno ni el tuyo
await Promise.all(
Array.from({ length: CONCURRENCY }, async () => {
while (queue.length) {
const url = queue.shift()
const result = await probe(url)
if (!result.ok) broken.push({ ...result, files: links.get(url) })
}
})
)
console.log(`Enlaces unicos verificados: ${links.size}`)
console.log(`Rotos: ${broken.length}`)
for (const item of broken) {
console.log(`${item.status || item.error}\t${item.url}\t${item.files.slice(0, 3).join(', ')}`)
}
process.exit(broken.length > 0 ? 1 : 0)Ejecuta esto una vez sobre tu contenido antiguo. El resultado suele doler.
Poniendo el check en el CI cada semana
La auditoria manual es esa que haces una vez y nunca mas. Programala:
# .github/workflows/link-check.yml
name: link-check
on:
schedule:
# Todos los lunes a las 06:00 UTC
- cron: '0 6 * * 1'
workflow_dispatch:
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
# Falla el job cuando aparece un enlace muerto, y la alerta llega por e-mail
- run: node scripts/check-links.mjs
Redirigir en vez de borrar
Cuando cambias un slug, el enlace externo que apuntaba al antiguo no cambia contigo. La unica salida honesta es la redireccion permanente. En un proyecto Nuxt, eso vive en las routeRules:
// nuxt.config.ts
export default defineNuxtConfig({
routeRules: {
// 301: permanente. Google transfiere la autoridad del enlace antiguo.
'/blog/post-antiguo': { redirect: { to: '/blog/post-nuevo', statusCode: 301 } },
// Seccion entera que cambio de lugar
'/articulos/**': { redirect: { to: '/blog/**', statusCode: 301 } },
},
})Tres detalles que marcan la diferencia:
- 301, no 302. El 302 es temporal y le dice al buscador que siga indexando la URL antigua. Si el cambio es definitivo, usa 301.
- No encadenes redirecciones.
A -> B -> Cfunciona en el navegador y desperdicia presupuesto de rastreo. ApuntaA -> Cdirecto. - Nunca redirijas todo a la home. Para el buscador, redirigir contenido que desaparecio hacia la home se trata como un 404 disfrazado. Si no existe un destino equivalente, devuelve un 410 honesto.
Guardando lo que citas antes de que desaparezca
Tu controlas tus URLs. No controlas las URLs que citas. La defensa es archivar la fuente en el momento en que escribes, y no el dia en que se rompe.
// scripts/archive-sources.mjs
// Manda cada fuente al Wayback Machine y guarda el snapshot.
const SAVE_ENDPOINT = 'https://web.archive.org/save/'
const AVAILABILITY = 'https://archive.org/wayback/available?url='
export async function ensureArchived(url) {
// 1. Ya existe snapshot?
const check = await fetch(`${AVAILABILITY}${encodeURIComponent(url)}`)
const data = await check.json()
const snapshot = data?.archived_snapshots?.closest
if (snapshot?.available) {
return { url, archived: snapshot.url, created: false }
}
// 2. No existe: pide el archivado ahora
const saved = await fetch(`${SAVE_ENDPOINT}${url}`, { method: 'GET', redirect: 'follow' })
if (!saved.ok) {
throw new Error(`Fallo al archivar ${url}: HTTP ${saved.status}`)
}
return { url, archived: saved.url, created: true }
}Con eso, cuando la fuente muera, tu articulo sigue probando lo que afirma. En las citas mas importantes, vale la pena enlazar directo al snapshot y dejar el original como referencia secundaria.
Un checklist para paginas que atraviesan la decada
Lo que la Million Dollar Homepage acerto sin querer, tu puedes hacerlo a proposito:
- Salida estatica siempre que sea posible. El HTML que no depende de runtime no se rompe cuando el runtime se descontinua. Un sitio generado estaticamente sobrevive al cambio de host con un
rsync. - Menos dependencias. Cada paquete en el
package.jsones una oportunidad de que el build de manana no funcione. La pagina de 2005 tiene cero. - Nada de contenido atrapado en una API de terceros. Si el texto de tu articulo solo existe dentro de un CMS SaaS, tu archivo esta en manos del plan de precios de esa empresa.
- URLs sin tecnologia y sin fecha.
/blog/nombre-del-temasobrevive a cualquier migracion. - Assets en tu dominio. Una imagen alojada en un servicio gratuito de terceros es link rot con fecha marcada.
- Sitemap y
lastmodcorrectos. Ayuda al buscador a percibir lo que sigue vivo. - Backup del contenido en texto plano, versionado en Git. El markdown en un repositorio es el formato mas duradero que existe hoy: texto simple, legible sin ninguna herramienta.
Nada de esto es exotico. Es lo contrario: es elegir lo aburrido y lo simple en vez de lo impresionante y fragil.
Lo que esto cambia para quien publica en 2026
Existe una ironia buena aqui. En 2005, publicar una pagina que dura era el estandar accidental, porque el stack era pobre. En 2026, con todas las herramientas que tenemos, publicar algo que dure se convirtio en una decision deliberada, que exige disciplina contra la tentacion de agregar una capa mas.
Y la presion aumento. Con buscadores y asistentes de IA resumiendo contenido en vez de mandar clic, la cita que queda es el enlace. Cuando ese enlace muere, desaparece tambien la evidencia de que tu trabajo existio primero. Mantener una URL viva dejo de ser buena practica de SEO y se convirtio en preservacion de autoria.
La Million Dollar Homepage no es un caso de exito de marketing viral, o no solo eso. Es la prueba de que lo mas dificil en la web no es publicar. Es seguir publicado. Alex Tew hizo lo suyo durante 21 anos: ejecuta el script de auditoria en tu contenido hoy y descubre cuantos anos ya perdiste.
Vamos con todo! 🦅
📚 Quieres Seguir lo Que Viene Por Delante?
Este articulo cubrio link rot, URLs permanentes y como auditar tu propio contenido, pero el ecosistema cambia cada semana y no todo se convierte en articulo aqui.
En X comparto lo que estoy probando, el detras de camaras de los proyectos y las novedades que aparecen antes de volverse post.
Sigueme Alla
💡 Contenido diario sobre desarrollo, carrera y las herramientas que realmente uso

