Build and verify a local AI research service before enabling controlled remote access
Local Deep Research is a self-hosted research application with a browser interface, search integrations, and support for local or compatible cloud model endpoints. This guide installs the Python package on Windows, macOS, or Linux, runs SearXNG with Docker, connects Ollama, and tests the workflow at http://localhost:5000. We explain the documented per-user login and SQLCipher storage model, including the important limitations of unencrypted development mode. Only after checking the installed version and access controls do we connect the service to a Localtonet HTTP tunnel.
π What's in this guide
What you are installing
Local Deep Research, or LDR, searches web sources, academic services, and local documents before synthesizing reports with citations. This tutorial follows its pip installation guide. The project recommends Docker for most general deployments because it handles more dependencies automatically. Pip is useful for developers and operators who want a conventional Python environment, but supporting services remain your responsibility.
The PyPI package listing supplied for this revision identifies release 1.10.7. Repository documentation on the main branch can change independently of a published package. Use the version command below to identify your actual installation and record your own test results. This article is a documented procedure, not a claim that we executed a 1.10.7 deployment or completed a route-level security audit.
gemma3:12b.Keep these layers separate during diagnosis. A successful package installation does not prove that search, model generation, database encryption, or authorization works. Likewise, local model inference does not mean all activity stays on the machine: web searches and source downloads contact external services, and a cloud model provider receives the information sent to it.
Prerequisites for Windows, macOS, and Linux
Install Python 3.10 or newer with pip, Docker for SearXNG, and Ollama for the local model example. Use the official Python downloads, Docker installation instructions, and Ollama installer. Package dependency compatibility can narrow the usable Python versions on a particular platform; review installation errors rather than assuming every newer interpreter has compatible wheels.
Check Python and pip
python --version
python -m pip --version
On Windows, use py --version and py -m pip --version if the Python launcher is your entry point. On macOS or Linux, use python3 --version and python3 -m pip --version if necessary. Invoking pip through the interpreter helps prevent installation into a different Python environment.
Check Docker and Ollama
docker --version
docker info
The first command checks the Docker executable; the second contacts its daemon. Start Docker Desktop or the operating system's Docker service if the daemon is unavailable. Install and launch Ollama separately. If it is not already running as an application or background service, start it with:
ollama serve
Leave that terminal running and use another terminal to check the model API:
curl http://localhost:11434/api/tags
A JSON response confirms connectivity, not model availability. You can also open this address in a browser. Do not start a second Ollama server if one already owns the port.
Hardware, storage, and optional dependencies
The project documents an AVX-capable processor requirement for x86-64 systems, with Intel Sandy Bridge and AMD Bulldozer around 2011 as the compatibility floor. Scientific Python wheels can fail with Illegal instruction on older processors. ARM64, also called aarch64, is documented as supported.
Earlier project installation guidance estimates approximately 100 MB for LDR, 1 to 2 GB for SearXNG, and 5 to 15 GB for model files. Treat those as planning estimates, not a complete storage budget. Python dependencies, Docker layers, documents, indexes, backups, and model selection add to the total. Model memory requirements also depend on model size and runtime configuration.
| Platform | Foundation | Important difference |
|---|---|---|
| Windows | Python, Docker Desktop, Ollama | PowerShell and Command Prompt use different activation and environment syntax. PDF export needs Pango/Cairo libraries. |
| macOS | Python, Docker Desktop, Ollama | Use the POSIX shell examples. Common CJK and emoji fonts ship with the operating system. |
| Linux | Python, Docker Engine, Ollama | Confirm Docker access. Optional PDF exports may require additional host fonts. |
Create and activate a Python virtual environment
A virtual environment separates LDR dependencies from system packages. Choose the commands for one shell, create a dedicated directory, and reactivate the environment whenever you return.
Windows PowerShell
mkdir local-deep-research
cd local-deep-research
py -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip --version
If your installation uses python instead of py, substitute python -m venv .venv. If PowerShell blocks activation, use Command Prompt or invoke .\.venv\Scripts\python.exe directly in place of python. Do not disable system security controls globally just to activate an environment.
Windows Command Prompt
mkdir local-deep-research
cd local-deep-research
py -m venv .venv
.venv\Scripts\activate.bat
python -m pip --version
macOS or Linux
mkdir local-deep-research
cd local-deep-research
python3 -m venv .venv
source .venv/bin/activate
python -m pip --version
The pip path should be inside .venv. That is stronger evidence than the prompt's optional (.venv) prefix. If your Linux distribution separates virtual-environment support into an operating-system package, install the matching package for your interpreter before retrying. Run deactivate when you want to leave the environment.
Install and configure Local Deep Research with pip
Follow the pip guide's five stages with the environment active. The SearXNG command below deliberately narrows Docker's host binding to IPv4 loopback instead of using the guide's all-interface publishing shorthand.
Install and identify the package
Install with the active interpreter, then record the installed version and confirm the import.
python -m pip install local-deep-research
python -m pip show local-deep-research
python -c "import local_deep_research; print('Local Deep Research import succeeded')"
Record the Version and Location fields. The supplied release baseline is 1.10.7, but an unpinned install can select a later compatible release. Do not label an installation βtestedβ until you complete the checks below.
Pull and run SearXNG on loopback
docker pull searxng/searxng
docker run -d -p 127.0.0.1:8080:8080 --name searxng searxng/searxng
docker ps
docker logs searxng
docker port searxng
Confirm the published address is 127.0.0.1:8080, not 0.0.0.0:8080 or an all-interface IPv6 address. This assumes Docker runs on the same host as the pip-installed LDR process.
Start and verify Ollama
Launch the installed application or use ollama serve if no server is running.
curl http://localhost:11434/api/tags
Download the example model
ollama pull gemma3:12b
ollama list
Confirm gemma3:12b appears. The Python package does not contain the model, and downloading it can consume several gigabytes.
Approve SearXNG and start LDR
Set the exact SearXNG origin in the launching shell using the platform-specific commands below, then start the web application.
-p 8080:8080 normally publishes on all host interfaces. Docker's port-publishing documentation describes specifying 127.0.0.1 to restrict host access to loopback. It also warns that Docker releases older than 28.0.0 can allow same-L2-network hosts to reach localhost-published ports. Use a maintained Docker release and test from another device. Do not rely solely on a generic host-firewall rule without checking how Docker's networking rules interact with it.
If you previously created an all-interface container, docker restart will not change its port mapping. Preserve needed configuration, stop and remove that container, then recreate it with the loopback command. Do not tunnel port 8080 or Ollama's port 11434 for this workflow.
macOS and Linux startup
export LDR_SEARCH_ENGINE_WEB_SEARXNG_DEFAULT_PARAMS_INSTANCE_URL=http://localhost:8080
python -m local_deep_research.web.app
Windows PowerShell startup
$env:LDR_SEARCH_ENGINE_WEB_SEARXNG_DEFAULT_PARAMS_INSTANCE_URL = "http://localhost:8080"
python -m local_deep_research.web.app
Windows Command Prompt startup
set LDR_SEARCH_ENGINE_WEB_SEARXNG_DEFAULT_PARAMS_INSTANCE_URL=http://localhost:8080
python -m local_deep_research.web.app
The README documents the module entry point; the pip guide also documents ldr-web. Both start the web interface. The module form makes the interpreter explicit and avoids console-script PATH confusion.
Pinning the SearXNG URL both configures it and marks it operator-approved; the setting becomes read-only in the web interface. LDR otherwise blocks private, loopback, and link-local search-engine URLs. If localhost resolves only to IPv6 in your environment, use http://127.0.0.1:8080 consistently for the configured origin and tests.
The exact-origin alternative LDR_SEARCH_PRIVATE_ENGINE_URL_ALLOWLIST was introduced in 1.10.5. That is historical context, not the current release baseline. Confirm support in your installed release before using alternatives. Avoid the broader LDR_SEARCH_ALLOW_PRIVATE_ENGINE_URLS=true unless you have explicitly reviewed its wider scope.
Shell variables apply to that shell and its child processes. Set them again when reopening a terminal, and restart LDR after changing them. A browser refresh does not update the server process environment.
SQLCipher and the development fallback
The current pip guide documents AES-256 SQLCipher databases and pre-built sqlcipher3 wheels for Windows, macOS, and Linux. The current PyPI description says each user has an isolated database, its key is derived from that user's password, and per-user model API keys are encrypted inside that database. Login attempts to decrypt the database rather than comparing a stored password.
LDR_BOOTSTRAP_ALLOW_UNENCRYPTED=true permits standard SQLite only when SQLCipher is unavailable or nonfunctional. It does not disable working SQLCipher. In fallback mode, database contents and stored API keys are plaintext, and account passwords are not verified. The project limits this mode to isolated local development, not shared or family hosting. Never publish a fallback deployment through a tunnel or treat its login screen as an authentication boundary.
For this tutorial, leave that variable unset and resolve encryption failures rather than enabling fallback. Check startup output before storing secrets. Neither a successful import nor an absence of errors conclusively demonstrates that the application's actual database files are encrypted. The supplied documentation does not provide an application-specific, reproducible at-rest verification procedure, so we do not claim that these checks certify encryption. Use the project's SQLCipher guidance and the installed release's diagnostics if independent storage verification is required.
Verify the complete local installation
Check search and model services
docker ps
docker port searxng
curl http://localhost:8080
curl http://localhost:11434/api/tags
ollama list
SearXNG should return its page, Ollama should return JSON, and the model should be listed. A working SearXNG home page does not prove its search API or upstream engines work; the research test supplies that additional check. Inspect docker logs searxng if the container is unhealthy.
Open LDR and establish a test account
Keep the LDR terminal open and visit http://localhost:5000. In a clean browser profile, inspect the installed version's account interface. If registration is offered, create a disposable test account with a unique password. If account provisioning differs, follow that release's supported account flow rather than inventing a default username or password. Do not upload confidential documents yet.
Sign out, attempt to sign in with the correct username and an intentionally wrong password, and confirm rejection. Then sign in with the correct password. Repeat from a separate clean profile so an existing session cannot mask a failure. An incorrect password being accepted is a stop condition, especially if fallback might be active.
Check the listener if the page does not load
On macOS or Linux, use lsof -i :5000. On Windows:
netstat -ano | findstr :5000
Identify the owning process and its bind address. Opening a localhost URL does not prove the listener is loopback-only. An address such as 0.0.0.0 or :: indicates a wildcard listener. Restrict unwanted network access using supported application configuration or host/network controls before proceeding. This guide does not invent an alternate-port or bind-address flag absent from the supplied pip evidence.
Run a small research request
In the authenticated interface, select the intended Ollama endpoint and downloaded model. Submit a non-sensitive question about a public technical topic and request citations. Confirm that generation finishes, search-backed material appears, and the report is available to the test account. Watch the LDR logs during the request.
If generation works without search results, inspect the SearXNG approval setting and search errors. If the interface opens but generation fails, check Ollama, model selection, and available memory. Localtonet cannot repair these local failures.
Stop, restart, inspect, and update the installation
This manual pip deployment contains a foreground LDR process and separately managed Docker and Ollama services. It does not automatically install a cross-platform production service manager.
Manage SearXNG
docker stop searxng
docker start searxng
docker restart searxng
docker logs searxng
docker logs -f searxng
Run the command appropriate to your task, not necessarily the whole block. Stopping preserves the container. Following logs continues until interrupted. To update the image deliberately, preserve configuration and data that would otherwise be lost, then:
docker pull searxng/searxng
docker stop searxng
docker rm searxng
docker run -d -p 127.0.0.1:8080:8080 --name searxng searxng/searxng
docker port searxng
Review SearXNG changes before updating an important deployment. The unpinned image tag can change, and removing a container discards changes stored only inside it.
Restart LDR
Stop the tunnel first if remote access is active. Press Ctrl+C in the LDR terminal. To restart, return to the project directory, reactivate .venv with your platform's earlier command, restore the SearXNG environment variable, and run python -m local_deep_research.web.app. Confirm Docker and Ollama are still running.
Update the package and maintain deployment notes
Back up application data using the installed release's supported approach, preserve necessary account credentials securely, and review the release notes. Stop LDR before updating in its active environment:
python -m pip install --upgrade local-deep-research
python -m pip show local-deep-research
Repeat the local research and security checks after each update. Do not assume changing an environment variable retroactively encrypts development databases. Treat any previous plaintext API keys as exposed to anyone who could access those files or backups.
Keep a small deployment record containing the actual tested package version, Python and Docker versions, test date, image identity, listener addresses, fallback status, and pass/fail results for login and route checks. Record unresolved storage verification separately. Never include passwords, tokens, API keys, or session cookies in that record.
Test built-in accounts before remote exposure
LDR's current documentation establishes application-level password access and isolated encrypted user databases. An authenticated reverse proxy is therefore an optional defense-in-depth control, not a substitute for supposedly undocumented LDR login. However, encryption and a working login form do not establish that every route or account capability is suitable for internet exposure.
The supplied package description does not establish whether registration can be disabled, whether it is invitation-only, or how all APIs, settings, streaming routes, and document operations enforce authorization. It also does not specify every session expiry, revocation, cookie, or proxy behavior. Those are verification gaps, not confirmed vulnerabilities or confirmed protections.
Run a clean-session access test
- Create disposable account A locally and add only non-sensitive test research or documents. Note the application URLs and requests used by those operations.
- Sign out and open a different browser profile with no LDR cookies. Request the protected report, settings, and document URLs directly. Expect authentication or denial, not protected content.
- Attempt login with A's username and a wrong password. Confirm rejection, then confirm the correct password works.
- Sign out again and retry protected requests. Check that the server denies them; a cached page alone is not proof of continued server access.
- If registration is available, create disposable account B. Check that B cannot read, change, download, or delete A's resources, including through direct resource URLs.
Use browser developer tools to identify actual routes and request methods in your installed version. Replay only requests against your own test deployment, removing session cookies or using B's session as appropriate. Do not guess endpoint paths or test destructive operations against real data. A 200 response containing a login page is different from a 200 response containing a private report.
| Boundary | What to test | Publication decision |
|---|---|---|
| Registration | Can a new visitor create an account and immediately run research? | If only invited users should have access, unrestricted registration does not meet that policy. Restrict the audience or keep the service local. |
| APIs and settings | Repeat actual read and update requests without authentication and as another user. | Protected data and mutations must remain inaccessible. A hidden navigation link is not authorization. |
| Reports and documents | Test direct viewing, download, search, upload, and deletion with disposable data. | Check both anonymous denial and cross-user isolation. Do not infer file protection from database encryption. |
| Streaming research | Inspect the live request used during research, then test it without a session and after logout. | Verify protected output does not leak and session behavior meets your policy. |
| Sessions | Test logout, clean profiles, expiry behavior, and cookies on the external HTTPS origin. | Document actual behavior. Do not assume localhost cookie or redirect behavior is identical through a proxy. |
Authentication answers who can sign in; authorization determines what that account can do. Even perfectly isolated databases do not prevent unknown registered users from consuming your CPU, GPU, disk, search capacity, or provider credits. Decide whether this is a single-user service, a small invited group, or intentional public hosting before enabling a tunnel.
The documented storage model also has boundaries. Credentials are held in process memory during active sessions, and database encryption does not secure a compromised running host. Protect operating-system accounts, backups, exports, downloaded files, and provider credentials. Do not assume every file generated by the application shares the database's encryption.
Keep remote access disabled if wrong-password login succeeds, anonymous requests disclose protected information, cross-user access succeeds, or registration permits an audience you did not intend. Unchecked routes are not a passing result. A login test is useful evidence of password enforcement, but it is not conclusive verification of encryption at rest or a complete security audit.
Use a gateway when it adds a needed control
An authenticated gateway can restrict access to approved identities before visitors reach LDR registration, add organizational authentication, or narrow the exposed audience. Keep LDR's own accounts enabled and test them too. Configure the gateway to cover all application routes, APIs, document functions, and streaming connections, then target the gateway's local port with Localtonet.
Prevent untrusted access to the backend around the gateway. Test denied access before login and successful access afterward. Gateway configuration depends on the selected product, so no unverified proxy configuration is presented here. If you cannot establish the required controls, keep LDR local.
Configure the Localtonet HTTP tunnel
Our client establishes an outbound connection to a relay, so this workflow does not require inbound router port forwarding, firewall changes, VPN setup, or a public IP address. HTTP tunneling is not a VPN. Localtonet provides connectivity; LDR and any gateway remain responsible for application accounts and authorization.
The sequence below follows our documented common tunnel lifecycle. Consult the HTTP tunnel documentation for current screen placement and available options; no fixed dashboard layout or region list is assumed.
Install and run our client
Use a device that can reach the protected local service. Running it on the LDR machine makes a loopback target possible.
Authenticate and select the device
Use its device-specific authentication token. Keep the token secret and out of screenshots, repositories, examples, and shared notes.
Select an available relay
Choose a server or region offered in the current dashboard. Availability and options can vary.
Create the HTTP configuration
Set the local host and port of the protected target. Use localhost and 5000 only if our client runs on that same machine and direct LDR access passed your checks. With a gateway, use the gateway's verified port instead.
Start and use the assigned URL
Review the target and access path, press Start, and test the public address as described below. Saving a configuration does not start it.
Stop or delete when finished
Remove remote exposure when it is no longer required, before risky maintenance, or immediately if an access-control test fails.
HTTP Process Type options include Random Sub Domain, Custom Sub Domain where supported, and Custom Domain. These serve the target at a public HTTPS address. Check current custom-domain documentation before changing DNS; do not assume all options are available on every plan.
Repeat authentication tests externally
From another network and a clean browser profile, open the public URL before signing in. Public login or registration pages may be intentionally reachable, but protected content must not be. Repeat the direct-route, wrong-password, logout, cross-user, and streaming checks on this origin. Then run a small authenticated research request and confirm redirects, cookies, and downloads work as intended.
The tunnel is available only while the selected client is connected and the tunnel is running. Useful application access also requires the target service and any gateway to remain reachable. Stopping LDR, the gateway, our client, or the tunnel interrupts remote use.
Troubleshoot from the inside out
Check Python, dependencies, Docker, search, model access, LDR, account controls, and finally the tunnel. Changing several layers simultaneously makes the original cause harder to identify.
| Symptom | Likely cause | Next check |
|---|---|---|
| Python, pip, or ldr-web not found | PATH or inactive environment | Reactivate .venv; use interpreter-based pip and module startup. |
| Wrong package location or version | Interpreter mismatch | Compare python -m pip --version and python -m pip show local-deep-research. |
| Wheel or dependency failure | Interpreter or platform compatibility | Read the full error and check supported wheels. Do not enable plaintext fallback to hide unrelated failures. |
| Docker daemon unavailable | Engine stopped or inaccessible | Run docker info and start the appropriate Docker service. |
| Container name already used | Existing SearXNG container | Use docker ps -a; start it or deliberately recreate it after preserving needed data. |
| 8080 occupied or broadly exposed | Port conflict or old mapping | Inspect docker port searxng. Recreate with the loopback binding; restart alone cannot change it. |
| SearXNG has no results | Origin approval or search failure | Check Docker and LDR logs; restore the exact approved URL in the launching environment and restart. |
| Ollama unavailable or model missing | Stopped server, wrong endpoint, or missing download | Check /api/tags, ollama list, and the selected endpoint and model. |
| Illegal instruction | Unsupported CPU capability | Check AVX support on x86-64. ARM64 is separately supported. |
| SQLCipher failure | Encryption dependency problem | Resolve the error. Fallback stores plaintext and does not verify passwords; it is not suitable for tunneling. |
| Port 5000 does not respond | Stopped process or occupied port | Read startup logs and inspect the listener with lsof or netstat. |
| Environment change ignored | Wrong shell or no restart | Set the variable in the launching process environment and restart LDR. |
| Public URL fails or shows another service | Wrong target or tunnel state | Check device, relay, local host and port, client connection, and Start state. |
| Protected content loads without login | Access-control failure or bypass | Stop the tunnel immediately. Retest locally, including fallback and gateway routing. |
PDF exports and optional integrations
On Windows, PDF export requires Pango/Cairo system libraries; use the WeasyPrint platform instructions matching your installation. A working web page does not validate these dependencies.
For missing CJK glyphs on Debian or Ubuntu, the pip guide documents sudo apt install fonts-noto-cjk && fc-cache -fv. Fedora and RHEL use google-noto-sans-cjk-fonts. Emoji output may require Noto emoji packages; package naming varies by distribution and release. macOS and Windows include commonly used CJK and emoji fonts. Test export with representative text before relying on it.
The pip guide also documents python -m pip install "local-deep-research[mcp]" for its optional MCP integration. That extra is not required for this browser tutorial and should not be confused with our separate Localtonet MCP features.
Frequently asked questions
Does pip installation work on Windows, macOS, and Linux?
Yes. The project documents all three platform families and pre-built SQLCipher wheels. Activation syntax, Docker setup, dependency compatibility, and optional PDF libraries differ by platform.
Which version does this guide describe?
The supplied PyPI listing identifies 1.10.7. Run python -m pip show local-deep-research to identify your installation. Record that version with your actual test results; repository main-branch documentation can differ from released code.
Should I use ldr-web or the Python module command?
Both are documented. This guide uses python -m local_deep_research.web.app to make the selected interpreter explicit. The documented browser address is http://localhost:5000.
Does LDR have built-in authentication?
Current documentation describes per-user password access, isolated SQLCipher databases, password-derived keys, and encrypted per-user API-key storage. Verify wrong-password rejection, registration policy, protected routes, and user isolation in the installed version before public exposure.
Is unencrypted fallback safe for a shared deployment?
No. It is for isolated local development when SQLCipher is unavailable or nonfunctional. It leaves database contents and stored API keys in plaintext and does not verify account passwords. It does not disable working SQLCipher.
Why does LDR block my localhost SearXNG URL?
Private search-engine origins require operator approval. Pinning the exact URL through the documented SearXNG environment variable configures and approves it. Restart LDR after changing the variable.
Can I use another model provider?
LDR documents Ollama and compatible cloud endpoints. Use the installed release's provider settings rather than guessing credentials or model names. Review what research content will be sent to any external provider.
Does creating a tunnel start remote access automatically?
No. Our selected client must be connected and the tunnel must be started. The target must remain reachable. No inbound router port forwarding or public IP address is required. Stop or delete the tunnel when finished.
Connect your verified research service with Localtonet
Install locally, record your package version, test search and model generation, and verify the account boundaries you need. Keep development fallback disabled and resolve security gaps before starting an HTTP tunnel to your controlled local target.
Get Started Free β