Getting started¶
This guide takes you from an empty directory to a searchable index of your own site. You will need Python 3.13 and MySQL 8 or later.
What you need¶
- Python 3.13 — from python.org or your package manager.
- MySQL 8+ — MySQL Community Edition is free. MariaDB 11 works too; the schema uses nothing exotic.
- Git — to clone the source.
A shared hosting account is enough. Dead Simple Search needs no MySQL plugins and no server-configuration changes.
Older Python versions
The project targets Python 3.13. Earlier versions may work but are not tested.
Step 1: Get the code¶
Step 2: Set up Python¶
Using uv:
# Install uv if you don't have it — see https://docs.astral.sh/uv/
curl -LsSf https://astral.sh/uv/install.sh | sh
uv venv --python 3.13
source .venv/bin/activate
uv pip install -r requirements.txt
Or with the standard library's venv:
Install the dependencies, don't skip them
protego handles wildcard rules in robots.txt. Without it the application still runs, but falls back to a parser that ignores those rules and logs a warning — meaning it may crawl paths a site asked it to leave alone.
Step 3: Set up MySQL¶
Create a database and a user:
CREATE DATABASE IF NOT EXISTS deadsimplesearch
CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER IF NOT EXISTS 'deadsimplesearch'@'localhost'
IDENTIFIED BY 'choose-a-strong-password';
GRANT ALL PRIVILEGES ON deadsimplesearch.*
TO 'deadsimplesearch'@'localhost';
FLUSH PRIVILEGES;
That is all the manual setup required. The tables are created automatically on the first API request, and later versions add their own columns the same way — there is no separate migration step and no schema file to import.
Step 4: Configure¶
Set your database password and an API key:
export MYSQL_PASSWORD=choose-a-strong-password
export API_KEY=$(python -c "import secrets; print(secrets.token_urlsafe(32))")
Without API_KEY, the endpoints that register sites and trigger crawls accept unauthenticated requests. That is fine on your laptop and a bad idea anywhere else.
If exporting variables is inconvenient on your host, put the same KEY=VALUE lines in a .env file beside config.py.
See the configuration reference for every available setting.
Step 5: Run¶
The server listens on http://localhost:5555. For production, run it under gunicorn with a single worker:
Step 6: Add your first site¶
curl -X POST http://localhost:5555/api/sites \
-H "X-API-Key: $API_KEY" \
-H "Content-Type: application/json" \
-d '{"domain": "yourwebsite.com", "start_url": "https://yourwebsite.com/"}'
Trigger a crawl:
The crawl runs in the background. Check on it:
Once it reports completed, search:
Search and status are read endpoints and need no key.
Getting good dates in your results¶
Results carry page_published and page_modified. Both come first from the page's own markup, so a site that declares its dates gets the best data. Adding Schema.org JSON-LD to your templates is the single most useful thing you can do for search result quality:
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "WebPage",
"datePublished": "2019-03-04",
"dateModified": "2026-01-15"
}
</script>
Open Graph, Microdata and Dublin Core work too. Without any of them, page_modified can still fall back to your sitemap's <lastmod> or the HTTP Last-Modified header, but page_published will be empty — no external source can know when a page was created.
Next steps¶
- The API reference for every endpoint
- The configuration guide to tune crawling, search and limits
- How it works for the design behind it