seekdb on Ubuntu 24.04 on Azure User Guide
Overview
seekdb is an open-source database from the OceanBase project, built for applications and AI agents that need to keep ordinary business data and semantic data in one place. It speaks the MySQL network protocol, so existing MySQL clients, drivers, ORMs and BI tools connect to it unchanged and standard SQL works as written. The same engine also stores dense and sparse vectors, builds HNSW indexes over them, and answers approximate nearest-neighbour queries.
Because relational rows and vectors live in the same engine, one SQL statement can filter on structured columns and rank by vector similarity at the same time. That removes the common pattern of running a separate vector index next to a primary database and writing code to keep the two in sync.
seekdb is the single-node member of the OceanBase family. It targets one machine rather than a distributed cluster, which keeps it straightforward to run while retaining the vector and hybrid search capabilities.
The cloudimg image installs seekdb 1.3.0 from the vendor's own Ubuntu 24.04 package, SHA-256 verified during the build against the digest published on the upstream release, and runs it under systemd. Backed by 24/7 cloudimg support.
What is included:
- seekdb 1.3.0 (Apache-2.0), installed from the vendor's official Ubuntu 24.04 package and SHA-256 verified
- A single-node deployment run by systemd, serving the MySQL protocol on port
2881 - Vector columns with HNSW indexes and distance functions for similarity search
- A unique per-VM database password generated on first boot, with no default credential ever present
- Database storage on a dedicated 40 GiB Azure data disk at
/var/lib/oceanbase - Database sizing computed at first boot from the VM you actually run
- The database and its management agent restricted to loopback by default
- Log rotation configured so the data volume cannot fill with logs
- Vendor telemetry disabled
- 24/7 cloudimg support
This is a database product. seekdb serves the MySQL protocol on port 2881, but the Azure NSG opens port 22 only, and the image restricts the database to loopback in its own firewall. Reach it over an SSH tunnel, or follow Step 9 to open it to a trusted network.
A note on default credentials
Upstream seekdb initialises a single root account with an empty password. This image never ships that state. The build wipes the entire database directory before the image is captured, so the image you launch contains no initialised database and no account at all. On your VM's first boot, seekdb initialises a fresh database and immediately sets a strong password unique to that VM, then refuses to complete first boot if any account still accepts an empty password.
Prerequisites
- An Azure subscription
- The Azure CLI (
az) installed and logged in, or access to the Azure Portal - An SSH key pair
- A MySQL client on your workstation if you want to connect remotely (
mysql, or any MySQL-compatible tool)
Step 1 - Deploy from the Azure Marketplace
- In the Azure Portal, search the Marketplace for seekdb on Ubuntu 24.04 LTS by cloudimg.
- Select Create.
- Choose your subscription, resource group and region.
- Choose a VM size.
Standard_B4ms(4 vCPU / 16 GiB) is recommended; the image also runs on smaller sizes such asStandard_B2s(2 vCPU / 4 GiB). - Set the administrator username and paste your SSH public key.
- Leave inbound ports at SSH (22) only.
- Select Review + create, then Create.
Step 2 - Deploy from the Azure CLI
az group create --name seekdb-rg --location eastus
az vm create \
--resource-group seekdb-rg \
--name seekdb-vm \
--image cloudimg:seekdb-ubuntu-24-04:default:latest \
--size Standard_B4ms \
--admin-username azureuser \
--generate-ssh-keys \
--public-ip-sku Standard \
--os-disk-delete-option Delete \
--nic-delete-option Delete
# Then get the public IP of the new VM:
az vm list-ip-addresses \
--resource-group seekdb-rg \
--name seekdb-vm \
--query "[0].virtualMachine.network.publicIpAddresses[0].ipAddress" \
--output tsv
Both commands run on your own workstation, not on the VM.
Step 3 - Connect to your VM
ssh azureuser@<vm-ip>
The message of the day shows where the credentials live and how to check the service.
Step 4 - Confirm the database is running
First boot initialises the database and generates your password. On a Standard_B2s this takes about 30 seconds; give it a moment after the VM first reports ready.
sudo systemctl status seekdb --no-pager
You should see active (running):
● seekdb.service - seekdb
Loaded: loaded (/usr/lib/systemd/system/seekdb.service; enabled; preset: enabled)
Drop-In: /etc/systemd/system/seekdb.service.d
└─cloudimg.conf
Active: active (running)
Confirm first boot completed:
sudo systemctl is-active seekdb-firstboot.service

