[Blog](https://deploywithox.com/blog) [Guides](https://deploywithox.com/blog#c-guides) # How to self-host SearXNG on your own VPS, no Docker Run SearXNG, the private metasearch engine, on your own Ubuntu server with ox: three variables and no database, from the config that passed its test. Saurav Sharma Oct 17, 2026 9 min read On this page - [What you need](https://deploywithox.com/blog/self-host-searxng#what-you-need) - [The steps](https://deploywithox.com/blog/self-host-searxng#steps) - [The ox.toml, line by line](https://deploywithox.com/blog/self-host-searxng#config) - [Results come from other engines](https://deploywithox.com/blog/self-host-searxng#engines) - [Services](https://deploywithox.com/blog/self-host-searxng#services) - [Updates and backups](https://deploywithox.com/blog/self-host-searxng#updates) - [Frequently asked questions](https://deploywithox.com/blog/self-host-searxng#faq) To self-host SearXNG you need an Ubuntu server, a fork of the SearXNG repo with one `ox.toml` file in it, and three variables. In our run the first deploy took about 2 minutes, and the app needed no database or other service. **How we tested** On Oct 17, 2026, ox deployed SearXNG from commit [`b00212a8`](https://github.com/searxng/searxng/commit/b00212a8366131936856b726ed4dd9bd281e4d7e) on a fresh DigitalOcean server with 8 vCPUs and 16 GB of memory. The run then redeployed it and rebooted the server. Then a separate test agent, one that did not write the config, searched the web from the home page and got results from several engines with an info box, and checked the app's services. [SearXNG](https://github.com/searxng/searxng) is a metasearch engine. It sends your query to many other search engines and shows their answers on one results page, and its project says users are neither tracked nor profiled. It is a Flask app in Python, served by Granian, and it is licensed under the AGPL. It has no accounts: you open the page and search. Your theme, language and chosen engines are kept in a cookie in your browser. Its docs call it a rolling release: every commit to the master branch is a release, so this guide names a commit, not a version. ox deployed SearXNG (commit b00212a8) on Oct 17, 2026 on a fresh DigitalOcean server with 8 vCPUs and 16 GB of memory; the first deploy took 2 minutes and a redeploy took 26 seconds. - **First deploy:** 2 minutes, from adding the project until the app passed the run's first checks. - **Redeploy of the same commit:** 26 seconds, until the app passed the checks again. - **Server:** DigitalOcean, 8 vCPUs and 16 GB of memory (`s-8vcpu-16gb`), with this app alone on it. Every one of the 85 apps we deployed ran on this one size, so it was not picked for this app. - **Memory in use after the reboot:** 721 MB of 15986 MB, for the whole server: Ubuntu, the app, its services, Caddy and the ox agent. On a server with no apps, ox's tests on real servers hold the agent to 40 MB or less and Caddy to 50 MB or less. - **Source:** [github.com/searxng/searxng](https://github.com/searxng/searxng), commit [`b00212a8`](https://github.com/searxng/searxng/commit/b00212a8366131936856b726ed4dd9bd281e4d7e). The SearXNG search page SearXNG results for eiffel tower from several engines ## What you need - An Ubuntu LTS server with root access. The facts above name the size the run used and the memory in use after its reboot. - A GitHub account to fork `searxng/searxng`, and an ox account, which you open by signing in with GitHub. - No outside account and no API key. SearXNG asks other search engines for results, so the server must be able to reach them. ## The steps In the ox dashboard, press Add a server. It shows one install command with a fresh token in it. Run that as root on the machine. It puts only the ox agent and Caddy there. Fork `searxng/searxng` on GitHub and check out commit `b00212a8`, the one the run deployed. Add the `ox.toml` shown below to the root of the fork, then commit and push. SearXNG needed no other added file. On your laptop, write a file named `searxng.env` with the three keys from the variables section. For `SEARXNG_SECRET`, `openssl rand -hex 32` makes a long random value. With the [ox CLI](https://deploywithox.com/docs/cli) signed in, run: Shell ```bash ox new /searxng ox review searxng --from-file searxng.env --wait ``` The review saves the values and starts the first deploy, and `--wait` prints the log until it ends. The [quickstart](https://deploywithox.com/docs/quickstart) shows the same two steps in the browser. When the deploy is green, open the address ox shows for the project. The home page has a search box and no sign-in. The test agent typed `eiffel tower` and pressed Enter. The results listed the official Eiffel Tower site and Wikipedia, each with the engines that found it, duckduckgo and google cse, and an info box about the tower sat on the right. The run served SearXNG on its preview address only. A domain of your own was not part of it, and the [domains page](https://deploywithox.com/docs/operate/domains) covers how ox adds one. ## The ox.toml, line by line TOML ```toml # SearXNG (Flask metasearch, no accounts), run outside Docker the way its # image does: container/builder.dockerfile installs requirements.txt and # requirements-server.txt into a venv, and container/dist.dockerfile runs # granian on searx.webapp:app with its GRANIAN_* settings. The repo's # package.json, go.mod and mise.toml are developer tools. Settings are the # defaults in searx/settings.yml with the image's two changes # (container/settings.template.yml) given as SEARXNG_* variables. # searx/webapp.py exits while server.secret_key is still "ultrasecretkey"; # SEARXNG_SECRET replaces it (the image's entrypoint makes a random one). required_variables = ["SEARXNG_SECRET"] [app] # dist.dockerfile's ENV, with ox's host and port in place of GRANIAN_HOST # and GRANIAN_PORT. start = "GRANIAN_PROCESS_NAME=searxng GRANIAN_INTERFACE=wsgi GRANIAN_WEBSOCKETS=false GRANIAN_BLOCKING_THREADS=4 GRANIAN_WORKERS_KILL_TIMEOUT=30s GRANIAN_BLOCKING_THREADS_IDLE_TIMEOUT=5m exec granian --host 127.0.0.1 --port $PORT searx.webapp:app" health = "/healthz" [build] install = "uv venv && uv pip install --requirements requirements.txt --requirements requirements-server.txt" # The image ships searx/version_frozen.py, which upstream's GitHub Actions # build writes (utils/lib_sxng_container.sh). Without it the app asks git at # every start, finds no repository, and its footer's "Source code" link # reads "unknown". A build's .git has no remote, so name the repository and # branch the way GitHub Actions does (searx/version.py reads both). commands = ["GITHUB_REPOSITORY=searxng/searxng GITHUB_REF_NAME=master python -m searx.version freeze"] ``` The repo holds a `package.json`, a `go.mod` and a `mise.toml`, but they belong to SearXNG's developer tools. The app is Python, so the config names how to build and start it, as SearXNG's container files do, without the container. - `required_variables` lists `SEARXNG_SECRET`. SearXNG's `webapp.py` exits at start while the secret key is still its placeholder, `ultrasecretkey`. The official image makes a random key at its first start. Here you give one, and `ox review` says before the first deploy if it is missing. - `[app] start` runs Granian, the server the official image uses, which `requirements-server.txt` pins at 2.8.4. The settings in front of `exec` are the image's own from `container/dist.dockerfile`: the process name, the WSGI interface, websockets off, four blocking threads, a 30 second kill timeout for workers and a 5 minute idle timeout for those threads. `--host 127.0.0.1 --port $PORT` replaces the image's host and port. ox hands the app a port in `$PORT`, and Caddy serves the public address in front of it. `searx.webapp:app` is the Flask app. - `health` is `/healthz`, a route in `webapp.py` that answers OK as plain text. ox moves traffic to a new release only after it answers. - `[build] install` follows `container/builder.dockerfile`: make a virtual environment with `uv`, then install `requirements.txt` and `requirements-server.txt` into it. ox's default install for a `requirements.txt` reads that file alone, and Granian lives in the second file, so the line names both. - `commands` runs `python -m searx.version freeze`, which writes `searx/version_frozen.py`. The official image ships that file. Without it the app asks git for its version at every start, and the footer's Source code link reads unknown. `GITHUB_REPOSITORY` and `GITHUB_REF_NAME` tell it the repository and branch, as SearXNG's own GitHub build does, because the server's copy has no remote. There is no `migrate`, `[services]` or `[storage]`, and no workers or cron jobs. SearXNG has no database to set up and keeps no data of its own, so the test agent found nothing to back up. The config also adds no `settings.yml`. SearXNG reads its built-in defaults, and the variables override the three values below. Shell ```bash SEARXNG_SECRET SEARXNG_BASE_URL SEARXNG_IMAGE_PROXY ``` - `SEARXNG_SECRET` replaces `server.secret_key`, which the docs say is used for cryptography. - `SEARXNG_BASE_URL` replaces `server.base_url`, the address SearXNG uses to build its inbound links. The run set it to the project's own address. In an env file, `${PUBLIC_URL}` is the reference ox fills in with it. See [variables](https://deploywithox.com/docs/operate/variables) for how references work. - `SEARXNG_IMAGE_PROXY` replaces `server.image_proxy`. Set to true, as the official image does, your server fetches image results for the visitor, and the docs note it uses memory space. The run did not open the Images tab, so image results were not tested. ## Results come from other engines SearXNG holds no index of its own, so results depend on the outside engines, and they change from one search to the next. An engine that answers with a captcha, too many requests or an access denied error is suspended for a while, and the results page names the engines that did not answer. Some engines turn away a data center's address, so a few may be missing on a hosted server. The others still answer. The run's search came back from duckduckgo and google cse. ## Services ox ran none for this app. SearXNG's compose file starts a Valkey container, but the default settings leave `valkey.url` false and the limiter off, so the instance never connects to one. The docs say the limiter, which rate limits requests and blocks some bots, needs Valkey. The limiter was not tested. SearXNG keeps SQLite caches in the system's temp folder. ## Updates and backups To move to a newer commit, merge it into your fork and push, or run `ox deploy searxng --wait`. ox builds the new release beside the running one and switches only when `/healthz` answers. SearXNG's docs ask you to read their "migrate and stay tuned" section before you upgrade an instance. The app has no database, uploads or accounts, so the run had nothing to back up and made no backup. A restore was not tested. If you add a service or a kept folder later, the [backups page](https://deploywithox.com/docs/operate/backups) covers what ox backs up. ## Frequently asked questions ### Do I need Docker to self-host SearXNG? No. SearXNG's docs offer a container image and install scripts, and this run used neither. ox built the app from your fork on the server with uv and runs it as a system service behind Caddy. There is no image to pull, and an update is a push to your fork. ### Does SearXNG have an admin account or a password? No. SearXNG has no users and no sign-in, and the only value it cannot start without is SEARXNG_SECRET. Anyone who has the address can search, and the run put no login in front of it. Adding one, or making the instance private, was not tested. ### Does SearXNG need Valkey or a database? Not with its default settings. This run asked ox for no service, and the app has no database of its own to set up. Valkey is needed only for the limiter, which is off by default. Using the limiter was not tested. ### How much memory does SearXNG use? The facts above show what the whole server used after its reboot, with SearXNG, Caddy and the ox agent running. SearXNG's docs note that the image proxy uses memory space. ox takes any server from 1 GB up, and it says so when memory is why the app stopped. ### How do I update a self-hosted SearXNG? SearXNG is a rolling release, so each commit to its master branch is a release. Merge the newer commit into your fork and push, or run ox deploy searxng. ox builds the new release beside the running one and switches when it answers. A redeploy of the same commit took the time shown in the facts. New to running apps on your own server? [How ox self-hosts your apps](https://deploywithox.com/self-hosting) shows what ox sets up on your server. On this page - [What you need](https://deploywithox.com/blog/self-host-searxng#what-you-need) - [The steps](https://deploywithox.com/blog/self-host-searxng#steps) - [The ox.toml, line by line](https://deploywithox.com/blog/self-host-searxng#config) - [Results come from other engines](https://deploywithox.com/blog/self-host-searxng#engines) - [Services](https://deploywithox.com/blog/self-host-searxng#services) - [Updates and backups](https://deploywithox.com/blog/self-host-searxng#updates) - [Frequently asked questions](https://deploywithox.com/blog/self-host-searxng#faq) - [Do I need Docker to self-host SearXNG?](https://deploywithox.com/blog/self-host-searxng#faq-docker) - [Does SearXNG have an admin account or a password?](https://deploywithox.com/blog/self-host-searxng#faq-account) - [Does SearXNG need Valkey or a database?](https://deploywithox.com/blog/self-host-searxng#faq-database) - [How much memory does SearXNG use?](https://deploywithox.com/blog/self-host-searxng#faq-memory) - [How do I update a self-hosted SearXNG?](https://deploywithox.com/blog/self-host-searxng#faq-update) Written by Saurav Sharma Builds ox. Writes about running apps on servers you own, without Docker and without a platform bill. [Older post How to self-host solidtime on your own VPS without Docker](https://deploywithox.com/blog/self-host-solidtime) [Newer post How to self-host Saleor without Docker on your own VPS](https://deploywithox.com/blog/self-host-saleor) ## Keep reading - Guides [Self-Hosted Open-Source Apps Deployed with ox: All 85](https://deploywithox.com/blog/self-hosted-open-source-apps-deployed-with-ox) ox deployed 85 open-source apps from pinned commits on fresh servers, with no Docker. The stacks, services, deploy times and a table of every app. Saurav Sharma Oct 17, 2026 16 min read - Guides [How to self-host AFFiNE on your own VPS without Docker](https://deploywithox.com/blog/self-host-affine) Run AFFiNE v0.27.4 on your own Ubuntu server with ox: Postgres with pgvector, Redis, a Rust and Node build, and an admin made from two variables. Saurav Sharma Oct 17, 2026 12 min read - Guides [How to self-host Akaunting on your own VPS without Docker](https://deploywithox.com/blog/self-host-akaunting) Run Akaunting 3.2.4 on your own Ubuntu server with ox: PHP, MariaDB, a scheduler and the first company and admin made on deploy, from the config that ran. Saurav Sharma Oct 17, 2026 10 min read ## Deploy to a server you own ox sets up systemd, Caddy and PostgreSQL on your Ubuntu server and deploys on every push. Free for your first project. [Sign up with GitHub](https://deploywithox.com/login/github) [Read the docs](https://deploywithox.com/docs)