Meilisearch 1.55.0
Overview
Meilisearch is an open-source search engine with a REST API. It returns relevant, typo-tolerant results in milliseconds. It supports filters, facets, sorting, synonyms, multi-language tokenization, and hybrid search that combines keyword relevance with vector similarity from an embedder you configure (OpenAI, Hugging Face, Ollama or any REST service).
This guide covers launching and using the SecureAnyCloud Meilisearch 1.55.0 on Ubuntu 24.04 AMI on Amazon EC2. It is one version of the SecureAnyCloud vector databases and RAG listing on AWS Marketplace. You pick it as the software version when you subscribe and launch. Applications send documents to an index and query it over HTTPS, and official client libraries exist for most languages.
What you get:
- Keys unique to your instance. First boot generates a 64-character master key on the instance. It writes the key to
/root/meilisearch-credentials.txt(root only), together with the Default Admin API Key and Default Search API Key that Meilisearch derives from it. No key is baked into the image. - Production mode. Meilisearch refuses to start without the master key, every data route needs a key, and the search preview page is off. The service also refuses to start if its configuration ever loses the key or switches to development mode.
- HTTPS from the first boot. nginx serves the API on port 443 with a certificate generated on your instance's first boot. Port 80 redirects to HTTPS. Meilisearch itself listens on
127.0.0.1:7700only. - Closed until first boot, and fail closed. Meilisearch cannot start before first boot has written its key, and nginx ships switched off. First boot opens the public listener only after Meilisearch works on loopback and an authenticated check passes. If anything fails, the listener is closed again.
- Hardened defaults. Anonymous analytics are off. Meilisearch runs as its own unprivileged account in a systemd sandbox that can write only to its data directory. Meilisearch and nginx are blocked from the instance metadata service, and Meilisearch's own outbound policy is kept. That policy refuses private and link-local addresses for embedders and webhooks. The AMI requires IMDSv2, and requests for any host name the instance does not serve are dropped.
- Fully patched Ubuntu 24.04 LTS at build time, with unattended security upgrades switched on.
What is on the image: Meilisearch 1.55.0 Community Edition (the official meilisearch-linux-amd64 release binary, checksum pinned) at /usr/local/bin/meilisearch, nginx, Ubuntu 24.04 LTS, cloud-init and the AWS Systems Manager agent. The database (data.ms), dumps and snapshots live under /var/lib/meilisearch. No database, index or key ships in the image.
Default user: ubuntu | Architecture: x86_64 | Recommended instance type: m5.large
Prerequisites
- An AWS account subscribed to the listing, an EC2 key pair, and a VPC subnet with a route to the internet (or a private route you use for management)
- A security group that allows TCP 22 (SSH), TCP 443 (the Meilisearch API) and TCP 80 (redirects to HTTPS) from your own networks only. Never open 7700, because Meilisearch listens on the instance's loopback address only
Launch the instance
In the AWS Marketplace listing, choose Continue to Subscribe, then Continue to Configuration. Pick Meilisearch 1.55.0 on Ubuntu 24.04 as the software version, choose your Region, then choose Launch through EC2.
Choose m5.large, your key pair and a security group as described above. Meilisearch uses up to two thirds of the instance's memory while indexing, so size up for large datasets.
Size the root EBS volume for your indexes. They live under /var/lib/meilisearch on the root volume, which you can grow later.
With the AWS CLI, replace the values in angle brackets:
aws ec2 run-instances --region <region> --image-id <ami-id-from-the-listing> \
--instance-type m5.large --key-name <your-key-pair> \
--security-group-ids <your-security-group> --subnet-id <your-subnet> \
--metadata-options HttpTokens=required,HttpEndpoint=enabled \
--block-device-mappings 'DeviceName=/dev/sda1,Ebs={VolumeSize=30,VolumeType=gp3}' \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=meilisearch}]'Connect to your instance
Version SSH user
Meilisearch 1.55.0 on Ubuntu 24.04 ubuntu
ssh -i <your-key.pem> ubuntu@<public-ip>Check the services
First boot generates the certificate and the master key, starts Meilisearch, opens nginx, and runs an authenticated check before it finishes. This takes well under a minute:
systemctl is-active meilisearch nginx meilisearch-firstboot
sudo test -f /var/lib/sac/data/meilisearch-firstboot.done && echo FIRSTBOOT_DONEactive active active FIRSTBOOT_DONEOnly SSH and nginx listen on public addresses. Meilisearch listens on loopback:
sudo ss -lntp | awk 'NR>1 {print $4, $6}' | grep -v '127.0.0.5' | sort0.0.0.0:22 users:(("sshd",...)) 0.0.0.0:443 users:(("nginx",...)) 0.0.0.0:80 users:(("nginx",...)) 127.0.0.1:7700 users:(("meilisearch",...)) [::]:22 users:(("sshd",...)) [::]:443 users:(("nginx",...)) [::]:80 users:(("nginx",...))Get your URL and keys
Read the credentials file:
sudo grep -E '^MEILI_' /root/meilisearch-credentials.txtOnly root can read the file. It looks like this:
MEILI_URL=https://ec2-<public-ip-dashed>.<region>.compute.amazonaws.com/ MEILI_MASTER_KEY=<MEILI_MASTER_KEY> MEILI_ADMIN_API_KEY=<MEILI_ADMIN_API_KEY> MEILI_SEARCH_API_KEY=<MEILI_SEARCH_API_KEY>MEILI_URLis the API endpoint. It uses the instance's public DNS name from EC2 instance metadata, or the public IP address when the subnet has no public DNS names. The certificate also names the public and private IP addresses. To serve Meilisearch under your own DNS name, see Step 9.MEILI_MASTER_KEYis the root key, and every API key is derived from it. Keep it on the server.MEILI_ADMIN_API_KEY(the Default Admin API Key) manages indexes, documents, settings and tasks. Use it from your backend only.MEILI_SEARCH_API_KEY(the Default Search API Key) can only search. Use it from a web or mobile front end.
Send a key in the Authorization: Bearer <key> header.
The examples below read the key from the credentials file and hand it to curl on standard input (-H @-). The key never appears on a command line or in your shell history.
Confirm the API requires a key
Send requests with no key and with a wrong key, then with the master key:
C=/etc/ssl/meilisearch/meilisearch.crt; U=https://127.0.0.1 curl -s --cacert $C -o /dev/null -w 'no key -> HTTP %{http_code}\n' $U/indexes printf 'Authorization: Bearer %s\n' wrong-key | curl -s --cacert $C -o /dev/null -w 'wrong key -> HTTP %{http_code}\n' -H @- $U/indexes
sudo sed -n 's/^MEILI_MASTER_KEY=/Authorization: Bearer /p' /root/meilisearch-credentials.txt | curl -s --cacert $C -H @- $U/version; echo curl -s --cacert $C $U/health; echono key -> HTTP 401 wrong key -> HTTP 403 {"commitSha":"420ff1362801adb58c938aec89700e8f7e32e566","commitDate":"2026-10-12T08:45:13.000000000Z","pkgVersion":"1.55.0"} {"status":"available"}/health stays open for load balancers and reveals nothing.
From another machine, use MEILI_URL instead of https://127.0.0.1. Because the certificate is self-signed, also pass -k or the instance's certificate.
Index documents and search
Add a few documents to a movies index with the admin key. Make two fields filterable and one sortable, and wait for each task:
C=/etc/ssl/meilisearch/meilisearch.crt; U=https://127.0.0.1 admin() {
sudo sed -n 's/^MEILI_ADMIN_API_KEY=/Authorization: Bearer /p' /root/meilisearch-credentials.txt | curl -s --cacert "$C" -H @- -H 'Content-Type: application/json' "$@"; } wait_task() { for i in $(seq 1 30); do
S=$(admin "$U/tasks/$1" | jq -r .status); [ "$S" = succeeded ] && break; sleep 1; done; echo "task $1: $S"; }
T=$(admin -X POST --data '[{"id":1,"title":"Carol","genres":["Romance","Drama"],"year":2015},{"id":2,"title":"Wonder Woman","genres":["Action","Adventure"],"year":2017},{"id":3,"title":"Life of Pi","genres":["Adventure","Drama"],"year":2012},{"id":4,"title":"Mad Max: Fury Road","genres":["Adventure","Science Fiction"],"year":2015},{"id":5,"title":"Moana","genres":["Fantasy","Action"],"year":2016}]' "$U/indexes/movies/documents?primaryKey=id" | jq -r .taskUid); wait_task "$T"
T=$(admin -X PATCH --data '{"filterableAttributes":["genres","year"],"sortableAttributes":["year"]}' "$U/indexes/movies/settings" | jq -r .taskUid); wait_task "$T"task 0: succeeded task 1: succeededSearch with the search key. A query with two typos still finds the film, filters and sorting work, and the search key cannot write:
C=/etc/ssl/meilisearch/meilisearch.crt; U=https://127.0.0.1 search() {
sudo sed -n 's/^MEILI_SEARCH_API_KEY=/Authorization: Bearer /p' /root/meilisearch-credentials.txt | curl -s --cacert "$C" -H @- -H 'Content-Type: application/json' "$@"; } search -X POST --data '{"q":"wondr womn"}' "$U/indexes/movies/search" | jq -c '{hits: [.hits[] | {id, title}], estimatedTotalHits}' search -X POST --data '{"q":"","filter":"genres = Adventure AND year >= 2015","sort":["year:desc"]}' "$U/indexes/movies/search" | jq -c '[.hits[] | {title, year}]' search -o /dev/null -w 'search key writing a document -> HTTP %{http_code}\n' -X POST --data '[{"id":9,"title":"x"}]' "$U/indexes/movies/documents"{"hits":[{"id":2,"title":"Wonder Woman"}],"estimatedTotalHits":1} [{"title":"Wonder Woman","year":2017},{"title":"Mad Max: Fury Road","year":2015}] search key writing a document -> HTTP 403For hybrid (keyword plus vector) search, add an embedder to the index settings (embedders) that points at your embedding provider. Then search with a hybrid parameter. See the Meilisearch documentation on AI-powered search.
Embedder and webhook URLs must be public addresses. Meilisearch refuses private and link-local addresses by default.
Run the built-in check
The image ships an end-to-end check you can run at any time. First boot runs a read-only version of it.
The check reads the credentials file itself and talks to the API over HTTPS through nginx, with the instance's certificate pinned. It confirms that:
- Port 80 redirects.
- An unknown host name is dropped.
- No key is refused, and a wrong key is refused.
- The search key cannot write or read keys.
- The admin key creates a temporary index and adds documents that the search key then finds. The check then deletes the index.
Run it:
sudo meilisearch-verify.shport 80 -> 301 https://ec2-<public-ip-dashed>.<region>.compute.amazonaws.com/ ; an unknown Host is dropped on 80 and 443 ; certificate verifies for ec2-<public-ip-dashed>.<region>.compute.amazonaws.com production mode: / is the status JSON (no dashboard); no key 401, wrong key 403, master key 200; version 1.55.0 search key: write 403, /keys 403 ; admin key: /indexes 200 round trip: admin key created sac_verify_<n> and added 3 documents, the search key found 'Wonder Woman' for 'wondr woman' and could not write, index deleted MEILISEARCH_ROUNDTRIP_OKRun the security checks
The files that matter are locked down. The configuration file holds the master key:
sudo stat -c '%a %U:%G %n' /etc/meilisearch/config.toml /root/meilisearch-credentials.txt /var/lib/meilisearch /etc/ssl/meilisearch/meilisearch.key640 root:meilisearch /etc/meilisearch/config.toml 600 root:root /root/meilisearch-credentials.txt 750 meilisearch:meilisearch /var/lib/meilisearch 600 root:root /etc/ssl/meilisearch/meilisearch.keyThe binary is the official Community Edition release asset. Its SHA-256 equals the digest GitHub publishes for meilisearch-linux-amd64 v1.55.0. It runs in production mode with analytics off:
sha256sum /usr/local/bin/meilisearch; /usr/local/bin/meilisearch --version sudo grep -E '^(env|http_addr|db_path|dump_dir|snapshot_dir|no_analytics) ' /etc/meilisearch/config.toml journalctl -u meilisearch -b --no-pager -o cat | grep -E '^(Environment|Anonymous telemetry|Package version):'7e33f5889235f14290074a19a6d3574bd9b10fb2ee8731eabb7dafd0714b0513 /usr/local/bin/meilisearch meilisearch 1.55.0 env = "production" http_addr = "127.0.0.1:7700" db_path = "/var/lib/meilisearch/data.ms" dump_dir = "/var/lib/meilisearch/dumps" snapshot_dir = "/var/lib/meilisearch/snapshots" no_analytics = true Environment: "production" Package version: "1.55.0" Anonymous telemetry: "Disabled"Meilisearch runs unprivileged in a sandbox that can write only to its data directory. Neither Meilisearch nor nginx can reach the instance metadata service, so an embedder or webhook URL cannot be pointed at it:
systemctl show meilisearch -p User -p ProtectSystem -p ReadWritePaths -p NoNewPrivileges -p IPAddressDeny
systemctl show nginx -p IPAddressDenyIPAddressDeny=169.254.169.254/32 168.63.129.16/32 fd00:ec2::254/128 User=meilisearch ReadWritePaths=/var/lib/meilisearch ProtectSystem=strict NoNewPrivileges=yes IPAddressDeny=169.254.169.254/32 168.63.129.16/32 fd00:ec2::254/128nginx passes Meilisearch a fixed host name and the real client address from the connection. It never passes values a client sends:
grep -E 'proxy_set_header (Host|X-Forwarded-For|X-Real-IP|Forwarded)' /etc/nginx/meilisearch-proxy.confproxy_set_header Host $meili_host; proxy_set_header Forwarded ""; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $remote_addr;The certificate was generated on this instance and names its own addresses. Check it:
H=$(sudo sed -n 's#^MEILI_URL=https://\([^/]*\)/.*#\1#p' /root/meilisearch-credentials.txt)
echo | openssl s_client -connect 127.0.0.1:443 -servername "$H" 2>/dev/null | openssl x509 -noout -subject -ext subjectAltNamesubject=CN = ec2-<public-ip-dashed>.<region>.compute.amazonaws.com, O = sac X509v3 Subject Alternative Name: DNS:ec2-<public-ip-dashed>.<region>.compute.amazonaws.com, IP Address:<public-ip>, IP Address:<private-ip>, DNS:ip-<private-ip-dashed>.ec2.internal, IP Address:127.0.0.1, DNS:localhostNo key reached a log, the journal, shell history, backups or /etc, other than the configuration file. Confirm it:
sudo meilisearch-secret-leak-check.shLEAKCHECK_OK no master or API key in the journal, auth.log, syslog, cloud-init, nginx logs, shell history, MOTD, /var/backups, /etc (master key only in config.toml), /usr/local or /tmpUse your own DNS name and certificate
Point a DNS record at the instance, then set the name Meilisearch is served as. This command mints a new self-signed certificate for the name, updates nginx's host rule and the URL in /root/meilisearch-credentials.txt, and reloads nginx. The name is kept across reboots:
sudo meilisearch-set-hostname <your-domain>Without a configured name, the instance re-reads its address from EC2 instance metadata at every boot. A stop and start that changes the public IP address keeps the API reachable.
To use a certificate from your own certificate authority instead, copy it over /etc/ssl/meilisearch/meilisearch.crt and meilisearch.key (key mode 0600). Then run sudo systemctl reload nginx. Running meilisearch-set-hostname again replaces it with a self-signed one.
A certbot client works too, if you open port 80 to the certificate authority.
Manage API keys and the master key
Create API keys for each application with the master key. A key can be limited to some indexes, some actions and an expiry date. For example, this creates a key that can only search the movies index:
sudo sed -n 's/^MEILI_MASTER_KEY=/Authorization: Bearer /p' /root/meilisearch-credentials.txt \
| curl -s --cacert /etc/ssl/meilisearch/meilisearch.crt -H @- -H 'Content-Type: application/json' \
-X POST --data '{"name":"movies-search","actions":["search"],"indexes":["movies"],"expiresAt":null}' \
https://127.0.0.1/keysIf the master key was ever exposed, generate a new one:
sudo meilisearch-rotate-master-keyThe command writes the new key to /etc/meilisearch/config.toml, restarts Meilisearch and rewrites /root/meilisearch-credentials.txt.
Every API key value changes with the master key, because Meilisearch derives them from it. Update every client afterwards. The keys' permissions and names are kept.
Create dumps and snapshots
Dumps are portable and suited to upgrades and migrations. Snapshots are fast and work within the same version. Both are written to the data directory, in /var/lib/meilisearch/dumps and /var/lib/meilisearch/snapshots.
Create a dump with the admin key, then copy the .dump file off the instance. It holds your documents and API key definitions, so treat it as secret:
sudo sed -n 's/^MEILI_ADMIN_API_KEY=/Authorization: Bearer /p' /root/meilisearch-credentials.txt \
| curl -s --cacert /etc/ssl/meilisearch/meilisearch.crt -H @- -X POST https://127.0.0.1/dumps
sudo ls -l /var/lib/meilisearch/dumps/EBS snapshots of the root volume are the simplest whole-instance backup.
Change the configuration
Settings live in /etc/meilisearch/config.base.toml, which holds no key. /etc/meilisearch/config.toml is rendered from it plus the master key.
Edit the base file, for example max_indexing_memory, http_payload_size_limit or log_level. See the Meilisearch configuration reference. Then re-render with the current key and restart:
sudo nano /etc/meilisearch/config.base.toml
sudo meilisearch-set-master-key --keepKeep env = "production". The service refuses to start in development mode, which would serve the API without authentication.
Keep http_addr on 127.0.0.1 so nginx stays the only public listener.
If your embedder or webhook runs on a private address in your VPC, allow that range explicitly with experimental_allowed_ip_networks. Never allow the metadata address.
Server components
/usr/local/bin/meilisearch --version; nginx -v 2>&1; lsb_release -ds ls /usr/share/doc/sac/meilisearch/meilisearch 1.55.0 nginx version: nginx/1.24.0 (Ubuntu) Ubuntu 24.04.5 LTS LICENSE LICENSE-MIT VERSIONComponent Version Notes
Meilisearch 1.55.0 Community Edition /usr/local/bin/meilisearch, service meilisearch, data /var/lib/meilisearch
nginx 1.24.0 TLS on 443, redirect on 80, site /etc/nginx/sites-available/sac-meilisearch
Ubuntu 24.04 LTS unattended security upgrades on
To upgrade Meilisearch, create a dump and stop the service. Replace the binary with the newer official meilisearch-linux-amd64 release, and check its SHA-256 against the release page. Then import the dump as the Meilisearch upgrade guide describes.
Troubleshooting
curl: (60) SSL certificate problem: the certificate is self-signed. Pass--cacert /etc/ssl/meilisearch/meilisearch.crton the instance, use-kfor a quick test elsewhere, or install your own certificate (Step 9).- The connection is closed without a response: the request used a host name the instance does not serve, and nginx drops unknown names. Use
MEILI_URLor the instance's IP address, or set your name withmeilisearch-set-hostname. - HTTP 401 or 403: 401 means there is no
Authorizationheader. 403 means the key is wrong, expired, or lacks the action or index. Aftermeilisearch-rotate-master-key, every key value has changed. - A task stays
processingwith an embedder: Meilisearch retries an unreachable embedder for a few minutes. Checkjournalctl -u meilisearchand the task'serror. Private and link-local URLs are refused by design. - First boot:
journalctl -u meilisearch-firstbootshows what it did. If it failed, it closed the public listener. Fix the cause and runsudo systemctl restart meilisearch-firstboot.
Security notes
- Restrict the security group to your own networks. Use the search key (or keys you create per index) in front ends, and use the admin key only in backends.
- Rotate the master key if it was ever exposed, and create expiring, narrowly scoped keys for applications.
- The build was audited against the RustSec advisory database. Two dependency advisories, for rustls 0.23.43 and rustls-webpki 0.103.13, have no upstream fix yet. They concern outbound HTTPS only, which Meilisearch uses solely for embedders, webhooks and remote instances you configure. Nothing connects out by default. Point those settings only at providers you trust. SecureAnyCloud publishes a new version when Meilisearch ships the fixed libraries.
Support and licensing
SecureAnyCloud provides 24/7 technical support by email and live chat: sales@secureanycloud.com.
This image contains Meilisearch Community Edition, licensed under the MIT license (/usr/share/doc/sac/meilisearch/LICENSE-MIT). The Meilisearch repository is licensed "MIT AND BUSL-1.1". The Enterprise Edition features (BUSL-1.1) are not included in this image and are not built into its binary.
Meilisearch is a trademark of Meili SAS. SecureAnyCloud is not affiliated with or endorsed by Meili SAS.
Deploy on AWS
Launch Meilisearch 1.55.0 on Ubuntu 24.04 on AWS with 24/7 support from SecureAnyCloud.
View on Marketplace
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com