Cómo instalar y configurar Link Shortener: Acortador de URLs Autohospedado en Docker

Autohospedado

Link Shortener: Acortador de URLs autohospedado con analíticas y panel administrativo

Solución open source en TypeScript, Fastify y PostgreSQL para crear enlaces cortos con dominio propio, panel de administración y estadísticas de clics, desplegable con Docker Compose y Caddy con HTTPS automático.



Vídeo tutorial en YouTube

Mira el vídeo completo sobre cómo instalar y usar Link Shortener: Acortador de URLs autohospedado con analíticas y panel administrativo en el canal GENBYTE:

¿Qué es Link Shortener: Acortador de URLs autohospedado con analíticas y panel administrativo?

Link Shortener es un acortador de enlaces autohospedado que permite usar un dominio propio, ofrece un panel administrativo con autenticación segura y proporciona analíticas detalladas de clics. Está construido con Node.js 22, Fastify 5, PostgreSQL 16 y Drizzle ORM, y se despliega mediante Docker Compose con Caddy como proxy inverso que gestiona certificados TLS de Let's Encrypt de forma automática. El proyecto está licenciado bajo MIT y su código está disponible en GitHub.

Despliegue en producción con HTTPS automático mediante Caddy y Let's Encrypt, sin necesidad de configurar certificados manualmente.

Características principales

Enlaces cortos con dominio propio

Permite crear URLs cortas utilizando un hostname personalizado configurado mediante la variable SHORTENER_DOMAIN.

Redirecciones configurables

Soporte para códigos de estado HTTP 301, 302, 307 y 308, configurable globalmente o por enlace mediante REDIRECT_STATUS_CODE.

Panel administrativo seguro

Interfaz de administración con autenticación basada en sesiones, hash de contraseñas Argon2id y protección CSRF integrada.

Gestión completa de enlaces

Crear, editar, desactivar y archivar enlaces; cada uno puede tener vencimiento, título, descripción y metadatos personalizados.

Analíticas globales y por enlace

Series temporales de clics, distribución por países, referrers y listado de clics recientes, tanto a nivel global como por enlace individual.

API JSON para automatización

Endpoints REST para listar, crear, obtener, actualizar, desactivar enlaces y consultar estadísticas, protegidos por autenticación de sesión o token heredado.

Captura de IP respetuosa con la privacidad

Las direcciones IP de los visitantes no se almacenan en claro; solo se guarda un hash para análisis geográfico sin identificar usuarios.

Despliegue listo para producción

Stack Docker Compose que incluye la aplicación, PostgreSQL en red interna, Caddy como reverse proxy y emisión/renovación automática de certificados TLS.

Desarrollo local simplificado

Entorno de desarrollo con docker-compose.yml que expone puertos y permite crear usuario administrador con contraseña definida por variable de entorno.

Validación estricta de configuración

La aplicación valida todas las variables de entorno requeridas al arranque y falla inmediatamente si falta algún valor obligatorio.

Requisitos del sistema

  • VPS con Ubuntu 22.04, 24.04 o 26.04 y acceso SSH como root
  • Registro DNS tipo A apuntando el subdominio deseado a la IPv4 pública del VPS
  • Puertos TCP 80 y 443 abiertos en el firewall del proveedor y del servidor
  • Docker Engine y Docker Compose (plugin docker-compose-plugin) instalados desde el repositorio oficial de Docker para Ubuntu
  • Clonar el repositorio y configurar archivo .env.production con valores seguros generados mediante openssl

Instalación con Docker Compose

1. Preparar el VPS y el DNS

Crear un VPS con Ubuntu, anotar su IPv4 pública y crear un registro A en el proveedor DNS para el subdominio elegido (ej. go.example.com -> 203.0.113.10). Verificar que los puertos 80 y 443 estén permitidos.

# Ejemplo de registro DNS go.example.com -> 203.0.113.10

2. Instalar Docker Engine y Docker Compose

Utilizar el repositorio oficial de Docker para Ubuntu para instalar docker-ce, docker-ce-cli, containerd.io, docker-buildx-plugin y docker-compose-plugin. Verificar la instalación con hello-world y docker compose version.

