Deployment guide

GPT Researcher

Overview

GPT Researcher is an open-source autonomous research agent. You give it a topic or a question. It plans its own research questions, searches the web, reads and summarises what it finds across many sources, and writes a long-form report with inline citations and a reference list. Reports export as Markdown, PDF or Word, and you can keep asking follow-up questions against a finished report.

A single run aggregates and cross-checks many sources rather than answering from one page. That is what makes the output a research report rather than a search result.

GPT Researcher calls an AI provider. It does not host a model. That makes it cheap to run: no GPU and one small VM. You bring your own provider key, so you control which model you use and what it costs.

This SecureAnyCloud image runs GPT Researcher 3.5.1, installed from upstream source pinned to an exact commit. It is served by uvicorn behind nginx on port 80, with a private SearXNG instance for web search bound to the VM's loopback interface.

GPT Researcher upstream has no sign-in of any kind. SecureAnyCloud therefore locks the whole instance behind a credential that every VM generates for itself on first boot, so an instance is never left open to strangers.

What you get:

  • GPT Researcher 3.5.1 (assafelovic/gpt-researcher, Apache-2.0), installed from upstream source pinned to commit 409b8b60b477d50f2f844bc9598d1bcb7b056eee so the shipped version never drifts
  • A private SearXNG search engine on the VM, so web search works out of the box with no search API key at all
  • nginx on :80 enforcing HTTP Basic authentication against a per-VM credential, with response buffering disabled so the agent's progress streams live
  • A fail-closed authentication gate: nginx refuses to start if the credential file is ever missing
  • An unauthenticated /healthz endpoint for load balancer and uptime checks
  • No AI provider key baked into the image. You add exactly one after launch.
  • docker.service, nginx.service, gpt-researcher-search.service, gpt-researcher.service and gpt-researcher-firstboot.service as enabled, active systemd units
  • 24/7 SecureAnyCloud support

How this image is secured

GPT Researcher upstream is designed for local, single-user use and ships no authentication whatsoever. Deployed as upstream ships it, a VM on a public IP with a working provider key would let anyone who finds it spend your AI credits. One report means many model calls plus many page fetches, so that is an expensive door to leave open. This image closes it in four ways:

  • nginx requires a credential on every path except the static /healthz probe. The username is randomised per VM and the password is 24 random characters. Both are generated on the VM at first boot and written to a root-only file. There is no default, shared or documented credential at any point.
  • Port 80 stays shut until the credential exists. nginx.service carries a condition on a marker file. First boot creates the file only after it has minted the credential and confirmed that an unauthenticated request is refused. A VM cannot serve a single request before it is locked down.
  • The gate fails closed, not open. nginx.service also runs a pre-start assertion that re-checks the authentication directives and the credential file. If either is missing, nginx will not start at all rather than serve openly. Step 12 demonstrates this on your own VM.
  • The application does not start until it is configured. gpt-researcher.service carries a condition on the per-VM environment file, which is absent from the image. The enabled unit does nothing until first boot writes the file.

Prerequisites

You need an active Azure subscription, an SSH key pair, and a VNet with a subnet in the target region.

The recommended size is Standard_B2ms (2 vCPU / 8 GiB RAM). The idle stack is modest, but a running report fans out concurrent workers that fetch and parse HTML and PDF sources in parallel. The LangChain runtime also holds its models and embeddings in memory. 8 GiB gives that real headroom without a swap file. Choose Standard_B4ms for a busy shared instance or for deep research runs.

Configure the network security group to allow inbound 22/tcp from your management network and 80/tcp from wherever you will use GPT Researcher. The image serves plain HTTP on port 80. For anything reachable from the internet, terminate TLS in front of it and use a real hostname. You can use an Azure Application Gateway or Front Door, or your own certificate on the VM's nginx.

Nothing else needs opening. The application itself (8000) and SearXNG (8080) are both bound to the loopback interface and are unreachable from outside the VM.

You also need an API key from one AI provider. OpenAI is the default. Anthropic, Google Gemini, Azure OpenAI, Groq, Mistral, Cohere, Together, any LiteLLM target and a local Ollama endpoint also work. You do not need a search provider key, because this image runs its own search engine.

Step 1 - Deploy from the Azure Marketplace

In the Azure portal, choose Create a resource. Search for GPT Researcher on Ubuntu 24.04 LTS by SecureAnyCloud and select Create.

Pick your subscription, resource group and region, and set the size to Standard_B2ms. Choose SSH public key authentication with the username azureuser. Allow inbound ports 22 and 80.

Step 2 - Deploy from the Azure CLI

Accept the Marketplace terms, create the VM and open port 80:

# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:gpt-researcher-ubuntu-24-04:default:latest
az vm create \
  --resource-group my-gptr-rg \
  --name my-gptr \
  --image sac1647283583153:gpt-researcher-ubuntu-24-04:default:latest \
  --size Standard_B2ms \
  --storage-sku StandardSSD_LRS \
  --admin-username azureuser \
  --generate-ssh-keys \
  --public-ip-sku Standard
