Cambiar tema

Servicio de URLs cortas propio con Workers + KV: de cero a producción

Easton editorial illustration: lifecycle journey rail

¿Por qué monté mi propio servicio de URLs cortas?

Durante casi dos años usé un servicio de acortamiento de terceros. Una mañana, todos los enlaces dejaron de funcionar: el proveedor anunció el cierre de repente y cientos de enlaces compartidos en redes sociales devolvían 404.

En ese momento pensé: ¿y si tuviera un servicio totalmente mío? Datos bajo mi control, personalización a medida y sin depender de que un tercero desaparezca.

Cloudflare Workers + KV encaja perfectamente:

  • Cuota gratuita muy generosa (100.000 solicitudes al día)
  • Más de 200 nodos globales, acceso rapidísimo
  • Despliegue sencillo, pocas líneas de código
  • Datos bajo tu control, los guardas el tiempo que quieras

En este artículo comparto cómo monté mi servicio con Workers + KV: códigos personalizados, estadísticas de visitas y más. Incluyo todo el código; siguiendo los pasos, en media hora puedes tenerlo online.

¿Por qué Workers + KV?

¿Qué es Cloudflare Workers?

En pocas palabras, Workers son funciones serverless que corren en la red edge de Cloudflare. Escribes el código, se despliega en más de 200 nodos y el tráfico se enruta al más cercano, con latencia muy baja.

Lo importante: la cuota gratuita es muy generosa:

  • 100.000 solicitudes al día
  • 10 ms de CPU por solicitud
  • Para uso personal o equipos pequeños, suele bastar

Ventajas del almacenamiento KV

KV (Key-Value) es la base de datos distribuida de Cloudflare, optimizada para edge computing:

  • Lecturas muy rápidas: mediana de 12 ms, con datos en caché en nodos edge
  • Sincronización global: tras escribir, en 60 segundos llega a todos los nodos
  • Cuota gratuita: 100.000 lecturas y 1.000 escrituras al día

Para URLs cortas, KV encaja de maravilla:

  • Código corto como clave, URL original como valor
  • Escenario lectura intensiva (pocas creaciones, muchas visitas)
  • Distribución global, acceso rápido desde cualquier lugar
100.000/día
Cuota gratuita
100.000 solicitudes al día
12 ms
Velocidad de lectura KV
Mediana, datos en caché en nodos edge
200+
Nodos globales
Acceso muy rápido

Comparación con servicios de terceros

CaracterísticaServicio de tercerosPropio con Workers + KV
Control de datosDatos en manos del proveedorControl total
PersonalizaciónFunciones fijasLo que necesites
EstabilidadRiesgo de cierreRespaldo de Cloudflare
PublicidadPosible página intermediaSin anuncios
CostoPosible pagoPrácticamente gratis
VelocidadDepende del proveedorRed edge global

Montar el servicio desde cero

Basta de teoría, vamos a la práctica.

Preparación

1. Registrar cuenta en Cloudflare

Ve a cloudflare.com y crea una cuenta; el plan gratuito basta.

2. Instalar Wrangler CLI

Wrangler es la herramienta oficial de línea de comandos de Cloudflare para gestionar proyectos Workers.

npm install -g wrangler
# o con yarn
yarn global add wrangler

Tras instalar, inicia sesión en tu cuenta:

wrangler login

Se abrirá el navegador para autorizar; acepta y listo.

3. Crear el proyecto

mkdir my-shortlink
cd my-shortlink
wrangler init

Sigue las indicaciones y elige un proyecto JavaScript (también puedes usar TypeScript).

Paso 1: crear el espacio de nombres KV

KV requiere un «namespace» (espacio de nombres), algo así como una tabla en una base de datos.

Ejecuta:

# Crear espacio KV de producción
wrangler kv namespace create SHORTLINKS
# Crear espacio KV de preview (pruebas locales)
wrangler kv namespace create SHORTLINKS --preview

El comando devuelve dos ID, algo como:

{ binding = "SHORTLINKS", id = "abc123..." }
{ binding = "SHORTLINKS", preview_id = "def456..." }

Importante: anota ambos ID, los necesitarás.

Luego edita wrangler.toml y añade la vinculación KV:

name = "my-shortlink"
main = "src/index.js"
compatibility_date = "2025-12-01"
# Vinculación del espacio de nombres KV
kv_namespaces = [
  { binding = "SHORTLINKS", id = "tu ID de producción", preview_id = "tu ID de preview" }
]

