Workload · Running your own search engine

Self-hosted Meilisearch: fast search for your site or app, on a server you control

You can self-host Meilisearch on one server in an evening: start the official Docker image or the release binary in production mode with a long random master key, keep it on the loopback address, and let Nginx serve it over HTTPS. Your search box then answers as people type, with typo tolerance, and the index stays on hardware you rent whole. This guide follows Meilisearch's own documentation for sizing, keys, backups and upgrades, and says plainly where a single server stops being enough.

The short version
  1. Docker or a plain binary, both set up step by step
  2. Your master key lives in a root-only file, never in a command
  3. Port 7700 stays on loopback; visitors reach it through HTTPS
  4. Daily snapshots for a bad day, dumps for a new version
  5. Free MIT-licensed Community Edition, no telemetry once you opt out

Is your project a good fit?

Yes, if the job is search that people use directly: a product catalogue, a help centre, documentation, a directory or an app's records. Meilisearch is built for results that appear while someone types and forgive their spelling. It is a poor fit for storing logs for months and charting them; that job suits OpenSearch on your own server. Keep the original records in a proper database, for example PostgreSQL on a dedicated server, and treat the search index as a copy you can rebuild.

One thing to know up front: the free Community Edition runs as one instance. Spreading an index over several machines (sharding), along with the replication described in the sharding guide, needs the Enterprise Edition, whose licence does not allow free production use. On the free edition your safety net is backups, not a second server taking over.

How much server does your index need?

Memory and fast disks set search speed; more cores let it answer more searches at the same time. Meilisearch stores its index in LMDB, which maps the database files into memory and lets the operating system decide what stays in RAM. Here is what its documentation says, in plain terms:

  • Disk: as a starting point, give it at least ten times the size of your raw data. More searchable and filterable fields make the database bigger.
  • Memory: it runs fastest with the entire database held in RAM. Meilisearch reports that having about a third of the database size in RAM does not materially hurt performance, and that a tenth is often fine. How much you need depends on how hard you search and index.
  • Disk speed: low-latency storage, NVMe for instance, beats a hard drive or network storage.
  • During indexing: by default it caps itself at two thirds of the RAM and half of the CPU cores, so searches keep running while new documents go in.

For a feel of the numbers, the docs measured one small example, a movie dataset described as 8.6 MB of JSON in their text and 9.1 MB in their table: after indexing it occupied 224 MB of disk and roughly 305 MB of memory. Treat it as a single data point, not a rule of thumb. They also warn that nobody can reliably predict a database's final size, and that deleting documents does not hand the disk space back to the system. The honest way to size is to index your own data on a test machine and look at the result.

Officially supported Linux means x86-64 or ARM64 with glibc 2.35 or newer. Run ldd --version on the server first.

The server that fits

On a whole server nothing else competes for the memory your index lives in, and you have root to choose where data, backups and temporary files go. Browse every option in our dedicated server range:

  • A shop or docs site: the compact cartridge servers with NVMe storage. The Xeon E3-1585L v5 has four cores and 16, 32 or 64 GB; the Xeon D-1587 has sixteen cores, an NVMe-SSD of 1.92 TB and memory from 16 GB to 128 GB.
  • A big catalogue or many indexes: two-processor servers on Xeon Gold 6130 or Xeon E5-2630L v3, with memory options up to 256 GB on their cards. The NVMe servers page explains the disk choice.
  • Something specific: describe it on custom builds. When we hold the parts, expect the build 4 to 24 hours once your order has cleared review.

A ready server reaches you within 30 minutes of payment approval. Our rack servers and blades include a console screen and a power button that keep working when SSH is down; the m510 and m710x cartridges include one as well. One IPv4 address is included and IPv6 costs nothing, which is why the firewall below covers both.

Up and running with Docker

