Linkding es un gestor de marcadores autoalojado, rápido y minimalista: guarda enlaces con etiquetas y notas, permite buscarlos, marcarlos como pendientes de leer y compartirlos, y ofrece una extensión de navegador y una API REST. Funciona con SQLite y consume muy pocos recursos, así que puede convivir con otros servicios en el mismo servidor. En este tutorial instalarás Linkding con Docker Compose en Ubuntu 24.04, lo publicarás en tu dominio con Nginx y HTTPS, conectarás la extensión del navegador y probarás la API.

Requisitos previos

  • Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath. Con 512 MB de RAM es suficiente.
  • Un usuario no root con privilegios sudo.
  • Docker Engine y el plugin Docker Compose instalados desde el repositorio oficial de Docker.
  • Un subdominio (en esta guía, links.tu_dominio) con un registro DNS A que apunte a la IP pública del servidor.
  • UFW activo con SSH permitido.

Paso 1: Preparar el directorio y las variables

Crea un directorio para el proyecto con una subcarpeta para los datos:

mkdir -p ~/linkding/data
cd ~/linkding

Linkding lee su configuración de variables de entorno que empiezan por LD_. Guárdalas en un archivo .env para no dejar la contraseña del administrador dentro del archivo de Compose:

nano ~/linkding/.env
LD_SUPERUSER_NAME=admin
LD_SUPERUSER_PASSWORD=your_strong_password
LD_CSRF_TRUSTED_ORIGINS=https://links.tu_dominio

Sustituye your_strong_password por una contraseña robusta y links.tu_dominio por tu subdominio real. Qué hace cada variable:

  • LD_SUPERUSER_NAME y LD_SUPERUSER_PASSWORD crean el usuario administrador en el primer arranque. Si el usuario ya existe, se ignoran.
  • LD_CSRF_TRUSTED_ORIGINS es obligatoria cuando Linkding está detrás de un proxy con HTTPS. Sin ella, Django rechaza el inicio de sesión con un error 403 CSRF verification failed.

Restringe los permisos del archivo:

chmod 600 ~/linkding/.env

Paso 2: Crear el archivo de Docker Compose

Crea compose.yaml en el mismo directorio:

nano ~/linkding/compose.yaml
services:
  linkding:
    image: sissbruecker/linkding:latest
    container_name: linkding
    restart: unless-stopped
    ports:
      - "127.0.0.1:9090:9090"
    volumes:
      - ./data:/etc/linkding/data
    env_file:
      - .env

El puerto 9090 se publica solo en 127.0.0.1. Docker se salta las reglas de UFW para los puertos publicados, así que exponerlo en todas las interfaces dejaría Linkding accesible por HTTP sin cifrar. El acceso público irá por Nginx.

Paso 3: Arrancar Linkding

Inicia el contenedor:

docker compose up -d

Comprueba que está en ejecución:

docker compose ps --format "table {{.Name}}\t{{.Status}}\t{{.Ports}}"
NAME       STATUS          PORTS
linkding   Up 15 seconds   127.0.0.1:9090->9090/tcp

Verifica que la aplicación responde en local. La portada redirige a la página de inicio de sesión:

curl -sI http://127.0.0.1:9090 | head -n 1
HTTP/1.1 302 Found

La base de datos SQLite se crea en ~/linkding/data/db.sqlite3:

ls ~/linkding/data

Paso 4: Publicar Linkding con Nginx y HTTPS

Instala Nginx y Certbot:

sudo apt update
sudo apt install nginx certbot python3-certbot-nginx

Crea el bloque de servidor:

