Skip to main contentSkip to navigation
[email protected]
Client AreaSupport
Hosting Mammoth
HostingMammothYour Data, Our Responsibility
Home
Solutions
Hosting Services
Store
Pricing
About
Blog
API
Contact

Stay Ahead of the Curve

Get the latest insights on cybersecurity, AI innovations, and enterprise data solutions delivered to your inbox.

Hosting Mammoth
HostingMammothEnterprise Solutions

Enterprise-grade data solutions. Hosting, recovery, cybersecurity, and AI-powered services for businesses worldwide.

[email protected]
Sun - Fri, 9:00am - 5:00pm

Services

  • Cloud Hosting
  • Data Recovery
  • Cybersecurity
  • Legal Support
  • MSP Services
  • Web Development
  • AI Services
  • Free Server Migration

Hosting

  • VPS Hosting (NVMe SSD)
  • VDS Hosting (NVMe)
  • Storage VPS (High SSD)
  • GPU Servers
  • Managed Services
  • Cloud Firewall
  • Load Balancer
  • One-Click Apps
  • n8n Hosting
  • Object Storage
  • FAQ

Company

  • Store
  • Pricing
  • About Us
  • Locations
  • Blog
  • Testimonials
  • Contact
  • Affiliate Program
  • White-Label
  • Terms of Service
  • Privacy Policy
  • Browser Cookies
  • SLA

Support

  • Client Area
  • Submit Ticket
  • Knowledge Base
  • Server Status
  • API Documentation

© 2026 Hosting Mammoth. All rights reserved.

Knowledge Base
Getting StartedAccount ManagementVPS HostingGPU ServersStorage VPSCloud FirewallLoad BalancerServer ManagementBilling & PaymentsSupport & TicketsAffiliate ProgramReseller ProgramMarketplace & Appsn8n HostingManaged ServicesServer MigrationAPI & DevelopersSecurityTroubleshootingGlossaryInstall Guides
  1. Home
  2. /
  3. Support
  4. /
  5. Install Guides
  6. /
  7. How To Install Typesense Ubuntu
GUIDEInstall Guides

How to Install Typesense on Ubuntu 24.04 VPS: Open-Source Instant Search (Algolia Alternative)

28 min read

How to Install Typesense on Ubuntu 24.04 VPS: Open-Source Instant Search (Algolia Alternative)

Typesense is an open-source, typo-tolerant search engine designed to deliver sub-50ms instant search for e-commerce catalogs, blogs, SaaS dashboards, and documentation sites. This guide walks you through a production-grade install on Ubuntu 24.04 LTS: from APT repository setup and systemd tuning through collections, scoped API keys, a 3-node high-availability cluster, and an Nginx TLS front door. By the end you will have a self-hosted Algolia replacement serving live queries over HTTPS.

Looking for a lightweight starting point? The CloudCore Starter VPS gives you enough headroom to run a single-node Typesense install comfortably for small-to-medium datasets.

