<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[TEI (Text Embeddings Inference) on Cloudron - Community Package]]></title><description><![CDATA[<h1>Text Embeddings Inference (Hugging Face TEI), packaged for Cloudron</h1>
<p dir="auto">A community package for <strong>Text Embeddings Inference (TEI)</strong> — Hugging Face's fast Rust server for text<br />
embeddings and reranking. It is the embedding tier of a self-hostable, OpenAI-compatible retrieval<br />
stack: TEI turns text into vectors, a vector database such as Qdrant stores and searches them, and an<br />
LLM answers over what is retrieved.</p>
<ul>
<li>Package: <a href="https://github.com/OrcVole/TEI-Cloudron" target="_blank" rel="noopener noreferrer nofollow ugc">https://github.com/OrcVole/TEI-Cloudron</a></li>
<li>Upstream: <a href="https://github.com/huggingface/text-embeddings-inference" target="_blank" rel="noopener noreferrer nofollow ugc">https://github.com/huggingface/text-embeddings-inference</a></li>
</ul>
<h2>TL;DR</h2>
<p dir="auto">TEI gives you a private, self-hosted <strong>embeddings API</strong> (OpenAI-compatible <code>/v1/embeddings</code>, plus a<br />
native <code>/embed</code>). Install it from the versions URL, the API key is generated for you on first run, point any app that<br />
speaks the OpenAI embeddings API at it, and you have on-box embeddings for retrieval-augmented<br />
generation (RAG) and semantic search — no documents leaving your server. It pairs directly with the<br />
Qdrant Cloudron package to make a complete pure-Rust retrieval pipeline. It is <strong>API-only (no web<br />
UI)</strong>, <strong>amd64-only</strong> (the CPU build bundles Intel MKL), and verified working on Cloudron 9.x,<br />
including a live TEI-to-Qdrant round trip.</p>
<h2>Installation</h2>
<p dir="auto">Click on the Add custom app drop down top right in the App Store and choose Community app:<br />
Then paste in the CloudronVersions.json URL into the box that pops up:</p>
<p dir="auto"><img src="/assets/uploads/files/1782552662907-community-package-resized.jpeg" alt="Community Package.jpeg" class=" img-fluid img-markdown" /> <img src="/assets/uploads/files/1782552663029-cloudronversions.jpeg" alt="CloudronVersions.jpeg" class=" img-fluid img-markdown" /></p>
<p dir="auto">From CLI:<br />
Install:</p>
<pre><code>cloudron install \
  --versions-url https://raw.githubusercontent.com/OrcVole/TEI-Cloudron/main/CloudronVersions.json \
  --location tei.example.com
</code></pre>
<hr />
<h2>For potential users</h2>
<p dir="auto"><strong>What it is.</strong> You send TEI text, it returns an embedding (a vector of ~384 numbers for the default<br />
model). That vector is the "meaning" of your text as coordinates, which a vector database can compare<br />
and search. TEI speaks the <strong>OpenAI embeddings API</strong>, so anything that already calls OpenAI for<br />
embeddings can call your own box instead.</p>
<p dir="auto"><strong>There is no web page.</strong> TEI is a service, not a website — opening its domain shows a blank page, and<br />
that is normal. The only browsable page is the interactive Swagger API docs at <code>/docs</code> (behind your<br />
Cloudron login; the app's "Open" button goes there). You check it works by calling it: <code>GET /health</code><br />
returns <code>OK</code>, and a real embedding request returns a JSON list of ~384 decimal numbers. That wall of<br />
numbers is the correct output — it is for machines, not people.</p>
<p dir="auto"><strong>What you can do with it.</strong></p>
<ul>
<li>Give <strong>OpenWebUI, AnythingLLM, n8n, or <code>rig</code></strong> a private embeddings backend for document chat and<br />
semantic search, instead of sending your files to a third-party API.</li>
<li>Build a <strong>RAG pipeline</strong>: embed your documents with TEI, store and search them in Qdrant, and let an<br />
LLM (e.g. Ollama) answer questions grounded in your own data.</li>
<li>Switch the model with one environment variable (<code>TEI_MODEL_ID</code>) — multilingual, larger/higher<br />
recall, or a <strong>cross-encoder reranker</strong> (for the <code>/rerank</code> endpoint) to sharpen search results.</li>
</ul>
<p dir="auto"><strong>Synergy with other Cloudron apps.</strong> TEI is one tier of a stack you can run entirely on Cloudron:</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>App</th>
<th>Role</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>TEI</strong> (this)</td>
<td>Text -&gt; embeddings (and reranking)</td>
</tr>
<tr>
<td><strong>Qdrant</strong></td>
<td>Stores the vectors, does similarity search</td>
</tr>
<tr>
<td><strong>Ollama</strong></td>
<td>The LLM that answers</td>
</tr>
<tr>
<td><strong>OpenWebUI</strong></td>
<td>The chat UI; point its embedding engine at TEI for document RAG</td>
</tr>
<tr>
<td><strong>agentgateway</strong></td>
<td>One gated front door: routes chat to the LLM and exposes Qdrant as an agent (MCP) tool</td>
</tr>
<tr>
<td><strong>n8n</strong></td>
<td>Automates ingestion: pull documents, embed via TEI, upsert to Qdrant</td>
</tr>
</tbody>
</table>
<p dir="auto">The default model is <code>BAAI/bge-small-en-v1.5</code> (384-dim), which matches the Qdrant package's examples,<br />
so the pieces line up dimensionally out of the box.</p>
<p dir="auto"><strong>Good defaults.</strong> TEI has no auth of its own, so the package generates a strong API key on first run<br />
and injects it through the environment; the embedding endpoints require it, <code>/health</code> stays open for<br />
monitoring, and the Swagger docs sit behind Cloudron single sign-on. The model cache and the key live<br />
under <code>/app/data</code>, so Cloudron's backup covers them and a restore brings the same key back.</p>
<p dir="auto"><strong>Caveats:</strong> no web UI; amd64 only; a large model needs more than the 2 GB default and a slower first<br />
boot (it downloads once, then is cached); the default model does embeddings only (<code>/rerank</code> needs a<br />
reranker model).</p>
<hr />
<h2>For other packagers</h2>
<p dir="auto"><strong>What helped.</strong></p>
<ul>
<li>A <strong>multi-stage Dockerfile</strong> onto <code>cloudron/base:5.0.0</code>: pull the runtime out of the official<br />
upstream image in stage one, assemble onto the base in stage two. On-server build (<code>cloudron install</code> from source) meant no local Docker was needed for iterating; rootless <strong>podman</strong> built it<br />
locally.</li>
<li>Putting <strong>all state under <code>/app/data</code></strong> (the model cache and the generated key) made the<br />
<code>localstorage</code> backup just work — a real backup then <code>clone</code> brought the key back byte-for-byte.</li>
<li>A <strong>build-time linkage gate</strong> (<code>ldd</code> + <code>--version</code> in the Dockerfile) catches a missing library or<br />
glibc symbol at build time instead of at runtime.</li>
<li>The <strong>reference packages</strong> (agentgateway, and the sibling Qdrant package) set the patterns: the<br />
two-surface auth model, the <code>/run</code> vs <code>/app/data</code> discipline, the release gates.</li>
</ul>
<p dir="auto"><strong>What was difficult.</strong></p>
<ul>
<li>The CPU build is <strong>not a lone binary</strong> — it carries a ~320 MB Intel MKL math runtime. The real trap:<br />
<code>libiomp5.so</code> in the upstream image is a symlink whose internal soname is <code>libomp.so.5</code>, so<br />
<code>ldconfig</code> indexes it under the wrong name and the binary fails to resolve it. Fix: <code>cp -L</code> it to a<br />
concrete <code>libiomp5.so</code> and resolve the MKL libs via <code>LD_LIBRARY_PATH</code> (filename match), not<br />
ldconfig. And the linkage gate does <strong>not</strong> load the MKL libs (they are dlopened at inference time),<br />
so the only honest test is a runtime <code>/embed</code> smoke on the assembled image.</li>
<li>The router defaults <code>--hostname</code> to the <code>HOSTNAME</code> env var, which Docker sets to the <strong>container<br />
id</strong>, so it binds the wrong interface unless you pass <code>--hostname 0.0.0.0</code> explicitly. The upstream<br />
default port is 80, which the unprivileged <code>cloudron</code> user cannot bind — move it to 8080.</li>
<li><code>proxyAuth</code> with <code>supportsBearerAuth: true</code> let <strong>any</strong> bearer header skip the SSO wall on <code>/docs</code>;<br />
for a docs-only wall, drop the flag (<code>"proxyAuth": { "path": "/docs" }</code>).</li>
<li><strong>Users expect a GUI</strong> and there is none, so set <code>configurePath: /docs</code> and say so plainly in the<br />
post-install notes, including that a successful embedding is a wall of numbers.</li>
<li>Publishing on a <strong>podman-only host</strong>: <code>cloudron versions add</code> could not see the image through the<br />
podman socket, so I hand-built <code>CloudronVersions.json</code> (inlining the <code>file://</code> description, changelog,<br />
and post-install message; keeping <code>icon</code> as <code>file://</code>; pinning the digest). It validated on the real<br />
versions-url install.</li>
</ul>
<p dir="auto"><strong>How we made it compatible with other Cloudron apps.</strong></p>
<ul>
<li><strong>OpenAI-compatible endpoint</strong> is the key: it lets OpenWebUI, n8n, AnythingLLM, and <code>rig</code> use TEI by<br />
changing one base URL, with no app-specific glue.</li>
<li><strong>API-key auth on the data plane, SSO only on <code>/docs</code></strong>, so a sibling app authenticates with a key<br />
and gets TEI's own 401 (not a login redirect) when the key is wrong — that is what makes<br />
app-to-app calls work.</li>
<li><strong>Dimensional alignment with Qdrant</strong> (both default to bge-small-en-v1.5, 384-dim) so vectors are<br />
comparable across the stack.</li>
<li>We <strong>wired it live</strong>: OpenWebUI's embedding engine pointed at TEI via the package's <code>env.sh</code>, and a<br />
verified TEI-to-Qdrant retrieval round trip. agentgateway already fronts Qdrant (as an MCP tool) and<br />
Ollama, so TEI slots in as the embeddings tier.</li>
</ul>
<hr />
<h2>For the Cloudron maintainers</h2>
<p dir="auto">Friendly asks from packaging this:</p>
<ul>
<li><strong><code>iconUrl</code> couples to the <code>minBoxVersion</code> floor.</strong> A <code>--versions-url</code> manifest must include<br />
<code>iconUrl</code>, and <code>iconUrl</code> forces <code>minBoxVersion &gt;= 9.1.0</code>; omitting it fails validation. So every<br />
community-channel app is pinned to box 9.1.0+ purely by the icon requirement, even when it runs on<br />
8.3. Only the real versions-url path surfaces this (on-server <code>cloudron install</code> accepts a lower<br />
floor). Please document or decouple. (This affects the Qdrant package too.)</li>
<li><strong><code>cloudron versions add</code> needs the image via the Docker API, with no working podman bridge.</strong> On a<br />
podman-only host it reported "No docker image found, run cloudron build first" even with<br />
<code>DOCKER_HOST</code> pointed at the podman socket and the image present. A documented podman path, or a<br />
<code>cloudron versions add --image &lt;ref&gt;</code> that takes a registry reference directly, would remove the need<br />
to hand-build the versions file.</li>
<li>The <code>manifestVersion</code> is still 2 and these primitives look stable, which is reassuring for the<br />
Cloudron 10 upgrade — the one thing a packager will need to re-verify on 10 is the <code>cloudron/base</code><br />
pin (re-run the linkage gate).</li>
</ul>
<h2>For the developers of the program (Hugging Face / TEI)</h2>
<p dir="auto">Friendly asks that would make TEI easier to run in any container:</p>
<ul>
<li><code>--hostname</code> defaulting to the <code>HOSTNAME</code> env var is container-hostile (Docker sets <code>HOSTNAME</code> to<br />
the container id, so the server binds the wrong interface). Consider defaulting to <code>0.0.0.0</code>.</li>
<li>A CPU image that does <strong>not</strong> bundle Intel MKL (or a clearly separate slim tag) would make a small,<br />
reproducible base copy much simpler. The MKL + <code>libfakeintel</code> + <code>libiomp5</code> set, and the<br />
<code>libiomp5.so</code> soname mismatch, were the bulk of the packaging effort.</li>
<li>Publish a <strong>minimum glibc per release</strong> — the binary is dynamically linked, and a slim base needs to<br />
know the floor (a toolchain bump that raises it fails at runtime, not build time).</li>
<li>An <strong>arm64 CPU image</strong> would let TEI run on arm Cloudron hosts; today the CPU/MKL image is amd64-only.</li>
</ul>
<hr />
<p dir="auto">It tracks upstream TEI releases and keeps the binary unmodified. Hugging Face and the model names are<br />
trademarks of their owners; this is a community package, not affiliated with or endorsed by Hugging<br />
Face. Feedback, issues, and suggestions are very welcome.</p>
<p dir="auto">#text-embeddings-inference #huggingface #embeddings #rag #cloudron-9.1</p>
]]></description><link>https://forum.cloudron.io/topic/15648/tei-text-embeddings-inference-on-cloudron-community-package</link><generator>RSS for Node</generator><lastBuildDate>Fri, 10 Jul 2026 07:30:52 GMT</lastBuildDate><atom:link href="https://forum.cloudron.io/topic/15648.rss" rel="self" type="application/rss+xml"/><pubDate>Thu, 25 Jun 2026 22:07:47 GMT</pubDate><ttl>60</ttl></channel></rss>