Skip to main contentSkip to navigation
[email protected]
Client AreaSupport
Hosting Mammoth
HostingMammothYour Data, Our Responsibility
Home
Solutions
Hosting Services
Store
Pricing
About
Blog
API
Contact

Stay Ahead of the Curve

Get the latest insights on cybersecurity, AI innovations, and enterprise data solutions delivered to your inbox.

Hosting Mammoth
HostingMammothEnterprise Solutions

Enterprise-grade data solutions. Hosting, recovery, cybersecurity, and AI-powered services for businesses worldwide.

[email protected]
Sun - Fri, 9:00am - 5:00pm

Services

  • Cloud Hosting
  • Data Recovery
  • Cybersecurity
  • Legal Support
  • MSP Services
  • Web Development
  • AI Services
  • Free Server Migration

Hosting

  • VPS Hosting (NVMe SSD)
  • VDS Hosting (NVMe)
  • Storage VPS (High SSD)
  • GPU Servers
  • Managed Services
  • Cloud Firewall
  • Load Balancer
  • One-Click Apps
  • n8n Hosting
  • Object Storage
  • FAQ

Company

  • Store
  • Pricing
  • About Us
  • Locations
  • Blog
  • Testimonials
  • Contact
  • Affiliate Program
  • White-Label
  • Terms of Service
  • Privacy Policy
  • Browser Cookies
  • SLA

Support

  • Client Area
  • Submit Ticket
  • Knowledge Base
  • Server Status
  • API Documentation

© 2026 Hosting Mammoth. All rights reserved.

Knowledge Base
Getting StartedAccount ManagementVPS HostingGPU ServersStorage VPSCloud FirewallLoad BalancerServer ManagementBilling & PaymentsSupport & TicketsAffiliate ProgramReseller ProgramMarketplace & Appsn8n HostingManaged ServicesServer MigrationAPI & DevelopersSecurityTroubleshootingGlossaryInstall Guides
  1. Home
  2. /
  3. Support
  4. /
  5. Install Guides
  6. /
  7. How To Install Meilisearch Ubuntu
GUIDEInstall Guides

How to Install Meilisearch on Ubuntu 24.04 VPS: Lightning-Fast Open-Source Search Engine

28 min read

How to Install Meilisearch on Ubuntu 24.04 VPS: Lightning-Fast Open-Source Search Engine

Search is one of those features your users only notice when it is bad. Slow autocomplete, irrelevant results, zero-tolerance for typos -- any of these will tank engagement no matter how good the rest of your product is. Meilisearch is an open-source, Rust-based search engine that solves all three problems out of the box, with a developer experience that rivals Algolia and costs you nothing beyond the VPS it runs on. This guide walks you through installing Meilisearch on an Ubuntu 24.04 VPS, from package install to a production deployment with HTTPS, tenant tokens, and automated backups.

Self-hosting search saves real money. Algolia's pricing starts around $0.50 per 1,000 search requests and scales to thousands of dollars per month for medium-traffic apps. A Meilisearch instance on a CloudCore Starter VPS handles millions of searches per month at a flat rate.

