Target environment: RamNode KVM VPS, Ubuntu 24.04 LTS. Covers a single-node quick deploy and a 3-node HA cluster, both fronted by nginx + Let's Encrypt.
1. Sizing and prerequisites
- Typesense keeps its index in RAM plus a disk-backed persistence layer (RocksDB). Budget RAM at roughly 2–3x your raw dataset size as a starting point.
- Single-node: any RamNode VPS with enough RAM for your dataset. Attach a dedicated data volume if your plan supports it, otherwise use a subdirectory on the root disk with adequate free space.
- HA cluster: 3 RamNode VPS nodes (odd number required — Typesense uses Raft consensus, needs a quorum). Put them in the same datacenter region for low-latency Raft replication; cross-region Raft is possible but latency will show up as write slowness.
- Firewall: Typesense API port (default
8108) should NOT be exposed publicly — put it behind nginx, or restrict to your app servers' IPs at the RamNode firewall/security-group level. The Raft peering port (default8107) should be restricted to just the cluster nodes.
2. Single-node install (Docker)
sudo mkdir -p /opt/typesense/data
sudo apt-get update && sudo apt-get install -y docker.io
sudo systemctl enable --now docker
# Generate an API key up front
TYPESENSE_API_KEY=$(openssl rand -hex 32)
echo "Save this key: $TYPESENSE_API_KEY"
sudo docker run -d \
--name typesense \
--restart unless-stopped \
-p 127.0.0.1:8108:8108 \
-v /opt/typesense/data:/data \
typesense/typesense:27.1 \
--data-dir /data \
--api-key="$TYPESENSE_API_KEY" \
--enable-corsNote the bind is to 127.0.0.1 only — nginx on the same box proxies to it; the container port is
not reachable from outside the VPS directly.
Verify:
curl "http://localhost:8108/health"
curl -H "X-TYPESENSE-API-KEY: $TYPESENSE_API_KEY" "http://localhost:8108/collections"3. Single-node install (native binary, no Docker)
If you'd rather run it as a systemd unit directly (running it as a plain systemd service):
curl -O https://dl.typesense.org/releases/27.1/typesense-server-27.1-amd64.deb
sudo apt install ./typesense-server-27.1-amd64.debEdit /etc/typesense/typesense-server.ini:
[server]
api-address = 127.0.0.1
api-port = 8108
data-dir = /var/lib/typesense
api-key = <your-generated-key>
enable-cors = truesudo systemctl enable --now typesense-server
sudo systemctl status typesense-server4. nginx reverse proxy + TLS
Standard Let's Encrypt setup with certbot:
server {
listen 443 ssl;
server_name search.internal.ramnode.example;
ssl_certificate /etc/letsencrypt/live/search.internal.ramnode.example/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/search.internal.ramnode.example/privkey.pem;
location / {
proxy_pass http://127.0.0.1:8108;
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;
}
}sudo certbot --nginx -d search.internal.ramnode.exampleSince the API key is the only auth layer, also restrict access at the firewall to known app-server
IPs, and consider a second nginx location block using scoped/search-only API keys (see section 6)
for anything client-facing.
5. HA cluster (3 nodes, Raft)
On each node, systemd/native install as in section 3, but with cluster-aware config. Example for
node 1 of 3 (10.0.0.11, 10.0.0.12, 10.0.0.13 as private IPs):
[server]
api-address = 0.0.0.0
api-port = 8108
peering-address = 10.0.0.11
peering-port = 8107
data-dir = /var/lib/typesense
api-key = <shared-key-same-on-all-nodes>
nodes = 10.0.0.11:8107:8108,10.0.0.12:8107:8108,10.0.0.13:8107:8108Write nodes to a shared file each node reads at startup (Typesense also supports --nodes pointing
at a file path — useful if you manage this via Ansible and want to template it once):
echo "10.0.0.11:8107:8108,10.0.0.12:8107:8108,10.0.0.13:8107:8108" | sudo tee /etc/typesense/nodesThen reference nodes = /etc/typesense/nodes in the ini instead of the inline list.
Restart all three, then check cluster health from any node:
curl -H "X-TYPESENSE-API-KEY: <key>" http://localhost:8108/health
curl -H "X-TYPESENSE-API-KEY: <key>" http://localhost:8108/debug/debug on the leader shows Raft state and committed index; use this to confirm all three nodes
agree before pointing production traffic at the cluster. Put all three behind a single nginx
upstream with least_conn or round-robin — reads can go to any node, writes are automatically
forwarded to the leader internally.
RamNode firewall notes for the cluster: allow 8107/tcp and 8108/tcp between the three private
IPs only; do not open peering port 8107 beyond the cluster nodes.
6. Scoped/search-only API keys
Don't hand out the admin key to anything client-facing. Generate scoped keys per collection:
curl -X POST "http://localhost:8108/keys" \
-H "X-TYPESENSE-API-KEY: <admin-key>" \
-H "Content-Type: application/json" \
-d '{
"description": "search-only for products collection",
"actions": ["documents:search"],
"collections": ["products"]
}'7. Backups
Typesense supports on-demand snapshots:
curl -X POST "http://localhost:8108/operations/snapshot?snapshot_path=/opt/typesense/backups/$(date +%F)" \
-H "X-TYPESENSE-API-KEY: <admin-key>"Cron this nightly and rotate old snapshots (e.g., keep 7 days) — wire it into whatever backup pull/off-box process you already use for other RamNode internal service state.
0 3 * * * curl -s -X POST "http://localhost:8108/operations/snapshot?snapshot_path=/opt/typesense/backups/$(date +\%F)" -H "X-TYPESENSE-API-KEY: <admin-key>" >> /var/log/typesense-snapshot.log 2>&18. Common issues
| Symptom | Likely cause | Fix |
|---|---|---|
Not Found on /health behind nginx | Missing trailing slash or wrong proxy_pass target | Confirm proxy_pass http://127.0.0.1:8108; with no trailing path segment mismatch |
| Cluster node won't join | Peering port blocked or IP list mismatch across nodes | Ensure 8107 open between nodes and the nodes list/file is identical (order doesn't matter) on all three |
| High memory usage | Full index held in RAM by design | Right-size the VPS RAM plan; there's no "disk-only" mode for the searchable index itself |
| Writes slow in cluster mode | Nodes spread across regions with high inter-node latency | Keep Raft cluster members in the same DC; use single-node + async replication to other regions instead if you need geographic spread |
