---
title: "Instalar Sink: acortador de enlaces autoalojado gratuito (guía 2026)"
description: "Despliega Sink, un acortador de enlaces gratuito y de código abierto con analíticas, en Cloudflare Workers. Guía paso a paso con base de datos D1, caché KV y generación de slugs con IA."
date: 2024-09-09
categories: ["self-hosting"]
tags: ["cloudflare","link-shortener","cloudflare-workers"]
---

import YouTubeEmbed from "@components/widgets/YouTubeEmbed.astro";
import Button from "@components/widgets/Button.astro";
import Notice from "@components/widgets/Notice.astro";
import ListCheck from "@components/widgets/ListCheck.astro";
import Accordion from "@components/widgets/Accordion.astro";
import { Picture } from "astro:assets";
import img1 from "@assets/images/24/09/ai-analytics.png";
import img2 from "@assets/images/24/09/sink-ui.png";

[Sink](https://github.com/miantiao-me/Sink) es un acortador de enlaces autoalojado, gratuito y de código abierto que funciona íntegramente en la red edge de Cloudflare. Creado originalmente por ccbikai, el proyecto se ha trasladado a la organización de GitHub `miantiao-me` y ya ronda las 7.000 estrellas. Con la v0.3.0, la capa de almacenamiento pasó de KV a Cloudflare D1 como base de datos principal, un cambio que rompe la compatibilidad y deja obsoleta la guía de instalación anterior. Este artículo cubre el despliegue de Sink en Cloudflare Workers con la arquitectura actual basada en D1, actualizado para 2026.

## ¿Qué es Sink?

Sink es un acortador de enlaces autoalojado que funciona sobre Cloudflare Workers. Usa D1 (la base de datos SQL de Cloudflare) para el almacenamiento permanente de enlaces y KV como caché de lectura de paso directo para redirecciones rápidas. El plan gratuito de Cloudflare es suficiente para uso personal y equipos pequeños. Sin VPS, sin contenedores Docker, sin servidor que mantener.

El proyecto está ahora en la v0.3.0 (última versión estable pre-D1: la v0.2.11 si prefieres la versión anterior). El repositorio está en [github.com/miantiao-me/Sink](https://github.com/miantiao-me/Sink). Tiene licencia AGPL-3.0.

## ¿Por qué elegir un acortador de enlaces autoalojado gratuito?

Los acortadores alojados como Bitly empiezan en 8 $/mes. Dub.co tiene un plan gratuito pero limita funciones detrás de un muro de pago. Short.io te pone un tope en el plan gratuito. Sink no cuesta nada si te mantienes dentro de los límites del plan gratuito de Cloudflare.

El enfoque autoalojado importa: eres dueño de tus datos, no hay dependencia de un proveedor y obtienes analíticas, generación de slugs con IA y funciones como protección por contraseña y enrutamiento geográfico. Todo incluido, sin ventas adicionales.

Si estás montando un servidor doméstico con [contenedores Docker](/es/contenedores-docker-servidor-casa/), Sink es una incorporación ligera a tu stack autoalojado, aunque se ejecuta en Cloudflare, no en tu servidor. Para uso empresarial, [Sink complementa otras herramientas autoalojadas](/es/contenedores-docker-empresas/) de tu stack.

<Notice type="info" title="¿No quieres autoalojar?">
El mismo autor ofrece [S.EE](https://s.ee), una plataforma de enlaces gestionada con más de 180.000 usuarios, pruebas A/B, páginas de link-in-bio y planes comerciales. El README de Sink recomienda explícitamente S.EE para necesidades profesionales o de negocio.
</Notice>

## Novedades de Sink (2024-2026)

Sink ha añadido muchas cosas desde la versión original. Estos son los puntos destacados:

- **D1 sustituye a KV como base de datos principal** (v0.3.0): KV ahora es solo una caché de redirecciones
- **Etiquetas de enlaces, filtrado y ordenación** (v0.3.0)
- **Webhooks de clics con firmas HMAC** (v0.2.11): payloads al estilo de Dub
- **Autenticación con Cloudflare Access** (v0.2.11): alternativa a `NUXT_SITE_TOKEN`
- **Detección de URL duplicadas** (v0.2.11)
- **Panel de comprobación de enlaces** (v0.2.10): detección por lotes de enlaces rotos con exportación a CSV
- **Redirección por país/geolocalización** (v0.2.9): dirige a los visitantes según el país detectado por Cloudflare
- **Generación de OpenGraph con IA** (v0.2.9): genera metadatos OG a partir del contenido de la página
- **Constructor de parámetros UTM** (v0.2.8): integrado, con vista previa en vivo
- **Protección por contraseña y encubrimiento de enlaces** (v0.2.6): contraseña por enlace, enmascaramiento con iframe a pantalla completa
- **Redirección por dispositivo** (v0.2.3): dirige a iOS/Android/Escritorio de forma distinta
- **Personalización de OpenGraph** (v0.2.3): título, descripción e imagen OG por enlace
- **Analíticas en tiempo real** (v0.2.4+): globo 3D WebGL, registro de eventos con sondeo cada 10 segundos
- **Generación de códigos QR**: integrada para todos los enlaces cortos
- **Importación/exportación**: JSON para enlaces, CSV para analíticas
- **Interfaz multiidioma**: más de 10 idiomas

El ecosistema también ha crecido: ahora hay una extensión de Chrome («Sink Quick Shorten»), una extensión de Raycast, una app de iOS y compatibilidad con Atajos de Apple.

## Funciones clave

### Generación de slugs con IA

Sink usa Workers AI con el modelo `@cf/qwen/qwen3-30b-a3b-fp8` por defecto. Al crear un enlace, puedes dejar que la IA sugiera un slug relevante y llamativo basado en la URL de destino. Ahorra tiempo cuando acortas enlaces en masa.

### Protección por contraseña y encubrimiento de enlaces

Establece una contraseña por enlace para restringir el acceso, útil para compartir documentos internos o contenido sensible al paso del tiempo. El encubrimiento de enlaces (link cloaking) renderiza el destino dentro de un iframe a pantalla completa, enmascarando la URL real. Nota: el encubrimiento solo funciona en sitios que permiten ser incrustados en iframes.

### Redirección por dispositivo y geolocalización

Dirige a los visitantes a URL distintas según su dispositivo (iOS/Android/Escritorio) o su país (detectado por Cloudflare). Es muy útil para enlaces a tiendas de apps: envía a los usuarios de iPhone a la App Store, a los de Android a Google Play y a los de escritorio a una landing page.

### Analíticas avanzadas y monitorización del estado de los enlaces

Sink registra los clics con datos geográficos, información del referente y desglose por dispositivo, representados en un globo 3D WebGL. El panel de comprobación de enlaces (v0.2.10) verifica por lotes si las URL de destino responden y exporta los enlaces rotos en CSV. También puedes exportar las analíticas de acceso en CSV.

Sink incluye analíticas integradas, pero si necesitas analíticas para todo el sitio web más allá de los clics en los enlaces, [Plausible es un gran compañero autoalojado](/es/instalar-plausible-analytics/).

### Webhooks, API e integraciones

Los webhooks de clics (v0.2.11) envían payloads al estilo de Dub a una URL configurada, con firmas HMAC opcionales. Cada instancia de Sink expone documentación OpenAPI en `/docs/scalar`, lo que facilita la integración con herramientas de automatización y proxies MCP. La extensión de Chrome, la de Raycast, la app de iOS y las integraciones con Atajos de Apple hacen que Sink sea práctico para el uso diario.

## Tecnologías que impulsan Sink

El stack tecnológico de Sink ha evolucionado desde la versión original:

| Componente | Rol |
|---|---|
| **Nuxt 4** | Framework frontend (actualizado desde Nuxt.js) |
| **Cloudflare D1** | Base de datos principal, almacena todos los enlaces (NUEVO en v0.3.0) |
| **Cloudflare Workers KV** | Caché de lectura de paso directo para redirecciones rápidas |
| **Drizzle ORM** | Capa de acceso a la base de datos para D1 |
| **Cloudflare R2** | Opcional: copias de seguridad automáticas e imágenes sociales |
| **Shadcn-vue + Tailwind CSS** | Componentes de UI y estilos (sin cambios) |

<Notice type="info" title="Cómo trabajan juntos D1 y KV">
D1 almacena tus enlaces de forma permanente. KV los cachea para redirecciones rápidas. Ambos son necesarios. Cuando creas un enlace, se escribe primero en D1 y después en KV. Las redirecciones leen de KV (rápido) y recurren a D1 si hay un fallo de caché. Es una arquitectura distinta a la del artículo original, donde KV era el único almacenamiento.
</Notice>

## Desplegar Sink en Cloudflare Workers (recomendado)

Cloudflare Workers es el método de despliegue recomendado. Pages todavía funciona pero está obsoleto. Esta sección recorre la configuración completa.

<YouTubeEmbed
  url="https://www.youtube.com/embed/MkU23U2VE9E"
  label="Instalación de Sink"
/>

<Notice type="warning" title="El vídeo puede estar desactualizado">
El vídeo de arriba se grabó antes de la migración a D1. Sigue los pasos escritos de abajo para el proceso de despliegue actual.
</Notice>

### Requisitos previos

<ListCheck>

- Cuenta de Cloudflare (el plan gratuito es suficiente)
- Cuenta de GitHub (para hacer fork del repositorio)
- Un dominio añadido a Cloudflare (para URL cortas personalizadas)
- Token de API de Cloudflare con permiso Account > Account Analytics > Read (se crea en Profile > API Tokens)

</ListCheck>

### Paso 1: haz fork del repositorio

Ve a [github.com/miantiao-me/Sink](https://github.com/miantiao-me/Sink) y haz clic en **Fork**. Esto crea tu propia copia bajo tu cuenta de GitHub.

Si anteriormente hiciste fork de `ccbikai/Sink`, las redirecciones de GitHub siguen funcionando, pero actualiza tus marcadores y cualquier referencia de CI a la nueva URL.

### Paso 2: crea una base de datos Cloudflare D1

<Notice type="warning" title="Este paso es nuevo desde la v0.3.0">
Sin una base de datos D1, Sink no puede almacenar enlaces. Esto no existía cuando se escribió el artículo original.
</Notice>

1. Ve a **Cloudflare Dashboard** > **D1** > **Create database**
2. Nómbrala `sink`
3. Copia el **database ID** desde la página de detalles de la base de datos. Lo necesitarás más tarde

### Paso 3: crea un namespace KV

1. Ve a **Cloudflare Dashboard** > **Workers & Pages** > **KV** > **Create a namespace**
2. Nómbralo `sink`
3. Copia el **namespace ID**. Lo necesitarás en el siguiente paso

### Paso 4: despliega con la integración Git de Workers

1. Ve a **Cloudflare Dashboard** > **Workers & Pages** > **Create**
2. Selecciona **Workers** (no Pages)
3. Haz clic en **Connect to Git** y autoriza GitHub
4. Selecciona tu repositorio Sink forkeado y la rama `master`
5. Define **Build command**: `pnpm build`
6. Define **Deploy command**: `pnpm deploy:worker`
7. Haz clic en **Save and Deploy**

### Paso 5: configura las variables de build y los bindings

Tras el primer despliegue, configura dos grupos de ajustes.

**Variables de build** (Settings > Variables and Secrets):

| Variable | Valor |
|---|---|
| `DEPLOY_D1_DATABASE_ID` | Tu ID de base de datos D1 del paso 2 |
| `DEPLOY_KV_NAMESPACE_ID` | Tu ID de namespace KV del paso 3 |

**Bindings en tiempo de ejecución** (Settings > Bindings):

| Nombre del binding | Tipo | Recurso |
|---|---|---|
| `DB` | D1 Database | `sink` |
| `KV` | KV Namespace | `sink` |
| `ANALYTICS` | Analytics Engine | Dataset: `sink` |
| `R2` | R2 Bucket | Opcional: nombre: `sink` |
| `AI` | Workers AI | Opcional: para las funciones de IA |

<Notice type="warning" title="El binding DB es obligatorio">
Sin el binding `DB` de D1, obtendrás errores al crear enlaces. Es el error de despliegue más común desde la v0.3.0.
</Notice>

**Variables de entorno** (Settings > Variables and Secrets):

| Variable | Valor |
|---|---|
| `NUXT_SITE_TOKEN` | Tu contraseña de administrador (mínimo 8 caracteres) |
| `NUXT_CF_ACCOUNT_ID` | Tu ID de cuenta de Cloudflare (visible en la URL del dashboard) |
| `NUXT_CF_API_TOKEN` | Token de API con permiso Account Analytics Read |

<Picture formats={["webp"]} fallbackFormat="webp" src={img1} alt="Configuración de bindings de Cloudflare Workers para Sink" />

### Paso 6: completa la configuración del almacenamiento (primera ejecución)

Tras el despliegue, debes inicializar la base de datos. Es un paso que se hace una sola vez.

1. Abre `https://your-domain/dashboard`
2. Inicia sesión con tu `NUXT_SITE_TOKEN`
3. Ve a **Links**

Esto dispara la inicialización del almacenamiento. Hasta que lo hagas, la API devuelve HTTP 423 (Storage not ready). Si omites este paso, la creación de enlaces fallará.

### Paso 7: añade tu dominio personalizado

1. Ve a **Workers & Pages** > tu proyecto > **Settings** > **Domains & Routes**
2. Haz clic en **Add custom domain**
3. Introduce tu dominio (p. ej., `go.tudominio.com`)
4. Cloudflare gestiona el DNS y el TLS automáticamente

Verifica que el dominio está activo:

```bash
curl -I https://your-domain/test-slug
```

Deberías obtener una redirección 301 o 302 (aunque el slug no exista todavía, el worker está respondiendo).

<Picture formats={["webp"]} fallbackFormat="webp" src={img2} alt="Panel de Sink mostrando la interfaz de gestión de enlaces" />

## Desplegar Sink en Cloudflare Pages (obsoleto)

<Notice type="error" title="Cloudflare Pages está obsoleto">
Usa Workers (arriba) para instalaciones nuevas. Los pasos siguientes son para usuarios existentes de Pages que quieran actualizar.
</Notice>

El despliegue en Pages todavía funciona pero requiere configuración adicional:

1. Activa el flag de compatibilidad `nodejs_compat` en los ajustes de tu proyecto Pages (antes no era necesario)
2. Añade `CLOUDFLARE_API_TOKEN` con permiso D1 Edit y `CLOUDFLARE_ACCOUNT_ID` como variables de entorno. El script `postbuild` ejecuta la migración de D1 automáticamente en los builds de la rama `master`
3. Todos los demás bindings (DB, KV, ANALYTICS, R2, AI) siguen aplicando

¿Ya alojas un [blog de Astro en Cloudflare](/deploy-astrojs-cloudflare/)? Sink encaja junto a tus proyectos de Cloudflare existentes, aunque Workers es ahora el camino más sencillo.

## Post-despliegue: verificación y resolución de problemas

### Verifica tu despliegue

<ListCheck>

- Abre `https://your-domain/dashboard` — debería mostrar la pantalla de inicio de sesión
- Inicia sesión con `NUXT_SITE_TOKEN`
- Crea un enlace corto de prueba — verifica que la redirección funciona visitándolo en un navegador
- Revisa la página de analíticas — visita tu enlace de prueba desde otro dispositivo/navegador y confirma que aparece el clic
- Visita `/docs/scalar` — la documentación de la API debería ser accesible

</ListCheck>

### Problemas comunes y soluciones

<Accordion label="No puedo crear enlaces cortos / errores HTTP 423" group="troubleshooting">

**Causa:** el almacenamiento no está inicializado, o faltan los bindings `DB` y `KV`.

**Solución:** abre tu panel de Sink y navega a Links una vez para disparar la inicialización. Si no ayuda, comprueba que los bindings `DB` (D1) y `KV` están configurados en los ajustes de Workers. Redespliega después de añadir los bindings.

</Accordion>

<Accordion label="Las analíticas están vacías" group="troubleshooting">

**Causa:** falta el binding `ANALYTICS`, el nombre del dataset es incorrecto o el token de API carece del permiso adecuado.

**Solución:** asegúrate de que existe el binding `ANALYTICS` con el nombre de dataset `sink`. Verifica que tu `NUXT_CF_API_TOKEN` tiene el permiso «Account > Account Analytics > Read». Redespliega tras los cambios.

</Accordion>

<Accordion label="Los slugs personalizados pierden las mayúsculas" group="troubleshooting">

**Causa:** los slugs no distinguen mayúsculas por defecto.

**Solución:** define `NUXT_CASE_SENSITIVE=true` en las variables de entorno y redespliega. Ten en cuenta que esto significa que `Go/Link` y `go/link` serán URL distintas.

</Accordion>

<Accordion label="La página encubierta se muestra en blanco" group="troubleshooting">

**Causa:** el sitio de destino bloquea la incrustación en iframes mediante las cabeceras `X-Frame-Options` o `Content-Security-Policy`.

**Solución:** el encubrimiento solo funciona en sitios que permiten ser incrustados. La mayoría de los sitios grandes (Google, GitHub) lo bloquean. Prueba con un sitio que controles.

</Accordion>

<Accordion label="Las redirecciones muestran el destino antiguo" group="troubleshooting">

**Causa:** el navegador o la CDN está cacheando la respuesta de redirección.

**Solución:** define `NUXT_REDIRECT_NO_STORE=true` en las variables de entorno para evitar la caché. También puedes ajustar `NUXT_LINK_CACHE_TTL` (por defecto: 60 segundos) para controlar la duración de la caché de KV.

</Accordion>

<Accordion label="Migración desde pre-v0.3.0 (solo KV) a D1" group="troubleshooting">

**Causa:** actualización desde una versión que almacenaba los enlaces solo en KV.

**Solución:** despliega la v0.3.0 con tu namespace KV original todavía vinculado. Después abre Dashboard > Links — esto dispara la migración de KV a D1 automáticamente. La API devuelve HTTP 423 hasta que la migración termina. Los enlaces existentes siguen funcionando durante la migración mientras el namespace KV original permanezca vinculado.

</Accordion>

## Opciones avanzadas de configuración

Sink expone muchas variables de entorno para ajustar el comportamiento. Cambiar cualquiera de ellas requiere un redespliegue en Workers.

<Accordion label="Referencia de variables de entorno" group="config">

| Variable | Por defecto | Propósito |
|---|---|---|
| `NUXT_HOME_URL` | vacío | Redirige `/` a una URL |
| `NUXT_NOT_FOUND_REDIRECT` | vacío | Destino 404 personalizado |
| `NUXT_REDIRECT_STATUS_CODE` | `301` | Código HTTP de redirección (301/302/307/308) |
| `NUXT_LINK_CACHE_TTL` | `60` | TTL de la caché KV en segundos |
| `NUXT_REDIRECT_WITH_QUERY` | `false` | Reenvía los query params del visitante al destino |
| `NUXT_CASE_SENSITIVE` | `false` | Conserva las mayúsculas del slug |
| `NUXT_DISABLE_BOT_ACCESS_LOG` | `false` | Excluye el tráfico de bots de las analíticas |
| `NUXT_DISABLE_AUTO_BACKUP` | `false` | Desactiva las copias de seguridad programadas en R2 |
| `NUXT_AI_MODEL` | `@cf/qwen/qwen3-30b-a3b-fp8` | Modelo de Workers AI para sugerencias de slugs |
| `NUXT_WEBHOOK_URL` | vacío | URL del webhook de clics |
| `NUXT_WEBHOOK_SECRET` | vacío | Secreto HMAC del webhook (prefijo `whsec_`) |
| `NUXT_CF_ACCESS_TEAM_DOMAIN` | vacío | Dominio de equipo de Cloudflare Access |
| `NUXT_CF_ACCESS_AUD` | vacío | AUD de Cloudflare Access |
| `NUXT_PUBLIC_SLUG_DEFAULT_LENGTH` | `6` | Longitud del slug autogenerado |
| `NUXT_API_CORS` | vacío | Activa CORS para `/api/**` |

Referencia completa: [docs.sink.cool/configuration](https://docs.sink.cool/configuration/)

Para deshacer un cambio: elimina la variable y redespliega.

</Accordion>

## Copias de seguridad y notas para producción

Si configuraste el binding R2 (paso 5), Sink ejecuta copias de seguridad automáticas según una programación. Desactívalas con `NUXT_DISABLE_AUTO_BACKUP=true`. Para estrategias de backup en R2 más amplias, mira cómo [configurar copias de seguridad de Dokploy con Cloudflare R2](/es/backups-dokploy-cloudflare-r2/) — el proceso de configuración de R2 es similar.

**Límites del plan gratuito de Cloudflare (relevantes para Sink):**

| Producto | Límite gratuito | Notas |
|---|---|---|
| Workers requests | 100.000/día | Se reinicia a las 00:00 UTC |
| D1 rows read | 5 millones/día | Se reinicia a las 00:00 UTC |
| D1 rows written | 100.000/día | Se reinicia a las 00:00 UTC |
| D1 storage | 5 GB en total | Suma de todas las bases de datos de tu cuenta |
| KV reads | 100.000/día | |
| KV writes | 1.000/día | |
| R2 storage | 10 GB | |

<Notice type="info" title="Resumen de costes">
Sink funciona gratis en el plan gratuito de Cloudflare para uso personal. El tráfico intenso (miles de enlaces, millones de clics) puede requerir el plan Workers Paid a 5 $/mes, con exceso de D1 a 0,001 $ por millón de filas leídas. Para la mayoría de la gente que acorta enlaces para redes sociales o campañas de email, el plan gratuito es más que suficiente.
</Notice>

Cada instancia de Sink también expone documentación OpenAPI en `/docs/scalar`, útil para la automatización y la [integración con agentes de IA](/es/skill-despliegue-docker-ia/).

## Sink frente a las alternativas

| Función | Sink | Dub.co | Bitly | Short.io |
|---|---|---|---|---|
| Autoalojado | Sí | Sí (open-core) | No | No |
| Coste | Gratis (Cloudflare) | Plan gratuito + pago | Desde 8 $/mes | Plan gratuito + pago |
| Generación de slugs con IA | Sí | No | No | No |
| Enrutamiento geo/dispositivo | Sí | Sí | Sí (de pago) | Sí (de pago) |
| Protección por contraseña | Sí | No | No | No |
| Nativo de Cloudflare | Sí | No | No | No |

La principal ventaja de Sink es que funciona íntegramente en el plan gratuito de Cloudflare sin servidor que gestionar. Si administras un conjunto autoalojado más amplio, puedes [comparar los mejores paneles de servidor](/best-self-hosted-panels/) o echar un vistazo a [Coolify](/es/instalar-coolify-alternativa-heroku/) como PaaS autoalojado. Si usas [Dokploy para autoalojar](/dokploy-install/), Sink es un servicio más que puedes ejecutar en paralelo, aunque en Cloudflare en lugar de tu VPS.

## Cómo ampliar Sink: apps e integraciones

Sink tiene varios clientes e integraciones:

- **Extensión de Chrome**: «Sink Quick Shorten» te permite acortar cualquier URL con el clic derecho (Chrome Web Store)
- **Extensión de Raycast**: «Sink Short Links Manager» para usuarios avanzados de macOS (Raycast Store)
- **App de iOS**: app nativa de iPhone en la App Store
- **Atajos de Apple**: integración de automatización en macOS e iOS
- **API**: documentación OpenAPI en `/docs/scalar`, soporte MCP mediante proxy OpenAPI

Esto hace que Sink sea mucho más práctico que una herramienta de solo panel. Puedes acortar enlaces desde tu navegador, teléfono o terminal sin abrir el panel.

## Conclusión

Sink empezó como un simple acortador basado en Cloudflare KV y ahora es una plataforma completa de gestión de enlaces. La migración a D1 de la v0.3.0 lo convierte en una aplicación con base de datos de verdad manteniendo el modelo de despliegue sin servidor y sin coste. La protección por contraseña, el enrutamiento geográfico, los webhooks y el ecosistema de extensiones (Chrome, Raycast, iOS, Atajos de Apple) lo convierten en una opción sólida para quien quiera acortar enlaces sin cuotas mensuales ni dependencia de un proveedor.

Si estás construyendo tu stack autoalojado, Sink combina bien con [contenedores Docker para tu servidor doméstico](/es/contenedores-docker-servidor-casa/) — uno se ejecuta en tu infraestructura, el otro funciona gratis en el edge de Cloudflare. Sink es una de las [29 apps autoalojadas en Cloudflare Workers](/es/apps-autoalojadas-cloudflare-workers/) que hemos catalogado, incluyendo clientes de email, gestores de contraseñas y apps de notas.

<Button text="Ver Sink en GitHub" link="https://github.com/miantiao-me/Sink" variant="solid" color="blue" size="md" icon="arrow-right" />