Step 5 - Retrieve your per-VM database password
sudo cat /root/seekdb-credentials.txt
The file is readable by root only and looks like this, with a password unique to your VM:
seekdb.host=<vm-ip>
seekdb.port=2881
seekdb.root.user=root
seekdb.root.password=<a strong password unique to this VM>

Step 6 - Connect over the MySQL protocol
seekdb speaks the MySQL wire protocol, so the standard mysql client works:
sudo bash -c 'MYSQL_PWD=$(sed -n "s/^seekdb.root.password=//p" /root/seekdb-credentials.txt) mysql -h 127.0.0.1 -P 2881 -uroot -e "SELECT VERSION();"'
+-------------------------------+
| VERSION() |
+-------------------------------+
| 5.7.25-OceanBase seekdb-v1.3.0.0 |
+-------------------------------+
The version string reports MySQL 5.7 compatibility followed by the seekdb version, which is what lets MySQL drivers negotiate normally.
Step 7 - Run SQL
Create a database and a table, insert rows and read them back:
sudo bash -c 'MYSQL_PWD=$(sed -n "s/^seekdb.root.password=//p" /root/seekdb-credentials.txt) mysql -h 127.0.0.1 -P 2881 -uroot' <<'SQL'
CREATE DATABASE IF NOT EXISTS demo;
USE demo;
DROP TABLE IF EXISTS items;
CREATE TABLE items (id INT PRIMARY KEY, name VARCHAR(32), qty INT);
INSERT INTO items VALUES (1,'alpha',10),(2,'beta',20),(3,'gamma',30);
SELECT id, name, qty FROM items ORDER BY id;
SELECT SUM(qty) AS total FROM items;
SQL
+----+-------+------+
| id | name | qty |
+----+-------+------+
| 1 | alpha | 10 |
| 2 | beta | 20 |
| 3 | gamma | 30 |
+----+-------+------+
+-------+
| total |
+-------+
| 60 |
+-------+
Step 8 - Vector similarity search
This is what seekdb is built for. Create a table with a VECTOR column, build an HNSW index over it, insert embeddings and search by distance.
sudo bash -c 'MYSQL_PWD=$(sed -n "s/^seekdb.root.password=//p" /root/seekdb-credentials.txt) mysql -h 127.0.0.1 -P 2881 -uroot' <<'SQL'
USE demo;
DROP TABLE IF EXISTS docs;
CREATE TABLE docs (id INT PRIMARY KEY, label VARCHAR(32), embedding VECTOR(3));
CREATE VECTOR INDEX docs_vidx ON docs(embedding) WITH (distance=l2, type=hnsw, lib=vsag);
INSERT INTO docs VALUES (1,'origin','[0,0,0]'),(2,'near','[1,0,0]'),(3,'mid','[5,0,0]'),(4,'far','[20,0,0]');
SELECT id, label, l2_distance(embedding,'[0.5,0,0]') AS dist
FROM docs ORDER BY dist APPROXIMATE LIMIT 3;
SQL
+----+--------+------+
| id | label | dist |
+----+--------+------+
| 1 | origin | 0.5 |
| 2 | near | 0.5 |
| 3 | mid | 4.5 |
+----+--------+------+
The three nearest vectors to [0.5,0,0] come back in distance order, and far at distance 19.5 is correctly left out.
APPROXIMATE tells seekdb to use the HNSW index rather than scanning every row, which is what keeps search fast as the table grows. Confirm the index is a real vector index:
sudo bash -c 'MYSQL_PWD=$(sed -n "s/^seekdb.root.password=//p" /root/seekdb-credentials.txt) mysql -h 127.0.0.1 -P 2881 -uroot -e "USE demo; SHOW INDEX FROM docs;"'
The docs_vidx row reports Index_type of VECTOR and a comment of available.

