SiriDB
Overview
SiriDB is an open source time series database written in C. It is built for workloads that write many timestamped points and read them back over ranges, such as infrastructure and application metrics, sensor and industrial telemetry, and financial ticks. SiriDB holds recent points in an in-memory buffer for high ingest rates, then writes them into compressed shards on disk, so storage stays compact without giving up query speed.
The SecureAnyCloud image installs SiriDB Server 2.0.54 built from the pinned upstream source. It also installs the two official command line tools: siridb-prompt for queries and imports, and siridb-admin for service accounts and database management. Each VM generates its own random credentials at first boot, and the database starts empty.
SiriDB has its own compact query language instead of general-purpose SQL. It covers selection, filtering, grouping and aggregating by time window, merging and downsampling.
What you get:
- SiriDB Server 2.0.54, built from upstream commit
b4d290bf07d6ccc0c936b6c7e6195215d8a95d2b, running as thesiridb-server.servicesystemd unit - The official
siridb-prompt(2.1.12) andsiridb-admin(1.2.0) command line tools - An empty database named SecureAnyCloud, created on this VM at first boot with second time precision
- Per-VM credentials for both the
saservice account and theirisdatabase user, written to a root-only file - Loopback-only binding on the client port
9000and the backend port9010, with both optional HTTP services left off - A bootstrap-ready gate that keeps the database port closed until every credential has been rotated
- The C build toolchain removed from the finished image
- 24/7 SecureAnyCloud support
The image is built as a private database appliance. Both listeners, the native client port (127.0.0.1:9000) and the server backend port (127.0.0.1:9010), bind to loopback. The network firewall opens SSH (22) only, so the database is never reachable directly from the internet. You reach it over an SSH tunnel or from within your own virtual network.
SiriDB publishes well-known default passwords for its service account and for the first user of every new database. This image never ships them. Each VM generates its own long random secrets at first boot and replaces every published default before the database port is opened at all. It then re-verifies at run time that no account still accepts a published or guessable password. The image creates the database fresh and completely empty on every VM.
Prerequisites
- An active Azure subscription, an SSH key pair, and a VNet and subnet in the target region
- A Standard_B2s VM (2 vCPU / 4 GiB RAM), which is a good starting point. Scale up for higher ingest rates or larger retention.
- A network security group inbound rule that allows
22/tcpfrom your management network only
You do not open the database port. SiriDB binds to loopback and you reach it over an SSH tunnel, so 9000 and 9010 are never exposed.
Step 1 - Deploy from the Azure Marketplace
Sign in to the Azure Portal, choose Create a resource, search the Marketplace for SiriDB by SecureAnyCloud and select Create.
On Basics, pick your subscription, resource group, region and size (Standard_B2s). Under Administrator account, choose SSH public key and paste your key. Under Inbound port rules, allow SSH (22) only. Then select Review + create and Create.
Step 2 - Deploy from the Azure CLI
# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:siridb-ubuntu-24-04:default:latest
az vm create \
--resource-group <your-rg> \
--name siridb \
--image sac1647283583153:siridb-ubuntu-24-04:default:latest \
--size Standard_B2s \
--admin-username azureuser \
--ssh-key-values ~/.ssh/id_ed25519.pub \
--vnet-name <your-vnet> --subnet <your-subnet> \
--public-ip-sku StandardOnly SSH (22) needs to be reachable. Do not add an inbound rule for 9000 or 9010.
Step 3 - Read your per-VM credentials
SSH in as azureuser. The first-boot service writes this VM's credentials to a root-only file, including the exact SSH tunnel command for this machine:
sudo cat /root/siridb-credentials.txtYour addresses and passwords will differ from the expected output below. The two passwords are 48-character random hex strings generated on this VM:
# SiriDB - Per-VM Credentials
# Generated: Sun Jul 26 07:37:19 UTC 2026
#
# SiriDB listens on the LOOPBACK interface only (client 127.0.0.1:9000,
# backend 127.0.0.1:9010) and the firewall opens SSH (22) only, so the database
# is not reachable from the internet. Reach it over an SSH tunnel:
#
# ssh -N -L 9000:127.0.0.1:9000 azureuser@20.0.0.1
#
# Both passwords below were generated on THIS virtual machine at first boot. SIRIDB_VERSION=2.0.54 SIRIDB_HOST=127.0.0.1 SIRIDB_CLIENT_PORT=9000 SIRIDB_DATABASE=sac SIRIDB_DB_USER=iris SIRIDB_DB_PASSWORD=... SIRIDB_SERVICE_ACCOUNT=sa SIRIDB_SERVICE_PASSWORD=...Use SIRIDB_DB_PASSWORD for queries and inserts. SIRIDB_SERVICE_PASSWORD belongs to the server-level account that creates and drops databases.
Step 4 - Check the service and the network posture
sudo systemctl is-active siridb-server.service siridb-firstboot.service siridb-server --version sudo ss -ltn | grep -E ':(9000|9010)\b'Expected output:
active active SiriDB Server 2.0.54 Contributers: https://github.com/SiriDB/siridb-server/contributors Home-page: https://siridb.net LISTEN 0 128 127.0.0.1:9010 0.0.0.0:* LISTEN 0 128 127.0.0.1:9000 0.0.0.0:*Both listen addresses are 127.0.0.1. Nothing on this VM listens for database traffic on a routable address.
The database unit is also gated, so it cannot start before first boot has finished locking the machine down:
sudo systemctl cat siridb-server.service | grep -E 'ConditionPathExists|^User=|^Group='
sudo ls -l /var/lib/sac/data/Expected output:
ConditionPathExists=/var/lib/sac/data/siridb-bootstrap-ready User=siridb Group=siridb total 0 -rw------- 1 root root 0 Jul 26 07:37 siridb-bootstrap-ready -rw------- 1 root root 0 Jul 26 07:37 siridb-firstboot.doneThe image creates siridb-bootstrap-ready only after every upstream default password has been replaced, so the client port cannot open before that has happened. The daemon runs as the unprivileged siridb account, not as root.
Step 5 - Confirm no published default password works
SiriDB's upstream defaults are sa / siri for the service account and iris / siri for the first user of a new database. Both are replaced on this VM. Prove it with this check:
for CRED in "service sa siri" "db iris siri"; do set -- $CRED if
sudo /usr/local/sbin/siridb-authprobe "$1" 127.0.0.1:9000 "$2" "$3" sac 2>/dev/null; then echo "PROBLEM: upstream default $2/$3 still authenticates" else echo "upstream default $2/$3 -> rejected" fi doneExpected output:
upstream default sa/siri -> rejected upstream default iris/siri -> rejectedThe image also re-checks this generically at run time. Instead of testing a fixed list, it asks the server which accounts it has and probes each one:
sudo /usr/local/sbin/siridb-assert-no-default-credsExpected output:
probed 1 service account(s) [sa] and 1 database user(s) [iris] NO_DEFAULT_CREDENTIALS_OKStep 6 - Open an SSH tunnel from your workstation
From your own machine, forward the SiriDB client port over SSH. Leave this command running in its own terminal:
ssh -N -L 9000:127.0.0.1:9000 azureuser@<vm-ip>Any SiriDB client then connects to 127.0.0.1:9000 on your workstation as if the database were local. Clients include siridb-prompt, the Python, Go, C and Node.js connectors, and the Grafana data source.
Step 7 - Run your first queries
On the VM, siridb-q is a small root-only wrapper that reads this machine's credentials and runs a query for you. Use it for quick checks:
sudo /usr/local/sbin/siridb-q 'show dbname, time_precision, version, uptime'
sudo /usr/local/sbin/siridb-q 'count series'
sudo /usr/local/sbin/siridb-q 'list users'
sudo /usr/local/sbin/siridb-q 'list servers'Expected output:
{"data":[{"name":"dbname","value":"sac"},{"name":"time_precision","value":"s"},{"name":"version","value":"2.0.54"},{"name":"uptime","value":85}]} {"series":0} {"columns":["name","access"],"users":[["iris","full"]]} {"columns":["name","pool","version","online","status"],"servers":[["127.0.0.1:9010",0,"2.0.54",true,"running"]]}count series is 0 because the image ships an empty database with no demo data.
To use the official interactive client instead, read the credentials and run siridb-prompt directly. The same command works from your workstation through the tunnel from Step 6:
DB=$(sudo /usr/local/sbin/siridb-cred SIRIDB_DATABASE)
USER=$(sudo /usr/local/sbin/siridb-cred SIRIDB_DB_USER)
PASS=$(sudo /usr/local/sbin/siridb-cred SIRIDB_DB_PASSWORD) siridb-prompt -d "$DB" -u "$USER" -p "$PASS" -s 127.0.0.1:9000 --json -r 'show status' </dev/nullExpected output:
{"data":[{"name":"status","value":"running"}]}To get the full-screen interactive client with history and syntax help, run siridb-prompt -d "$DB" -u "$USER" -p "$PASS" -s 127.0.0.1:9000 without -r.
Step 8 - Insert time series data
SiriDB inserts points over its native protocol. siridb-prompt accepts a JSON or CSV file with the import command.
The JSON form is a map of series name to a list of [timestamp, value] pairs. This database uses second precision, so timestamps are plain Unix seconds.
NOW=$(date -u +%s);
BASE=$(( NOW - 3600 )) python3 - "$BASE" > /tmp/siridb-demo.json <<'PY' import json, sys b = int(sys.argv[1]) cpu = [[b + i*60, round(0.20 + 0.35*((i*7) % 11)/11, 3)] for i in range(60)] mem = [[b + i*60, 1024 + (i*13) % 256] for i in range(60)] json.dump({"cpu.load.web01": cpu, "mem.used_mb.web01": mem}, sys.stdout) PY
sudo /usr/local/sbin/siridb-q "import /tmp/siridb-demo.json"
sudo /usr/local/sbin/siridb-q 'list series'
sudo /usr/local/sbin/siridb-q 'count series length'Expected output:
{"success_msg":"Successfully inserted 120 point(s)."} {"columns":["name"],"series":[["cpu.load.web01"],["mem.used_mb.web01"]]} {"series_length":120}The first point written to a series creates it implicitly. There is no schema to declare.
Step 9 - Select, aggregate and downsample
A selection takes a time window and an optional aggregation with a group-by interval:
sudo /usr/local/sbin/siridb-q "select * from 'cpu.load.web01' after now - 5m"
sudo /usr/local/sbin/siridb-q "select mean(15m) from 'cpu.load.web01' after now - 1h"
sudo /usr/local/sbin/siridb-q "select max(1h) prefix 'max-', min(1h) prefix 'min-' from 'cpu.load.web01' after now - 1h"
sudo /usr/local/sbin/siridb-q "select mean(30m) from /.*web01/ after now - 1h"Expected output (values will differ):
{"cpu.load.web01":[[1785051248,0.2],[1785051308,0.423],[1785051368,0.295],[1785051428,0.518],[1785051488,0.391]]} {"cpu.load.web01":[[1785048300,0.34850000000000003],[1785049200,0.36546666666666666],[1785050100,0.3463333333333333],[1785051000,0.37393333333333334],[1785051900,0.35555555555555557]]} {"max-cpu.load.web01":[[1785049200,0.518],[1785052800,0.518]],"min-cpu.load.web01":[[1785049200,0.2],[1785052800,0.2]]} {"cpu.load.web01":[[1785049200,0.3606190476190476],[1785051000,0.36013333333333336],[1785052800,0.35555555555555557]],"mem.used_mb.web01":[[1785049200,1141.8095238095239],[1785051000,1135.6333333333334],[1785052800,1227]]}Points to note:
after now - 1his the time window.between ... and ...andbefore ...also work.mean(15m)downsamples into 15-minute buckets.max,min,sum,count,median,variance,first,lastand others are available with the same interval syntax.- When you select with more than one aggregation in a single statement, give each one a
prefixorsuffixso that the returned series names stay unique. - A
/regex/in place of a series name selects every matching series at once. merge as '<name>' using mean(1)collapses several series into one.
Put timeit in front of any query to report how long each server spent on it:
sudo /usr/local/sbin/siridb-q "timeit select mean(30m) from 'cpu.load.web01' after now - 1h"Expected output:
{"__timeit__":[{"server":"127.0.0.1:9010","time":0.000135402}],"cpu.load.web01":[[1785049200,0.3606190476190476],[1785051000,0.36013333333333336],[1785052800,0.35555555555555557]]}Remove the demo series when you are finished with them. SiriDB refuses a drop that would remove every series in a pool unless you say so explicitly:
sudo /usr/local/sbin/siridb-q "drop series /.*web01/ set ignore_threshold true"
sudo /usr/local/sbin/siridb-q 'count series'
sudo rm -f /tmp/siridb-demo.jsonExpected output:
{"success_msg":"Successfully dropped 2 series."} {"series":0}Step 10 - Users, access and additional databases
You manage database users with SiriDB queries. Grant access from this set: read, write, select, show, list, count, create, alter, drop, grant, revoke and full. Choose a strong password of your own:
sudo /usr/local/sbin/siridb-q "create user 'reporting' set password '<new-password>'"
sudo /usr/local/sbin/siridb-q "grant select, list, count, show to user 'reporting'"
sudo /usr/local/sbin/siridb-q 'list users'To see the current users and their access levels at any time:
sudo /usr/local/sbin/siridb-q 'list users'Expected output:
{"columns":["name","access"],"users":[["iris","full"]]}Server-level operations use siridb-admin with the sa account. These operations include creating and dropping databases and managing service accounts:
SA=$(sudo /usr/local/sbin/siridb-cred SIRIDB_SERVICE_ACCOUNT)
SAPW=$(sudo /usr/local/sbin/siridb-cred SIRIDB_SERVICE_PASSWORD) siridb-admin -u "$SA" -p "$SAPW" -s 127.0.0.1:9000 get-databases </dev/null siridb-admin -u "$SA" -p "$SAPW" -s 127.0.0.1:9000 get-accounts </dev/nullExpected output:
[sac] [sa]To create a second database, for example with millisecond precision, run siridb-admin -u "$SA" -p "$SAPW" -s 127.0.0.1:9000 new-database -d metrics_ms -t ms.
Every new database is seeded with the upstream default user iris / siri. Change the password immediately with alter user 'iris' set password '<new-password>' against the new database. This is exactly what the image does for the database it creates at first boot.
Step 11 - Optional: enabling the HTTP API
SiriDB can also expose an HTTP API (insert and query over JSON) and an HTTP status endpoint. Both are switched off in this image, as they are upstream.
The reason matters. SiriDB 2.0.54 binds those two servers to every interface and offers no setting to restrict them to loopback, so turning one on without a firewall rule would publish it.
To enable the HTTP API, set http_api_port = 9020 in /etc/siridb/siridb.conf and restart siridb-server.service. Then restrict the port to your own network before anything else, for example with a host firewall rule scoped to your management range:
sudo nft add rule inet filter input ip saddr <your-mgmt-cidr> tcp dport 9020 acceptKeep the Azure network security group closed to 9020 as well. The tunnel in Step 6 remains the recommended access path.
Step 12 - Backups
SiriDB keeps everything under /var/lib/siridb. The safest snapshot is one taken with the service stopped, which is quick on a single node:
sudo systemctl stop siridb-server.service
sudo tar -C /var/lib -czf /var/backups/siridb-$(date -u +%Y%m%d).tar.gz siridb
sudo systemctl start siridb-server.service
sudo /usr/local/sbin/siridb-wait-port 9000 60
sudo ls -lh /var/backups/ | tail -2Expected output ends with READY and a listing of the new archive.
For a logical export instead, select the series you care about and dump the result. In the interactive client, siridb-prompt writes the last result to a file with dump <file>.json or dump <file>.csv.
Copy backups off the VM to Azure Blob Storage or another account on a schedule that matches your retention policy.
Step 13 - Maintenance
The image is patched at build time and keeps Ubuntu's unattended security upgrades enabled, so operating system fixes continue to arrive.
SiriDB itself is a single binary at /usr/bin/siridb-server. To move to a newer upstream release, back up as in Step 12, replace the binary and restart the unit.
sudo systemctl status siridb-server.service --no-pager | head -6 sudo journalctl -u siridb-server.service --no-pager -n 10Configuration lives in /etc/siridb/siridb.conf. Restart siridb-server.service after any change. Useful settings:
buffer_sync_interval: milliseconds between buffer fsyncs.0means fsync every insert.optimize_interval: seconds between shard optimization runs.enable_shard_compression: turns shard compression on or off.
Troubleshooting
siridb-server.service will not start and reports a failed condition. The bootstrap-ready marker is missing. Check that first boot completed with sudo systemctl status siridb-firstboot.service and sudo journalctl -u siridb-firstboot.service. Re-run it with sudo systemctl restart siridb-firstboot.service. It is safe to run again and rebuilds the marker.
A client cannot connect from my workstation. The database listens on loopback only, by design. Confirm that the tunnel from Step 6 is still running. Then point the client at 127.0.0.1:9000 on your own machine instead of at the VM's address.
Authentication fails. Read the current values with sudo cat /root/siridb-credentials.txt. The passwords are unique to this VM and are not the upstream defaults.
A drop is refused with a message about a percentage of series. SiriDB guards against dropping an entire pool by accident. When you do want that, add set ignore_threshold true to the statement.
Ingest slows under heavy write load. Raise buffer_sync_interval in /etc/siridb/siridb.conf (for example to 500) so that the buffer is flushed on an interval instead of on every insert. Then restart the service.
Support
24/7 support is included with this image. Contact SecureAnyCloud at sales@secureanycloud.com or see secureanycloud.com.
Deploy on Azure
Launch SiriDB on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.
View this image
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com