Docker is the quickest route. Three choices in this setup keep you safe:

  1. Turn the firewall on first, letting in only SSH and web traffic, and confirm IPV6=yes in /etc/default/ufw so IPv6 is filtered too.
  2. Put the settings, including a master key made by openssl rand, in a file only root can read (mode 600 inside a 700 folder). Passed with --env-file, the key never shows up in ps or your shell history.
  3. Publish port 7700 on 127.0.0.1 only. Docker places its own port rules ahead of ufw's, so a plain -p 7700:7700 exposes the port on all of the machine's addresses, reachable from the internet no matter what ufw says.
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
grep IPV6 /etc/default/ufw          # expect IPV6=yes
sudo ufw enable
sudo mkdir -m 700 /etc/meilisearch
sudo sh -c 'umask 077; cat > /etc/meilisearch/meili.env' <<EOF
MEILI_ENV=production
MEILI_MASTER_KEY=$(openssl rand -hex 32)
MEILI_NO_ANALYTICS=true
MEILI_SCHEDULE_SNAPSHOT=86400
MEILI_SNAPSHOT_DIR=/meili_data/snapshots
EOF
sudo docker volume create meili_data
sudo docker run -d --name meilisearch --restart unless-stopped \
  --env-file /etc/meilisearch/meili.env \
  -p 127.0.0.1:7700:7700 \
  -v meili_data:/meili_data \
  getmeili/meilisearch:v1.55.0
curl -s http://127.0.0.1:7700/health

Name an exact version tag, as above. Meilisearch advises against latest, because two servers set up weeks apart would quietly run different releases. The named volume keeps your index when the container is replaced.

Prefer a plain binary? The systemd setup

Meilisearch's production tutorial pipes https://install.meilisearch.com straight into sh. We skip that: it runs a script nobody on your side has reviewed, with the rights of whoever typed it. The release page offers the finished binary, and the docs' update guide fetches it with curl in just this way. Choose meilisearch-linux-amd64 (or -aarch64 on ARM), not a file with enterprise in its name, which is the separately licensed Enterprise build.

curl -fL -o meilisearch https://github.com/meilisearch/meilisearch/releases/download/v1.55.0/meilisearch-linux-amd64
sudo install -m 755 meilisearch /usr/local/bin/
sudo useradd -r -m -d /var/lib/meilisearch -s /bin/false meilisearch
sudo -u meilisearch mkdir /var/lib/meilisearch/data /var/lib/meilisearch/dumps /var/lib/meilisearch/snapshots /var/lib/meilisearch/tmp
sudo chmod 750 /var/lib/meilisearch
sudo sh -c 'umask 077; cat > /etc/meilisearch.env' <<EOF
MEILI_ENV=production
MEILI_MASTER_KEY=$(openssl rand -hex 32)
MEILI_HTTP_ADDR=127.0.0.1:7700
MEILI_DB_PATH=/var/lib/meilisearch/data
MEILI_DUMP_DIR=/var/lib/meilisearch/dumps
MEILI_SNAPSHOT_DIR=/var/lib/meilisearch/snapshots
MEILI_SCHEDULE_SNAPSHOT=86400
MEILI_NO_ANALYTICS=true
TMPDIR=/var/lib/meilisearch/tmp
EOF
sudo tee /etc/systemd/system/meilisearch.service >/dev/null <<'EOF'
[Unit]
Description=Meilisearch
After=systemd-user-sessions.service
[Service]
Type=simple
WorkingDirectory=/var/lib/meilisearch
EnvironmentFile=/etc/meilisearch.env
ExecStart=/usr/local/bin/meilisearch
User=meilisearch
Group=meilisearch
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now meilisearch

Run the firewall lines from the Docker step before the last command. The unit is the production tutorial's, changed in one place by us: the EnvironmentFile=/etc/meilisearch.env line stands in for --config-file-path /etc/meilisearch.toml, the TOML file that would hold the key. The tmp folder and the TMPDIR line are our additions too: according to the docs, snapshots and dumps are assembled in TMPDIR first, and a small /tmp runs out of room.

Letting visitors in over HTTPS

Point a hostname at the server, then put Nginx in front and ask certbot for a certificate. Meilisearch itself never faces the internet. If the only thing that talks to it is an application on this same server, the docs say you can leave the proxy out.

sudo apt install -y nginx python3-certbot-nginx
sudo tee /etc/nginx/conf.d/meilisearch.conf >/dev/null <<'EOF'
server {
    listen 80;
    listen [::]:80;
    server_name search.example.com;
    client_max_body_size 100m;
    location / {
        proxy_pass http://127.0.0.1:7700;
    }
}
EOF
sudo nginx -t && sudo systemctl reload nginx
sudo certbot --nginx -d search.example.com