Other distance functions are available, including cosine_distance, inner_product and l1_distance. Set the one you want when you create the index (distance=l2, distance=cosine, distance=inner_product) and use the matching function in your query.
Step 9 - Network access
By default seekdb answers on 127.0.0.1 only. Two separate things keep it there: the Azure NSG opens port 22 only, and the image runs a small nftables policy that drops traffic to ports 2881 and 2886 unless it is addressed to a loopback address.
Option A - SSH tunnel (recommended)
Nothing to change on the VM. From your workstation:
# On your workstation - open the tunnel:
ssh -L 2881:127.0.0.1:2881 azureuser@<vm-ip>
# Then, in another terminal on your workstation:
mysql -h 127.0.0.1 -P 2881 -uroot -p
Paste the password from Step 5 at the prompt.
Option B - Open the port to your own subnet
Open /etc/cloudimg/seekdb-loopback.nft in your editor and add an accept rule for
your network inside the chain input block, above the tcp dport { 2881, 2886 } drop
line — for example:
ip saddr 10.0.0.0/24 tcp dport 2881 accept
Reload the policy:
sudo systemctl restart seekdb-loopback-firewall
Then open port 2881 to the same trusted range in your Azure NSG:
az network nsg rule create \
--resource-group seekdb-rg \
--nsg-name seekdb-vmNSG \
--name allow-seekdb \
--priority 1010 \
--source-address-prefixes 10.0.0.0/24 \
--destination-port-ranges 2881 \
--access Allow --protocol Tcp
Never open port 2881 to 0.0.0.0/0. A database reachable from the whole internet is exposed to credential-stuffing regardless of how strong the password is.

Step 10 - Where your data lives
The database, its redo log and its logs are on a dedicated 40 GiB Azure data disk mounted at /var/lib/oceanbase, so they never compete with the operating system disk:
df -h /var/lib/oceanbase
Sizing is chosen at first boot from the VM you actually launched, not fixed at build time:
grep -E 'cpu_count|memory_limit|datafile|log_disk' /etc/seekdb/seekdb.cnf
On a Standard_B2s this yields memory_limit=2048M; on a Standard_B4ms it yields 8192M. These are initialisation-time values, so they are set once when the database is first created.
Maintenance
Restart or stop the database:
sudo systemctl restart seekdb
Read the most recent service log entries:
sudo journalctl -u seekdb -n 50 --no-pager
To follow the log live instead, add -f (sudo journalctl -u seekdb -f) and press
Ctrl+C when you are done.
The database's own logs are in /var/lib/oceanbase/log/. Log rotation is configured (daily, 7 kept, 128 MB maximum per file), so the data volume will not fill with log output.
To change the root password:
sudo bash -c 'MYSQL_PWD=$(sed -n "s/^seekdb.root.password=//p" /root/seekdb-credentials.txt) mysql -h 127.0.0.1 -P 2881 -uroot -e "ALTER USER '"'"'root'"'"'@'"'"'%'"'"' IDENTIFIED BY '"'"'your-new-password'"'"';"'
Remember to update /root/seekdb-credentials.txt if you do, so the file stays accurate.
Operating system security updates are applied automatically by unattended-upgrades.
Support
This image is maintained by cloudimg with 24/7 support. If you have a question about the image or hit a problem, contact us at support@cloudimg.co.uk.
seekdb itself is an open-source project; its documentation is at docs.seekdb.ai and its source is at github.com/oceanbase/seekdb.