Launch QuestDB with systemd

Use systemd to run QuestDB as a service. For production deployments, we strongly recommend a system service running as a dedicated, unprivileged user. It starts at boot without depending on an interactive login and lets systemd apply the required resource limits directly.

This guide provides system-service examples for QuestDB Open Source and QuestDB Enterprise.

Prerequisites

The prerequisites for deploying QuestDB with systemd are:

  • A 64-bit Linux system (x86-64 or ARM64) running systemd
  • The QuestDB archive for your edition and architecture. Runtime archives include Java. QuestDB Open Source on ARM64 uses the no-JRE archive and also requires Java 25 and unzip.

Initial system configuration

Create a dedicated system user and group. The unit will create and manage its QuestDB root directory at /var/lib/questdb. If the questdb user already exists, skip the useradd command.

sudo useradd --system --user-group \
--home-dir /var/lib/questdb \
--shell /usr/sbin/nologin \
questdb

For QuestDB Open Source, select your server architecture:

Download the current Linux runtime and extract it to /opt/questdb:

curl -fL https://github.com/questdb/questdb/releases/download/9.4.3/questdb-9.4.3-rt-linux-x86-64.tar.gz -o questdb.tar.gz

sudo install -d -o root -g root -m 0755 /opt/questdb
sudo tar -xzf questdb.tar.gz -C /opt/questdb --strip-components 1
sudo chown -R root:root /opt/questdb

For QuestDB Enterprise, extract the runtime archive for your architecture to /opt/questdb. Run these commands from the directory containing the archive:

sudo install -d -o root -g root -m 0755 /opt/questdb
sudo tar -xzf questdb-enterprise-*-rt-linux-amd64.tar.gz \
-C /opt/questdb \
--strip-components 1
sudo chown -R root:root /opt/questdb

SELinux

If you have SELinux enabled, apply the default SELinux labels after extracting QuestDB:

sudo restorecon -R /opt/questdb

Using a QuestDB server.conf

With this unit, QuestDB creates /var/lib/questdb/conf/server.conf with default settings on first start. See the configuration reference for available options.

Example questdb.service

Create a file named questdb.service using the configuration for your edition. The examples set QDB_ROOT to /var/lib/questdb; QuestDB stores its conf, db, log, and public directories beneath it. Adjust the installation paths if necessary.

[Unit]
Description=QuestDB
Documentation=https://questdb.com/docs/deployment/systemd/

[Service]
Type=exec
User=questdb
Group=questdb
Restart=always
RestartSec=2
KillSignal=SIGTERM
SuccessExitStatus=143

# QuestDB root directory
Environment=QDB_ROOT=/var/lib/questdb
StateDirectory=questdb
StateDirectoryMode=0750
ExecStartPre=/usr/bin/mkdir -p ${QDB_ROOT}/db

ExecStart=/opt/questdb/bin/java \
-DQuestDB-Runtime-66535 \
-Dcontainerized=false \
-ea -Dnoebug \
-XX:ErrorFile=${QDB_ROOT}/db/hs_err_pid+%%p.log \
-XX:+UnlockExperimentalVMOptions \
-XX:+AlwaysPreTouch \
-XX:+UseParallelGC \
--sun-misc-unsafe-memory-access=allow \
--enable-native-access=io.questdb \
--add-opens=java.base/java.lang=io.questdb \
--add-opens=java.base/java.lang.reflect=io.questdb \
--add-opens=java.base/java.nio=io.questdb \
--add-opens=java.base/java.time.zone=io.questdb \
--add-exports=java.base/jdk.internal.vm=io.questdb \
-m io.questdb/io.questdb.ServerMain \
-d ${QDB_ROOT}

# Raise the open-files limit to QuestDB's recommended value
LimitNOFILE=1048576

ProtectSystem=full
StandardOutput=journal
StandardError=journal
SyslogIdentifier=questdb

[Install]
WantedBy=multi-user.target

The unit above uses the bundled x86-64 runtime. On ARM64, replace its ExecStart directive with the following one:

ExecStart=/usr/bin/java \
-DQuestDB-Runtime-66535 \
-Dcontainerized=false \
-Dquestdb.libs.dir=/opt/questdb/lib \
-ea -Dnoebug \
-XX:ErrorFile=${QDB_ROOT}/db/hs_err_pid+%%p.log \
-XX:+UnlockExperimentalVMOptions \
-XX:+AlwaysPreTouch \
-XX:+UseParallelGC \
--sun-misc-unsafe-memory-access=allow \
--enable-native-access=io.questdb \
--add-opens=java.base/java.lang=io.questdb \
--add-opens=java.base/java.lang.reflect=io.questdb \
--add-opens=java.base/java.nio=io.questdb \
--add-opens=java.base/java.time.zone=io.questdb \
--add-exports=java.base/jdk.internal.vm=io.questdb \
-p /opt/questdb/questdb.jar \
-m io.questdb/io.questdb.ServerMain \
-d ${QDB_ROOT}

-XX:ErrorFile writes JVM crash logs beneath QDB_ROOT/db; %%p is intentional.

SuccessExitStatus=143 records systemctl stop as a successful orderly shutdown.

Configure vm.max_map_count and other recommended OS settings separately. See OS configuration.

Install the unit:

sudo install -o root -g root -m 0644 \
questdb.service \
/etc/systemd/system/questdb.service

Reload systemd, enable QuestDB at boot, and start it now:

sudo systemctl daemon-reload
sudo systemctl enable --now questdb.service

Check the service status:

sudo systemctl status questdb.service

View its journal:

sudo journalctl --unit=questdb.service --follow

Unexpected restarts

If QuestDB restarts without an error, check the systemd journal:

sudo journalctl --unit=questdb.service --since "today"

On Ubuntu, package updates may restart affected services through needrestart, including during unattended upgrades. See Ubuntu's automatic updates documentation for configuration options.