binding = "SHORTLINKS" significa que en el código accedes al almacenamiento con env.SHORTLINKS.

Paso 2: implementar la funcionalidad básica

Escribe el código principal. Abre src/index.js y pega lo siguiente:

export default {
  async fetch(request, env) {
    const url = new URL(request.url);
    const path = url.pathname.slice(1); // quitar la / inicial
    // Ruta raíz
    if (path === '') {
      return new Response('¡Bienvenido al servicio de URLs cortas!', { status: 200 });
    }
    // GET: redirección de URL corta
    if (request.method === 'GET') {
      // Consultar en KV la URL original del código corto
      const targetUrl = await env.SHORTLINKS.get(path);
      if (targetUrl) {
        // Encontrada: redirección 301
        return Response.redirect(targetUrl, 301);
      } else {
        // No encontrada: 404
        return new Response('La URL corta no existe', { status: 404 });
      }
    }
    // POST: crear URL corta
    if (request.method === 'POST') {
      try {
        const body = await request.json();
        const { url: targetUrl, code } = body;
        // Validación básica
        if (!targetUrl) {
          return new Response('Falta el parámetro url', { status: 400 });
        }
        // Generar código corto
        const shortCode = code || generateRandomCode();
        // Comprobar si ya existe
        const existing = await env.SHORTLINKS.get(shortCode);
        if (existing) {
          return new Response('El código corto ya existe', { status: 409 });
        }
        // Guardar en KV
        await env.SHORTLINKS.put(shortCode, targetUrl);
        // Devolver resultado
        return new Response(JSON.stringify({
          shortCode,
          shortUrl: `${url.origin}/${shortCode}`,
          targetUrl
        }), {
          status: 201,
          headers: { 'Content-Type': 'application/json' }
        });
      } catch (error) {
        return new Response('Formato de solicitud incorrecto', { status: 400 });
      }
    }
    // Otros métodos no soportados
    return new Response('Método no permitido', { status: 405 });
  }
};
// Generar código aleatorio (6 caracteres alfanuméricos)
function generateRandomCode(length = 6) {
  const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
  let code = '';
  for (let i = 0; i < length; i++) {
    code += chars.charAt(Math.floor(Math.random() * chars.length));
  }
  return code;
}

Explicación del código:

  1. Petición GET: al visitar tudominio.com/abc123, consulta en KV la URL de abc123 y redirige con 301
  2. Petición POST: recibe url y opcionalmente code; si no hay code, genera uno aleatorio y lo guarda en KV
  3. generateRandomCode: genera una combinación aleatoria de 6 caracteres

Paso 3: pruebas locales

Tras escribir el código, prueba en local:

wrangler dev

Arranca un servidor local, normalmente en http://localhost:8787.

Probar creación de enlace:

curl -X POST http://localhost:8787 \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com"}'

Respuesta:

{
  "shortCode": "aBc123",
  "shortUrl": "http://localhost:8787/aBc123",
  "targetUrl": "https://example.com"
}

Probar acceso al enlace corto:

Abre http://localhost:8787/aBc123 en el navegador; debería redirigir a https://example.com.

Si todo va bien, la funcionalidad básica está lista.

Paso 4: soporte de códigos personalizados

El código anterior ya admite códigos personalizados: basta enviar el parámetro code en el POST:

curl -X POST http://localhost:8787 \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com", "code": "my-link"}'

Para mayor robustez, añade validación:

// En el manejo de POST, antes de generar el código corto
// Si el usuario envía un código personalizado, validar formato
if (code) {
  // Solo letras, números y guiones
  if (!/^[a-zA-Z0-9-]+$/.test(code)) {
    return new Response('Formato de código corto incorrecto (solo letras, números y guiones)', { status: 400 });
  }
  // Límite de longitud
  if (code.length < 3 || code.length > 20) {
    return new Response('La longitud del código corto debe estar entre 3 y 20', { status: 400 });
  }
}

Así evitas códigos raros con caracteres especiales o demasiado largos.

Paso 5: estadísticas de visitas

A menudo no solo quieres acortar enlaces, sino saber cuántas veces se visita cada uno.

Enfoque:

  • En cada visita, además de redirigir, incrementa el contador
  • Las estadísticas también van en KV, con clave stats:{shortCode}

Modifica la parte GET:

// GET: redirección de URL corta
if (request.method === 'GET') {
  const targetUrl = await env.SHORTLINKS.get(path);
  if (targetUrl) {
    // Actualizar estadísticas en segundo plano (sin bloquear la redirección)
    const statsKey = `stats:${path}`;
    // Actualización en background, sin afectar la velocidad
    env.SHORTLINKS.get(statsKey).then(count => {
      const newCount = (parseInt(count) || 0) + 1;
      env.SHORTLINKS.put(statsKey, newCount.toString());
    });
    return Response.redirect(targetUrl, 301);
  } else {
    return new Response('La URL corta no existe', { status: 404 });
  }
}

Añadir endpoint de consulta de estadísticas:

// Antes del manejo GET, añade esta comprobación
if (path.startsWith('stats/')) {
  const shortCode = path.slice(6); // quitar el prefijo stats/
  const statsKey = `stats:${shortCode}`;
  const count = await env.SHORTLINKS.get(statsKey);
  return new Response(JSON.stringify({
    shortCode,
    visits: parseInt(count) || 0
  }), {
    headers: { 'Content-Type': 'application/json' }
  });
}

Ahora puedes consultar visitas en http://localhost:8787/stats/abc123.

Nota: KV no soporta operaciones atómicas; bajo alta concurrencia las estadísticas pueden ser imprecisas. Para precisión exacta, usa Durable Objects. Para la mayoría de usos personales, esta solución basta.

Paso 6: despliegue a producción

Tras las pruebas, despliega en la red global de Cloudflare:

wrangler deploy

Tras el despliegue, Wrangler te da una URL como https://my-shortlink.your-subdomain.workers.dev.

Esa es la dirección de tu servicio, con acceso global y buena velocidad.

Vincular dominio personalizado (opcional):

Si tienes un dominio (por ejemplo short.example.com), vincúlalo en Cloudflare Dashboard:

  1. Entra en Workers & Pages
  2. Selecciona tu Worker
  3. Settings > Triggers
  4. Añade Custom Domain

Así podrás usar tu dominio, por ejemplo https://short.example.com/abc123.

Funciones avanzadas

La base ya está; si quieres ir más allá, puedes añadir:

1. Creación por lotes

A veces necesitas crear varios enlaces de una vez:

// En el manejo de POST, añade lógica de lote
if (request.method === 'POST' && url.pathname === '/batch') {
  try {
    const body = await request.json();
    const links = body.links; // formato: [{url, code?}, ...]
    if (!Array.isArray(links)) {
      return new Response('links debe ser un array', { status: 400 });
    }
    const results = [];
    for (const link of links) {
      const { url: targetUrl, code } = link;
      const shortCode = code || generateRandomCode();
      // Comprobar si ya existe
      const existing = await env.SHORTLINKS.get(shortCode);
      if (!existing) {
        await env.SHORTLINKS.put(shortCode, targetUrl);
        results.push({ shortCode, targetUrl, success: true });
      } else {
        results.push({ shortCode, targetUrl, success: false, error: 'El código corto ya existe' });
      }
    }
    return new Response(JSON.stringify({ results }), {
      headers: { 'Content-Type': 'application/json' }
    });
  } catch (error) {
    return new Response('Formato de solicitud incorrecto', { status: 400 });
  }
}

Uso:

curl -X POST http://localhost:8787/batch \
  -H "Content-Type: application/json" \
  -d '{
    "links": [
      {"url": "https://example1.com", "code": "link1"},
      {"url": "https://example2.com"}
    ]
  }'

2. Configurar expiración

KV admite TTL (Time To Live) para que los enlaces caduquen solos:

// Al guardar en KV, añade expirationTtl
await env.SHORTLINKS.put(shortCode, targetUrl, {
  expirationTtl: 86400 // se borra tras 24 horas, en segundos
});

Para que el usuario defina la expiración:

const { url: targetUrl, code, ttl } = body;
const options = {};
if (ttl) {
  options.expirationTtl = parseInt(ttl);
}
await env.SHORTLINKS.put(shortCode, targetUrl, options);

3. Control de acceso

Si no quieres que cualquiera cree enlaces, añade validación con API Token:

// En wrangler.toml añade variable de entorno
# [vars]
# API_TOKEN = "your-secret-token"
// Antes del manejo POST, valida
if (request.method === 'POST') {
  const token = request.headers.get('Authorization');
  if (token !== `Bearer ${env.API_TOKEN}`) {
    return new Response('No autorizado', { status: 401 });
  }
  // ... lógica de creación
}

