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 Surrealdb Ubuntu
GUIDEInstall Guides

How to Install SurrealDB on Ubuntu 24.04 — Multi-Model Database Setup

26 min read

How to Install SurrealDB on Ubuntu 24.04 — Multi-Model Database Setup

SurrealDB is a relatively new database that collapses four traditionally separate systems — a document store, a graph database, a key-value store, and a relational database — into a single engine with one query language. For teams that would otherwise run PostgreSQL for relational data, MongoDB for documents, Redis for key-value caching, and Neo4j for relationships, SurrealDB offers a compelling simplification. This tutorial walks through installing SurrealDB on Ubuntu 24.04, picking a storage engine, bootstrapping users, writing your first SurrealQL, enabling live queries, and putting the service behind an Nginx TLS proxy.

Prefer managed databases? CloudCore Professional VPS plans come with Docker pre-installed and enough memory to run SurrealDB comfortably alongside your application. Launch a Professional VPS now and start building in under five minutes.

Table of Contents

  • What is SurrealDB?
  • Why Self-Host SurrealDB Instead of Surreal Cloud?
  • Prerequisites
  • Step 1: Update System Packages
  • Step 2: Install SurrealDB
  • Step 3: Choose a Storage Engine — RocksDB vs TiKV
  • Step 4: Create a systemd Unit
  • Step 5: Bootstrap the Root User, Namespace, and Database
  • Step 6: SurrealQL Basics
  • Step 7: Schema-Full vs Schema-Less Tables
  • Step 8: Users, Roles, and Scopes
  • Step 9: Live Queries
  • Step 10: Nginx TLS Reverse Proxy
  • Backups and Upgrades
  • Troubleshooting
  • FAQ
  • Next Steps
  • What is SurrealDB?

    SurrealDB is an open-source, end-to-end, cloud-native database written in Rust. Its headline feature is that it is multi-model: a single running instance stores and queries four different data shapes without needing bolt-on extensions or a second database server.

    • Document model — Tables are collections of JSON-like records. Nested objects, arrays, and flexible attributes are first-class citizens.
    • Graph model — Records are linked through typed edges. You can traverse relationships in SurrealQL with arrow syntax such as user->follows->user without writing recursive CTEs.
    • Key-value model — Every record is addressable by a stable ID like person:alice. Direct lookups are O(log n) against the underlying KV store.
    • Relational model — Tables, fields, constraints, indexes, and joins behave like a traditional SQL database. You can enforce types, unique indexes, and assertions.
    A single query language, SurrealQL, covers all four models. It is intentionally familiar to anyone who has written SQL, but it adds record links, graph traversals, live subscriptions, and embedded objects. Compared to running several specialized databases in parallel, SurrealDB dramatically reduces operational surface area for teams that need more than one data model.

    SurrealDB supports two transport layers out of the box. The HTTP endpoint accepts RESTful SurrealQL requests for one-shot queries, imports, and exports. The WebSocket endpoint carries authenticated sessions, streaming results, and live subscriptions — the mechanism that makes real-time features so natural in SurrealDB.

    Typical use cases include real-time collaboration backends, social graphs, knowledge graphs, IoT telemetry, inventory and catalog systems, and any application that would otherwise need PostgreSQL plus a caching layer plus a graph store. If you are currently evaluating Postgres with extensions, or gluing together a relational database and a graph database, SurrealDB is worth a serious look.

    Why Self-Host SurrealDB Instead of Surreal Cloud?

    SurrealDB offers a hosted product called Surreal Cloud. It is convenient, but self-hosting on your own VPS gives you tangible advantages:

    • Data sovereignty — Your data sits on a server whose physical location you picked. For EU businesses bound by GDPR, that means no cross-border transfers, no US-based subprocessors, and a much simpler DPIA. Regulated industries (healthcare, finance, legal) often require data residency guarantees that only self-hosting can satisfy.
    • Predictable flat-rate cost — A Professional VPS costs the same whether your database holds 5 GB or 500 GB. There is no per-operation pricing, no egress fees, and no surprise bills when an application loops on a query.
    • No vendor lock-in — A self-hosted SurrealDB is a single binary plus a data directory. You can migrate between VPS providers in minutes using surreal export and surreal import.
    • Full control over versions — Upgrade when you are ready. Pin the exact version that your application was tested against. Test release candidates in staging before production.
    • Custom networking — Put SurrealDB in a private network, expose only a WireGuard tunnel, bind to a Tailscale IP, or lock it behind Cloudflare Zero Trust. Managed providers give you none of these options at low tiers.
    • Integration with your stack — Run SurrealDB on the same VPS as your application for single-digit-millisecond query latency. Share logs, monitoring, and backup tooling with the rest of your infrastructure.
    For solo developers and small teams, self-hosting SurrealDB on a single Ubuntu VPS is a production-grade setup. You only need to move to a distributed deployment (TiKV, Kubernetes) once you outgrow one node, and even then you keep complete control.

    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 RocksDB-backed workloads with caching)
    • At least 20 GB of disk space for the binary, data directory, and initial growth
    • A domain name pointing at your server if you plan to expose a TLS endpoint
    Recommended Plan: CloudCore Professional
    >
    For a comfortable production deployment — with headroom for the RocksDB cache, your application, and operating system overhead — we recommend the CloudCore Professional plan:
    >
    - 6 vCPU cores
    - 12 GB RAM
    - 100 GB NVMe SSD
    - Unmetered bandwidth
    - EUR 19.99/month
    >
    NVMe storage is particularly important for the RocksDB storage engine, which is write-heavy and benefits dramatically from low-latency disks.

    Connect to your server via SSH:

    bash
    ssh root@your-server-ip

    Step 1: Update System Packages

    Patch the base system before installing anything.

    bash
    sudo apt update && sudo apt upgrade -y

    Expected output (abbreviated):

    text
    Hit:1 http://archive.ubuntu.com/ubuntu noble InRelease
    Reading package lists... Done
    Building dependency tree... Done
    0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.

    If the kernel was updated, reboot:

    bash
    sudo reboot

    Install a few utilities you will use throughout the guide:

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

    Step 2: Install SurrealDB

    SurrealDB ships a single static binary. The easiest way to install it is with the official install script from surrealdb.com.

    bash
    curl -sSf https://install.surrealdb.com | sh

    Expected output:

    text
    SurrealDB is now installed.
    Visit https://surrealdb.com/docs for the full documentation.

    $ surreal version 1.5.4 for linux on x86_64

    Run surreal help for usage information.

    The script places the binary at /usr/local/bin/surreal. Confirm it:

    bash
    surreal version

    Expected output:

    text
    1.5.4 for linux on x86_64

    Create a dedicated system user and data directory so SurrealDB does not run as root:

    bash
    sudo useradd --system --home /var/lib/surrealdb --shell /usr/sbin/nologin surrealdb
    sudo mkdir -p /var/lib/surrealdb/data
    sudo chown -R surrealdb:surrealdb /var/lib/surrealdb

    Step 3: Choose a Storage Engine — RocksDB vs TiKV

    SurrealDB decouples its query engine from the underlying key-value store. You choose the storage engine with a URI passed to surreal start.

    RocksDB (Single Node)

    RocksDB is an embedded LSM-tree key-value store developed by Facebook. It runs inside the SurrealDB process with no network hop, no separate cluster to manage, and no external dependencies.

    • Best for: Single-server deployments, developer workstations, staging environments, and production systems up to hundreds of gigabytes.
    • Pros: Zero operational overhead, excellent write throughput, good compression, small RAM footprint.
    • Cons: No built-in replication, no horizontal scale, no automatic failover. You own backups and redundancy.
    • URI: rocksdb:/var/lib/surrealdb/data

    TiKV (Distributed)

    TiKV is a distributed, transactional key-value store that the TiDB project battle-tested for petabyte-scale workloads. SurrealDB pointed at a TiKV cluster becomes effectively stateless — you can scale the query layer horizontally and rely on TiKV for durability and replication.

    • Best for: Multi-node SurrealDB deployments, high-availability setups, workloads that outgrow a single box, and environments that need transactional guarantees across a cluster.
    • Pros: Horizontal scale, Raft-based replication, automatic failover, snapshot isolation, multi-region friendly.
    • Cons: Non-trivial to operate (Placement Driver, TiKV nodes, monitoring), higher baseline hardware cost, added network hop per query.
    • URI: tikv://pd0:2379

    Other Engines

    For completeness, SurrealDB also supports memory (volatile, great for tests), surrealkv (native KV engine, experimental for production), and foundationdb (if you already run FDB). Most self-hosted installations use rocksdb.

    For this tutorial we will use RocksDB. If you later outgrow a single node, you can migrate to TiKV using surreal export and surreal import without changing application code.

    Step 4: Create a systemd Unit

    Running SurrealDB under systemd gives you automatic restarts, boot-time startup, log integration with journalctl, and clean shutdowns.

    Create the unit file:

    bash
    sudo tee /etc/systemd/system/surrealdb.service > /dev/null <<'EOF'
    [Unit]
    Description=SurrealDB Multi-Model Database
    Documentation=https://surrealdb.com/docs
    After=network-online.target
    Wants=network-online.target

    [Service] Type=simple User=surrealdb Group=surrealdb Environment=SURREAL_LOG=info

    ExecStart=/usr/local/bin/surreal start \ --bind 127.0.0.1:8000 \ --user root \ --pass CHANGE_ME_STRONG_PASSWORD \ rocksdb:/var/lib/surrealdb/data

    Restart=on-failure RestartSec=5s LimitNOFILE=1048576

    Hardening

    NoNewPrivileges=true ProtectSystem=strict ProtectHome=true PrivateTmp=true ReadWritePaths=/var/lib/surrealdb

    [Install] WantedBy=multi-user.target EOF

    Replace CHANGE_ME_STRONG_PASSWORD with a long random password before saving — generate one quickly with:

    bash
    openssl rand -base64 32

    A few notes on the ExecStart flags:

    • --bind 127.0.0.1:8000 keeps SurrealDB bound to loopback. External access goes through the Nginx TLS proxy configured in Step 10.
    • --user root and --pass ... declare the initial root credentials. They are only used to bootstrap the database — after Step 5 you should rotate them and rely on database-scoped users.
    • The storage URI rocksdb:/var/lib/surrealdb/data selects the RocksDB engine with a data directory owned by the surrealdb system user.
    Enable and start the service:

    bash
    sudo systemctl daemon-reload
    sudo systemctl enable --now surrealdb
    sudo systemctl status surrealdb

    Expected output (abbreviated):

    text
    ● surrealdb.service - SurrealDB Multi-Model Database
         Loaded: loaded (/etc/systemd/system/surrealdb.service; enabled; preset: enabled)
         Active: active (running) since Thu 2026-04-16 10:00:00 UTC; 3s ago
       Main PID: 1234 (surreal)
         Status: "Started web server on 127.0.0.1:8000"

    Verify the HTTP endpoint is responding:

    bash
    curl http://127.0.0.1:8000/health

    Expected output:

    text
    OK

    Tail the logs to confirm there are no errors:

    bash
    sudo journalctl -u surrealdb -n 50 --no-pager

    Step 5: Bootstrap the Root User, Namespace, and Database

    SurrealDB organizes data in a three-level hierarchy: namespace → database → table. A namespace is typically one per tenant or one per environment; a database is one per application.

    Connect with the SurrealDB CLI using the root credentials from your unit file:

    bash
    surreal sql \
      --endpoint http://127.0.0.1:8000 \
      --username root \
      --pass your-root-password \
      --pretty

    You are now at an interactive prompt:

    text
    >

    Create a namespace and a database, then switch into them:

    sql
    DEFINE NAMESPACE app;
    USE NS app;

    DEFINE DATABASE main; USE NS app DB main;

    Expected output:

    json
    [{ "status": "OK", "time": "1.2ms" }]

    From now on, you can either keep reusing the root user or — preferred — create a namespace-scoped admin user and use that instead. We will cover user management in Step 8.

    To exit the CLI:

    text
    > /exit

    Step 6: SurrealQL Basics

    SurrealQL looks like SQL but treats records as first-class objects with stable IDs. Start the CLI again and try a few queries.

    bash
    surreal sql --endpoint http://127.0.0.1:8000 \
      --username root --pass your-root-password \
      --ns app --db main --pretty

    Insert Records

    sql
    CREATE person:alice SET
      name = "Alice",
      email = "[email protected]",
      created_at = time::now();

    CREATE person:bob SET name = "Bob", email = "[email protected]", created_at = time::now();

    Each record has an explicit ID (person:alice). You can also let SurrealDB generate one with CREATE person SET ....

    Query Records

    sql
    SELECT * FROM person;

    SELECT name, email FROM person WHERE name = "Alice";

    Update and Delete

    sql
    UPDATE person:alice SET last_login = time::now();

    DELETE person:bob;

    Graph Edges

    Connect records with typed edges. Graph traversal uses arrow syntax.

    sql
    RELATE person:alice->follows->person:bob SET since = time::now();

    -- Who does Alice follow? SELECT ->follows->person.* FROM person:alice;

    -- Who follows Alice? SELECT <-follows<-person.* FROM person:alice;

    This is the graph database capability in action — no separate Neo4j required. If you previously considered a graph database for relationship-heavy workloads, SurrealDB covers the same use cases with SurrealQL.

    Nested Objects and Arrays

    Document-style storage is a native first-class feature.

    sql
    CREATE product:laptop SET
      name = "UltraBook 14",
      price = 1299.00,
      specs = {
        cpu: "Intel Core Ultra 7",
        ram_gb: 32,
        ssd_gb: 1024
      },
      tags = ["laptop", "business", "ultrabook"];

    Query into the object:

    sql
    SELECT name, specs.cpu FROM product WHERE specs.ram_gb >= 16;

    The HTTP API

    Everything the CLI does is also available over HTTP. Any application can POST SurrealQL to /sql:

    bash
    curl -X POST http://127.0.0.1:8000/sql \
      -u root:your-root-password \
      -H "NS: app" \
      -H "DB: main" \
      -H "Content-Type: application/json" \
      --data 'SELECT * FROM person;'

    The response is a JSON array of statement results.

    Step 7: Schema-Full vs Schema-Less Tables

    By default, SurrealDB tables are schema-less — any field you write gets stored, any type is accepted. This is great for prototyping, bad for long-term maintainability.

    For production, use schema-full tables where you declare fields, types, assertions, and defaults with DEFINE FIELD.

    Declare a Schema-Full Table

    sql
    DEFINE TABLE user SCHEMAFULL;

    DEFINE FIELD name ON user TYPE string ASSERT $value != NONE AND string::len($value) > 0;

    DEFINE FIELD email ON user TYPE string ASSERT string::is::email($value);

    DEFINE FIELD password ON user TYPE string ASSERT string::len($value) >= 60; -- bcrypt hashes are 60 chars

    DEFINE FIELD role ON user TYPE string VALUE $value OR "member" ASSERT $value IN ["member", "admin", "owner"];

    DEFINE FIELD created_at ON user TYPE datetime VALUE time::now() READONLY;

    DEFINE INDEX user_email_idx ON user FIELDS email UNIQUE;

    Now rejected writes are rejected up front:

    sql
    CREATE user SET name = "Carol", email = "not-an-email", password = "short";
    -- ERROR: Found 'not-an-email' for field email, with record user:...,
    -- but field must conform to: string::is::email($value)

    Schema-full tables catch data-quality bugs before they pollute your production dataset. Make the switch as soon as the shape of a table stabilizes.

    When to Stay Schema-Less

    Logs, audit trails, and event streams with deliberately flexible payloads are reasonable candidates for schema-less tables. You still get the other benefits of SurrealDB (graph edges, live queries, SurrealQL) without locking yourself into a specific field layout.

    Step 8: Users, Roles, and Scopes

    SurrealDB has a three-tier auth model:

  • Root users — Full access to everything across all namespaces. Use only for bootstrap and cluster operations.
  • Namespace users — Access to one namespace. Typical tier for tenant admins.
  • Database users — Access to one database inside a namespace. Typical tier for application service accounts.
  • Scopes — Programmatic signup and signin flows for end users of your application (not covered in depth here, see the SurrealDB docs).
  • Create a Namespace User

    sql
    DEFINE USER ns_admin ON NAMESPACE
      PASSWORD "strong-ns-password"
      ROLES OWNER;

    Create a Database User

    sql
    USE NS app DB main;

    DEFINE USER app_service ON DATABASE PASSWORD "strong-service-password" ROLES EDITOR;

    Available roles at the database level are OWNER, EDITOR, and VIEWER.

    Rotate the Root Password

    Once namespace and database users are in place, change the root password by editing the systemd unit's --pass flag, then running:

    bash
    sudo systemctl daemon-reload
    sudo systemctl restart surrealdb

    For service-to-service auth, your application should log in as app_service against the specific namespace and database, not as root.

    Example: Connecting From Node.js

    javascript
    import Surreal from "surrealdb";

    const db = new Surreal(); await db.connect("http://127.0.0.1:8000/rpc"); await db.signin({ namespace: "app", database: "main", username: "app_service", password: "strong-service-password", }); await db.use({ namespace: "app", database: "main" });

    const users = await db.select("user");

    Step 9: Live Queries

    Live queries are one of SurrealDB's most distinctive features. A client opens a WebSocket connection, subscribes to a LIVE SELECT, and receives push notifications every time a matching record is created, updated, or deleted.

    Start a Live Query From the CLI

    Open an interactive SurrealQL session and run:

    sql
    LIVE SELECT * FROM user WHERE role = "admin";

    Expected output (the live UUID is the subscription handle):

    json
    [
      {
        "result": "9f1e6f92-7b32-4a3c-9e7b-...",
        "status": "OK",
        "time": "0.5ms"
      }
    ]

    In a second session, modify an admin user:

    sql
    UPDATE user:alice SET role = "admin";

    The first session receives a notification:

    json
    {
      "action": "CREATE",
      "id": "9f1e6f92-7b32-4a3c-9e7b-...",
      "result": {
        "id": "user:alice",
        "name": "Alice",
        "role": "admin"
      }
    }

    Live Queries From an Application

    Over the WebSocket API, a frontend can stream changes directly to the browser — no polling, no custom pub/sub layer. This is ideal for chat apps, collaborative editors, dashboards, and real-time inventory displays.

    javascript
    await db.live("user", (action, result) => {
      console.log(action, result);
    });

    Stop a Live Query

    sql
    KILL "9f1e6f92-7b32-4a3c-9e7b-...";

    Step 10: Nginx TLS Reverse Proxy

    SurrealDB ships its own TLS support, but for most deployments it is easier to terminate TLS at Nginx and keep the database bound to loopback. You also gain centralized logging, rate limiting, and the ability to host other services on the same domain.

    Install Nginx and Certbot

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

    Point your DNS (A record) at the VPS IP and wait for propagation. For this example we will use db.example.com.

    Create the Nginx Site

    bash
    sudo tee /etc/nginx/sites-available/surrealdb > /dev/null <<'EOF'
    server {
        listen 80;
        server_name db.example.com;
        return 301 https://$host$request_uri;
    }

    server { listen 443 ssl http2; server_name db.example.com;

    ssl_certificate /etc/letsencrypt/live/db.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/db.example.com/privkey.pem;

    # Security headers add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; add_header X-Content-Type-Options nosniff always; add_header X-Frame-Options DENY always;

    client_max_body_size 50m;

    # HTTP / RPC endpoint location / { proxy_pass http://127.0.0.1:8000; 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;

    # WebSocket upgrade for live queries and RPC proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade";

    # Long-lived connections for live queries proxy_read_timeout 3600s; proxy_send_timeout 3600s; proxy_buffering off; } } EOF

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

    Issue a TLS Certificate

    bash
    sudo certbot --nginx -d db.example.com
    sudo systemctl reload nginx

    Certbot automatically edits the ssl_certificate paths if needed and schedules auto-renewal via a systemd timer.

    Lock Down the Firewall

    Block direct access to port 8000 from the internet. Only 443 (HTTPS) and 22 (SSH) should be exposed.

    bash
    sudo ufw allow 22/tcp
    sudo ufw allow 80/tcp
    sudo ufw allow 443/tcp
    sudo ufw deny 8000
    sudo ufw enable
    sudo ufw status

    Test the TLS endpoint:

    bash
    curl https://db.example.com/health
    

    OK

    Your SurrealDB instance is now reachable over TLS with a trusted certificate, and the database process itself never accepts connections from outside the loopback interface.

    Backups and Upgrades

    Export a Database

    SurrealDB includes a logical export tool that writes SurrealQL statements to a file. Run it against the running service:

    bash
    sudo -u surrealdb surreal export \
      --endpoint http://127.0.0.1:8000 \
      --username root --pass your-root-password \
      --ns app --db main \
      /var/lib/surrealdb/backups/main-$(date +%F).surql

    Schedule daily exports with cron or a systemd timer and ship the resulting files to S3, Backblaze B2, or another offsite destination.

    Import a Database

    bash
    sudo -u surrealdb surreal import \
      --endpoint http://127.0.0.1:8000 \
      --username root --pass your-root-password \
      --ns app --db restored \
      /var/lib/surrealdb/backups/main-2026-04-16.surql

    Snapshot the RocksDB Directory

    For RocksDB, you can additionally stop the service and snapshot /var/lib/surrealdb/data for a fast, physically consistent backup:

    bash
    sudo systemctl stop surrealdb
    sudo tar -C /var/lib/surrealdb -czf /var/backups/surrealdb-$(date +%F).tar.gz data
    sudo systemctl start surrealdb

    Upgrade SurrealDB

    Re-run the install script to upgrade the binary, then restart the service:

    bash
    curl -sSf https://install.surrealdb.com | sh
    sudo systemctl restart surrealdb
    surreal version

    Always test a new version in a staging environment first and take a fresh export before upgrading production.

    Troubleshooting

    ProblemCauseSolution
    curl: (7) Failed to connect to 127.0.0.1 port 8000Service not running or bound to a different addresssudo systemctl status surrealdb and check journalctl -u surrealdb for startup errors.
    There was a problem with authenticationWrong root credentials in the CLIVerify --user and --pass match the systemd unit. Passwords changed in the unit require systemctl daemon-reload and systemctl restart surrealdb.
    The namespace does not existNot running USE NS <name> or missing --ns flagPass --ns app --db main to the CLI, or run USE NS app DB main; at the start of a session.
    Live queries never fireWebSocket upgrade not forwarded by NginxConfirm the proxy_set_header Upgrade and Connection "upgrade" lines are present.
    permission denied writing to data directoryWrong ownership on /var/lib/surrealdb/datasudo chown -R surrealdb:surrealdb /var/lib/surrealdb and restart the service.
    RocksDB uses a lot of RAMDefault caches are generousLimit resources in the systemd unit with MemoryMax=4G, or pass tuning flags via environment variables documented at surrealdb.com.
    Schema-full migrations fail on existing rowsExisting data violates new assertionsRun a cleanup UPDATE first, then re-apply the DEFINE FIELD ... ASSERT.
    View logs live:

    bash
    sudo journalctl -u surrealdb -f

    FAQ

    What makes SurrealDB different from PostgreSQL or MongoDB?

    SurrealDB combines document, graph, key-value, and relational models in one engine. Instead of running PostgreSQL for relational data and another system for documents or graph relationships, you query all four through SurrealQL. You still get typed schemas, indexes, transactions, and role-based access control, but you also get graph traversals and live queries without adding a second database. For applications whose domain model includes strong relationships (social graphs, org charts, knowledge graphs, inventory dependencies), SurrealDB often eliminates an entire service from the stack.

    Should I use RocksDB or TiKV as the storage engine?

    Use RocksDB for single-node deployments. It is embedded in the SurrealDB process, needs no extra moving parts, and handles workloads up to a few hundred gigabytes comfortably. Switch to TiKV when you need horizontal scale, Raft-replicated durability, and automatic failover across multiple SurrealDB nodes — typical for high-traffic SaaS products or when you are already operating distributed systems like CockroachDB. You can migrate between engines using surreal export and surreal import, so starting with RocksDB and upgrading later is a safe path.

    What is the difference between schema-full and schema-less tables?

    Schema-less tables accept any fields of any shape — ideal for rapid prototyping or genuinely unstructured data such as audit logs. Schema-full tables require you to declare each field with DEFINE FIELD, including its type, a default value, and optional ASSERT expressions. Writes that violate a schema-full declaration are rejected, which catches data-quality bugs early and documents the table's contract. Production systems should default to schema-full.

    How do live queries work in SurrealDB?

    A client subscribes to a LIVE SELECT statement over the WebSocket endpoint. SurrealDB registers the subscription, and every subsequent CREATE, UPDATE, or DELETE that matches the query triggers a push message containing the action and the affected record. Subscriptions are stopped with KILL <uuid>. This replaces the polling loops or custom pub/sub plumbing you would otherwise build yourself — ideal for dashboards, chat apps, real-time notifications, and collaborative editors.

    Is self-hosting SurrealDB better than Surreal Cloud for data sovereignty?

    Self-hosting on a VPS in a region you control is the strongest guarantee that your data never leaves the intended jurisdiction. For GDPR-regulated EU businesses or HIPAA-regulated US healthcare teams, that is often a requirement rather than a preference. Surreal Cloud is convenient but runs on the vendor's chosen infrastructure with the vendor's list of subprocessors, which complicates DPIAs and audit trails. Self-hosting also gives you full control over TLS, network boundaries, and backup destinations.

    Can I expose the SurrealDB HTTP API directly to the internet?

    Technically yes, but you should not. Run SurrealDB bound to 127.0.0.1 and put Nginx (or Caddy, or Traefik) in front for TLS termination, rate limiting, and access logging. Block port 8000 with ufw. Always run with authentication enabled — there is no anonymous mode. This is the same principle that applies to any database server: keep the data plane behind a proxy and a firewall.

    How do I back up a SurrealDB database?

    Use surreal export to dump a namespace and database to a .surql file. Schedule it daily with cron or a systemd timer and ship the file to offsite storage such as S3, Backblaze B2, or Wasabi. For RocksDB-backed deployments you can also snapshot the /var/lib/surrealdb/data directory after stopping the service — that snapshot restores instantly when copied back into place. Test restores regularly; a backup you have not restored is not a backup.

    Next Steps

    Now that SurrealDB is running behind TLS on your VPS, build on the setup:

    • Connect a frontend with the official SDK — SurrealDB has official clients for JavaScript/TypeScript, Python, Go, Rust, Java, and .NET. Drop one into your application and take advantage of live queries and the graph model directly from your code.
    • Design your graph model — Spend time on relationships before you ship. Unlike bolt-on graph layers, SurrealDB's native edges cost almost nothing to traverse, which changes what is worth modeling. A user-follows-user graph, a product-category hierarchy, and a tag taxonomy all become first-class queries.
    • Add full-text search — Use DEFINE ANALYZER and DEFINE INDEX ... SEARCH to add BM25-ranked full-text search directly inside SurrealDB. For many applications this replaces a separate Elasticsearch cluster.
    • Combine with a relational database — SurrealDB is excellent for operational and relational-graph workloads, but you may still want a dedicated OLAP database for analytics. Pair it with PostgreSQL or CockroachDB for heavy reporting and keep SurrealDB for the live application layer.
    • Monitor with Prometheus — Scrape the /metrics endpoint, wire the output into Grafana, and alert on query latency, connection counts, and disk usage.
    • Read the official documentation — surrealdb.com/docs is the canonical reference for SurrealQL, indexes, permissions, and deployment patterns. Keep it bookmarked.

    Launch Your SurrealDB VPS Today
    >
    Our CloudCore Professional plan gives you 6 vCPU, 12 GB RAM, and 100 GB NVMe storage — enough to run SurrealDB, your application server, and a reverse proxy comfortably on one box.
    >
    - 6 vCPU cores
    - 12 GB RAM
    - 100 GB NVMe SSD
    - Unmetered bandwidth
    - EUR 19.99/month
    >
    Launch a Professional VPS now and have SurrealDB running in under 30 minutes.

    Was this article helpful?

    ← Back to Install GuidesBrowse all categories →

    Still have questions?

    Contact Support →Submit a Ticket