Overview
SearXNG is a privacy-respecting metasearch engine: it holds no index of its own, forwards each query to many upstream engines, and merges the results while keeping no profile and setting no tracking cookies. This template deploys it as a stateless workload serving the web UI and the JSON API on port8080, with a bundled Redis, on by default, that backs the rate limiter and the shared state a multi-replica install needs.
The JSON API is the reason this template exists. GET /search?q=...&format=json returns merged web results as JSON with no API key, no per-query bill and no vendor quota, which makes it a search backend an AI agent can call directly. formats ships as [html, json], so the API is live on a default install alongside the human UI.
The signing key SearXNG uses for preference cookies and CSRF tokens is not a template value. The workload reads it from an opaque secret you create before installing, so the key never passes through Helm and never lands in the release.
publicAccess.enabled is false and limiter.enabled is false. Those two defaults belong together — see Choosing an Access Shape before publishing the instance.What Gets Created
Prerequisites
One secret must exist before you install. It holds the key that signs preference cookies and CSRF tokens. Secrets are org-level, so no GVC flag is involved.Create the signing-key secret
secretKey.secretName to this name. Every replica reads the same secret, which is what lets any replica verify any user’s preference cookie.Installation
Install the chart from the marketplace registry, pointing it at the secret you created:UI
CLI
Terraform
Pulumi
Configuration
Each block below is the shipped default for that part ofvalues.yaml.
SearXNG Server and Resources
Search Behavior
formats— a format that is not listed is refused, so removingjsondisables the API.imageProxy— relays result images through this instance so a user’s browser never contacts the origin; on a public instance that also makes it an open image relay.baseUrl— leave empty for the canonical*.cpln.appendpoint; set it only behind a custom domain. It drives theopensearch.xmldocument browsers use to add the instance as a search provider.extraSettings— merged over the keys above, so anything in the upstream settings reference is reachable (engine selection,safe_search,outgoingtimeouts). An override of a key this template also sets wins cleanly.
settings.yml, not on the workload — after changing them, follow Changing Settings.
Signing Key
reveal on exactly that secret and injects it as an environment variable, so the key never appears in the rendered configuration.
Access
publicAccess.enabled: true serves the UI, the API, /config and /stats to anyone who finds the endpoint — turn limiter.enabled on first. Outbound access is always open and is not configurable: querying upstream engines over the public internet is the entire function of the service. A change to either access key can take several minutes to take effect; re-test before concluding it did not apply.
Redis
The bundled datastore exists for the limiter and for shared state across replicas. It stores no search results and nothing durable.redis.enabled: falseruns SearXNG standalone;limiter.enabledmust then stayfalse, and the chart refuses to render the combination.redis.redis.replicasmust stay1, and the chart rejects anything else: SearXNG’s client is not Sentinel-aware and has to reach the master directly, so extra replicas would be read-only and would silently break the limiter. One Sentinel is required by the redis template and cannot be scaled to zero.- Change
redis.redis.auth.password.valuefrom the placeholder if you enableAUTH.redis.redis.auth.fromSecretis not supported by this template.
Connecting
SearXNG has no login, so there are no credentials anywhere in this table. A default install is private: nothing outside Control Plane can reach it, and workloads inside the GVC reach it subject tointernalAccess.type.
http://localhost:8080 for the UI. cpln port-forward is a top-level command, not a cpln workload subcommand.
First Run
There is no login and no setup wizard: open the endpoint and search.Choosing an Access Shape
The rate limiter and the JSON API pull in opposite directions, and this is the decision to get right before you publish anything. The limiter is bot detection, not a simple request counter: it inspects each request and rejects anything that does not look like a real browser. A plaincurl, a Python HTTP client or an AI agent therefore gets 429 Too Many Requests on /search — including format=json — while a browser-shaped request is served normally and then throttled. Turning the limiter off makes the JSON API usable by any client, and also means nothing throttles the instance, which is fine behind a closed firewall and a problem on the open internet.
publicAccess.enabled: true and limiter.enabled: true in your values, upgrade the release, then read the assigned *.cpln.app address:
limiter.enabled: true requires redis.enabled: true.
Using the JSON API
From another workload in the same GVC, using the fully-qualified internal name:categories (for example general, images, news), language, time_range, safesearch and pageno; the full set is in the upstream search API reference.
Keep limiter.enabled: false for this. If the instance must be public and callable by an agent, the agent has to send browser-shaped headers — a realistic User-Agent plus Accept, Accept-Language and Accept-Encoding — and it is still throttled like any browser.
Operations
Changing Settings
instanceName, formats, imageProxy, limiter.enabled and extraSettings are rendered into settings.yml, which the workload reads from the RELEASE_NAME-searxng-settings secret mounted as a file. A cpln helm upgrade that changes only those keys rewrites the secret but leaves the workload itself unchanged, and a running replica does not pick up a changed secret file on its own. After such an upgrade, force a redeployment so every replica restarts against the new file:
image, replicas, resources, baseUrl, publicAccess or internalAccess alter the workload spec and roll it out on their own.
Rotating the Signing Key
Rotation is not a routine operation: preferences live in a cookie signed with this key, so a new key discards every saved preference in every browser. Rotate only if the key is compromised.cpln secret update cannot change a secret’s value — it edits only the description and tags. Write the new value with cpln apply, then force a redeployment; running replicas keep the key they started with until they restart:
Scaling and Availability
replicasscales the SearXNG tier horizontally. Instances share nothing on disk and there is no server-side session to pin, so any replica can serve any request; withredis.enabled: truethe limiter’s counters are shared across replicas.- The bundled datastore is a single Redis instance and the chart keeps it that way. If it restarts, limiter counters reset and nothing is lost, because search results were never stored there.
- With
limiter.enabled: true, a SearXNG container that starts while the datastore is unreachable refuses to start rather than coming up silently unthrottled. With the limiter off, it logs a warning and starts normally. - The first
cpln helm upgradeafter an install can re-apply resources that did not change, including the datastore workloads, which restarts them once. Atreplicas: 1budget a brief interruption on that first upgrade. - A workload runs in every location its GVC has. Extra locations multiply both the instance count and the outbound query volume upstream engines see from you, so install into a single-location GVC unless you mean otherwise.
- There is nothing to back up: the template holds no durable data of its own. Keep a copy of your signing key outside Control Plane, and a reinstall against the same secret keeps every preference cookie valid.
Troubleshooting
Workload never becomes ready and cpln logs returns nothing
Workload never becomes ready and cpln logs returns nothing
RELEASE_NAME-searxng stays not ready indefinitely, and cpln logs '{gvc="GVC_NAME", workload="RELEASE_NAME-searxng"}' --limit 50 --since 10m returns zero lines.Cause: secretKey.secretName names a secret that does not exist, so the container is never started. The message is only visible in status.versions[].message:cpln workload force-redeployment RELEASE_NAME-searxng --gvc GVC_NAME.JSON API returns 429 Too Many Requests to curl or an agent
JSON API returns 429 Too Many Requests to curl or an agent
GET /search?q=...&format=json from curl, an HTTP client library or an agent returns 429 Too Many Requests on every call, while the same search works from a browser.Cause: limiter.enabled: true. The limiter is bot detection and rejects requests that do not look like a real browser.Fix: for an agent backend, run the private shape (limiter.enabled: false, publicAccess.enabled: false) — see Choosing an Access Shape. If the instance must stay public, the client has to send browser-shaped headers and accept being throttled.Requests with format=json are refused with 403
Requests with format=json are refused with 403
/search?...&format=json returns 403 Forbidden while the HTML UI works.Cause: json was removed from formats. SearXNG refuses any output format that is not listed there.Fix: add json back to formats, upgrade, and force a redeployment as in Changing Settings.Container exits with searxng-startup FATAL datastore unreachable
Container exits with searxng-startup FATAL datastore unreachable
limiter.enabled: true, RELEASE_NAME-searxng restarts instead of becoming ready, and its logs end with:RELEASE_NAME-redis with cpln workload get-deployments RELEASE_NAME-redis --gvc GVC_NAME -o yaml and its logs. If redis.redis.auth.password.enabled is on, make sure redis.redis.auth.password.value is set. Once the datastore is healthy, SearXNG starts on its next restart.Install refused with limiter.enabled requires redis.enabled
Install refused with limiter.enabled requires redis.enabled
cpln helm install or cpln helm upgrade stops before touching any resource:limiter.enabled: true with redis.enabled: false.Fix: enable the datastore, or turn the limiter off. The two settings are validated together at render time.Install refused with redis.redis.replicas must be 1
Install refused with redis.redis.replicas must be 1
cpln helm install or cpln helm upgrade stops before touching any resource:redis.redis.replicas above 1.Fix: leave redis.redis.replicas at 1. Scale SearXNG itself with replicas instead.A settings change did not take effect after an upgrade
A settings change did not take effect after an upgrade
instanceName, formats, imageProxy, limiter.enabled or extraSettings, the upgrade reported the settings secret updated, but the running instance still shows the old behaviour.Cause: those keys live in a secret mounted as a file, and a running replica does not re-read a changed secret.Fix: cpln workload force-redeployment RELEASE_NAME-searxng --gvc GVC_NAME — see Changing Settings.Important Notes
- Create the signing-key secret before installing. A reference to a secret that does not exist wedges the workload with no log output; see Prerequisites for the one command that shows the reason.
- Treat the signing key as write-once and keep a copy. Rotating it invalidates every saved preference cookie — see Rotating the Signing Key.
- There is no authentication of any kind. With
publicAccess.enabled: truethe UI, the API,/configand/statsare served to anyone who finds the endpoint. Turnlimiter.enabledon before you publish. - The limiter blocks the JSON API for non-browser clients. Pick one of the two shapes in Choosing an Access Shape deliberately; never run public with the limiter off.
- Settings changes need a forced redeployment.
settings.ymlis a mounted secret and running replicas do not re-read it — see Changing Settings. redis.redis.replicasmust stay1, andlimiter.enabledrequiresredis.enabled. Both are enforced at render time, so a bad combination fails the install rather than shipping a silently unlimited instance./metricsis off as shipped and needs a password to open. Upstream gates it ongeneral.open_metrics, which is empty by default; setting it throughextraSettingsenables the route behind HTTP basic auth with that password.extraSettings: {general: {enable_metrics: false}}stops collecting the data behind/stats.- Uninstalling removes everything the template created — workloads, secrets, identities and policies, with no volume sets left behind. Your own signing-key secret is yours and is left alone.
External References
SearXNG Project
Settings Reference
extraSettingsServer Settings
server.* block, including the limiter and image proxyThe Limiter
Search API
/search