The client_max_body_size line matters: Nginx turns away request bodies above 1 MB unless told otherwise, while Meilisearch accepts batches of documents up to 100 MB by default.

Which key goes where

Think of the master key as the key to the key cabinet: use it only to create, list and delete API keys. Once it is set, Meilisearch locks every route except /health and makes four API keys for you:

  • Default Search API Key: can do nothing but search. This is the one your website's search box may carry.
  • Default Admin API Key: adding documents, changing settings, making backups. Keep it in your backend, never in a page.
  • Read-only admin and chat keys: for reading the whole database, and for the conversational search feature.

To see them without typing the master key anywhere, let awk turn the file's line into a header that curl reads from standard input: sudo awk 'sub(/^MEILI_MASTER_KEY=/, "Authorization: Bearer ")' /etc/meilisearch.env | curl -sS --header @- http://127.0.0.1:7700/keys (with Docker, the file is /etc/meilisearch/meili.env). Better still, make a key that can only search the one index your site uses, with an expiry date. If you ever change the master key, every API key stops working, so your apps need new ones.

Backups and upgrades without the panic

Meilisearch offers two kinds of backup, and you want both. A snapshot is an exact copy of the database: quick to restore, but only into the same version. The settings above make one every 24 hours, and each replaces the previous, so copy it somewhere else each day. A dump (POST /dumps with the admin key) is a portable export that a newer version can import; restoring it re-indexes everything, which takes time and memory. Dumps never contain API key values.

Only the newest release gets fixes, and there are between four and six releases a year, not counting patches. To move up:

  1. Ask for a fresh snapshot (POST /snapshots) and let its task finish successfully. The docs warn the upgrade is not atomic.
  2. Stop Meilisearch and swap in the new binary, or change the image tag.
  3. Start it once with the upgrade option: MEILI_UPGRADE_DB=true in the environment file. Moving to a release older than v1.51? Then the option still has its earlier name; set MEILI_EXPERIMENTAL_DUMPLESS_UPGRADE=true in the file instead (--experimental-dumpless-upgrade as a flag). Searches carry on while the UpgradeDatabase task runs; remove the line afterwards.
  4. If the database dates from before v1.12, that shortcut is refused. Go back to the old version, export a dump, set the old data aside, then launch the new version, passing the dump file to --import-dump.

The fine print: licence and telemetry

No charge for the Community Edition: it ships under the MIT licence with both keyword and AI-powered search. The Enterprise Edition is licensed under BUSL, which rules out free use in production: its binaries can be tried out, and for production you talk to Meilisearch's sales team. Meilisearch's configuration reference also lists saving snapshots straight to S3 as Enterprise-only, so on the Community Edition copy the snapshot file off the server yourself.

Out of the box, Meilisearch sends anonymous usage statistics, such as system specs, search latency and feature use. Its policy rules out IP addresses and your documents' contents. The MEILI_NO_ANALYTICS=true line in both setups switches it off.

Questions people ask

Can Meilisearch run on a small server?
Yes, for a small index. What matters is the size of the database after indexing compared with your RAM, and a fast disk. If memory runs short during big imports, the docs suggest sending documents in smaller batches or lowering --max-indexing-memory.
Does Meilisearch send data home?
By default it sends anonymous usage metrics. The policy promises that no IP addresses, emails or site URLs are gathered, and nothing from your documents is kept. Set MEILI_NO_ANALYTICS=true and restart to stop it.
What if I start it without a master key?
In production mode it will not start, and a key under 16 bytes is refused too; it suggests a strong one instead. In development mode it starts with every route open, which is only acceptable on a machine nobody else can reach.
Is there an admin screen in the browser?
Only a basic search preview, and production mode switches it off. You manage indexes, settings and keys through the HTTP API or one of the official SDKs.
Do I have to use Docker?
No. Both routes run the same engine. Docker makes swapping versions a one-line change; the binary with systemd has fewer moving parts. Pick the one you are happier maintaining.

Give your search its own server

Pick a server with the memory and NVMe your index needs; a ready one is handed over within 30 minutes of approval.

Choose a server for your search

Read next