az vm open-port --resource-group my-gptr-rg --name my-gptr --port 80 --priority 1010

Step 3 - Connect to your VM

Connect over SSH as azureuser:

ssh azureuser@<vm-ip>

First boot generates this VM's credentials and locks the instance down before port 80 opens. It normally completes within a minute of the VM becoming reachable.

Step 4 - Confirm first boot completed and the services are running

Check that the first-boot service finished:

sudo systemctl is-active gpt-researcher-firstboot.service
active

Then check the four runtime services:

systemctl is-active docker.service nginx.service gpt-researcher-search.service gpt-researcher.service
active active active active

All four report active. If gpt-researcher.service is not yet active, first boot is still running. Wait a few seconds and repeat.

To see what first boot did, read its log:

sudo journalctl -u gpt-researcher-firstboot.service --no-pager | tail -20

The log shows the order that matters. First boot writes the per-VM search secret and web credential first. It then starts the application and confirms it is healthy. Only after that does it create the marker that lets nginx open port 80.

gpt-researcher-firstboot: Writing the per-VM SearXNG secret gpt-researcher-firstboot: Starting the private web search stack gpt-researcher-firstboot: VM address resolved to 10.0.0.13 gpt-researcher-firstboot: Minting the per-VM web credential into /etc/nginx/gpt-researcher.htpasswd gpt-researcher-firstboot: Writing /etc/gpt-researcher/gpt-researcher.env (NO provider API key - the customer supplies exactly one) gpt-researcher-firstboot: Starting gpt-researcher.service with the per-VM environment gpt-researcher-firstboot: GPT Researcher is serving on the host loopback gpt-researcher-firstboot: Creating the bootstrap-ready marker /var/lib/sac/data/gpt-researcher-bootstrap-ready (this is what un-gates nginx) gpt-researcher-firstboot: Starting nginx (:80 opens only now, already authenticated) gpt-researcher-firstboot: Proving this VM refuses an UNAUTHENTICATED request with exactly 401 gpt-researcher-firstboot: Proving a one character mutated password is refused with exactly 401 gpt-researcher-firstboot: Proving the per-VM credential reaches GPT Researcher with exactly 200 gpt-researcher-firstboot: First boot complete; GPT Researcher is serving behind an authenticated nginx with per-VM secrets.

Step 5 - Confirm only port 80 is exposed

The application and the search engine must be reachable only from the VM itself. nginx is the single external surface. List the listening sockets:

sudo ss -lntp | grep -E ':(80|8000|8080)\s'
LISTEN 0 511 0.0.0.0:80 0.0.0.0:* users:(("nginx",pid=8169,fd=5),...) LISTEN 0 2048 127.0.0.1:8000 0.0.0.0:* users:(("uvicorn",pid=7997,fd=7)) LISTEN 0 4096 127.0.0.1:8080 0.0.0.0:* users:(("docker-proxy",pid=7053,fd=8)) LISTEN 0 511 [::]:80 [::]:* users:(("nginx",pid=8169,fd=6),...)

Ports 8000 (GPT Researcher) and 8080 (SearXNG) are bound to 127.0.0.1 only. Port 80 is the only one bound to a routable address.

Step 6 - Retrieve your per-VM sign-in credential

Read the credentials file as root:

sudo cat /root/gpt-researcher-credentials.txt

The file is 0600 root:root. It contains the instance URL, the randomised username and the 24-character password generated for this VM. Store them in your password manager.

Step 7 - Confirm the instance refuses anonymous access

Run this check on every deployment. An unauthenticated request must be refused:

curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1/
401

The health probe stays open so load balancers work without a credential:

curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1/healthz
200

Your own credential is accepted. Replace the values in angle brackets with those from Step 6:

curl -s -o /dev/null -w '%{http_code}\n' -u '<GPTR_WEB_USERNAME>:<GPTR_WEB_PASSWORD>' http://127.0.0.1/
200

Step 8 - Add your AI provider key

No key ships in the image, and GPT Researcher cannot run any research until you add one.

In the environment file, uncomment the OPENAI_API_KEY= <set-at-first-boot> line and paste your own key. The same key covers both the language model and the embeddings that GPT Researcher uses to rank sources. Edit the file with sudo nano /etc/gpt-researcher/gpt-researcher.env, or make the change in one step:

sudo sed -i 's|^# OPENAI_API_KEY=.*|OPENAI_API_KEY=<your-token>|' /etc/gpt-researcher/gpt-researcher.env
sudo systemctl restart gpt-researcher

The file is 0600 root:root, so your key is readable only by root.

To use a provider other than OpenAI, also set the model selectors in the same file. The commented examples show the pattern for Anthropic. Every provider LangChain supports is available, and the selector format is provider:model-name.

Step 9 - Check web search, with no search API key