Incluye el token en la petición:

curl -X POST http://localhost:8787 \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer your-secret-token" \
  -d '{"url": "https://example.com"}'

4. Evitar abuso (rate limiting)

Para impedir la creación masiva de enlaces, limita la frecuencia:

// Usar la IP como identificador de límite
const clientIp = request.headers.get('CF-Connecting-IP');
const rateLimitKey = `ratelimit:${clientIp}`;
// Obtener contador actual
const count = await env.SHORTLINKS.get(rateLimitKey);
if (parseInt(count) >= 10) {
  return new Response('Demasiadas solicitudes, inténtalo más tarde', { status: 429 });
}
// Incrementar contador, expira en 1 hora
const newCount = (parseInt(count) || 0) + 1;
await env.SHORTLINKS.put(rateLimitKey, newCount.toString(), {
  expirationTtl: 3600 // 1 hora
});

Esto limita a 10 enlaces creados por IP y hora.

Optimización de rendimiento y buenas prácticas

Consejos de rendimiento

1. Estrategia de caché

Las lecturas de KV ya son rápidas (mediana 12 ms), pero puedes añadir caché en memoria del Worker:

// Map como caché en memoria sencilla
const cache = new Map();
const targetUrl = cache.get(path) || await env.SHORTLINKS.get(path);
if (targetUrl) {
  cache.set(path, targetUrl);
  return Response.redirect(targetUrl, 301);
}

Ojo: la memoria del Worker no es persistente; se pierde al reiniciar.

2. Reducir escrituras en KV

La cuota gratuita son 1.000 escrituras al día; si las estadísticas escriben demasiado, puedes superarla.

Opciones:

  • Usar Durable Objects para estadísticas (operaciones atómicas)
  • Escribir en KV solo cada N visitas
  • Usar Cloudflare Analytics Engine

3. Configuración CORS

Si el frontend llamará al servicio, añade cabeceras CORS:

const corsHeaders = {
  'Access-Control-Allow-Origin': '*',
  'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
  'Access-Control-Allow-Headers': 'Content-Type',
};
// Manejo de OPTIONS
if (request.method === 'OPTIONS') {
  return new Response(null, { headers: corsHeaders });
}
// Añadir CORS en la respuesta
return new Response(body, {
  headers: { ...headers, ...corsHeaders }
});

Control de costos

La cuota gratuita de Cloudflare Workers es generosa, pero conviene tenerla presente:

Cuota gratuita:

  • 100.000 solicitudes al día
  • KV: 100.000 lecturas y 1.000 escrituras al día
  • 10 ms de CPU por solicitud

Costes al superar la cuota (plan Workers Paid, desde $5/mes):

  • $0,50 por millón de solicitudes
  • $0,50 por millón de lecturas KV
  • $5,00 por millón de escrituras KV
  • $0,50 por GB/mes de almacenamiento KV

Para uso personal, rara vez superas la cuota. Equipos pequeños con decenas de miles de visitas diarias también suelen estar cubiertos.

Ahorrar solicitudes:

  • Redirección 301 (caché del navegador) en lugar de 302
  • Recursos estáticos (panel de gestión) en Workers Pages, sin consumir solicitudes del Worker
  • TTL adecuado para limpiar enlaces caducados

Consideraciones de seguridad

1. Evitar enlaces maliciosos

Si el servicio es público, alguien puede acortar sitios maliciosos.

Recomendaciones:

  • Validación con API Token
  • Lista negra de dominios conocidos
  • Registrar IP del creador para trazabilidad

2. Evitar colisiones de códigos

Aunque 6 caracteres alfanuméricos dan 62^6 ≈ 56.800 millones de posibilidades y la colisión es improbable, hay que comprobar:

// Al crear enlace, comprobar si ya existe
const existing = await env.SHORTLINKS.get(shortCode);
if (existing) {
  return new Response('El código corto ya existe', { status: 409 });
}

3. Restringir URL de destino

Puedes usar una lista blanca de dominios permitidos:

const allowedDomains = ['example.com', 'mywebsite.com'];
const targetDomain = new URL(targetUrl).hostname;
if (!allowedDomains.some(d => targetDomain.endsWith(d))) {
  return new Response('Dominio de destino no permitido', { status: 403 });
}