apt update apt install -y ca-certificates curl git install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg \ -o /etc/apt/keyrings/docker.asc chmod a+r /etc/apt/keyrings/docker.asc tee /etc/apt/sources.list.d/docker.sources >/dev/null <<EOF Types: deb URIs: https://download.docker.com/linux/ubuntu Suites: $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") Components: stable Architectures: $(dpkg --print-architecture) Signed-By: /etc/apt/keyrings/docker.asc EOF apt update apt install -y docker-ce docker-ce-cli containerd.io \ docker-buildx-plugin docker-compose-plugin docker run --rm hello-world docker compose version

3. Descargar y configurar Link Shortener

Clonar el repositorio, copiar el archivo de ejemplo de producción a .env.production, restringir permisos y editar las variables requeridas: SHORTENER_DOMAIN (solo hostname), POSTGRES_PASSWORD (hexadecimal de 32 bytes) y SESSION_SECRET (Base64 de al menos 32 caracteres).

git clone https://github.com/pablokbs/link-shortener.git cd link-shortener cp .env.production.example .env.production chmod 600 .env.production nano .env.production # Generar valores seguros openssl rand -hex 32 openssl rand -base64 48

4. Levantar la aplicación con HTTPS automático

Ejecutar docker compose con el archivo compose.production.yml y el archivo de entorno .env.production. El stack incluye la app, PostgreSQL (solo red interna), Caddy y certificados Let's Encrypt automáticos. Verificar el estado con curl al endpoint /healthz.

docker compose --env-file .env.production \ -f compose.production.yml up --build -d docker compose --env-file .env.production \ -f compose.production.yml ps curl "https://$(grep '^SHORTENER_DOMAIN=' .env.production | cut -d= -f2)/healthz"

5. Crear el primer usuario administrador

Ejecutar el script create-admin dentro del contenedor de la app, proporcionando el email. La contraseña se solicita de forma interactiva y oculta. Luego acceder al panel en https://<dominio>/admin/login.

docker compose --env-file .env.production \ -f compose.production.yml exec app \ npm run create-admin -- \ --email=admin@example.com # Acceder a: # https://go.example.com/admin/login

Acceder al proyecto

Panel administrativo

Acceder mediante navegador a https://<SHORTENER_DOMAIN>/admin/login tras crear el usuario administrador.

Health check del servicio