Upstream GPT Researcher defaults to the paid Tavily search API. This image instead runs a private SearXNG instance on the VM and pins RETRIEVER=searx. Web search therefore works with no second key and no external search subscription. Confirm that it returns live results:

curl -s 'http://127.0.0.1:8080/search?q=azure+virtual+machine&format=json' -o /tmp/searx.json head -c 300 /tmp/searx.json; echo
{"query": "azure virtual machine", "results": [{"template": "default.html", "title": "Azure Virtual Machines", "content": "Create Linux and Windows virtual machines (VMs) in seconds and reduce costs. Build, deploy, and run your applications on resilient and scalable infrastructure.", "img_src": "",

Your only running cost is your own AI provider usage.

Step 10 - Sign in to the web interface

Open http://<vm-public-ip>/ in a browser. The instance asks for the username and password from Step 6. This prompt is the appliance refusing anonymous access, and it stops a stranger from running reports on your provider account.

After you sign in, the GPT Researcher interface opens. It has a research box, a report type selector, a tone selector, and controls for the number of sources and results.

Step 11 - Run your first report

Enter a research question, choose a report type and select the research button. The agent streams its progress live: the questions it planned, the sources it is reading, and then the report as it is written. A standard research report typically takes two to five minutes, depending on the model and the breadth of the topic.

The progress panel shows the research context the agent assembled from the web, the running cost of the run, and the point at which it starts writing the report.

When the report finishes, you can copy it or download it as Markdown, PDF or Word.

Step 12 - Confirm the fail-closed gate

The authentication gate is enforced at start-up, not just configured. If the credential file is missing, nginx refuses to start rather than serve an open instance.

The commands below hide the credential file, prove that nginx will not start without it, and put everything back:

sudo systemctl stop nginx
sudo mv /etc/nginx/gpt-researcher.htpasswd /tmp/htpasswd.check
sudo systemctl start nginx 2>/dev/null && echo "UNEXPECTED: nginx started ungated" || echo "nginx REFUSED to start without a credential file"
sudo mv /tmp/htpasswd.check /etc/nginx/gpt-researcher.htpasswd
sudo chown root:www-data /etc/nginx/gpt-researcher.htpasswd
sudo chmod 0640 /etc/nginx/gpt-researcher.htpasswd
sudo systemctl reset-failed nginx
sudo systemctl start nginx
sudo systemctl is-active nginx
nginx REFUSED to start without a credential file active

Step 13 - Confirm the shipped versions are the pinned ones

Read the provenance record:

sudo cat /opt/gpt-researcher/.sac-provenance
product.name=GPT Researcher product.version=3.5.1 product.upstream=https://github.com/assafelovic/gpt-researcher.git product.tag=v3.5.1 product.commit=409b8b60b477d50f2f844bc9598d1bcb7b056eee product.licence=Apache-2.0 product.licence.sha256=c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4 search.image=searxng/searxng@sha256:854f239d5c181db9c4282cd0ffc1737a61232dd6ad0ea964028b96df17d7758a search.image.tag_at_pin=2026.7.22-ef8f6470e search.licence=AGPL-3.0-or-later search.upstream=https://github.com/searxng/searxng

The record shows the exact upstream commit the application was built from, the sha256 of its Apache-2.0 licence file, and the immutable digest of the SearXNG image. The bundled component licences and their source locations are listed here:

cat /usr/share/doc/sac/THIRD-PARTY-NOTICES

Changing the sign-in credential

To change the password for the existing user, run:

sudo htpasswd -bB /etc/nginx/gpt-researcher.htpasswd '<GPTR_WEB_USERNAME>' '<new-password>'
sudo systemctl reload nginx

Omit the final argument to be prompted for the password instead of passing it on the command line.

To replace the user entirely, use htpasswd -cB with a new username. Keep exactly one entry in the file unless you want to share access.

Sharing the instance

This is a single-tenant appliance, so everyone who signs in shares one report library. Add a second htpasswd entry only if you want that.

Serving GPT Researcher on your own domain

Point a DNS record at the VM's public IP. Then either terminate TLS on an Azure Application Gateway or Front Door in front of the VM, or add your own certificate to nginx at /etc/nginx/sites-available/sac-gpt-researcher and open port 443.

Maintenance

To see where your data lives, list the data directory:

sudo ls -la /var/lib/gpt-researcher

Reports, uploaded documents and logs are all under that directory. Back it up if the report history matters to you.

unattended-upgrades applies security updates automatically. To check the services after a reboot, run:

systemctl is-active gpt-researcher gpt-researcher-search nginx

To view the application logs, run:

sudo journalctl -u gpt-researcher --no-pager | tail -20

Support

Every SecureAnyCloud image includes 24/7 support. Contact sales@secureanycloud.com with your Azure subscription ID and the VM name.

Deploy on Azure

Launch GPT Researcher on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.

View this image

Need Help?

Our support team is available 24/7.

sales@secureanycloud.com

Deploy on Azure