DEV Community

Cover image for Samba, Spotlight & Manticore
Mario Ravalli
Mario Ravalli

Posted on • Originally published at mario.raval.li

Samba, Spotlight & Manticore

Part 1 — The Journey

The Goal

I have a NAS built on Proxmox with LXC containers. The idea was simple: share files via Samba and be able to search them from macOS Finder as if they were on a local disk, using Spotlight. Search for "Battiato" and find all the MP3s, PDFs, text files — everything indexed, everything reachable in a second.

Samba has supported Apple's Spotlight protocol since version 4.x, with an option called spotlight backend that allows delegating indexing to an external engine. Three backends are supported: noindex (no search), tracker (GNOME Tracker), and elasticsearch. None of these was exactly what I was looking for.

The Context: Proxmox, LXC, and Alpine Linux

My setup uses Proxmox as a hypervisor with LXC containers for services. The NAS initially ran on an Alpine Linux container — lightweight, fast, perfect for a fileserver.

The first obstacle came right away: I want Spotlight search, so I need to choose a backend. Tracker is out of the question on Alpine — it depends on D-Bus, the GNOME stack, systemd, none of which is practically available on Alpine with musl libc. Elasticsearch is heavy and requires a JVM. But there is an alternative.

Manticore Search: A Lightweight Elasticsearch

Manticore Search is a full-text search engine compatible with the Elasticsearch REST API, written in C++. It is much lighter, requires no JVM, and has excellent support for text indexing. The idea was to use it as the Elasticsearch backend for Samba, in a separate LXC container.

The two-container architecture makes sense: the search service is separate from the fileserver, they can be updated independently, and Manticore can be reached by multiple shares if needed.

The First Problem: spotlight.so Does Not Exist on Alpine

After configuring Samba with spotlight backend = elasticsearch and adding vfs objects = spotlight to the share, the result was:

Error loading module '/usr/lib/samba/vfs/spotlight.so': No such file or directory
Enter fullscreen mode Exit fullscreen mode

The Samba package on Alpine does not include the VFS module for Spotlight. It is not in the repositories, there is no separate package, and compiling it from source on Alpine with musl libc is an inadvisable adventure.

Migrating to Debian 13

I recreated the NAS container on Debian 13 (Bookworm). Samba 4.22 on Debian is compiled with Spotlight support — you can see this from the smbd -b output which shows WITH_SPOTLIGHT and HAVE_SPOTLIGHT_BACKEND_ES. The module is compiled statically into smbd, not as a separate .so, so it does not need to be added to vfs objects.

The Technical Problems, One by One

1. The Missing Mappings File

The first error after the migration:

mdssvc_es_init: Opening mapping file [/usr/share/samba/mdssvc/elasticsearch_mappings.json] failed
Enter fullscreen mode Exit fullscreen mode

Samba looks for a JSON file that maps Spotlight attributes (such as kMDItemFSName, kMDItemTitle) to Elasticsearch fields. The file was not included in the Debian package. Solution: download it from the official Samba repository and place it at the correct path.

2. Manticore Does Not Support Field Names With Dots

Samba sends queries with fields like path.real, file.filename, meta.title. Manticore does not accept field names containing dots — not as SQL, not with backticks, in no way.

Solution: rename the fields in the index (path_real, file_filename, etc.) and create an HTTP proxy that translates the names in both requests and responses.

3. The prefix Query Is Not Supported on Full-Text Fields

Samba filters results by share using a prefix query on the path.real field. Manticore does not support this type of query on full-text fields. The proxy must intercept and remove this filter.

4. Elasticsearch's query_string Syntax Is Not Compatible

Samba sends queries like "query": "Fran* OR content:Fran*" with "fields": ["file.filename", "content"]. Manticore does not understand the content:Fran* syntax inside a query_string. The proxy must rewrite the query into Manticore's format: @file_filename Fran* | @content Fran*.

5. json_loadb failed: the Content-Length

Even with a correct JSON response, Samba kept throwing json_loadb failed. The problem was that the proxy was not including the Content-Length header in the response. Samba reads exactly N declared bytes — without Content-Length, parsing fails.

6. Accented Characters and ensure_ascii

Python by default serializes non-ASCII characters as Unicode sequences (ÈE\u0300). Samba does not handle NFD (decomposed) form correctly. Solution: json.dumps(data, ensure_ascii=False).

7. The Nested Structure of path.real

The final error: Missing path.real in JSON result. Looking at the Samba source code reveals that the parser expects:

"_source": { "path": { "real": "/share/music/..." } }
Enter fullscreen mode Exit fullscreen mode

Not the flat key "path.real". The proxy must therefore transform path_real into the nested object {"path": {"real": "..."}} in the response.

The Python Proxy: The Solution

A small HTTP proxy written in Python, listening on port 9200, which intercepts Samba's requests and translates them for Manticore, then translates the responses back into the format Samba expects. About 80 lines of standard library code, no external dependencies.

The Result

Searching for "Battiato" from Finder shows Franco Battiato's MP3 files. Searching for "Robot" finds Ufo Robot songs and Asimov's Robot novels. Search works on filenames, ID3 titles, PDF and text file contents, and PHP and JavaScript source code.


Part 2 — Practical Guide

Prerequisites

  • Proxmox with two LXC containers
  • Samba CT: Debian 13, at least 512MB RAM
  • Manticore CT: Debian/Ubuntu, at least 1GB RAM

Architecture

macOS Finder (Spotlight)
        │  SMB + Spotlight RPC
        ▼
CT Debian — smbd + rpcd_mdssvc
        │  HTTP :9200
        ▼
CT Debian — ms-proxy.py
        │  HTTP :9308
        ▼
CT Manticore — Manticore Search
        ▲
CT Debian — spotlight-indexer.sh
        │  inotify + ffprobe/pdftotext/catdoc
        ▼
    /share (filesystem)
Enter fullscreen mode Exit fullscreen mode

CT Manticore — Installation

Recommended distro: Debian 12 or Ubuntu 22.04

wget https://repo.manticoresearch.com/manticore-repo.noarch.deb
dpkg -i manticore-repo.noarch.deb
apt update
apt install manticore manticore-extra
Enter fullscreen mode Exit fullscreen mode

Download the Manticore configuration file:

wget https://raw.githubusercontent.com/senzidee/samba-spotlight-manticore/refs/heads/main/manticore.conf
mv manticore.conf /etc/manticoresearch/manticore.conf
Enter fullscreen mode Exit fullscreen mode

Start the service:

systemctl enable manticore
systemctl start manticore
Enter fullscreen mode Exit fullscreen mode

CT Samba/Debian — Installation

apt install samba samba-vfs-modules \
    inotify-tools curl ffmpeg \
    poppler-utils catdoc \
    python3 jq
Enter fullscreen mode Exit fullscreen mode

Spotlight mappings file:

mkdir -p /usr/share/samba/mdssvc
curl -s https://raw.githubusercontent.com/samba-team/samba/master/source3/rpc_server/mdssvc/elasticsearch_mappings.json \
    -o /usr/share/samba/mdssvc/elasticsearch_mappings.json
Enter fullscreen mode Exit fullscreen mode

Download the required files:

wget https://raw.githubusercontent.com/senzidee/samba-spotlight-manticore/refs/heads/main/msctl
wget https://raw.githubusercontent.com/senzidee/samba-spotlight-manticore/refs/heads/main/ms-proxy.py
wget https://raw.githubusercontent.com/senzidee/samba-spotlight-manticore/refs/heads/main/ms-proxy.service
wget https://raw.githubusercontent.com/senzidee/samba-spotlight-manticore/refs/heads/main/smb.conf
wget https://raw.githubusercontent.com/senzidee/samba-spotlight-manticore/refs/heads/main/spotlight-indexer.service
wget https://raw.githubusercontent.com/senzidee/samba-spotlight-manticore/refs/heads/main/spotlight-indexer.sh

mv msctl /usr/bin/
mv ms-proxy.py /usr/local/bin/
mv ms-proxy.service /etc/systemd/system/
mv smb.conf /etc/samba/
mv spotlight-indexer.service /etc/systemd/system/
mv spotlight-indexer.sh /usr/local/bin/
Enter fullscreen mode Exit fullscreen mode

Start the services:

systemctl daemon-reload
systemctl enable ms-proxy spotlight-indexer
systemctl start ms-proxy spotlight-indexer
systemctl restart smbd
Enter fullscreen mode Exit fullscreen mode

Final Verification

# Check that services are running
systemctl status ms-proxy spotlight-indexer smbd

# Count documents in the index
msctl count

# Search for a file
msctl search README.md

# Real-time logs during a search from the Mac
journalctl -u smbd -f
journalctl -u ms-proxy -f
Enter fullscreen mode Exit fullscreen mode

Top comments (0)