Typesense es un motor de búsqueda de código abierto, tolerante a errores tipográficos y pensado para búsquedas instantáneas mientras el usuario escribe. Mantiene el índice en memoria, se configura con un único fichero y expone una API REST sencilla, lo que lo convierte en una alternativa ligera a Elasticsearch o Algolia. En este tutorial instalarás Typesense en Ubuntu 24.04 con el paquete oficial, crearás una colección de productos, harás búsquedas con filtros y facetas, generarás una clave de solo búsqueda para el frontend y publicarás la API con HTTPS detrás de Nginx.
Requisitos previos
Para seguir esta guía necesitas:
- Un servidor con Ubuntu 24.04 LTS de 64 bits (x86_64 o arm64), por ejemplo un VPS de CubePath.
- Un usuario no root con privilegios
sudo. - Al menos 1 GB de RAM. Typesense guarda todo el índice en memoria, así que calcula entre dos y tres veces el tamaño de los campos que indexes.
- Para el paso 7: un dominio o subdominio (en esta guía,
search.your_domain) con un registro DNS A apuntando a la IP del servidor.
Paso 1: Instalar Typesense
Typesense publica paquetes .deb oficiales para cada versión. Consulta la última versión estable en la página de descargas y guárdala en una variable; esta guía usa la 30.2:
TYPESENSE_VERSION=30.2
cd /tmp
curl -fLO "https://dl.typesense.org/releases/${TYPESENSE_VERSION}/typesense-server-${TYPESENSE_VERSION}-amd64.deb"
sudo apt install -y "./typesense-server-${TYPESENSE_VERSION}-amd64.deb"
En servidores arm64, sustituye amd64 por arm64 en el nombre del fichero.
El paquete instala el binario, crea el fichero de configuración /etc/typesense/typesense-server.ini con una clave de administración aleatoria y registra el servicio typesense-server. Habilítalo y arráncalo:
sudo systemctl enable --now typesense-server
Comprueba el estado del servicio:
systemctl status typesense-server --no-pager
La salida debe mostrar Active: active (running).
Paso 2: Revisar la configuración y probar la API
Abre el fichero de configuración:
sudo nano /etc/typesense/typesense-server.ini
Tendrá un contenido parecido a este:
[server]
api-address = 0.0.0.0
api-port = 8108
data-dir = /var/lib/typesense
api-key = aB3dE5fG7hJ9kL1mN3pQ5rS7tU9vW1xY
log-dir = /var/log/typesense
Cambia api-address a 127.0.0.1. Así Typesense solo acepta conexiones locales y, en el paso 7, Nginx se encargará de publicarlo con HTTPS. Guarda el fichero y reinicia el servicio:
sudo systemctl restart typesense-server
La clave api-key es la clave de administración: permite crear y borrar colecciones y claves, así que nunca debe salir del servidor ni de tu backend. Guárdala en una variable para los siguientes comandos:
export TYPESENSE_API_KEY=$(sudo awk -F' *= *' '/^api-key/ {print $2}' /etc/typesense/typesense-server.ini)
Comprueba que el servidor responde. El endpoint /health no necesita clave:
curl http://127.0.0.1:8108/health
{"ok":true}
Instala jq, que usarás para leer las respuestas JSON con comodidad:
sudo apt install -y jq
Paso 3: Crear una colección
Una colección es el equivalente a una tabla: tiene un esquema con los campos que se indexan y su tipo. Los campos con "facet": true permiten contar y filtrar resultados por valor, y default_sorting_field debe ser numérico. Crea una colección de productos:
curl -s -X POST http://127.0.0.1:8108/collections \
-H "Content-Type: application/json" \
-H "X-TYPESENSE-API-KEY: ${TYPESENSE_API_KEY}" \
-d '{
"name": "productos",
"fields": [
{"name": "nombre", "type": "string"},
{"name": "descripcion", "type": "string"},
{"name": "categoria", "type": "string", "facet": true},
{"name": "marca", "type": "string", "facet": true},
{"name": "etiquetas", "type": "string[]", "facet": true},
{"name": "precio", "type": "float"},
{"name": "stock", "type": "int32"}
],
"default_sorting_field": "stock"
}' | jq '.name, .num_documents'
"productos"
0
No hace falta declarar el campo id: Typesense lo usa como identificador si viene en el documento y lo genera si no.
Paso 4: Indexar documentos
Para cargas masivas, el endpoint de importación acepta un documento JSON por línea (formato JSONL). Crea un fichero de ejemplo:
nano ~/productos.jsonl
{"id": "1", "nombre": "Camiseta básica de algodón", "descripcion": "Camiseta unisex de algodón 100 %", "categoria": "Ropa", "marca": "BasicWear", "etiquetas": ["ropa", "algodón"], "precio": 19.99, "stock": 150}
{"id": "2", "nombre": "Zapatillas de running", "descripcion": "Zapatillas ligeras con amortiguación", "categoria": "Calzado", "marca": "SpeedRun", "etiquetas": ["deporte", "running"], "precio": 89.99, "stock": 45}
{"id": "3", "nombre": "Pantalón vaquero slim", "descripcion": "Vaquero ajustado de corte moderno", "categoria": "Ropa", "marca": "DenimPro", "etiquetas": ["ropa", "vaquero"], "precio": 49.99, "stock": 80}
{"id": "4", "nombre": "Zapatillas de montaña", "descripcion": "Calzado impermeable para trail", "categoria": "Calzado", "marca": "TrailMax", "etiquetas": ["deporte", "montaña"], "precio": 119.00, "stock": 20}
Impórtalo. action=upsert crea los documentos nuevos y reemplaza los que ya existen con el mismo id, de modo que puedes repetir la importación sin errores:
curl -s -X POST "http://127.0.0.1:8108/collections/productos/documents/import?action=upsert" \
-H "Content-Type: text/plain" \
-H "X-TYPESENSE-API-KEY: ${TYPESENSE_API_KEY}" \
--data-binary @"$HOME/productos.jsonl"
{"success":true}
{"success":true}
{"success":true}
{"success":true}
Typesense devuelve una línea por documento. Si alguna muestra "success":false, el campo error indica qué campo no cumple el esquema.
Para actualizar solo algunos campos de un documento, usa PATCH:
curl -s -X PATCH http://127.0.0.1:8108/collections/productos/documents/1 \
-H "Content-Type: application/json" \
-H "X-TYPESENSE-API-KEY: ${TYPESENSE_API_KEY}" \
-d '{"precio": 17.99}' | jq '.precio'
17.99
Paso 5: Buscar con filtros, orden y facetas
Una búsqueda indica el texto (q) y los campos en los que buscar (query_by). Prueba con una palabra mal escrita para ver la tolerancia a errores:
curl -s -G http://127.0.0.1:8108/collections/productos/documents/search \
-H "X-TYPESENSE-API-KEY: ${TYPESENSE_API_KEY}" \
--data-urlencode "q=zapatilas" \
--data-urlencode "query_by=nombre,descripcion" \
| jq '.found, [.hits[].document.nombre]'
2
[
"Zapatillas de running",
"Zapatillas de montaña"
]
Ahora combina filtros, orden y facetas. filter_by restringe los resultados, sort_by los ordena y facet_by devuelve cuántos resultados hay por cada valor, que es lo que se usa para construir los filtros laterales de una tienda:
curl -s -G http://127.0.0.1:8108/collections/productos/documents/search \
-H "X-TYPESENSE-API-KEY: ${TYPESENSE_API_KEY}" \
--data-urlencode "q=*" \
--data-urlencode "query_by=nombre" \
--data-urlencode "filter_by=precio:<100" \
--data-urlencode "sort_by=precio:asc" \
--data-urlencode "facet_by=categoria" \
| jq '[.hits[].document | {nombre, precio}], .facet_counts[0].counts'
[
{ "nombre": "Camiseta básica de algodón", "precio": 17.99 },
{ "nombre": "Pantalón vaquero slim", "precio": 49.99 },
{ "nombre": "Zapatillas de running", "precio": 89.99 }
]
[
{ "count": 2, "highlighted": "Ropa", "value": "Ropa" },
{ "count": 1, "highlighted": "Calzado", "value": "Calzado" }
]
q=* devuelve todos los documentos, útil para listados filtrados. Para dar más peso a un campo que a otro, añade query_by_weights con un valor por cada campo de query_by.
Paso 6: Crear una clave de solo búsqueda
El navegador de tus usuarios nunca debe ver la clave de administración. Crea una clave que solo pueda buscar en la colección productos:
curl -s -X POST http://127.0.0.1:8108/keys \
-H "Content-Type: application/json" \
-H "X-TYPESENSE-API-KEY: ${TYPESENSE_API_KEY}" \
-d '{
"description": "Búsqueda pública en productos",
"actions": ["documents:search"],
"collections": ["productos"]
}' | jq -r '.value'
El comando imprime la clave nueva. Typesense solo la muestra en esta respuesta, así que guárdala. Comprueba que sirve para buscar pero no para administrar, sustituyendo your_search_key por su valor:
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8108/collections \
-H "X-TYPESENSE-API-KEY: your_search_key"
401
Es la clave que usarás en el frontend con el cliente oficial typesense de JavaScript o con el adaptador typesense-instantsearch-adapter.
Paso 7: Publicar la API con Nginx y HTTPS
Para que un frontend consulte Typesense desde el navegador, la API debe estar disponible por HTTPS. Instala Nginx y Certbot:
sudo apt install -y nginx certbot python3-certbot-nginx
Crea un sitio para el subdominio de búsqueda:
sudo nano /etc/nginx/sites-available/typesense
server {
listen 80;
server_name search.your_domain;
location / {
proxy_pass http://127.0.0.1:8108;
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;
}
}
Actívalo, comprueba la sintaxis y recarga Nginx:
sudo ln -s /etc/nginx/sites-available/typesense /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
Si usas UFW, permite HTTP y HTTPS (y SSH, antes de activarlo):
sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enable
Obtén el certificado de Let's Encrypt. Certbot modifica el sitio para servir HTTPS y redirigir HTTP:
sudo certbot --nginx -d search.your_domain
Comprueba el acceso desde fuera del servidor:
curl https://search.your_domain/health
{"ok":true}
El puerto 8108 sigue cerrado al exterior, porque Typesense solo escucha en 127.0.0.1.
Solución de problemas
El servicio no arranca. Revisa el journal y el log propio de Typesense:
sudo journalctl -u typesense-server -n 50 --no-pager
sudo tail -n 50 /var/log/typesense/typesense.log
Un error típico es un valor mal escrito en el .ini o un directorio de datos sin permisos después de moverlo.
Las peticiones devuelven 401 Forbidden - a valid x-typesense-api-key header must be sent. La cabecera falta o la clave no es correcta. Comprueba que echo "$TYPESENSE_API_KEY" muestra la misma clave que el .ini; la variable se pierde al cerrar la sesión.
Could not find a field named ... in the schema. El campo usado en query_by, filter_by o facet_by no está en el esquema, o no tiene "facet": true si lo usas en facet_by. Añade campos a una colección existente con PATCH /collections/productos.
El proceso consume mucha memoria o lo mata el OOM killer. El índice no cabe en la RAM. Indexa solo los campos que realmente buscas o filtras, o amplía la memoria del servidor.
Conclusión
Tienes Typesense funcionando en Ubuntu 24.04, con una colección de productos, búsquedas con tolerancia a errores, filtros y facetas, una clave pública limitada a búsquedas y la API publicada con HTTPS. Como siguientes pasos, conecta tu frontend con typesense-instantsearch-adapter, programa copias de seguridad con el endpoint de snapshots (POST /operations/snapshot) y, si necesitas alta disponibilidad, despliega un clúster de tres nodos siguiendo la guía de alta disponibilidad de Typesense.
