Meilisearch es un motor de búsqueda de código abierto escrito en Rust que devuelve resultados en milisegundos, tolera errores tipográficos y permite filtrar y ordenar sin apenas configuración. Se maneja entero a través de una API REST, lo que lo hace muy práctico para buscadores de tiendas online, documentación o catálogos. En este tutorial instalarás Meilisearch en Ubuntu 24.04 como servicio systemd en modo producción, crearás un índice con documentos de ejemplo, configurarás filtros y claves de API con permisos limitados, y lo publicarás detrás de Nginx con un certificado de Let's Encrypt.
Requisitos previos
- Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath, con al menos 1 GB de RAM (Meilisearch usa memoria mapeada, así que más RAM significa índices más rápidos).
- Un usuario no root con privilegios
sudo. - Un dominio o subdominio (en esta guía
search.your_domain) con un registro DNS A apuntando a la IP de tu servidor. - Nginx instalado y UFW activo con los puertos 22, 80 y 443 abiertos.
Paso 1: Descargar el binario de Meilisearch
Meilisearch se distribuye como un único binario estático. Descarga la última versión estable desde las releases oficiales de GitHub. Para servidores x86_64 usa meilisearch-linux-amd64; en arm64 el archivo se llama meilisearch-linux-aarch64:
curl -fsSL -o meilisearch https://github.com/meilisearch/meilisearch/releases/latest/download/meilisearch-linux-amd64
Instálalo en /usr/local/bin con permisos de ejecución:
sudo install -m 0755 meilisearch /usr/local/bin/meilisearch
rm meilisearch
Comprueba que funciona:
meilisearch --version
meilisearch 1.x.y
Paso 2: Crear el usuario y los directorios de datos
Meilisearch no debe ejecutarse como root. Crea un usuario de sistema sin shell con su directorio de trabajo en /var/lib/meilisearch:
sudo useradd --system --home-dir /var/lib/meilisearch --create-home --shell /usr/sbin/nologin meilisearch
Crea los directorios para la base de datos, los volcados (dumps) y las instantáneas (snapshots):
sudo install -d -o meilisearch -g meilisearch -m 0750 /var/lib/meilisearch/data /var/lib/meilisearch/dumps /var/lib/meilisearch/snapshots
Paso 3: Configurar la clave maestra y el modo producción
En modo producción Meilisearch exige una clave maestra (master key) de al menos 16 bytes y desactiva el panel web de pruebas. Genera una clave aleatoria:
openssl rand -base64 32
k3Vq8fN0y2Qe7Zr1bLx9Hm4Tw6Pc5Ds0Aa2Ug8Jn1Ro=
Guarda ese valor en un gestor de contraseñas y crea el archivo de configuración:
sudo nano /etc/meilisearch.toml
Añade el siguiente contenido, sustituyendo your_master_key por la clave generada:
env = "production"
master_key = "your_master_key"
db_path = "/var/lib/meilisearch/data"
dump_dir = "/var/lib/meilisearch/dumps"
snapshot_dir = "/var/lib/meilisearch/snapshots"
http_addr = "127.0.0.1:7700"
Con http_addr = "127.0.0.1:7700" Meilisearch solo escucha en localhost; el acceso desde fuera pasará por Nginx. Como el archivo contiene la clave maestra, restringe sus permisos:
sudo chown root:meilisearch /etc/meilisearch.toml
sudo chmod 0640 /etc/meilisearch.toml
Paso 4: Ejecutar Meilisearch como servicio systemd
Crea la unidad de systemd:
sudo nano /etc/systemd/system/meilisearch.service
[Unit]
Description=Meilisearch
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=meilisearch
Group=meilisearch
WorkingDirectory=/var/lib/meilisearch
ExecStart=/usr/local/bin/meilisearch --config-file-path /etc/meilisearch.toml
Restart=on-failure
[Install]
WantedBy=multi-user.target
Recarga systemd y arranca el servicio:
sudo systemctl daemon-reload
sudo systemctl enable --now meilisearch
Comprueba el estado y el endpoint de salud, que no requiere autenticación:
systemctl status meilisearch --no-pager
curl -s http://127.0.0.1:7700/health
{"status":"available"}
Si el servicio no arranca, revisa el log con sudo journalctl -u meilisearch -n 50. El error más habitual es una clave maestra demasiado corta.
Paso 5: Obtener las claves de API
La clave maestra solo debe usarse para administrar claves, no desde las aplicaciones. Al arrancar, Meilisearch crea dos claves por defecto: una de búsqueda y otra de administración. Guarda la clave maestra en una variable de la sesión y lístalas:
export MEILI_MASTER_KEY='your_master_key'
curl -s http://127.0.0.1:7700/keys -H "Authorization: Bearer $MEILI_MASTER_KEY"
La respuesta incluye, entre otros campos, el nombre y el valor de cada clave:
{"results":[{"name":"Default Search API Key","description":"Use it to search from the frontend","key":"8dbb...","actions":["search"],"indexes":["*"],...},{"name":"Default Admin API Key","description":"Use it for anything that is not a search operation. Caution! Do not expose it on a public frontend","key":"f6f3...",...}],...}
Guarda la clave de administración en otra variable para los siguientes pasos:
export MEILI_ADMIN_KEY='your_admin_api_key'
Paso 6: Crear un índice y añadir documentos
Un índice es una colección de documentos JSON con un identificador único (clave primaria). Crea un archivo con algunos documentos de ejemplo:
nano movies.json
[
{ "id": 1, "title": "Blade Runner", "genre": "ciencia ficción", "year": 1982 },
{ "id": 2, "title": "El laberinto del fauno", "genre": "fantasía", "year": 2006 },
{ "id": 3, "title": "Interstellar", "genre": "ciencia ficción", "year": 2014 },
{ "id": 4, "title": "Amélie", "genre": "comedia", "year": 2001 }
]
Envíalos al índice movies. Si el índice no existe, Meilisearch lo crea y detecta id como clave primaria:
curl -s -X POST 'http://127.0.0.1:7700/indexes/movies/documents' \
-H "Authorization: Bearer $MEILI_ADMIN_KEY" \
-H 'Content-Type: application/json' \
--data-binary @movies.json
{"taskUid":0,"indexUid":"movies","status":"enqueued","type":"documentAdditionOrUpdate","enqueuedAt":"2026-09-25T10:00:00.000000Z"}
Las escrituras en Meilisearch son asíncronas: la API encola una tarea y responde al momento. Consulta su estado con el taskUid devuelto:
curl -s 'http://127.0.0.1:7700/tasks/0' -H "Authorization: Bearer $MEILI_ADMIN_KEY"
Cuando el campo status valga succeeded, los documentos ya se pueden buscar. Prueba una búsqueda con una errata intencionada:
curl -s -X POST 'http://127.0.0.1:7700/indexes/movies/search' \
-H "Authorization: Bearer $MEILI_ADMIN_KEY" \
-H 'Content-Type: application/json' \
--data '{ "q": "intrestelar" }'
{"hits":[{"id":3,"title":"Interstellar","genre":"ciencia ficción","year":2014}],"query":"intrestelar","processingTimeMs":1,"limit":20,"offset":0,"estimatedTotalHits":1}
La tolerancia a errores tipográficos está activada por defecto, por eso encuentra "Interstellar".
Paso 7: Configurar filtros, ordenación y campos de búsqueda
Para filtrar u ordenar por un campo hay que declararlo antes en la configuración del índice. También conviene indicar qué campos se buscan y en qué orden de importancia:
curl -s -X PATCH 'http://127.0.0.1:7700/indexes/movies/settings' \
-H "Authorization: Bearer $MEILI_ADMIN_KEY" \
-H 'Content-Type: application/json' \
--data '{
"searchableAttributes": ["title", "genre"],
"filterableAttributes": ["genre", "year"],
"sortableAttributes": ["year"]
}'
Este cambio también genera una tarea y reindexa los documentos. Cuando termine, combina búsqueda, filtro y ordenación:
curl -s -X POST 'http://127.0.0.1:7700/indexes/movies/search' \
-H "Authorization: Bearer $MEILI_ADMIN_KEY" \
-H 'Content-Type: application/json' \
--data '{ "q": "", "filter": "genre = \"ciencia ficción\" AND year > 2000", "sort": ["year:desc"] }'
{"hits":[{"id":3,"title":"Interstellar","genre":"ciencia ficción","year":2014}],"query":"","processingTimeMs":0,"limit":20,"offset":0,"estimatedTotalHits":1}
Paso 8: Crear una clave de búsqueda limitada a un índice
La clave que uses en el navegador del usuario solo debe permitir buscar, y a ser posible solo en los índices necesarios. Crea una con la clave maestra:
curl -s -X POST 'http://127.0.0.1:7700/keys' \
-H "Authorization: Bearer $MEILI_MASTER_KEY" \
-H 'Content-Type: application/json' \
--data '{
"name": "frontend-movies",
"description": "Búsqueda pública en movies",
"actions": ["search"],
"indexes": ["movies"],
"expiresAt": null
}'
El campo key de la respuesta es la clave que puedes incluir en tu frontend. Compruébalo: una búsqueda en movies funciona, pero intentar añadir documentos devuelve un error invalid_api_key:
curl -s -X POST 'http://127.0.0.1:7700/indexes/movies/documents' \
-H 'Authorization: Bearer your_search_key' \
-H 'Content-Type: application/json' \
--data '[{"id": 5, "title": "Prueba"}]'
{"message":"The provided API key is invalid.","code":"invalid_api_key","type":"auth","link":"https://docs.meilisearch.com/errors#invalid_api_key"}
Paso 9: Publicar Meilisearch con Nginx y HTTPS
Crea un bloque de servidor para el subdominio:
sudo nano /etc/nginx/sites-available/meilisearch
server {
listen 80;
listen [::]:80;
server_name search.your_domain;
client_max_body_size 100M;
location / {
proxy_pass http://127.0.0.1:7700;
proxy_http_version 1.1;
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;
}
}
client_max_body_size 100M coincide con el tamaño máximo de carga que acepta Meilisearch por defecto, para que Nginx no corte las importaciones grandes. Activa el sitio y recarga Nginx:
sudo ln -s /etc/nginx/sites-available/meilisearch /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
Obtén el certificado con Certbot, que modificará el bloque para servir HTTPS y redirigir HTTP:
sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d search.your_domain
Verifica el acceso externo desde tu equipo:
curl -s https://search.your_domain/health
{"status":"available"}
Paso 10: Crear copias de seguridad con snapshots
Una snapshot es una copia exacta de la base de datos que se restaura rápidamente en la misma versión de Meilisearch. Lánzala con la clave de administración:
curl -s -X POST 'http://127.0.0.1:7700/snapshots' -H "Authorization: Bearer $MEILI_ADMIN_KEY"
Cuando la tarea termine, el archivo aparecerá en el directorio configurado:
sudo ls -lh /var/lib/meilisearch/snapshots
Para migrar entre versiones de Meilisearch usa un dump (POST /dumps), que se guarda en /var/lib/meilisearch/dumps y es compatible entre versiones. Copia ambos tipos de archivo fuera del servidor.
Solución de problemas
missing_authorization_headeroinvalid_api_key: falta la cabeceraAuthorization: Bearer ...o la clave no tiene permiso para esa acción o índice.- El filtro devuelve
invalid_search_filter: el campo no está enfilterableAttributes, o la tarea de configuración aún no ha terminado. Revísalo enGET /tasks. - Nginx responde 413 al importar: sube
client_max_body_sizeo divide el JSON en lotes más pequeños. - El servicio no arranca tras actualizar el binario: la base de datos de una versión anterior puede no ser compatible. Crea un dump con la versión antigua e impórtalo en la nueva con la opción
--import-dump.
Conclusión
Tienes Meilisearch funcionando en Ubuntu 24.04 en modo producción, con una clave maestra, claves de API con permisos mínimos y acceso público solo a través de Nginx con HTTPS. Como siguientes pasos, puedes conectar tu aplicación con uno de los SDK oficiales (JavaScript, Python, PHP, Go...), configurar sinónimos y palabras vacías en los ajustes del índice, y programar snapshots periódicas con un temporizador de systemd.