Table of Contents

  • What is Meilisearch?
  • Why Self-Host Meilisearch?
  • Prerequisites
  • Step 1: Update System Packages
  • Step 2: Install Meilisearch
  • Step 3: Configure the Master Key and Environment
  • Step 4: Create the systemd Service
  • Step 5: Verify the Installation
  • Step 6: Create an Index and Add Documents
  • Step 7: Configure Index Settings
  • Step 8: Manage API Keys and Tenant Tokens
  • Step 9: Set Up Nginx Reverse Proxy with TLS
  • Step 10: Enable Snapshots and Dumps
  • Using the Built-in Search Preview Dashboard
  • Official SDKs
  • Troubleshooting
  • FAQ
  • Next Steps
  • What is Meilisearch?

    Meilisearch is an open-source, lightning-fast, typo-tolerant search engine written in Rust. It is distributed as a single static binary -- no JVM, no Python runtime, no external dependencies -- which makes it trivially easy to deploy on any Linux server. Under the hood it uses an LMDB-backed inverted index with custom ranking rules, and it returns results in under 50 milliseconds for most datasets, even on modest hardware.

    Meilisearch is designed around the concept of instant search: as the user types, results update on every keystroke. To make this feel natural, the engine ships with typo tolerance, prefix search, synonyms, and a ranking pipeline that can be reordered per index. You define searchable, filterable, and sortable attributes declaratively, and the engine handles the rest.

    The feature set covers the needs of the vast majority of product, content, and documentation search use cases. You get full-text search with typo tolerance (up to 2 typos by default, configurable per query), faceted filtering (for category, price-range, status pickers), geo-search (radius and bounding-box queries using _geo attributes), multi-index federated search (query multiple indexes in one request), ranking rules (typo, words, proximity, attribute, sort, exactness), synonyms and stop words, highlighting and cropping of matched snippets, and a built-in search preview dashboard served at the root URL. Since version 1.6, Meilisearch also ships with hybrid search, combining keyword search with vector embeddings for semantic matching -- useful for RAG applications and semantic product discovery.

    Typical use cases include e-commerce product search, documentation and knowledge base search, SaaS in-app search across customer data, media and article search for news sites, and embedded search for mobile apps. If you have a database table with more than a few thousand rows that users want to search through with typeahead, Meilisearch is almost certainly the right answer.

    Why Self-Host Meilisearch?

    Running search on your own VPS instead of paying a hosted service offers concrete advantages, especially as traffic grows:

    • Predictable flat-rate pricing -- Algolia charges per search request and per indexed record. At scale, this becomes one of the largest line items in a SaaS infrastructure budget. Meilisearch on a VPS costs the same whether you handle 10,000 or 10 million searches per month.
    • No per-record fees -- Algolia's record count metric penalizes apps with large catalogs or fine-grained nested documents. Self-hosted Meilisearch has no document-count limit beyond what your disk and RAM allow.
    • Data sovereignty -- Your users' search queries and your indexed data never leave your infrastructure. For GDPR, HIPAA, and SOC 2 compliance, keeping search on-premises eliminates an entire class of vendor risk.
    • Lower latency for colocated apps -- When your application server and Meilisearch live in the same data center (or the same machine), round-trip time drops to sub-millisecond levels. Hosted search APIs add 20-100 ms of network overhead on every query.
    • Full customization -- Tune ranking rules, add custom stop words, plug in your own embeddings model for hybrid search. No vendor lock-in, no feature gating by plan tier.
    • Open source -- MIT-licensed. Fork it, audit it, embed it in a commercial product. No license fees, no runtime royalties.

    Cost Comparison: Self-Hosted Meilisearch vs. Algolia

    ScenarioAlgoliaMeilisearch CloudSelf-Hosted Meilisearch (VPS)
    100K records, 100K searches/mo~$100-200/mo~$30/moEUR 7.50/mo (flat)
    1M records, 1M searches/mo~$1,000-2,500/mo~$150/moEUR 19.99/mo (flat)
    10M records, 10M searches/mo~$5,000-15,000/mo~$500+/moEUR 49/mo (flat)
    Search latency (p95)20-80 ms (edge)30-100 ms5-30 ms (same DC)
    Data residency controlLimitedLimitedFull
    Custom ranking rulesYesYesYes
    Tenant tokensYesYesYes
    For any application beyond the smallest prototype, self-hosted Meilisearch typically pays for itself within the first month and saves orders of magnitude as traffic grows.

    Prerequisites

    Before you begin, make sure you have:

    • A VPS running Ubuntu 24.04 LTS with root or sudo access
    • SSH access to your server
    • A domain name pointing to the server (required for HTTPS in Step 9)
    • At least 2 GB of RAM for datasets up to ~1 million documents (4 GB+ recommended for production)
    • At least 20 GB of free disk space (index size is typically 1.5-3x the raw JSON document size)
    Recommended Plan: CloudCore Starter
    >
    For up to ~1 million documents and steady search traffic, the CloudCore Starter plan is a great fit:
    >
    - 4 vCPU cores
    - 8 GB RAM
    - 100 GB NVMe SSD
    - Unmetered bandwidth
    >
    This gives Meilisearch enough memory to keep your full index mapped in RAM for sub-10ms query times, plus headroom for an application stack on the same server. For larger indexes (10M+ documents), scale up to CloudCore Professional or dedicate a separate VPS to search.

    Connect to your server via SSH:

    bash
    ssh root@your-server-ip

    Step 1: Update System Packages

    Start by updating the package index and installed packages. This ensures clean dependency resolution when you add the Meilisearch apt repository.

    bash
    sudo apt update && sudo apt upgrade -y

    Install a few utilities you will need throughout this guide:

    bash
    sudo apt install -y curl gnupg apt-transport-https ca-certificates jq

    If your kernel was upgraded, reboot before continuing:

    bash
    sudo reboot

    Step 2: Install Meilisearch

    Meilisearch provides two supported installation paths on Ubuntu: the official apt repository hosted on Gemfury, or the one-line curl installer. The apt method is recommended for production because it integrates with unattended upgrades.

    Option A: Install via apt (recommended)

    Add the Meilisearch apt repository and install the package:

    bash
    # Add the GPG key and repository
    echo "deb [trusted=yes] https://apt.fury.io/meilisearch/ /" | \
      sudo tee /etc/apt/sources.list.d/meilisearch.list

    sudo apt update sudo apt install -y meilisearch

    Verify the binary is installed:

    bash
    meilisearch --version

    Expected output:

    text
    meilisearch 1.11.0

    The apt package installs the meilisearch binary to /usr/bin/meilisearch. It does not create a systemd service automatically -- you will do that in Step 4.

    Option B: Install via curl (alternative)

    If you prefer to pin a specific version or cannot add third-party apt repositories, use the official install script:

    bash
    curl -L https://install.meilisearch.com | sh
    sudo mv ./meilisearch /usr/local/bin/

    Verify:

    bash
    /usr/local/bin/meilisearch --version

    Step 3: Configure the Master Key and Environment

    Meilisearch has two runtime modes: development (no auth, verbose logs) and production (authentication required, minimal logs). Always use production mode on any internet-reachable server.

    Create the data directory and user

    bash
    sudo useradd -r -s /bin/false -M meilisearch
    sudo mkdir -p /var/lib/meilisearch/data
    sudo mkdir -p /var/lib/meilisearch/dumps
    sudo mkdir -p /var/lib/meilisearch/snapshots
    sudo chown -R meilisearch:meilisearch /var/lib/meilisearch

    Generate a strong master key

    The master key is the root credential for your Meilisearch instance. Anyone with it has full admin control. Generate 48 random bytes and base64-encode them:

    bash
    openssl rand -base64 48

    Copy the output -- you will use it in the config file. Example (do not use this exact key):

    text
    Ht3k9sQvX2mY7NpLaRb8Zf4WjC5VyT6DxH1GqE0KpM3s

    Create the configuration file

    Meilisearch reads settings from /etc/meilisearch.toml by default when invoked with --config-file-path. Create it:

    bash
    sudo tee /etc/meilisearch.toml > /dev/null <<'EOF'
    

    ============================================================================

    Meilisearch configuration

    ============================================================================

    Master API key (REQUIRED in production). Minimum 16 bytes.

    master_key = "REPLACE_WITH_YOUR_GENERATED_KEY"

    Runtime environment. "production" enables auth; "development" disables it.

    env = "production"

    Address Meilisearch listens on. Keep 127.0.0.1 when using an Nginx proxy.

    http_addr = "127.0.0.1:7700"

    Where Meilisearch stores indexes on disk.

    db_path = "/var/lib/meilisearch/data"

    Dumps directory (portable backups).

    dump_dir = "/var/lib/meilisearch/dumps"

    Snapshots directory (fast binary backups).

    snapshot_dir = "/var/lib/meilisearch/snapshots"

    Enable automatic snapshots every 24 hours (in seconds).

    schedule_snapshot = 86400

    Log level: ERROR, WARN, INFO, DEBUG, TRACE

    log_level = "INFO"

    Max size of the indexing task queue.

    max_indexing_memory = "2 GiB" max_indexing_threads = 2 EOF

    Replace REPLACE_WITH_YOUR_GENERATED_KEY with the key you generated:

    bash
    sudo nano /etc/meilisearch.toml

    Secure the config file -- it contains the master key:

    bash
    sudo chown meilisearch:meilisearch /etc/meilisearch.toml
    sudo chmod 600 /etc/meilisearch.toml
    Alternative: environment variables. If you prefer not to use a config file, Meilisearch accepts the same settings via env vars: MEILI_MASTER_KEY, MEILI_ENV=production, MEILI_HTTP_ADDR, MEILI_DB_PATH, MEILI_DUMP_DIR, MEILI_SNAPSHOT_DIR, MEILI_SCHEDULE_SNAPSHOT. Set them in the systemd unit's Environment= directives.

    Step 4: Create the systemd Service

    The apt package does not ship a systemd unit file, so create one now. This ensures Meilisearch starts on boot and restarts on crash.

    bash
    sudo tee /etc/systemd/system/meilisearch.service > /dev/null <<'EOF'
    [Unit]
    Description=Meilisearch search engine
    After=network.target
    Documentation=https://www.meilisearch.com/docs

    [Service] Type=simple User=meilisearch Group=meilisearch ExecStart=/usr/bin/meilisearch --config-file-path /etc/meilisearch.toml Restart=on-failure RestartSec=5s

    Hardening

    NoNewPrivileges=true PrivateTmp=true ProtectSystem=strict ProtectHome=true ReadWritePaths=/var/lib/meilisearch LimitNOFILE=65536

    [Install] WantedBy=multi-user.target EOF

    If you installed Meilisearch via the curl installer (Option B in Step 2), replace /usr/bin/meilisearch with /usr/local/bin/meilisearch.

    Reload systemd, then enable and start the service:

    bash
    sudo systemctl daemon-reload
    sudo systemctl enable meilisearch
    sudo systemctl start meilisearch

    Check the service status:

    bash
    sudo systemctl status meilisearch

    Expected output (abbreviated):

    text
    ● meilisearch.service - Meilisearch search engine
         Loaded: loaded (/etc/systemd/system/meilisearch.service; enabled)
         Active: active (running) since Wed 2026-04-16 10:00:00 UTC; 5s ago
       Main PID: 1456 (meilisearch)
          Tasks: 8 (limit: 9321)
         Memory: 52.0M
         CGroup: /system.slice/meilisearch.service
                 └─1456 /usr/bin/meilisearch --config-file-path /etc/meilisearch.toml

    Step 5: Verify the Installation

    Store your master key in a shell variable so you do not have to retype it:

    bash
    export MEILI_KEY="REPLACE_WITH_YOUR_GENERATED_KEY"

    Ping the health endpoint -- it requires no auth:

    bash
    curl http://localhost:7700/health

    Expected output:

    json
    {"status":"available"}

    Fetch server version (requires auth in production mode):

    bash
    curl -H "Authorization: Bearer $MEILI_KEY" http://localhost:7700/version

    Expected output:

    json
    {
      "commitSha": "abc1234...",
      "commitDate": "2026-01-15T10:00:00Z",
      "pkgVersion": "1.11.0"
    }

    List existing indexes (should be empty):

    bash
    curl -H "Authorization: Bearer $MEILI_KEY" http://localhost:7700/indexes

    Expected output:

    json
    {"results":[],"offset":0,"limit":20,"total":0}

    Meilisearch is running and authenticated. Next, load some data.

    Step 6: Create an Index and Add Documents

    Meilisearch auto-creates indexes when you add documents to them -- no separate "create index" step required. You just need to pick a primary key: the field Meilisearch uses to uniquely identify each document. If your documents have an id field, Meilisearch detects it automatically.

    Add documents to a new index

    Create a sample dataset of movies:

    bash
    cat > /tmp/movies.json <<'EOF'
    [
      {"id": 1, "title": "The Matrix", "year": 1999, "genre": "Sci-Fi", "rating": 8.7},
      {"id": 2, "title": "Inception", "year": 2010, "genre": "Sci-Fi", "rating": 8.8},
      {"id": 3, "title": "The Dark Knight", "year": 2008, "genre": "Action", "rating": 9.0},
      {"id": 4, "title": "Interstellar", "year": 2014, "genre": "Sci-Fi", "rating": 8.6},
      {"id": 5, "title": "Parasite", "year": 2019, "genre": "Thriller", "rating": 8.5}
    ]
    EOF

    POST them to the movies index:

    bash
    curl -X POST "http://localhost:7700/indexes/movies/documents" \
      -H "Authorization: Bearer $MEILI_KEY" \
      -H "Content-Type: application/json" \
      --data-binary @/tmp/movies.json

    Expected output:

    json
    {
      "taskUid": 0,
      "indexUid": "movies",
      "status": "enqueued",
      "type": "documentAdditionOrUpdate",
      "enqueuedAt": "2026-04-16T10:15:00Z"
    }

    Indexing is asynchronous. Poll the task endpoint to confirm completion:

    bash
    curl -H "Authorization: Bearer $MEILI_KEY" http://localhost:7700/tasks/0

    Look for "status": "succeeded" in the response. For small datasets like this one, indexing completes in milliseconds.

    Run your first search

    bash
    curl -X POST "http://localhost:7700/indexes/movies/search" \
      -H "Authorization: Bearer $MEILI_KEY" \
      -H "Content-Type: application/json" \
      --data-binary '{"q": "matrix"}'

    Expected output:

    json
    {
      "hits": [
        {"id": 1, "title": "The Matrix", "year": 1999, "genre": "Sci-Fi", "rating": 8.7}
      ],
      "query": "matrix",
      "processingTimeMs": 1,
      "limit": 20,
      "offset": 0,
      "estimatedTotalHits": 1
    }

    Try typo tolerance -- query "matirx" (typo):

    bash
    curl -X POST "http://localhost:7700/indexes/movies/search" \
      -H "Authorization: Bearer $MEILI_KEY" \
      -H "Content-Type: application/json" \
      --data-binary '{"q": "matirx"}'

    Meilisearch still returns The Matrix. That is the out-of-the-box typo tolerance at work.

    Step 7: Configure Index Settings

    By default, all fields are searchable, none are filterable, and none are sortable. Tuning these settings is what turns Meilisearch from "search that works" into "search that feels instant and precise."

    Set searchable attributes (order matters for ranking)

    bash
    curl -X PUT "http://localhost:7700/indexes/movies/settings/searchable-attributes" \
      -H "Authorization: Bearer $MEILI_KEY" \
      -H "Content-Type: application/json" \
      --data-binary '["title", "genre"]'

    Fields listed earlier get higher ranking weight. Here, a match in title outranks a match in genre.

    Set filterable attributes

    Filterable attributes enable filter expressions in search requests (e.g., year > 2010, genre = "Sci-Fi"):

    bash
    curl -X PUT "http://localhost:7700/indexes/movies/settings/filterable-attributes" \
      -H "Authorization: Bearer $MEILI_KEY" \
      -H "Content-Type: application/json" \
      --data-binary '["genre", "year", "rating"]'

    Now you can run filtered searches:

    bash
    curl -X POST "http://localhost:7700/indexes/movies/search" \
      -H "Authorization: Bearer $MEILI_KEY" \
      -H "Content-Type: application/json" \
      --data-binary '{
        "q": "",
        "filter": "year > 2010 AND genre = \"Sci-Fi\""
      }'

    Set sortable attributes

    bash
    curl -X PUT "http://localhost:7700/indexes/movies/settings/sortable-attributes" \
      -H "Authorization: Bearer $MEILI_KEY" \
      -H "Content-Type: application/json" \
      --data-binary '["rating", "year"]'

    Sort results by rating descending:

    bash
    curl -X POST "http://localhost:7700/indexes/movies/search" \
      -H "Authorization: Bearer $MEILI_KEY" \
      -H "Content-Type: application/json" \
      --data-binary '{
        "q": "",
        "sort": ["rating:desc"]
      }'

    Configure ranking rules

    The default ranking pipeline is excellent for most use cases, but you can reorder or add custom rules. For example, prioritize higher-rated movies:

    bash
    curl -X PUT "http://localhost:7700/indexes/movies/settings/ranking-rules" \
      -H "Authorization: Bearer $MEILI_KEY" \
      -H "Content-Type: application/json" \
      --data-binary '[
        "words",
        "typo",
        "proximity",
        "attribute",
        "sort",
        "exactness",
        "rating:desc"
      ]'

    Add synonyms

    bash
    curl -X PUT "http://localhost:7700/indexes/movies/settings/synonyms" \
      -H "Authorization: Bearer $MEILI_KEY" \
      -H "Content-Type: application/json" \
      --data-binary '{
        "sci-fi": ["science fiction", "scifi"],
        "film": ["movie"]
      }'

    Now searching for "science fiction" matches documents tagged "Sci-Fi".

    Step 8: Manage API Keys and Tenant Tokens

    The master key is too powerful to ship to a browser or embed in a mobile app. Meilisearch provides two lower-privilege credential types: API keys (scoped to specific actions and indexes) and tenant tokens (JWTs derived from an API key that add row-level filters).

    List default keys

    Meilisearch auto-generates two keys on first boot. List them:

    bash
    curl -H "Authorization: Bearer $MEILI_KEY" http://localhost:7700/keys | jq

    You will see:

    • Default Admin API Key -- full access except managing other keys
    • Default Search API Key -- search-only, safe to expose in frontend code
    Copy the key value of the search key. That is what you embed in your frontend JavaScript.

    Create a custom scoped API key

    Create a key that can only search the movies index:

    bash
    curl -X POST "http://localhost:7700/keys" \
      -H "Authorization: Bearer $MEILI_KEY" \
      -H "Content-Type: application/json" \
      --data-binary '{
        "description": "Frontend search key for movies",
        "actions": ["search"],
        "indexes": ["movies"],
        "expiresAt": "2027-01-01T00:00:00Z"
      }'

    Tenant tokens (multi-tenant row-level security)

    Tenant tokens are the killer feature for SaaS apps. They are JWTs signed with a Meilisearch API key, containing a searchRules claim that enforces a filter on every search. Each customer gets a different token, each token pins a different filter, all on a single shared index.

    Generate one in Node.js using the official SDK:

    javascript
    import { Meilisearch } from 'meilisearch';

    const client = new Meilisearch({ host: 'https://search.yourdomain.com', apiKey: 'YOUR_ADMIN_KEY', });

    const apiKeyUid = 'the-uid-of-a-search-api-key';

    const tenantToken = await client.generateTenantToken( apiKeyUid, { movies: { filter: 'customerId = "customer_42"', }, }, { expiresAt: new Date('2026-12-31') } );

    // Hand this token to customer_42's browser.

    When the browser uses this token to search the movies index, Meilisearch automatically appends customerId = "customer_42" to every query. Even if the client manipulates the request, they cannot see other customers' documents.

    Step 9: Set Up Nginx Reverse Proxy with TLS

    Meilisearch speaks plain HTTP. Never expose it directly to the internet. Put Nginx in front of it for TLS termination, rate limiting, and optional basic auth on admin endpoints.

    Install Nginx and Certbot

    bash
    sudo apt install -y nginx certbot python3-certbot-nginx

    Open the firewall

    bash
    sudo ufw allow 'Nginx Full'
    sudo ufw allow OpenSSH
    sudo ufw --force enable

    Create the Nginx site

    Replace search.yourdomain.com with your actual domain:

    bash
    sudo tee /etc/nginx/sites-available/meilisearch > /dev/null <<'EOF'
    

    Rate limit search endpoints

    limit_req_zone $binary_remote_addr zone=meili_search:10m rate=30r/s;

    server { listen 80; server_name search.yourdomain.com; return 301 https://$host$request_uri; }

    server { listen 443 ssl http2; server_name search.yourdomain.com;

    # SSL certs filled in by Certbot ssl_certificate /etc/letsencrypt/live/search.yourdomain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/search.yourdomain.com/privkey.pem;

    # Security headers add_header Strict-Transport-Security "max-age=63072000" always; add_header X-Content-Type-Options nosniff; add_header X-Frame-Options DENY;

    client_max_body_size 100m;

    # Apply rate limit to search endpoints location ~ ^/indexes/[^/]+/search$ { limit_req zone=meili_search burst=50 nodelay; proxy_pass http://127.0.0.1:7700; 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; }

    location / { proxy_pass http://127.0.0.1:7700; 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; proxy_read_timeout 300s; } } EOF

    sudo ln -s /etc/nginx/sites-available/meilisearch /etc/nginx/sites-enabled/

    Obtain a Let's Encrypt certificate

    bash
    sudo certbot --nginx -d search.yourdomain.com
    sudo nginx -t && sudo systemctl reload nginx

    Test end-to-end:

    bash
    curl https://search.yourdomain.com/health

    Expected output:

    json
    {"status":"available"}

    Step 10: Enable Snapshots and Dumps

    Meilisearch supports two backup mechanisms. Use both.

    Snapshots are fast binary copies of the data directory. They are point-in-time and tied to the exact Meilisearch version. Ideal for crash recovery.

    Dumps are portable JSON exports. Slower to produce and restore, but they work across Meilisearch versions -- essential for upgrades and cross-environment migrations.

    Snapshots (already enabled)

    Snapshots are already scheduled every 24 hours thanks to schedule_snapshot = 86400 in /etc/meilisearch.toml. Verify they are being written:

    bash
    ls -lh /var/lib/meilisearch/snapshots/

    Trigger an on-demand snapshot via the API:

    bash
    curl -X POST -H "Authorization: Bearer $MEILI_KEY" \
      http://localhost:7700/snapshots

    Dumps (on-demand)

    Generate a dump:

    bash
    curl -X POST -H "Authorization: Bearer $MEILI_KEY" \
      http://localhost:7700/dumps

    Expected output:

    json
    {
      "taskUid": 42,
      "status": "enqueued",
      "type": "dumpCreation",
      "enqueuedAt": "2026-04-16T10:30:00Z"
    }

    The dump file appears in /var/lib/meilisearch/dumps/ as a .dump file.

    Automate off-site backups with cron

    Ship dumps to S3-compatible storage nightly:

    bash
    sudo tee /usr/local/bin/meili-backup.sh > /dev/null <<'EOF'
    #!/bin/bash
    set -euo pipefail
    MEILI_KEY="your-master-key"
    TIMESTAMP=$(date +%Y%m%d-%H%M%S)
    BUCKET="s3://your-backup-bucket/meilisearch"

    Trigger a dump

    curl -sS -X POST -H "Authorization: Bearer $MEILI_KEY" \ http://localhost:7700/dumps >/dev/null

    Wait for dump to complete (simple poll)

    sleep 60

    Upload latest dump

    LATEST=$(ls -t /var/lib/meilisearch/dumps/*.dump | head -1) aws s3 cp "$LATEST" "$BUCKET/dump-$TIMESTAMP.dump"

    Keep only 30 local dumps

    ls -t /var/lib/meilisearch/dumps/*.dump | tail -n +31 | xargs -r rm EOF

    sudo chmod 700 /usr/local/bin/meili-backup.sh sudo chown root:root /usr/local/bin/meili-backup.sh

    Schedule it:

    bash
    echo "0 3   * root /usr/local/bin/meili-backup.sh" | sudo tee /etc/cron.d/meili-backup

    Restoring from a dump

    Dumps are imported at startup:

    bash
    sudo systemctl stop meilisearch
    sudo -u meilisearch /usr/bin/meilisearch \
      --config-file-path /etc/meilisearch.toml \
      --import-dump /var/lib/meilisearch/dumps/20260416-030000.dump

    Once the import completes, restart normally:

    bash
    sudo systemctl start meilisearch

    Using the Built-in Search Preview Dashboard

    Meilisearch ships a built-in search preview dashboard served at the root URL of the instance. It is a simple HTML page for testing queries against your indexes without writing code.

    Visit:

    text
    https://search.yourdomain.com/

    You will be prompted for your API key. Paste your admin key and select an index. As you type in the search box, results update live. This dashboard is purely client-side -- it never stores your key and is safe to use in production.

    The dashboard is disabled when the MEILI_NO_ANALYTICS=true flag is set in combination with --no-dashboard, but it is enabled by default and does not expose any data that the corresponding API key could not already access.

    Official SDKs

    Meilisearch maintains first-party SDKs for every major language. Installing one is usually a better path than hand-rolling HTTP calls.

    LanguagePackageInstall
    JavaScript/TypeScriptmeilisearchnpm install meilisearch
    Pythonmeilisearchpip install meilisearch
    PHPmeilisearch/meilisearch-phpcomposer require meilisearch/meilisearch-php
    Rubymeilisearchgem install meilisearch
    Gogithub.com/meilisearch/meilisearch-gogo get github.com/meilisearch/meilisearch-go
    Rustmeilisearch-sdkcargo add meilisearch-sdk
    Javacom.meilisearch.sdk:meilisearch-javaMaven/Gradle
    .NETMeilisearchdotnet add package Meilisearch
    Swiftmeilisearch-swiftSwift Package Manager
    Dartmeilisearchflutter pub add meilisearch
    Minimal Node.js example:

    javascript
    import { Meilisearch } from 'meilisearch';

    const client = new Meilisearch({ host: 'https://search.yourdomain.com', apiKey: process.env.MEILI_SEARCH_KEY, });

    const results = await client.index('movies').search('inception', { filter: 'year > 2000', sort: ['rating:desc'], limit: 10, });

    console.log(results.hits);

    Frontend libraries like instant-meilisearch bridge Meilisearch with Algolia's React InstantSearch widgets, so you get polished autocomplete, faceted filters, and pagination UI out of the box.

    Troubleshooting

    ProblemCauseSolution
    401 Unauthorized on every requestMissing or wrong Authorization headerPrefix your key with Bearer: -H "Authorization: Bearer $MEILI_KEY". In production mode, every endpoint except /health requires auth.
    Service fails to start: "db is in an incompatible version"Upgraded Meilisearch binary but old data dirExport a dump with the old version, stop Meilisearch, clear /var/lib/meilisearch/data, start new version with --import-dump.
    413 Request Entity Too Large on bulk insertNginx client_max_body_size too smallIncrease to 100m or higher in the Nginx config, reload Nginx.
    High RAM usage, OS starts swappingIndex larger than available RAMMeilisearch memory-maps the index; swap is expected for datasets > RAM. Upgrade to a larger VPS for hot indexes.
    Search returns empty results after bulk insertIndexing task still runningcurl http://localhost:7700/tasks -- wait for status: succeeded. Large imports can take minutes.
    Connection refused on port 7700Meilisearch bound to wrong address or not runningCheck http_addr in config, systemctl status meilisearch, and logs via journalctl -u meilisearch.
    Tenant token rejected: invalid tokenWrong parent API key UID, or token expiredTokens must be signed with an API key that itself grants access to the index and actions requested. Regenerate with the correct apiKeyUid.
    Dashboard at / shows "Cannot connect"Browser blocking mixed content or wrong keyEnsure HTTPS is working end-to-end and paste an admin-level key.

    Viewing logs

    bash
    sudo journalctl -u meilisearch -f

    For the last 100 lines:

    bash
    sudo journalctl -u meilisearch -n 100 --no-pager

    FAQ

    Is Meilisearch free and open-source?

    Yes. Meilisearch is licensed under the MIT License and is free to self-host on any infrastructure. Meilisearch Cloud is a paid managed offering, but the engine itself carries no usage fees, no per-request billing, and no document-count limits.

    How much RAM does Meilisearch need?

    A general rule is that Meilisearch needs roughly 2x the size of your raw dataset in RAM for optimal performance, because the index is memory-mapped and the OS keeps hot pages resident. For up to 1 million documents with modest payloads (a few KB each), 2 GB of RAM is usually enough. For 10 million documents, plan on 8-16 GB. The engine does not crash when the index is larger than RAM -- the OS simply swaps pages in and out -- but latency increases measurably once working set exceeds RAM.

    How does Meilisearch compare to Elasticsearch, Typesense, and Algolia?

    Meilisearch is optimized for instant, typo-tolerant search on typical product and content datasets. Simplest to deploy (single binary), best developer experience, great defaults.

    Typesense is architecturally similar to Meilisearch (single binary, C++ instead of Rust). Very close in performance. Typesense has richer vector search and curation features today; Meilisearch has simpler tenant tokens and a more polished dashboard.

    Elasticsearch / OpenSearch are general-purpose distributed search and analytics engines. Use them when you need aggregations over billions of log lines, complex Lucene queries, or cluster-wide sharding. They are overkill for typeahead search and come with significant operational overhead.

    Algolia is a hosted-only SaaS with excellent global edge latency. Meilisearch matches or beats Algolia on features for a fraction of the cost once you self-host.

    See our comparison guides: How to Install Typesense on Ubuntu, How to Install Elasticsearch on Ubuntu, and How to Install OpenSearch on Ubuntu.

    Can I use Meilisearch for a multi-tenant SaaS?

    Yes. Meilisearch supports tenant tokens, which are JWT-style API keys scoped to a filter expression. You sign them with a parent API key and embed per-customer filters (customerId = "abc") so that each user can only search their own documents even though everything lives in a single shared index. This is significantly more efficient than creating one index per tenant and handles thousands of tenants effortlessly.

    How do I back up a Meilisearch instance?

    Meilisearch has two backup mechanisms. Snapshots are fast binary copies of the data directory -- ideal for crash recovery on the same Meilisearch version. Enable them with schedule_snapshot in the config. Dumps are portable JSON exports that can be restored on different Meilisearch versions -- essential for upgrades and cross-environment migrations. Trigger them with POST /dumps. A production setup should use both: scheduled snapshots locally for fast recovery, plus nightly dumps shipped to off-site object storage.

    Does Meilisearch support vector/semantic search?

    Yes, since version 1.6. You can either embed documents yourself and store the vectors in a _vectors field, or configure an embedders setting that calls OpenAI, HuggingFace, or a local model to generate embeddings automatically. Hybrid search blends keyword scores with vector similarity using a semanticRatio parameter per query, which is useful for RAG pipelines and semantic product discovery.

    What happens if the Meilisearch process crashes mid-index?

    Meilisearch uses an LMDB-backed transactional store, so crashes do not corrupt existing indexes. The currently-running indexing task is rolled back and re-enqueued, so you can safely restart the service. This is one of the practical reasons snapshots are fast to take -- the on-disk state is always consistent.

    Next Steps

    Now that Meilisearch is running on your VPS, here are recommended next steps to build on your setup:

    • Wire it into your application -- Install the official SDK for your stack and replace your database LIKE queries with Meilisearch search() calls. Start with the index that has the most user-facing search load.
    • Add InstantSearch UI -- The instant-meilisearch adapter lets you use Algolia's React/Vue/Angular InstantSearch widgets with Meilisearch as the backend. You get polished autocomplete, faceted filters, and paginated results with minimal code.
    • Enable hybrid semantic search -- If your users run long, natural-language queries, configure an embedder (OpenAI, HuggingFace, or a self-hosted model like Ollama -- see our Ollama install guide) and enable hybrid search on your most important index.
    • Set up monitoring -- Expose Meilisearch metrics with MEILI_EXPERIMENTAL_ENABLE_METRICS=true and scrape them with Prometheus. Alert on queue depth and indexing failures.
    • Tune ranking rules per index -- Meilisearch's default ranking pipeline is excellent, but every dataset has quirks. Use the search preview dashboard to iterate on ranking rules, synonyms, and typo tolerance until the top results match what you expect.
    • Read the official docs -- The Meilisearch documentation has deep guides on every setting, endpoint, and integration pattern covered here.

    Skip the manual setup -- deploy on a VPS built for it.
    >
    Our CloudCore Starter plan comes with enough RAM, NVMe storage, and unmetered bandwidth to run Meilisearch comfortably for most production workloads. Spin one up in under 60 seconds and follow this guide end-to-end in 25 minutes.
    >
    - 4 vCPU, 8 GB RAM, 100 GB NVMe
    - Unmetered bandwidth
    - Full root access
    - EUR 7.50/month starting price
    >
    Launch your CloudCore Starter VPS

    Was this article helpful?

    ← Back to Install GuidesBrowse all categories →

    Still have questions?

    Contact Support →Submit a Ticket