Table of Contents

  • What is Typesense?
  • Why Self-Host Typesense?
  • Prerequisites
  • Step 1: Update System Packages
  • Step 2: Install Typesense (APT Method)
  • Step 3: Install Typesense (Docker Method)
  • Step 4: Configure typesense-server.ini
  • Step 5: Enable the systemd Service
  • Step 6: Create Your First Collection
  • Step 7: Index Documents
  • Step 8: Run Searches (q, query_by, filter_by, facet_by, sort_by)
  • Step 9: Generate Scoped Search API Keys
  • Step 10: Configure a 3-Node High-Availability Cluster
  • Step 11: Front Typesense with Nginx + TLS
  • Performance Tuning
  • Troubleshooting
  • FAQ
  • Next Steps
  • What is Typesense?

    Typesense is an open-source search engine released under the GPL v3 license. It is written in C++, keeps its primary index in memory for predictable low-latency responses, and is designed to be as easy to operate as a managed service like Algolia. You POST JSON documents, you define a schema, and you query a REST API -- that is the whole mental model.

    Typesense ships with the features most teams end up bolting onto Elasticsearch or OpenSearch: native typo tolerance with configurable edit distance, prefix search for as-you-type interfaces, faceting, dynamic filtering, geo-search, curated results (pinning and hiding), synonyms, analytics, and multi-field ranking. It exposes an OpenAPI-documented REST API and maintains official client libraries for JavaScript, TypeScript, Python, PHP, Ruby, Go, Java, and Swift, plus an InstantSearch.js adapter so front-end code written for Algolia works with a few lines of configuration changes.

    Typical use cases include:

    • E-commerce product search with facets (category, brand, price ranges), typo-tolerant queries, and sort-by-popularity
    • SaaS application search across tickets, users, projects, and documents, with scoped keys per tenant
    • Documentation search for developer portals, with weighted ranking by section type and recency
    • Marketplace and listings search with geo-filtering ("within 5 km of lat/lng")
    • Log and audit search for small-to-medium volumes where Elasticsearch would be overkill
    • AI-augmented semantic search via Typesense's built-in vector search support, paired with embedding models

    Why Self-Host Typesense?

    Moving your search off a hosted platform like Algolia onto your own VPS delivers meaningful, measurable benefits:

    • Flat, predictable pricing -- Algolia charges per record and per operation. At 500K records with 200K searches/month you are easily paying USD 300-500/month. A self-hosted Typesense node on a EUR 7.99/month VPS delivers the same workload at a fraction of the cost, with unlimited operations.
    • Data sovereignty and GDPR compliance -- Your users' search queries and indexed content never leave your infrastructure. For EU-regulated businesses, hosting in-region on a known VPS removes an entire category of data-processing agreements and SCC paperwork.
    • No operation quotas -- Hosted search platforms meter everything. On your own server you can reindex thousands of times per day, run large batch imports, or spike to tens of thousands of QPS with no throttling beyond what your hardware provides.
    • Full feature set, no paywalls -- Open-source Typesense exposes every feature (synonyms, curation, analytics, vector search, multi-search). Nothing is gated behind a pricing tier.
    • Low latency -- When your application and Typesense share a VPN or a private network, p99 latency drops to single-digit milliseconds because you eliminate the round-trip to a third-party edge.
    • Customization -- Run custom build flags, mount indices on NVMe, tune Raft parameters, patch the source for niche requirements. None of this is possible on a SaaS.
    • Portability -- The entire dataset lives in a /var/lib/typesense/data directory you control. Snapshots, backups, cloning, and migrations are straightforward tar/rsync operations.

    Cost Comparison

    ScenarioAlgoliaElasticCloudSelf-Hosted Typesense
    100K records, 50K searches/mo~USD 50/mo~USD 95/moEUR 7.99/mo (CloudCore Starter)
    500K records, 200K searches/mo~USD 300/mo~USD 125/moEUR 7.99-11.99/mo
    2M records, 1M searches/mo~USD 800/mo~USD 250/moEUR 19.99/mo (Professional)
    Data leaves your infra?YesYesNo
    Per-op charges?YesNoNo

    Prerequisites

    Before you begin, make sure you have:

    • A VPS running Ubuntu 24.04 LTS with root or sudo access
    • SSH access to your server
    • At least 2 GB of RAM (4 GB recommended for datasets over 500K documents)
    • At least 10 GB of free disk space for the data directory and snapshots
    • A domain name (optional, needed only for Nginx TLS in Step 11)
    Recommended Plan: CloudCore Starter
    >
    For single-node Typesense installs handling up to a few hundred thousand documents, the CloudCore Starter plan is a strong baseline:
    >
    - 2 vCPU cores
    - 4 GB RAM
    - 40 GB NVMe SSD
    - Unmetered bandwidth
    - From EUR 7.99/month
    >
    Scale up to Professional or Enterprise tiers when your index exceeds a few million records or when you build a 3-node HA cluster.

    Connect to your server:

    bash
    ssh root@your-server-ip

    Step 1: Update System Packages

    Refresh the package index and apply any pending updates:

    bash
    sudo apt update && sudo apt upgrade -y

    Install the utilities you will need for the rest of the guide:

    bash
    sudo apt install -y curl gnupg ca-certificates jq ufw

    If the kernel updated, reboot:

    bash
    sudo reboot

    Step 2: Install Typesense (APT Method)

    Typesense publishes a signed APT repository at dl.typesense.org. This is the preferred method for bare-metal and VPS installs because you get a proper systemd unit, managed configuration at /etc/typesense/, and automatic security updates if unattended-upgrades is enabled.

    Import the GPG key

    bash
    curl -fsSL https://dl.typesense.org/apt/keyring.gpg | sudo gpg --dearmor -o /usr/share/keyrings/typesense-archive-keyring.gpg

    Add the repository

    bash
    echo "deb [signed-by=/usr/share/keyrings/typesense-archive-keyring.gpg] https://dl.typesense.org/apt/ stable main" | sudo tee /etc/apt/sources.list.d/typesense.list

    Install the server

    bash
    sudo apt update
    sudo apt install -y typesense-server

    The installer places the binary at /opt/typesense-server/typesense-server, drops a default config at /etc/typesense/typesense-server.ini, creates a typesense system user, and registers a systemd unit.

    Verify the install:

    bash
    typesense-server --version

    Expected output:

    text
    typesense-server 28.0

    Skip to Step 4 if you installed via APT.

    Step 3: Install Typesense (Docker Method)

    If you prefer Docker -- for reproducible deployments, easier version pinning, or to slot Typesense into an existing Compose stack -- use the official typesense/typesense image.

    Install Docker

    bash
    curl -fsSL https://get.docker.com | sudo sh
    sudo systemctl enable --now docker

    Create data and config directories

    bash
    sudo mkdir -p /var/lib/typesense/data /etc/typesense

    Create a Docker Compose file

    bash
    sudo tee /etc/typesense/docker-compose.yml > /dev/null <<'EOF'
    services:
      typesense:
        image: typesense/typesense:28.0
        container_name: typesense
        restart: unless-stopped
        ports:
          - "127.0.0.1:8108:8108"
        volumes:
          - /var/lib/typesense/data:/data
        command: >
          --data-dir /data
          --api-key=REPLACE_WITH_A_STRONG_RANDOM_STRING
          --listen-address=0.0.0.0
          --listen-port=8108
          --enable-cors
    EOF

    Generate a strong API key and drop it into the file:

    bash
    API_KEY=$(openssl rand -hex 32)
    sudo sed -i "s/REPLACE_WITH_A_STRONG_RANDOM_STRING/$API_KEY/" /etc/typesense/docker-compose.yml
    echo "Your Typesense admin API key: $API_KEY"

    Save this key somewhere safe -- you will use it for every admin call.

    Start the container

    bash
    cd /etc/typesense && sudo docker compose up -d

    Check health:

    bash
    curl http://localhost:8108/health

    Expected output:

    json
    {"ok":true}

    Docker users can skip to Step 6.

    Step 4: Configure typesense-server.ini

    The APT install drops a template at /etc/typesense/typesense-server.ini. Open it with your editor:

    bash
    sudo nano /etc/typesense/typesense-server.ini

    Replace the contents with a production-ready configuration:

    ini
    [server]

    api-key = REPLACE_WITH_A_STRONG_RANDOM_STRING data-dir = /var/lib/typesense/data log-dir = /var/log/typesense api-address = 0.0.0.0 api-port = 8108 listen-address = 127.0.0.1 listen-port = 8108 enable-cors = true

    Raft / cluster (single-node defaults; we revisit in Step 10)

    peering-address = 127.0.0.1 peering-port = 8107

    Resource limits

    max-memory-ratio = 0.75

    Snapshots

    snapshot-interval-seconds = 3600

    Key settings explained:

    • api-key -- The bootstrap admin key. Treat it like a root password. Generate with openssl rand -hex 32.
    • data-dir -- Where Typesense persists the index, WAL, and snapshots. Put this on NVMe if you can.
    • listen-address + listen-port -- Bind for the HTTP API. Keep it on 127.0.0.1:8108 and front it with Nginx (Step 11) for production. Set to 0.0.0.0 only if you are running a cluster without a reverse proxy and trust the network.
    • api-port -- The HTTP port Typesense listens on for client requests. Same as listen-port in most deployments.
    • peering-address + peering-port -- Raft replication endpoint. We tune this in Step 10.
    • max-memory-ratio -- Typesense will refuse writes when this fraction of system RAM is exceeded. 0.75 is a safe default.
    • enable-cors -- Required if the browser calls Typesense directly (InstantSearch, Algolia-compatible widgets).
    Generate and inject the API key:

    bash
    API_KEY=$(openssl rand -hex 32)
    sudo sed -i "s/REPLACE_WITH_A_STRONG_RANDOM_STRING/$API_KEY/" /etc/typesense/typesense-server.ini
    echo "Your Typesense admin API key: $API_KEY"
    sudo chown typesense:typesense /etc/typesense/typesense-server.ini
    sudo chmod 600 /etc/typesense/typesense-server.ini

    Create the log directory:

    bash
    sudo mkdir -p /var/log/typesense
    sudo chown typesense:typesense /var/log/typesense

    Step 5: Enable the systemd Service

    The APT package installs /lib/systemd/system/typesense-server.service. Inspect it:

    bash
    systemctl cat typesense-server

    Expected content (abbreviated):

    ini
    [Unit]
    Description=Typesense Server
    After=network.target

    [Service] User=typesense Group=typesense Type=simple ExecStart=/opt/typesense-server/typesense-server --config=/etc/typesense/typesense-server.ini Restart=on-failure LimitNOFILE=65535

    [Install] WantedBy=multi-user.target

    Enable and start the service:

    bash
    sudo systemctl daemon-reload
    sudo systemctl enable --now typesense-server

    Verify it is running:

    bash
    sudo systemctl status typesense-server

    Expected output:

    text
    ● typesense-server.service - Typesense Server
         Loaded: loaded (/lib/systemd/system/typesense-server.service; enabled)
         Active: active (running) since Thu 2026-04-16 10:00:00 UTC; 5s ago
       Main PID: 1234 (typesense-serve)
          Tasks: 12
         Memory: 58.2M
         CGroup: /system.slice/typesense-server.service
                 └─1234 /opt/typesense-server/typesense-server --config=/etc/typesense/typesense-server.ini

    Smoke test the API:

    bash
    curl http://localhost:8108/health

    Expected output:

    json
    {"ok":true}

    For convenience, export the API key into your shell so the rest of the guide reads cleanly:

    bash
    export TYPESENSE_API_KEY="paste-your-api-key-here"

    Step 6: Create Your First Collection

    A collection in Typesense is analogous to a table in a relational database or an index in Elasticsearch. You define its schema up front: field names, types, and whether each field is facetable, indexed, or sortable.

    Create a products collection for an e-commerce catalog:

    bash
    curl -X POST "http://localhost:8108/collections" \
      -H "X-TYPESENSE-API-KEY: $TYPESENSE_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "name": "products",
        "fields": [
          { "name": "name",        "type": "string",        "facet": false, "index": true, "sort": false },
          { "name": "description", "type": "string",        "facet": false, "index": true, "sort": false },
          { "name": "brand",       "type": "string",        "facet": true,  "index": true, "sort": false },
          { "name": "categories",  "type": "string[]",      "facet": true,  "index": true },
          { "name": "price",       "type": "float",         "facet": true,  "index": true, "sort": true  },
          { "name": "in_stock",    "type": "bool",          "facet": true,  "index": true },
          { "name": "rating",      "type": "float",         "facet": false, "index": true, "sort": true  },
          { "name": "created_at",  "type": "int64",         "facet": false, "index": true, "sort": true  },
          { "name": "location",    "type": "geopoint",      "facet": false, "index": true }
        ],
        "default_sorting_field": "rating"
      }'

    Expected output:

    json
    {
      "name": "products",
      "num_documents": 0,
      "fields": [ ... ],
      "default_sorting_field": "rating",
      "created_at": 1768636800
    }

    Schema field options explained

    • type -- Supported scalars: string, int32, int64, float, bool, geopoint. Array variants append [] (e.g. string[]). Use auto for dynamically typed fields when the schema is not fully known upfront.
    • facet -- Set to true to enable facet counts on this field. Required for drop-down filters, category trees, and price buckets.
    • index -- Set to true (default) to make the field searchable or filterable. Set to false for fields you only want to return in results but never query against, which saves memory.
    • sort -- Set to true on numeric fields you plan to sort by. string fields require "sort": true explicitly if you want alphabetical ordering.
    • optional -- Set to true if a field may be missing from some documents.
    List all collections to verify:

    bash
    curl "http://localhost:8108/collections" \
      -H "X-TYPESENSE-API-KEY: $TYPESENSE_API_KEY" | jq

    Step 7: Index Documents

    Typesense supports single-document inserts (POST /collections/<name>/documents) and bulk imports via JSONL (POST /collections/<name>/documents/import). Bulk import is dramatically faster and is what you want for initial loads and reindexing.

    Single document

    bash
    curl -X POST "http://localhost:8108/collections/products/documents" \
      -H "X-TYPESENSE-API-KEY: $TYPESENSE_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "id": "sku-1001",
        "name": "CloudCore Starter VPS",
        "description": "Entry-level NVMe VPS, 2 vCPU, 4 GB RAM, unmetered bandwidth.",
        "brand": "vps-server.host",
        "categories": ["vps", "cloud", "starter"],
        "price": 5.99,
        "in_stock": true,
        "rating": 4.7,
        "created_at": 1768636800,
        "location": [52.52, 13.405]
      }'

    Bulk import (JSONL)

    Create a file products.jsonl where each line is a single JSON object:

    bash
    cat > products.jsonl <<'EOF'
    {"id":"sku-1002","name":"CloudCore Professional","description":"6 vCPU, 12 GB RAM","brand":"vps-server.host","categories":["vps","pro"],"price":19.99,"in_stock":true,"rating":4.9,"created_at":1768636900,"location":[52.52,13.405]}
    {"id":"sku-1003","name":"CloudCore Enterprise","description":"12 vCPU, 32 GB RAM","brand":"vps-server.host","categories":["vps","enterprise"],"price":49.99,"in_stock":true,"rating":5.0,"created_at":1768637000,"location":[52.52,13.405]}
    {"id":"sku-1004","name":"GPU AI Node","description":"NVIDIA A30, 24 GB VRAM","brand":"vps-server.host","categories":["gpu","ai"],"price":149.99,"in_stock":false,"rating":4.8,"created_at":1768637100,"location":[52.52,13.405]}
    EOF

    Import with ?action=upsert so re-runs overwrite rather than error:

    bash
    curl -X POST "http://localhost:8108/collections/products/documents/import?action=upsert" \
      -H "X-TYPESENSE-API-KEY: $TYPESENSE_API_KEY" \
      -H "Content-Type: text/plain" \
      --data-binary @products.jsonl

    Expected output (one JSON object per line):

    text
    {"success":true}
    {"success":true}
    {"success":true}

    Typesense's bulk import handles tens of thousands of documents per second on modest hardware. For very large catalogs, chunk the input into 10K-50K document batches.

    Step 8: Run Searches

    Every search hits GET /collections/<name>/documents/search. The essential query parameters are:

    • q -- The user's search string. Use * to match everything (useful for pure browse/filter queries).
    • query_by -- Comma-separated list of fields to search against. Order matters for default ranking weights.
    • filter_by -- Boolean filter expression: price:<50 && in_stock:true && categories:=vps.
    • facet_by -- Comma-separated facetable fields to compute counts for.
    • sort_by -- Ordering spec: rating:desc,price:asc. Use _text_match:desc to sort by relevance.

    A simple typo-tolerant search

    bash
    curl "http://localhost:8108/collections/products/documents/search?q=proffesional&query_by=name,description" \
      -H "X-TYPESENSE-API-KEY: $TYPESENSE_API_KEY" | jq '.hits[].document.name'

    Expected output (note the typo in "proffesional" is corrected):

    json
    "CloudCore Professional"

    Filter + facet + sort

    bash
    curl -G "http://localhost:8108/collections/products/documents/search" \
      -H "X-TYPESENSE-API-KEY: $TYPESENSE_API_KEY" \
      --data-urlencode "q=*" \
      --data-urlencode "query_by=name" \
      --data-urlencode "filter_by=price:<100 && in_stock:true" \
      --data-urlencode "facet_by=brand,categories" \
      --data-urlencode "sort_by=rating:desc,price:asc" \
      --data-urlencode "per_page=10" | jq

    Expected output (abbreviated):

    json
    {
      "found": 2,
      "hits": [
        { "document": { "name": "CloudCore Enterprise", "price": 49.99, "rating": 5.0 } },
        { "document": { "name": "CloudCore Professional", "price": 19.99, "rating": 4.9 } }
      ],
      "facet_counts": [
        { "field_name": "brand", "counts": [ { "value": "vps-server.host", "count": 2 } ] },
        { "field_name": "categories", "counts": [ { "value": "vps", "count": 2 }, { "value": "pro", "count": 1 } ] }
      ],
      "search_time_ms": 2
    }

    Geo-search

    Find products within 50 km of Berlin:

    bash
    curl -G "http://localhost:8108/collections/products/documents/search" \
      -H "X-TYPESENSE-API-KEY: $TYPESENSE_API_KEY" \
      --data-urlencode "q=*" \
      --data-urlencode "query_by=name" \
      --data-urlencode "filter_by=location:(52.52,13.405,50 km)" \
      --data-urlencode "sort_by=location(52.52,13.405):asc"

    Federated (multi-collection) search

    POST to /multi_search with an array of searches to run multiple queries in a single round trip -- perfect for global search bars that surface products, articles, and users at once.

    bash
    curl -X POST "http://localhost:8108/multi_search" \
      -H "X-TYPESENSE-API-KEY: $TYPESENSE_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "searches": [
          { "collection": "products", "q": "vps",    "query_by": "name,description" },
          { "collection": "articles", "q": "vps",    "query_by": "title,body"       }
        ]
      }'

    Step 9: Generate Scoped Search API Keys

    Admin API keys let clients do anything: create collections, import documents, drop data. You never ship one to a browser. Instead, generate a dedicated search-only key, then derive scoped keys with embedded filters per tenant or per user.

    Create a search-only parent key

    bash
    curl -X POST "http://localhost:8108/keys" \
      -H "X-TYPESENSE-API-KEY: $TYPESENSE_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "description": "Search-only key for frontend",
        "actions": ["documents:search"],
        "collections": ["products", "articles"]
      }'

    Expected output:

    json
    {
      "id": 1,
      "actions": ["documents:search"],
      "collections": ["products","articles"],
      "description": "Search-only key for frontend",
      "value": "SEARCH_ONLY_KEY_ABCDEF123..."
    }

    Store the full value -- Typesense only returns the plaintext key once; subsequent GET /keys only returns a key prefix.

    Derive a scoped key client-side

    Scoped keys are HMAC-SHA256 signatures of a JSON blob of additional constraints, base64-encoded alongside the parent key's prefix. They are generated in your application (backend preferred, even browsers work) without calling Typesense.

    Node.js example:

    javascript
    import crypto from 'crypto';

    function generateScopedKey(parentKey, params) { const paramsJson = JSON.stringify(params); const digest = crypto .createHmac('sha256', parentKey) .update(paramsJson) .digest('base64'); const keyPrefix = parentKey.substring(0, 4); return Buffer.from(digest + keyPrefix + paramsJson).toString('base64'); }

    const scopedKey = generateScopedKey( 'SEARCH_ONLY_KEY_ABCDEF123...', { filter_by: 'tenant_id:=acme-corp', expires_at: Math.floor(Date.now() / 1000) + 3600 // 1 hour } );

    console.log(scopedKey);

    Ship scopedKey to the browser in place of the raw search key. Typesense validates the HMAC on every request and enforces filter_by: tenant_id:=acme-corp automatically -- the user cannot escape their tenant, and the key expires in one hour.

    This mechanism is what makes Typesense viable for multi-tenant SaaS: one collection, per-tenant scoped keys, zero data leakage.

    Step 10: Configure a 3-Node High-Availability Cluster

    Typesense uses Raft consensus for replication. A 3-node cluster tolerates one node failure while maintaining write quorum; a 5-node cluster tolerates two. Always run an odd number of nodes.

    Assume you have three VPS instances on a private network:

    • node1 -- 10.0.0.11
    • node2 -- 10.0.0.12
    • node3 -- 10.0.0.13

    Install Typesense on all three nodes

    Repeat Steps 1-5 on each node. Use the same api-key in every typesense-server.ini.

    Create the shared nodes file

    On every node, create /etc/typesense/nodes:

    bash
    sudo tee /etc/typesense/nodes > /dev/null <<'EOF'
    10.0.0.11:8107:8108,10.0.0.12:8107:8108,10.0.0.13:8107:8108
    EOF
    sudo chown typesense:typesense /etc/typesense/nodes

    The format is <peering-address>:<peering-port>:<api-port>, comma-separated.

    Update typesense-server.ini on every node

    Edit /etc/typesense/typesense-server.ini on each node. The only value that differs per node is peering-address (and api-address if you expose the API):

    node1 (10.0.0.11):

    ini
    [server]
    api-key = THE_SHARED_ADMIN_KEY
    data-dir = /var/lib/typesense/data
    log-dir = /var/log/typesense
    api-address = 0.0.0.0
    api-port = 8108
    peering-address = 10.0.0.11
    peering-port = 8107
    nodes = /etc/typesense/nodes
    enable-cors = true

    Repeat for node2 with peering-address = 10.0.0.12 and node3 with peering-address = 10.0.0.13.

    Open firewall ports between nodes

    Allow peering (8107) and API (8108) traffic between the three VPS IPs. With UFW on node1:

    bash
    sudo ufw allow from 10.0.0.12 to any port 8107,8108 proto tcp
    sudo ufw allow from 10.0.0.13 to any port 8107,8108 proto tcp

    Repeat symmetrically on node2 and node3.

    Restart all three nodes

    bash
    sudo systemctl restart typesense-server

    Verify cluster health

    From any node:

    bash
    curl "http://localhost:8108/debug" \
      -H "X-TYPESENSE-API-KEY: $TYPESENSE_API_KEY" | jq

    You should see "state": 1 on the leader and "state": 4 on followers. Check the leader's log for quorum:

    bash
    sudo journalctl -u typesense-server -n 30 --no-pager | grep -i "elected\|leader"

    Writes sent to any node are forwarded to the leader and replicated. Reads can be served by any node. Put a load balancer (Nginx upstream with least_conn or a dedicated TCP LB) in front for client-facing traffic.

    Step 11: Front Typesense with Nginx + TLS

    For any production deployment where clients reach Typesense over the internet, terminate TLS at Nginx. This gives you HTTPS, optional rate limiting, request logging, and the ability to strip or inject headers.

    Install Nginx and Certbot

    bash
    sudo apt install -y nginx certbot python3-certbot-nginx

    Point DNS

    Create an A record for search.yourdomain.com that points to your VPS IP (or to your load balancer for the HA cluster).

    Create the Nginx configuration

    bash
    sudo tee /etc/nginx/sites-available/typesense > /dev/null <<'EOF'
    

    Rate limit zone: 100 requests per second per IP, burst of 200

    limit_req_zone $binary_remote_addr zone=typesense_api:10m rate=100r/s;

    upstream typesense_backend { # For a single-node install, list localhost server 127.0.0.1:8108;

    # For an HA cluster, list all three nodes: # server 10.0.0.11:8108; # server 10.0.0.12:8108; # server 10.0.0.13:8108; keepalive 32; }

    server { listen 80; server_name search.yourdomain.com; return 301 https://$host$request_uri; }

    server { listen 443 ssl http2; server_name search.yourdomain.com;

    ssl_certificate /etc/letsencrypt/live/search.yourdomain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/search.yourdomain.com/privkey.pem;

    ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers on;

    add_header Strict-Transport-Security "max-age=63072000" always; add_header X-Content-Type-Options nosniff; add_header X-Frame-Options DENY;

    client_max_body_size 100m;

    location / { limit_req zone=typesense_api burst=200 nodelay;

    proxy_pass http://typesense_backend; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Connection "";

    proxy_buffering off; proxy_read_timeout 120s; proxy_send_timeout 120s; } } EOF

    sudo ln -s /etc/nginx/sites-available/typesense /etc/nginx/sites-enabled/ sudo nginx -t

    Issue the certificate

    bash
    sudo certbot --nginx -d search.yourdomain.com
    sudo systemctl reload nginx

    Certbot will auto-renew via a systemd timer. Confirm with systemctl list-timers | grep certbot.

    Test HTTPS end-to-end

    bash
    curl "https://search.yourdomain.com/collections" \
      -H "X-TYPESENSE-API-KEY: $TYPESENSE_API_KEY" | jq

    You now have Typesense behind HTTPS with rate limiting, ready for browser-direct search calls using a scoped API key.

    Performance Tuning

    • Pin the data directory to NVMe -- Typesense writes the Raft WAL on every mutation. Slow disks cap write throughput fast.
    • Increase ulimit -n -- The systemd unit ships with LimitNOFILE=65535. Verify with cat /proc/$(pgrep typesense-server)/limits.
    • Raise max-memory-ratio -- If your VPS is dedicated to Typesense, bump it to 0.85 to let the index use more RAM.
    • Use query_by_weights -- When searching multiple fields, weight them explicitly: query_by=name,description&query_by_weights=4,1.
    • Cache with use_cache=true -- Typesense has an in-process result cache keyed on query parameters. Enable it for high-frequency, identical searches.
    • Batch writes -- Always prefer /documents/import over per-document POSTs. Even 100x batching dramatically reduces CPU per document.
    • Snapshot off-peak -- Tune snapshot-interval-seconds or trigger manual snapshots via /operations/snapshot?snapshot_path=/var/lib/typesense/snapshots/$(date +%F) during low-traffic windows.
    • Vertical before horizontal -- A single well-provisioned 16 GB RAM box serves most applications. Move to a cluster for fault tolerance, not for throughput.

    Troubleshooting

    ProblemCauseSolution
    curl: (7) Failed to connect to localhost port 8108Service not running or bound to a different interfacesudo systemctl status typesense-server; verify listen-address in ini file
    {"message":"Forbidden - a valid x-typesense-api-key header must be sent."}Missing or wrong admin keyConfirm api-key in /etc/typesense/typesense-server.ini matches the header you sent
    Imports hang or return 503 Service Unavailablemax-memory-ratio threshold exceededAdd RAM, drop unused collections, or increase the ratio in config
    Cluster stuck electing a leaderNodes cannot reach each other on port 8107Check firewall and ping between peering addresses; review logs for "timeout"
    {"message":"Not ready or in maintenance mode"}Replica is catching up via snapshot installWait; monitor with curl /debug on the follower until it reports healthy
    Search returns zero hits despite matching documentsField has "index": false or schema mismatchInspect schema: curl /collections/<name>; reindex with corrected field definitions
    High p99 latency on geo queriesMissing radius filter combined with huge datasetAlways constrain geo searches with a reasonable km radius in filter_by

    Inspect logs

    bash
    # Live tail
    sudo journalctl -u typesense-server -f

    Last 100 lines

    sudo journalctl -u typesense-server -n 100 --no-pager

    Raft-specific

    sudo journalctl -u typesense-server | grep -i raft

    FAQ

    Is Typesense a drop-in replacement for Algolia?

    For most applications, yes. Typesense matches Algolia on typo tolerance, faceting, filtering, sorting, grouping, synonyms, curation, geo-search, and multi-index federated search. The official typesense-instantsearch-adapter package lets you reuse Algolia InstantSearch widgets with a five-line configuration swap. Gaps tend to be in managed-infrastructure conveniences (global edge CDN, dashboard analytics depth) which you replace with your own VPS footprint plus something like Umami or Plausible for analytics.

    How much RAM do I need?

    Typesense holds the active index in memory, so RAM is the dominant sizing factor. A practical rule of thumb: 1 GB of RAM per 1 million small documents (a product row, a short article), scaled up linearly with average document size. For a 500K-product catalog with long descriptions, plan on 4 GB. Run load tests with realistic documents before sizing for production; the built-in /metrics endpoint reports resident set size per collection.

    Should I use APT or Docker?

    APT wins on simplicity for dedicated VPS installs: clean systemd integration, standard config paths, zero Docker overhead, and easy integration with unattended-upgrades. Docker wins when Typesense is one service among many in an existing Compose or Kubernetes stack, when you need reproducible version pinning across dev/staging/prod, or when you want lightweight isolation from the host. Both deliver identical runtime behavior -- pick the one that matches your operational model.

    How does Typesense compare to Meilisearch, Elasticsearch, and OpenSearch?

    Meilisearch sits closest to Typesense in design philosophy: fast, typo-tolerant, developer-friendly, schema-optional. Typesense tends to edge out on raw throughput and mature clustering; Meilisearch has a more polished dashboard. See our Meilisearch install guide for a side-by-side setup.

    Elasticsearch is vastly more powerful but also more complex, more resource-hungry, and licensed under Elastic License 2.0. Use it when you need log aggregation at scale, custom analyzers, or deep query DSL. Our Elasticsearch install guide covers a production setup.

    OpenSearch is the AWS-led Apache 2.0 fork of Elasticsearch. Similar feature set to Elasticsearch, different license. The OpenSearch install guide walks through a cluster deploy.

    For most product search, site search, and application search workloads, Typesense or Meilisearch is the pragmatic choice. Reach for OpenSearch/Elasticsearch when you need log analytics or complex aggregations.

    Can Typesense do vector / semantic search?

    Yes. Typesense supports native vector fields and k-NN search. You either supply embeddings from your own model or configure Typesense to call a remote embedding API (OpenAI, Cohere, or a self-hosted model via an HTTP endpoint). This lets you do hybrid search: lexical query_by + vector similarity on the same collection with a single request.

    Is Typesense Cloud the same as self-hosted?

    Typesense Cloud is the managed offering from the Typesense team. It runs the same open-source binary you are installing here. Choosing self-hosted gives you lower cost, data sovereignty, and unconstrained tuning. Typesense Cloud gives you managed backups, monitoring, and multi-region. The codebase is identical, so migration in either direction is straightforward.

    Next Steps

    Now that Typesense is running on your VPS, here is where to go next:

    • Build a live InstantSearch UI -- Pair your scoped search-only key with the Typesense InstantSearch adapter to ship a facet sidebar, sort dropdown, and pagination in an afternoon.
    • Index your existing data -- Write a nightly sync script that pulls from your primary database (Postgres, MySQL) and upserts into Typesense. The Typesense docs on syncing cover CDC-friendly patterns.
    • Add analytics -- Enable Typesense's built-in search analytics to track top queries, zero-result queries, and click-through rates. Feed this into your product roadmap.
    • Set up automated backups -- Configure daily snapshots via /operations/snapshot, push them off-box to S3 or a separate storage VPS, and test restore quarterly.
    • Upgrade to HA when your SLA demands it -- One-node Typesense is fast and reliable, but HTTP is a single point of failure. Step 10 in this guide has the 3-node blueprint when you are ready.
    • Explore alternatives -- Compare with Meilisearch, Elasticsearch, and OpenSearch before committing long-term.
    For the authoritative reference on every endpoint, parameter, and configuration option, bookmark the official documentation at typesense.org/docs.

    Deploy a Typesense-Ready VPS in Under 60 Seconds
    >
    Spin up a fresh Ubuntu 24.04 VPS on the CloudCore Starter plan, follow this guide, and have typo-tolerant instant search running before your coffee gets cold.
    >
    - 2 vCPU / 4 GB RAM / 40 GB NVMe
    - Unmetered bandwidth, EU + North America locations
    - From EUR 7.99/month, no long-term contract
    >
    Launch a CloudCore Starter VPS

    Was this article helpful?

    ← Back to Install GuidesBrowse all categories →

    Still have questions?

    Contact Support →Submit a Ticket