Deployment guide

How to Host PrivateGPT on a VPS

Deploy on a VPS Cloud →

Tutorial

Artificial Intelligence

How to Host PrivateGPT on a VPS

PrivateGPT lets you ask questions of your own documents (PDF, Word, emails) via an AI, without any data leaving your infrastructure. It is a RAG solution designed for absolute confidentiality. Hosting it on a VPS gives you a private documentary assistant accessible remotely.

9 min read6 steps
Contents· Why self-host PrivateGPT on a VPS1/9
  1. 01Why self-host PrivateGPT on a VPS
  2. 02Concrete benefits of self-hosting
  3. 03PrivateGPT and Ollama: two complementary roles
  4. 04PrivateGPT vs Ollama: who does what
  5. 05Hardware and software requirements
  6. 06Pre-installation checklist
  7. 07Deploying PrivateGPT in local mode
  8. 08Back up and verify that no data leaves
  9. 09Troubleshooting: the most common errors

Why self-host PrivateGPT on a VPS

PrivateGPT is built around RAG (Retrieval-Augmented Generation): it ingests your documents, splits them into chunks, computes embeddings stored in a vector database (Qdrant by default, in local disk mode), then answers questions from that corpus while citing the passages it used. Since version 1.0, released in June 2026, PrivateGPT no longer runs models itself: it connects to an OpenAI-compatible inference server (Ollama, llama.cpp or vLLM) that you install alongside it on the same VPS. The LLM, the embeddings and the index therefore stay on your machine, and no request goes out to an AI provider.

On a dedicated VPS, you get a company document assistant isolated from individual workstations, with a centralized knowledge base the whole team can query, without ever exposing contracts, HR files or legal documents to a cloud service. There is a legal angle too: pasting a document containing personal data into a hosted AI API makes that provider a processor under the GDPR, and the processing must be governed by a contract (Article 28(3)). Processing that stays on your own server does not add that link to the chain.

Concrete benefits of self-hosting

  • Full confidentiality: documents, embeddings and the Qdrant index never leave the VPS
  • Sourced answers: every reply relies on passages retrieved from your files, not on the model's general memory
  • No API costs when the model runs locally through Ollama or llama.cpp
  • Ingestion of PDF, DOCX, PPTX, EPUB, CSV, Markdown, .mbox mail archives and even images or audio, organized into collections
  • A Messages-style API (modeled on the Anthropic API specification) to plug PrivateGPT into your internal tools
  • Easier compliance for sensitive data (GDPR, professional secrecy): no additional AI processor

PrivateGPT and Ollama: two complementary roles

The two tools are often confused, yet they sit at two different layers of the stack. Ollama is a model server: it downloads LLMs and embedding models, loads them into memory and exposes an API on port 11434. It knows nothing about your files: it answers from whatever context it is sent.

PrivateGPT (repository zylon-ai/private-gpt, Apache-2.0 license) is the RAG application layer: it indexes your documents, retrieves the relevant passages for each question and injects them into the context sent to Ollama. In 1.0 it therefore never works alone: without a reachable inference server, it starts with no models at all.

PrivateGPT vs Ollama: who does what

Scroll the table

CriterionPrivateGPT 1.0Ollama
RoleRAG application: ingestion, search, cited answersInference server: loads and runs the models
Runs the modelNo: delegates to an OpenAI-compatible serverYes, on CPU or GPU
Reads your filesYes: PDF, DOCX, CSV, `.mbox`… by collectionNo: context supplied by hand
Vector databaseQdrant (local disk by default)None
InterfaceWorkbench at `/ui`, no access controlREST API, no server-side web interface
Default port`8080``11434`, bound to `127.0.0.1`

Hardware and software requirements

Memory is sized for the model Ollama serves, not for PrivateGPT itself. The models suggested by default in the documentation target a GPU machine (qwen3.5:35b, about 24 GB to download): on a CPU VPS, pick a lighter variant from the same family, qwen3.5:4b (3.3 to 4 GB) or qwen3.5:9b (6.6 to 7.6 GB), plus mxbai-embed-large (about 670 MB) for embeddings. Plan 8 GB of RAM for the 4b variant and 16 GB for the 9b, to leave room for the system, Qdrant and documents being ingested, and at least 4 vCPUs: on CPU, core count sets generation speed.

Allow 30 GB of disk, ideally NVMe, for models, the Qdrant index and ingested documents: ingesting a large PDF reads and writes a lot. On the software side: Docker (or Python 3.11 and uv if you install the package outside a container), Ollama, and a domain pointing to the VPS to expose the interface behind a reverse proxy.

Pre-installation checklist

  • A VPS with at least 8 GB of RAM (16 GB for a 9-billion-parameter model) and 4 vCPUs
  • Up-to-date Debian 12 or Ubuntu 24.04, SSH access with sudo
  • Docker installed (docker version responds) or, failing that, uv with Python 3.11
  • 30 GB of free disk, NVMe preferred, for models and local_data/
  • A subdomain (for example docs.your-domain.com) pointing to the VPS IP
  • An active firewall: only SSH, 80 and 443 open, ports 8080 and 11434 stay closed