Endpoint público GET /healthz para verificar que la aplicación responde correctamente (ej. curl https://go.example.com/healthz).

Casos de uso

  • Acortador de URLs personal para marca o proyecto propio con dominio propio
  • Campañas de marketing con seguimiento de clics, países y referrers
  • Automatización de creación y gestión de enlaces mediante API JSON
  • Reemplazo autohospedado de servicios acortadores de terceros manteniendo control total de datos
  • Entornos donde se requiere privacidad: solo se almacena hash de IP, no la IP real
  • Desarrollo y pruebas de integraciones que requieren un servicio de redirección configurable

Configuración avanzada

Variables de entorno principales

Configuración validada al arranque: SHORTENER_DOMAIN (obligatorio), SHORTENER_SCHEME (default https), DATABASE_URL (obligatorio, armado por Compose en producción), SESSION_SECRET (obligatorio, mínimo 32 chars), SESSION_MAX_AGE_SECONDS (default 604800), SESSION_COOKIE_NAME, CSRF_COOKIE_NAME, REDIRECT_STATUS_CODE (default 302), ADMIN_TOKEN (opcional, heredado), NODE_ENV (production).

# Ejemplo .env.production SHORTENER_DOMAIN=go.example.com SHORTENER_SCHEME=https DATABASE_URL=postgres://shortener:password@db:5432/shortener SESSION_SECRET=base64_string_min_32_chars SESSION_MAX_AGE_SECONDS=604800 REDIRECT_STATUS_CODE=302 NODE_ENV=production

Uso de la API JSON

Endpoints principales: GET /api/links (lista), POST /api/links (crear), GET /api/links/:id (detalle), PATCH /api/links/:id (actualizar), DELETE /api/links/:id (desactivar), GET /api/links/:id/stats (estadísticas). Autenticación mediante cookie de sesión o header Authorization: Bearer <ADMIN_TOKEN> (heredado).

# Crear enlace (requiere autenticación) curl -X POST https://go.example.com/api/links \ -H "Content-Type: application/json" \ -H "Authorization: Bearer <token>" \ -d '{"url":"https://ejemplo.com","slug":"mi-enlace","title":"Ejemplo"}'

Workflow de despliegue continuo (GitHub Actions)

El repositorio incluye un workflow que valida PRs y, en push a main, construye y publica la imagen en ghcr.io/<owner>/<repo>. El deploy remoto está deshabilitado por defecto; para habilitarlo configurar variables DEPLOY_ENABLED=true, DEPLOY_COMMAND y secrets DEPLOY_HOST, DEPLOY_USER, DEPLOY_SSH_KEY en GitHub Actions.

# Variables de Actions (Settings -> Secrets and variables -> Actions -> Variables) DEPLOY_ENABLED=true DEPLOY_COMMAND=cd /opt/link-shortener && ./deploy.sh # Secrets de Actions (Settings -> Secrets and variables -> Actions -> Secrets) DEPLOY_HOST=tu-servidor.com DEPLOY_USER=deploy DEPLOY_SSH_KEY=-----BEGIN OPENSSH PRIVATE KEY-----...

Códigos de redirección personalizados

Cada enlace puede definir su propio código de redirección (301, 302, 307, 308) sobrescribiendo el valor global REDIRECT_STATUS_CODE. Útil para SEO (301) o redirecciones temporales (302/307).

# Al crear/actualizar enlace via API {"url":"https://destino.com","redirectStatusCode":301}

Rotación de credenciales

Script npm run rotate-credentials para regenerar secretos de sesión y CSRF sin perder datos, útil en respuesta a incidentes de seguridad.

docker compose --env-file .env.production \ -f compose.production.yml exec app \ npm run rotate-credentials

Gestión y mantenimiento

Ver logs en tiempo real

Seguir la salida combinada de todos los servicios del stack de producción.

docker compose --env-file .env.production -f compose.production.yml logs -f

Actualizar a la última versión

Obtener cambios del repositorio y reconstruir y reiniciar los contenedores manteniendo los volúmenes de datos.

git pull --ff-only docker compose --env-file .env.production \ -f compose.production.yml up --build -d

Detener el stack sin borrar datos

Para y elimina contenedores pero conserva volúmenes (base de datos, certificados TLS). No usar down -v a menos que se quiera borrar todo.

docker compose --env-file .env.production \ -f compose.production.yml down

Backup de datos persistentes

Los datos viven en volúmenes Docker (shortener_pgdata para PostgreSQL, shortener_caddy_data y shortener_caddy_config para Caddy). Realizar backup de los volúmenes con herramientas como docker run --rm -v shortener_pgdata:/data -v $(pwd):/backup alpine tar czf /backup/pgdata.tar.gz /data.

# Ejemplo backup volumen PostgreSQL docker run --rm \ -v shortener_pgdata:/data \ -v $(pwd):/backup \ alpine tar czf /backup/pgdata_$(date +%F).tar.gz /data

Rotación de secretos de sesión

Ejecutar el script de rotación para invalidar sesiones activas y generar nuevos secretos de cookies y CSRF.

docker compose --env-file .env.production \ -f compose.production.yml exec app \ npm run rotate-credentials

Stack técnico

  • Node.js 22
  • TypeScript 5
  • Fastify 5
  • PostgreSQL 16
  • Drizzle ORM
  • HTMX
  • Chart.js
  • Docker Compose
  • Caddy
  • Let's Encrypt
  • Argon2id (hash de contraseñas)
  • Zod (validación)
  • Pino (logging)

Apoya el canal GENBYTE

Sígueme en mis redes sociales

Comentarios

Entradas populares de este blog

Cómo Instalar y configurar SERVIDOR VPN WIREGUARD en MIKROTIK 🔐 #VPN #Wireguard #Mikrotik #RouterOS

Cómo instalar y configurar DSM SYNOLOGY 7.2.2 en PC | Guía completa, instalación, RAID 1, SMB

Cómo INSTALAR y CONFIGURAR OpenVPN en MIKROTIK. Guía completa paso a paso.