Mi experiencia real de uso

Llevo varios meses usándolo. Esto es lo que he visto:

Ventajas:

  • Muy rápido: latencia global suele estar por debajo de 50 ms, mucho mejor que el servicio de terceros anterior
  • Estable: la red de Cloudflare es muy fiable, casi sin caídas
  • Tranquilo: tras desplegar no hay que gestionar nada, escala sola ante picos de tráfico
  • Gratis: unos miles de solicitudes diarias, dentro de la cuota gratuita

Pequeños inconvenientes:

  • Retraso en escrituras KV: consistencia eventual; puede tardar decenas de segundos en sincronizarse globalmente. En URLs cortas suele importar poco, porque tras crear un enlace no suele visitarse al instante
  • Estadísticas imprecisas: KV no tiene operaciones atómicas; bajo alta concurrencia hay error. Para precisión exacta, Durable Objects; fuera de la cuota gratuita cuesta más

Próximos pasos:

  • Dashboard sencillo con Workers Pages para gestionar enlaces
  • Cloudflare Analytics para datos detallados (origen, región, etc.)
  • Generación de códigos QR para compartir offline

Resumen

Montar un servicio de URLs cortas con Cloudflare Workers + KV es rápido y económico. El código principal tiene menos de 100 líneas, el despliegue es un solo comando y los datos quedan en tus manos, sin depender de terceros.

Si tienes una necesidad similar, te animo a probarlo. Todo el código está aquí; cópialo y en media hora puedes tenerlo online.

Pasos clave:

  1. Registrar cuenta en Cloudflare e instalar Wrangler
  2. Crear espacio KV y configurar wrangler.toml
  3. Escribir código para GET (redirección) y POST (crear enlace)
  4. Probar en local y desplegar a producción

Luego puedes ir añadiendo estadísticas, lotes, expiración y más. El código es tuyo: lo modificas como quieras.

¿Dudas? Déjalas en los comentarios. ¡Que disfrutes montando tu propio servicio de URLs cortas!

Flujo completo para montar un servicio de URLs cortas con Cloudflare Workers + KV

Monta un servicio de acortamiento desde cero con creación de enlaces, redirección y estadísticas de visitas; online en media hora

⏱️ Estimated time: 30 min

  1. 1

    Step 1: Preparación: registrar cuenta de Cloudflare e instalar Wrangler CLI

    Paso 1: registrar cuenta en Cloudflare
    • Ve a cloudflare.com y crea una cuenta; el plan gratuito basta

    Paso 2: instalar Wrangler CLI
    • Wrangler es la herramienta oficial de línea de comandos de Cloudflare para gestionar proyectos Workers
    • Ejecuta: npm install -g wrangler
    • O bien: yarn global add wrangler
    • Tras instalar, inicia sesión: wrangler login
    • Se abrirá el navegador para autorizar; acepta y listo

    Paso 3: crear el proyecto
    • mkdir my-shortlink
    • cd my-shortlink
    • wrangler init
    • Sigue las indicaciones y elige un proyecto JavaScript (también puedes usar TypeScript)
  2. 2

    Step 2: Crear el espacio de nombres KV y configurar wrangler.toml

    Crear el espacio de nombres KV:

    Método 1: en Cloudflare Dashboard
    • Entra en Workers & Pages → KV
    • Haz clic en Create a namespace
    • Pon un nombre (por ejemplo SHORTLINKS) y créalo

    Método 2: línea de comandos
    • wrangler kv:namespace create SHORTLINKS

    Configurar wrangler.toml:
    Abre wrangler.toml y añade al final la vinculación KV:

    [[kv_namespaces]]
    binding = "SHORTLINKS"
    id = "tu ID de espacio de nombres"

    Así podrás acceder a KV desde el código con env.SHORTLINKS
  3. 3

    Step 3: Código principal: crear URLs cortas y redireccionar

    Funcionalidad principal:

    1. Generar código corto:
    • Soporta códigos personalizados y generación aleatoria
    • Puedes usar combinaciones de 6 caracteres alfanuméricos
    • Con 62^6≈56.800 millones de posibilidades, la probabilidad de colisión es muy baja

    2. Guardar en KV:
    • El código corto es la clave, la URL original el valor
    • También puedes guardar metadatos (fecha de creación, visitas, etc.)

    3. Redirección:
    • En peticiones GET, lee la URL original desde KV
    • Devuelve redirección 302 a la URL original

    4. Estadísticas de visitas:
    • Registra número de visitas y hora
    • Puedes guardarlo en metadatos de KV

    Ejemplo de código:
    • GET (redirección): obtén el código corto de la ruta, lee la URL en KV, si existe devuelve 302, si no 404
    • POST (crear enlace): recibe URL original y código opcional, genera código, comprueba colisiones, guarda en KV y devuelve la URL corta
  4. 4

    Step 4: Pruebas locales y despliegue a producción

    Pruebas locales:

    1. Ejecuta wrangler dev para el servidor local
    2. Prueba crear enlaces y la redirección

    Puedes usar curl:
    • Crear enlace:
    curl -X POST http://localhost:8787/create -H "Content-Type: application/json" -d '{"url":"https://example.com"}'

    • Visitar enlace corto:
    curl -L http://localhost:8787/abc123
    (redirige a la URL original)

    Despliegue a producción:
    • Ejecuta: wrangler deploy
    • Wrangler despliega el Worker en Cloudflare
    • Tras el despliegue verás una URL del tipo:
    your-worker-name.your-subdomain.workers.dev
    • ¡Tu servicio de URLs cortas ya está online!
  5. 5

    Step 5: Funciones avanzadas y consideraciones de seguridad

    Funciones avanzadas: 1) Estadísticas (registra visitas y hora en metadatos KV, actualiza el contador en cada acceso); 2) Expiración (TTL para que el enlace deje de funcionar); 3) Creación por lotes; 4) Panel de gestión (un dashboard sencillo con Workers Pages). Seguridad: 1) Evitar enlaces maliciosos (validación con API Token, lista negra de dominios, registrar IP del creador); 2) Evitar colisiones de códigos (comprobar si ya existe al crear); 3) Restringir URL de destino (lista blanca de dominios permitidos). Ahorrar solicitudes: usa redirección 301 (el navegador la cachea) en lugar de 302, sirve recursos estáticos con Workers Pages y configura TTL para limpiar enlaces caducados.

