QuestDB
Overview
QuestDB is a high-performance, open-source time-series database built for fast ingestion and low-latency SQL analytics. It speaks standard SQL with time-series extensions (SAMPLE BY, LATEST ON, ASOF JOIN), and ingests over the InfluxDB Line Protocol, REST and the PostgreSQL wire protocol. It ships an interactive web console for writing queries and visualising results.
This SecureAnyCloud image installs QuestDB 9.4.3 (with its bundled Java runtime) at /opt/questdb and runs it as a dedicated questdb system user. Every listener is bound to loopback behind an nginx reverse proxy on TCP 80 with HTTP Basic auth.
What you get:
- QuestDB 9.4.3 at
/opt/questdbwith a bundled Java runtime (no system Java required) - The interactive web console and the REST query and import API, fronted by nginx on
:80 - nginx HTTP Basic auth, because open-source QuestDB has no built-in authentication, with a unique web password generated on the first boot of every VM and stored in a root-only file
- A dedicated Azure data disk at
/var/lib/questdbthat holds the QuestDB data root (db, conf, log). It is separate from the OS disk and re-provisioned with every VM - The PostgreSQL wire protocol (8812) and InfluxDB Line Protocol (9009), bound to loopback for local tooling and SSH tunnels
questdb.serviceandnginx.serviceas systemd units, enabled and active- 24/7 SecureAnyCloud support
Prerequisites
- An active Azure subscription, an SSH key pair, and a VNet with a subnet in the target region
- NSG inbound rules that allow
22/tcpfrom your management network and80/tcpfor the web console and REST API. Front the console with TLS for public exposure (see Enabling HTTPS)
Standard_B2ms (2 vCPU, 8 GiB RAM) is a good starting point. Scale up for higher ingestion rates.
Step 1 - Deploy from the Azure Marketplace
Sign in to the Azure Portal. Choose Create a resource, search the Marketplace for QuestDB by SecureAnyCloud, and select Create.
On Basics, pick your subscription, resource group, region and size. Under Administrator account, choose SSH public key and paste your key. Under Inbound port rules, allow SSH (22) and HTTP (80).
Review the dedicated data disk on the Disks tab. 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:questdb-ubuntu-24-04:default:latest
az vm create \
--resource-group <your-rg> \
--name questdb \
--image sac1647283583153:questdb-ubuntu-24-04:default:latest \
--size Standard_B2ms \
--admin-username azureuser \
--ssh-key-values ~/.ssh/id_ed25519.pub \
--vnet-name <your-vnet> --subnet <your-subnet> \
--public-ip-sku Standard
az vm open-port --resource-group <your-rg> --name questdb --port 80 --priority 1010Step 3 - Connect to your VM
ssh azureuser@<vm-public-ip>Step 4 - Confirm the services are running
systemctl is-active questdb.service nginx.serviceBoth services report active. QuestDB starts in a few seconds and opens its loopback listeners. The REST API also reports the running build version.
Step 5 - Retrieve your web password
The admin password is generated uniquely on the first boot of your VM and written to a root-only file:
sudo cat /root/questdb-credentials.txtThis file contains QUESTDB_ADMIN_USER (admin) and QUESTDB_ADMIN_PASSWORD, plus the URLs for the web console and REST API. Store the password in a safe place.
Step 6 - Check the health endpoint
nginx serves an unauthenticated health endpoint for load balancers and probes. Request it:
curl -s http://localhost/healthThe endpoint returns ok. Every other path is gated by nginx Basic auth, and QuestDB's own listeners stay bound to loopback.
Step 7 - Open the QuestDB web console
Browse to http://<vm-public-ip>/ and sign in as admin with the password from Step 5. The web console is the built-in SQL workbench. Type a query in the editor and run it to get a results grid. A schema explorer sits on the left, and an import panel handles CSV files.
Create a table, insert a few rows, and select them back. The result grid shows the returned rows.
The schema explorer on the left lists every table with its columns and types.
The Import panel lets you drag and drop a CSV file straight into a new or existing table.
Step 8 - Run SQL from the command line
The REST /exec endpoint runs SQL behind the same Basic auth and returns JSON. Confirm that QuestDB is serving and report its version:
curl -s -u admin:<QUESTDB_ADMIN_PASSWORD> 'http://localhost/exec?query=SELECT%20version()' | head -c 300; echoThe response is JSON with a dataset array that carries the running version string.
Step 9 - Create a table and ingest data
QuestDB accepts SQL DDL and DML over the same REST endpoint. Create a time-series table, insert a few rows, and query them back:
curl -s -u admin:<QUESTDB_ADMIN_PASSWORD> -G 'http://localhost/exec' --data-urlencode "query=CREATE TABLE IF NOT EXISTS readings (ts TIMESTAMP, sensor SYMBOL, value DOUBLE) TIMESTAMP(ts) PARTITION BY DAY WAL" >/dev/null
curl -s -u admin:<QUESTDB_ADMIN_PASSWORD> -G 'http://localhost/exec' --data-urlencode "query=INSERT INTO readings VALUES (now(), 'sensor-a', 12.5), (now(), 'sensor-b', 13.1)" >/dev/null
curl -s -u admin:<QUESTDB_ADMIN_PASSWORD> -G 'http://localhost/exec' --data-urlencode "query=SELECT count() FROM readings" | head -c 300; echoThe count query returns a dataset with the number of rows. A full REST round trip creates a table, inserts rows and runs an aggregation.
For high-throughput ingestion, point an InfluxDB Line Protocol client at 127.0.0.1:9009 over an SSH tunnel, or connect a PostgreSQL client to 127.0.0.1:8812. Both listeners are loopback-only (see the next section).
Step 10 - Confirm data lives on the dedicated disk
The QuestDB data root is stored on the dedicated Azure data disk, so it survives OS changes and can be resized independently:
findmnt /var/lib/questdbThe mount is backed by a separate Azure data disk. The disk is captured into the image and re-provisioned on every VM. The QuestDB db, conf and log directories live on it.
Connecting over PostgreSQL wire and ILP
QuestDB also exposes the PostgreSQL wire protocol on 127.0.0.1:8812 and the InfluxDB Line Protocol on 127.0.0.1:9009. Both are bound to loopback, so they are not exposed to the network. Reach them from your workstation with an SSH tunnel, for example:
ssh -L 8812:127.0.0.1:8812 -L 9009:127.0.0.1:9009 azureuser@<vm-public-ip>Then connect a psql client to localhost:8812 (default user admin) or stream metrics to localhost:9009 with any ILP client.
Enabling HTTPS
The nginx reverse proxy terminates plain HTTP on port 80. For public exposure, put a certificate in front of it. Add a DNS name for the VM, and then choose one of two options:
- Use the companion SecureAnyCloud nginx-ssl-certbot image as a TLS reverse proxy.
- Install certbot and extend the existing nginx site with a listen 443 ssl; server block and your certificate paths.
Keep QuestDB itself bound to loopback, so that the only public surface is the authenticated, TLS-terminated proxy.
Maintenance
- Configuration: server settings live in
/var/lib/questdb/conf/server.conf(all listeners are bound to loopback). Edit it, and then runsudo systemctl restart questdbto apply the change. - Backups: snapshot the
/var/lib/questdbdata disk, or use QuestDB'sSNAPSHOTSQL for consistent backups. - Upgrades: replace the
/opt/questdbruntime with a newer release and restart the service. The on-disk data format is forward-compatible. - Security patches: unattended-upgrades remains enabled, so the OS continues to receive security updates automatically.
Support
SecureAnyCloud provides 24/7 expert support for this image. Contact sales@secureanycloud.com.
Deploy on Azure
Launch QuestDB 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
Overview
This image runs QuestDB, the open source, columnar time-series database built for high-throughput ingestion and low-latency SQL analytics. QuestDB speaks SQL with time-series extensions, ingests data over the InfluxDB line protocol and the PostgreSQL wire protocol, and answers queries through a REST API and an interactive web Console.
What you get:
- The QuestDB open source core, installed under
/opt/questdbwith its own bundled Java runtime, so the image needs no separate JRE - A dedicated, unprivileged
questdbsystem account that runs QuestDB under a systemd service, which starts it on boot and restarts it on failure - A database root at
/var/lib/questdbon a dedicated, independently resizable EBS data volume that holds the configuration, table data, write-ahead log, logs and the Console assets - Every listener bound to the loopback interface only, so the database is never exposed directly
- An nginx reverse proxy that publishes the web Console and the REST API on port 80 behind HTTP Basic authentication
- An admin password generated on the first boot of every deployed instance and written to
/root/questdb-credentials.txtwith mode 0600, so that only the root user can read it
QuestDB's open source web Console and REST API ship with no built-in authentication, which is why the proxy sits in front of them. Two instances launched from the same Amazon Machine Image never share a password.
Prerequisites
Before you deploy this image you need:
- An Amazon Web Services account where you can launch EC2 instances
- IAM permissions to launch instances, create security groups, and subscribe to AWS Marketplace products
- An EC2 key pair in the target Region for SSH access to the instance
- A VPC and subnet in the target Region, with a security group allowing inbound port 22 from your management network and port 80 for the web Console and the REST API
- The AWS CLI (version 2) installed locally if you plan to deploy from the command line
Launch the Instance from the AWS Marketplace
Sign in to the AWS Management Console, open the EC2 service, and select Launch instance. Under Application and OS Images, choose AWS Marketplace AMIs and search for QuestDB. Select the SecureAnyCloud listing and choose Select, then Continue on the subscription summary.
Pick an instance type of m6i.large or larger. Choose your EC2 key pair under Key pair (login). Under Network settings, select your VPC and subnet, and create or select a security group that opens port 22 from your management network and port 80 for the web Console and the REST API. Leave the root volume at the default size or larger.
Select Launch instance. First-boot initialisation takes a few seconds after the instance state becomes Running and the status checks pass. This is when the per-instance admin password is generated.
Launch the Instance from the AWS CLI
The following block launches an instance from the SecureAnyCloud QuestDB Marketplace AMI into an existing subnet and security group. Replace <ami-id> with the AMI ID shown on the Marketplace listing. Replace <key-name> with your EC2 key pair name and <subnet-id> with your subnet ID. Replace <security-group-id> with a security group that opens ports 22 and 80 as described above.
aws ec2 run-instances \
--image-id <ami-id> \
--instance-type m6i.large \
--key-name <key-name> \
--subnet-id <subnet-id> \
--security-group-ids <security-group-id> \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=questdb}]'When the instance reaches the Running state and its status checks pass, note its public IP address or DNS name. You can find it in the EC2 console or with aws ec2 describe-instances.
Connect to Your Instance
Connect over SSH using your key pair and the login user for your operating system variant. For Ubuntu 24.04, the login user is ubuntu:
ssh -i <key-name>.pem ubuntu@<public-ip>Retrieve the Admin Password
The web Console admin password is unique to your instance. It was generated on first boot. Read the credentials file as root:
sudo cat /root/questdb-credentials.txtThe file lists the Console URL, the admin user (admin) and the generated password, along with REST API examples and notes on the PostgreSQL wire and InfluxDB line protocol ports. Keep this password in a safe place.
Sign In to the Web Console
The QuestDB web Console is served on port 80 by nginx, which proxies to the database on 127.0.0.1:9000 behind HTTP Basic authentication. In a browser, go to:
http://<instance-public-ip>/The nginx proxy prompts you for credentials. Sign in as admin with the password from the credentials file. The Console then loads, with the SQL editor in the centre, the tables and schema explorer on the left, and the results pane below.
Type a SQL query into the editor and choose Run query (or press Ctrl+Enter). The results render in a sortable grid, and the Console reports the row count and timing for the query.
QuestDB's SQL has time-series extensions such as SAMPLE BY, which downsamples rows into fixed time buckets. Run an aggregation query and switch the results pane to the chart view. The Console plots the result so that you can visualise a series over time.
The tables and schema explorer on the left lists every table in the database. Expand a table to inspect its columns, their types and its storage details, without writing any SQL.
Confirm QuestDB Is Running
Over SSH, confirm that the database and the nginx proxy are active and that the health endpoint answers:
sudo systemctl is-active questdb nginxcurl -s http://127.0.0.1:9003/statusYou should see both services reported as active, and the health server on 127.0.0.1:9003 reports Status: Healthy.
The database binds these listeners, all loopback only:
- The web Console and REST API on
127.0.0.1:9000 - The health and metrics server on
127.0.0.1:9003 - The PostgreSQL wire protocol on
127.0.0.1:8812 - The InfluxDB line protocol on
127.0.0.1:9009
nginx publishes the Console and REST API on port 80.
Confirm the Java runtime that ships with QuestDB:
/opt/questdb/bin/java -versionRun SQL Over the REST API
QuestDB exposes its REST API on the same port 80 as the Console, behind the same HTTP Basic credentials. The /exec endpoint runs SQL and returns JSON. On the instance, you can call the loopback database directly without credentials:
curl -s -G 'http://127.0.0.1:9000/exec' --data-urlencode 'query=SELECT 1'From outside the instance, send the same request through the proxy on port 80 with basic auth user admin and the generated password, for example curl -G -u admin:<password> 'http://<instance-public-ip>/exec' --data-urlencode 'query=SELECT now()'.
The /imp endpoint bulk imports CSV, and the /exp endpoint exports query results as CSV. The REST API therefore doubles as an ingestion and extraction interface over your time-series data.
Ingest Data
QuestDB accepts high-throughput writes over two protocols. Both bind to loopback by default, so they are not exposed without a deliberate change:
- InfluxDB line protocol (ILP): the recommended high-throughput ingestion path, on TCP port 9009. Point an InfluxDB line protocol client or a Telegraf agent at the instance to stream metrics, events or tick data.
- PostgreSQL wire protocol: on TCP port 8812. Connect with any PostgreSQL client or driver (for example
psql, JDBC orpsycopg) using theadminuser and the generated password to run inserts and queries.
To expose either protocol beyond the instance, edit the bind addresses in /var/lib/questdb/conf/server.conf and restart the service. Then open the corresponding port in the security group, and restrict the source to the networks that ingest data. For production, front the exposed port with TLS as described in Step 11.
The web Console also has a built-in Import CSV panel for loading a file directly through the browser.
Query with SQL and Time Series Extensions
Query QuestDB through the web Console, the REST API, or any PostgreSQL client. QuestDB uses a columnar storage engine partitioned by time. Its SQL extensions cover downsampling (SAMPLE BY), interpolation (FILL) and time-aligned joins (ASOF JOIN and LT JOIN), so large time-series datasets stay fast on modest hardware.
On the instance, you can run any query over loopback without credentials:
curl -s -G 'http://127.0.0.1:9000/exec' --data-urlencode "query=SELECT now()"From outside the instance, send the same request to http://<instance-public-ip>/exec with basic auth user admin and the generated password.
The Data Volume
The QuestDB database root lives on a dedicated EBS volume mounted at /var/lib/questdb. This keeps the time-series store off the operating system disk and lets you resize or snapshot it independently. Confirm the mount:
df -h /var/lib/questdbThe volume holds the conf/ configuration, the db/ table data, write-ahead log and sequencer, and the log/ and public/ directories.
To grow the store, expand the EBS volume in the AWS console. Then grow the filesystem on the instance with sudo resize2fs on the underlying device. A snapshot of this volume captures the complete time-series database.
Enable HTTPS
nginx serves the web Console and REST API over plain HTTP on port 80. For production use, place them behind TLS.
Obtain a certificate for your domain. For example, use a managed certificate on an Application Load Balancer in front of the instance, or install Certbot on the instance.
Then configure nginx to listen on 443 with your certificate and proxy to 127.0.0.1:9000, exactly as the bundled site does for port 80. Keep the HTTP Basic authentication in place. Restrict the security group so that ports 80 and 443 are reachable only from the networks that ingest and query data.
Backup and Maintenance
Back up the database by snapshotting the /var/lib/questdb EBS volume, which captures the entire time-series store. Alternatively, use the QuestDB SNAPSHOT SQL command to take a consistent filesystem snapshot before you back up.
Apply operating system security updates with sudo apt-get update && sudo apt-get upgrade, and reboot when a new kernel is installed. QuestDB and nginx start automatically on boot.
Support
This image is published and supported by SecureAnyCloud. Support covers deployment, ingestion protocol configuration, schema and partitioning design, SQL queries, PostgreSQL and InfluxDB integration, the authenticating proxy, TLS and storage tuning. Contact SecureAnyCloud through the support channel listed on the AWS Marketplace listing.
All product and company names are trademarks or registered trademarks of their respective holders. Use of them does not imply any affiliation with or endorsement by them.
Deploy on AWS
Launch QuestDB on AWS with 24/7 support from SecureAnyCloud.
View on Marketplace
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com