Deploying PrivateGPT in local mode

  1. Install Ollama and pull the models

    Install Ollama with the official script, then download a CPU-friendly LLM and the recommended embedding model:

    curl -fsSL https://ollama.com/install.sh | sh
    ollama pull qwen3.5:4b
    ollama pull mxbai-embed-large

    By default Ollama only listens on 127.0.0.1:11434: keep it that way, only PrivateGPT needs to reach it. This is the only step that needs Internet access; once the models are in place, inference runs offline.

  2. Run PrivateGPT with Docker

    The official zylonai/private-gpt image ships the core package. On Linux the container must share the host network to reach Ollama on localhost, and a volume must keep the data, otherwise ingested documents vanish on restart:

    mkdir -p /opt/privategpt/local_data
    docker run -d --name privategpt --restart unless-stopped \
      --network host \
      -e OPENAI_API_BASE=http://localhost:11434/v1 \
      -v /opt/privategpt/local_data:/home/worker/app/local_data \
      zylonai/private-gpt:latest

    At startup, PrivateGPT calls GET /v1/models on Ollama and registers the models it finds automatically: no configuration file is required. The OPENAI_EMBEDDING_API_BASE variable is only needed if your embeddings are served elsewhere.

  3. Ingest your documents by collection

    Send your files to the ingestion API, grouping them into collections, for example one collection per client file or per department:

    curl -X POST http://localhost:8080/v1/artifacts/ingest \
      -F "file=@/srv/documents/contrat-cession.pdf" \
      -F "collection=legal"
    curl "http://localhost:8080/v1/artifacts/list?collection=legal"

    PrivateGPT splits, vectorizes and indexes each file in Qdrant. Formats without a dedicated reader are read as plain text.

  4. Query the corpus with citations

    Test first in the Workbench (http://localhost:8080/ui), then plug your tools into the Messages API. Document search goes through the built-in semantic_search_v1 tool, restricted to one collection:

    curl http://localhost:8080/v1/messages \
      -H "Content-Type: application/json" \
      -d '{"model": "qwen3.5:4b",
           "messages": [{"role": "user", "content": "What are the conditions precedent in the contract?"}],
           "tools": [{"name": "search_docs", "type": "semantic_search_v1",
                      "context": [{"type": "ingested_artifact", "context_filter": {"collection": "legal"}}]}]}'
  5. Set up the reverse proxy, SSL and authentication

    The Workbench has no access control: the documentation reserves it for local use. Expose it only behind Nginx or Caddy, with a Let's Encrypt certificate and basic authentication:

    server {
        listen 443 ssl;
        server_name docs.your-domain.com;
        ssl_certificate     /etc/letsencrypt/live/docs.your-domain.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/docs.your-domain.com/privkey.pem;
        auth_basic           "Restricted access";
        auth_basic_user_file /etc/nginx/.htpasswd;
        location / { proxy_pass http://127.0.0.1:8080; }
    }

    If only two or three people use it, an SSH tunnel (ssh -L 8080:127.0.0.1:8080 user@your-vps) avoids any public exposure at all.

  6. Lock down access

    PrivateGPT listens on 0.0.0.0 by default, so host networking publishes port 8080 on every interface. Close it at the firewall so that only the reverse proxy is reachable:

    ufw default deny incoming
    ufw allow OpenSSH
    ufw allow 80,443/tcp
    ufw enable

    Your users then go through https://docs.your-domain.com and query the corpus in natural language.

Ollama cannot report its models' context window, so PrivateGPT only estimates tokens roughly: on long documents, answers may come back truncated. Declare context_window explicitly in a model profile (a settings-<name>.yaml file, activated with PGPT_PROFILES), with a value well below the model's real limit. Also settle on your embedding model from the start: changing it later triggers an "Embedding dimensions mismatch" error and forces you to re-index the whole corpus (embed_dim is 1024 for mxbai-embed-large).

Back up and verify that no data leaves

What to back up. PrivateGPT's full state lives in /opt/privategpt/local_data (Qdrant index under local_data/qdrant, ingested files), plus your source documents and any settings-*.yaml profiles. Ollama models can be downloaded again, so there is no point backing them up. Stop the container while copying (docker stop privategpt), or copy a snapshot of the volume: an index copied during an ingestion may be inconsistent. For several instances or a large team, the documentation recommends a separate Qdrant server rather than local disk mode.

Check outbound traffic. Confidentiality is a property of the architecture, and it can be verified. While running a series of questions, list established connections: only PrivateGPT's connections to 127.0.0.1:11434, the reverse proxy's and your SSH session should appear.

ss -tnp state established

Any unexpected outbound connection deserves an explanation before you trust the tool with sensitive documents.

Troubleshooting: the most common errors

PrivateGPT starts with no models. Ollama was not running when the container started, or OPENAI_API_BASE is wrong: the URL must end with /v1. Check with curl http://localhost:11434/v1/models, then restart the container (docker restart privategpt).

"Connection refused" from the container. In a bridge-network container, localhost means the container itself. On Linux keep --network host; on macOS or Windows, target host.docker.internal.

"Embedding dimensions mismatch" during ingestion. The index was built with a different embedding model. Switch back to the original model, or wipe the vector store (make wipe in the repository) and re-ingest the documents.

Truncated answers on long documents. The context window is misestimated: declare context_window in a model profile (see the tip above).

Ollama killed mid-answer. The kernel ran out of memory (OOM): dmesg | grep -i oom confirms it. Switch to a smaller variant of the model or add RAM.

"Address already in use" at startup. Port 8080 is already taken: in Docker, set the PORT variable (for example -e PORT=8090), outside a container use the --port option of private-gpt serve, then adjust the Nginx proxy_pass.

Build your private documentary assistant

The ServOrbit Cloud VPS provides the RAM and SSD storage needed to run PrivateGPT and its Qdrant vector database locally, with preconfigured Docker for a fast RAG deployment.