FAQ

¿Por qué montar un servicio de URLs cortas propio? ¿Qué ventajas tiene Workers + KV?
¿Un servicio de terceros cerró de repente y cientos de enlaces dejaron de funcionar? Con un servicio propio controlas los datos y puedes personalizarlo sin depender de que un proveedor desaparezca.

Ventajas de Workers + KV:
• Cuota gratuita muy generosa (100.000 solicitudes/día)
• Más de 200 nodos globales, acceso muy rápido
• Despliegue sencillo, pocas líneas de código
• Datos bajo tu control, los guardas el tiempo que quieras

Comparado con servicios de terceros:
• Control de datos (terceros vs. control total)
• Personalización (funciones fijas vs. lo que necesites)
• Estabilidad (riesgo de cierre vs. respaldo de Cloudflare)
• Publicidad (páginas intermedias vs. sin anuncios)
• Costo (posible pago vs. prácticamente gratis)
• Velocidad (depende del proveedor vs. red edge global)
¿Qué ventajas tiene KV? ¿Por qué encaja con un servicio de URLs cortas?
KV (Key-Value) es la base de datos distribuida de Cloudflare, optimizada para edge computing.

Ventajas de KV:
• Lecturas muy rápidas, mediana de 12 ms (datos en caché en nodos edge)
• Sincronización global: tras escribir, en 60 segundos llega a todos los nodos
• Cuota gratuita: 100.000 lecturas y 1.000 escrituras al día

Para URLs cortas, KV encaja de maravilla:
• Código corto como clave, URL original como valor
• Escenario lectura intensiva (pocas creaciones, muchas visitas)
• Distribución global, acceso rápido desde cualquier lugar

Cuota gratuita:
• Workers: 100.000 solicitudes/día
• KV: 100.000 lecturas y 1.000 escrituras/día
• Para uso personal suele bastar; equipos pequeños con decenas de miles de visitas diarias también

Costes al superar la cuota (plan Workers Paid desde $5/mes):
• $0,50 por millón de solicitudes
• $0,50 por millón de lecturas KV
• $5,00 por millón de escrituras KV
• $0,50 por GB/mes de almacenamiento KV
¿Cómo montar un servicio de URLs cortas desde cero? ¿Cuáles son los pasos?
Preparación:

Paso 1: registrar cuenta en Cloudflare (cloudflare.com, plan gratuito)
Paso 2: instalar Wrangler CLI (npm install -g wrangler, luego wrangler login)
Paso 3: crear proyecto (mkdir my-shortlink, cd my-shortlink, wrangler init)

Crear espacio KV y configurar:
• En Dashboard: Workers & Pages → KV → Create a namespace (ej. SHORTLINKS)
• O en CLI: wrangler kv:namespace create SHORTLINKS

Configurar wrangler.toml:
• Añade la vinculación KV al final del archivo
• Accede desde el código con env.SHORTLINKS

Código principal:

GET (redirección):
• Obtén el código corto de la ruta
• Lee la URL original en KV
• Si existe, redirección 302; si no, 404

POST (crear enlace):
• Recibe URL original y código opcional
• Genera código (aleatorio si no hay personalizado)
• Comprueba si ya existe
• Guarda en KV y devuelve la URL corta

Pruebas y despliegue:
• wrangler dev para probar localmente
• wrangler deploy para producción
¿Cómo se implementan las funciones principales del servicio?
Funcionalidad principal:

1) Generar código corto:
• Códigos personalizados o aleatorios
• 6 caracteres alfanuméricos, 62^6≈56.800 millones de posibilidades, baja probabilidad de colisión

2) Guardar en KV:
• Código corto = clave, URL original = valor
• Metadatos opcionales: fecha de creación, visitas, etc.

3) Redirección:
• En GET, lee URL original desde KV
• Devuelve redirección 302

4) Estadísticas:
• Registra visitas y hora
• En metadatos KV, actualiza contador en cada acceso

Ejemplo de código:

GET (redirección):
• Código corto desde la ruta
• Lee URL en KV
• 302 si existe, 404 si no

POST (crear):
• URL original y código opcional
• Genera código, comprueba colisión
• Guarda en KV y devuelve URL corta

Funciones avanzadas:
• Estadísticas de visitas
• Expiración con TTL
• Creación por lotes
• Panel con Workers Pages
¿Qué consideraciones de seguridad hay al usar un servicio de URLs cortas?
Seguridad:

1) Evitar enlaces maliciosos:
• Si el servicio es público, alguien puede acortar sitios maliciosos
• Recomendaciones:
- Validación con API Token
- Lista negra de dominios conocidos
- Registrar IP del creador para trazabilidad

2) Evitar colisiones de códigos:
• Aunque 62^6≈56.800 millones de posibilidades hacen la colisión improbable, hay que comprobar:
const existing = await env.SHORTLINKS.get(shortCode);
if (existing) {
return new Response('El código corto ya existe', { status: 409 });
}

3) Restringir URL de destino:
• Lista blanca de dominios permitidos:
const allowedDomains = ['example.com', 'mywebsite.com'];
const targetDomain = new URL(targetUrl).hostname;
if (!allowedDomains.some(d => targetDomain.endsWith(d))) {
return new Response('Dominio de destino no permitido', { status: 403 });
}

Ahorrar solicitudes:
• Redirección 301 (caché del navegador) en lugar de 302
• Recursos estáticos en Workers Pages sin consumir solicitudes del Worker
• TTL adecuado para limpiar enlaces caducados
¿Cómo es la experiencia real de uso? ¿Ventajas y desventajas?
Experiencia real:

Ventajas:
• Muy rápido (latencia global suele estar por debajo de 50 ms, mucho mejor que servicios de terceros)
• Estable (la red de Cloudflare es muy fiable, casi sin caídas)
• Tranquilo (tras desplegar no hay que gestionar nada, escala sola)
• Gratis (con unos miles de solicitudes diarias, dentro de la cuota gratuita)

Pequeños inconvenientes:
• Retraso en escrituras KV (consistencia eventual; puede tardar decenas de segundos en sincronizarse globalmente; en URLs cortas suele importar poco)
• Estadísticas imprecisas (KV no tiene operaciones atómicas; bajo alta concurrencia hay error; para precisión usa Durable Objects, más caro fuera de la cuota)

Próximos pasos:
• Dashboard sencillo con Workers Pages
• Cloudflare Analytics para datos detallados (origen, región, etc.)
• Generación de códigos QR para compartir offline

12 min de lectura · Publicado el: 1 dic 2025 · Actualizado el: 21 ago 2026

Comentarios

Inicia sesión con GitHub para dejar un comentario

Easton BlogEaston Blog