sudo nano /etc/nginx/sites-available/linkding
server {
    listen 80;
    listen [::]:80;
    server_name links.tu_dominio;

    location / {
        proxy_pass http://127.0.0.1:9090;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Activa el sitio, valida la configuración y recarga Nginx:

sudo ln -s /etc/nginx/sites-available/linkding /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

Permite el tráfico web en UFW y solicita el certificado. Certbot añade la configuración TLS y la redirección de HTTP a HTTPS al mismo archivo:

sudo ufw allow 'Nginx Full'
sudo certbot --nginx -d links.tu_dominio
Congratulations! You have successfully enabled HTTPS on https://links.tu_dominio

Abre https://links.tu_dominio e inicia sesión con el usuario admin y la contraseña del archivo .env.

Paso 5: Configurar usuarios

Linkding no tiene registro público: todas las cuentas las crea un administrador. Puedes hacerlo desde el panel de administración de Django en https://links.tu_dominio/admin/ o desde la línea de comandos:

docker compose exec linkding python manage.py createsuperuser --username=ana --email=ana@tu_dominio

El comando pide la contraseña de forma interactiva. Para crear usuarios sin privilegios de administrador, usa el panel /admin/, entra en Users > Add user y deja sin marcar las casillas Staff status y Superuser status.

Si olvidas una contraseña, restablécela así:

docker compose exec linkding python manage.py changepassword admin

Paso 6: Instalar la extensión del navegador

La extensión oficial añade un botón para guardar la página actual con título, descripción y etiquetas. Está disponible para Firefox en Firefox Add-ons y para Chrome y navegadores basados en Chromium en la Chrome Web Store, en ambos casos con el nombre linkding extension.

Para configurarla necesitas un token de API:

  1. En Linkding, abre Settings > Integrations.
  2. Copia el valor de REST API (el token).
  3. En las opciones de la extensión, introduce la URL base https://links.tu_dominio y el token.
  4. Pulsa Test y guarda.

En la misma página de Integrations encontrarás un bookmarklet para navegadores donde no puedas instalar extensiones.

Paso 7: Etiquetas, búsqueda e importación

Al guardar un marcador, escribe las etiquetas separadas por espacios. Cada etiqueta se convierte en un filtro: haz clic en ella para ver todos los marcadores que la llevan.

La barra de búsqueda busca en título, descripción, notas y URL, y admite etiquetas con el prefijo #. Por ejemplo, docker #devops devuelve los marcadores que contienen «docker» y tienen la etiqueta devops. Linkding incluye además filtros para marcadores sin leer y sin etiquetar.

Para migrar desde el navegador o desde otro gestor, exporta tus marcadores en formato HTML de Netscape (el formato estándar de exportación de Firefox, Chrome o Pinboard) e impórtalos en Settings > General > Import. En la misma página, Export descarga todos tus marcadores en ese formato.

En Settings > General también puedes activar la creación automática de instantáneas en Internet Archive (Wayback Machine) para cada marcador nuevo, útil cuando una página desaparece.

Paso 8: Usar la API REST

La API permite automatizar altas y consultas. Guarda el token en una variable de la sesión para no repetirlo:

LD_TOKEN="your_api_token"

Crea un marcador con etiquetas:

curl -s -X POST https://links.tu_dominio/api/bookmarks/ \
  -H "Authorization: Token $LD_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://docs.docker.com/compose/", "title": "Docker Compose docs", "tag_names": ["docker", "docs"]}'

La respuesta es el marcador creado en JSON, con su id:

{"id":1,"url":"https://docs.docker.com/compose/","title":"Docker Compose docs",...,"tag_names":["docker","docs"],...}

Busca marcadores con los mismos operadores que en la interfaz. El parámetro q debe ir codificado en la URL (%23 es #):

curl -s "https://links.tu_dominio/api/bookmarks/?q=%23docker&limit=10" \
  -H "Authorization: Token $LD_TOKEN"

Lista las etiquetas existentes:

curl -s https://links.tu_dominio/api/tags/ \
  -H "Authorization: Token $LD_TOKEN"

Los listados están paginados: la respuesta incluye count, next y previous junto a results.

Paso 9: Actualizar y hacer copias de seguridad

Todos los datos (base de datos, favicons e instantáneas) están en ~/linkding/data. Para una copia consistente, detén el contenedor, empaqueta el directorio y vuelve a arrancarlo:

cd ~/linkding
docker compose stop
sudo tar -czf ~/linkding-backup-$(date +%F).tar.gz -C ~ linkding
docker compose start

Para actualizar, descarga la imagen nueva y recrea el contenedor. Las migraciones de base de datos se aplican solas al arrancar:

cd ~/linkding
docker compose pull
docker compose up -d

Para restaurar en otro servidor, extrae el archivo en el directorio personal y ejecuta docker compose up -d dentro de ~/linkding.

Solución de problemas

403 CSRF verification failed al iniciar sesión. LD_CSRF_TRUSTED_ORIGINS no coincide con la URL que usas, incluido el esquema (https://). Corrige el valor en .env y recrea el contenedor con docker compose up -d --force-recreate, ya que un simple reinicio no recarga el archivo .env.

La extensión responde con error de conexión. Comprueba el token con la API:

curl -s -o /dev/null -w "%{http_code}\n" https://links.tu_dominio/api/bookmarks/ -H "Authorization: Token $LD_TOKEN"

Un 200 indica que el token es válido; un 401 que es incorrecto o se ha regenerado.

502 Bad Gateway. Linkding no está escuchando en 127.0.0.1:9090. Revisa docker compose ps y los registros con docker compose logs linkding.

Conclusión

Linkding ya está funcionando en tu dominio con HTTPS, con usuarios gestionados por el administrador, la extensión del navegador conectada y la API lista para automatizaciones. Como siguientes pasos puedes importar tus marcadores actuales, programar la copia de seguridad del directorio data con un temporizador de systemd, o conectar la API con herramientas como n8n para guardar enlaces desde otras fuentes.