diff --git a/documentation/deployment/systemd.md b/documentation/deployment/systemd.md index 699b70216..1e8a1c7cf 100644 --- a/documentation/deployment/systemd.md +++ b/documentation/deployment/systemd.md @@ -4,202 +4,357 @@ sidebar_label: systemd description: This document describes how to launch QuestDB using systemd. --- -Use systemd to run QuestDB as a system or user service. This guide will -demonstrate an initial configuration which you can use as the basis for your -installation scripts. It will also demonstrate how to set up and start a QuestDB -systemd service. +import Tabs from "@theme/Tabs" +import TabItem from "@theme/TabItem" +import CodeBlock from "@theme/CodeBlock" +import InterpolateReleaseData from "../../src/components/InterpolateReleaseData" + +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 Unix machine supporting systemd -- Java 25 (OpenJDK 25 or compatible distribution) +- 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 -The following commands inform a basis for your systemd service. Prior to running -systemd, you will require some directory structure and a binary for QuestDB. -Depending on your specific needs and operational preferences, your commands may -differ. The goal is to give you a helpful starting point for the example -service. The example presumes that you have used a privileged user to create a -user with appropriately scoped permissions. +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. ```bash -#!/bin/bash - -# Install OpenJDK 25 -sudo apt-get update && sudo apt-get install -y openjdk-25-jdk -export JAVA_HOME=/usr/lib/jvm/java-25-openjdk-amd64 -export PATH=$JAVA_HOME/bin:$PATH - -# Download and set up QuestDB -curl -s https://dl.questdb.io/snapshots/questdb-latest-no-jre-bin.tar.gz -o questdb.tar.gz -mkdir -p ~/questdb/binary -mkdir -p ~/bin ~/var/lib/questdb -tar -xzf questdb.tar.gz -C ~/questdb/binary --strip-components 1 -mv ~/questdb/binary/questdb.jar ~/bin/ +sudo useradd --system --user-group \ + --home-dir /var/lib/questdb \ + --shell /usr/sbin/nologin \ + questdb ``` -### Using a QuestDB server.conf +For QuestDB Open Source, select your server architecture: -Your QuestDB configuration is done in a `server.conf` file. The `server.conf` -file is populated with safe defaults on first startup if it does not exist. It -is common for users of QuestDB to stick with the default configuration. -However, should you choose to update your own and serve it via a scripted method -or similar, you may do so. + -Read more about the available options in our -[Configuration reference page](/docs/configuration/overview/). + -## Example questdb.service +Download the current Linux runtime and extract it to `/opt/questdb`: -Create a new file called `questdb.service`: + -```shell -touch questdb.service + ( + +{`curl -fL https://github.com/questdb/questdb/releases/download/${release.name}/questdb-${release.name}-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`} + +)} +/> + + + + + + + +On ARM64, use the no-JRE archive. Install Java 25 and `unzip` with your package +manager, then download and extract QuestDB: + + + + ( + +{`curl -fL https://github.com/questdb/questdb/releases/download/${release.name}/questdb-${release.name}-no-jre-bin.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 install -d -o root -g root -m 0755 /opt/questdb/lib + +sudo unzip -jo /opt/questdb/questdb.jar \ + 'io/questdb/bin/linux-aarch64/*.so' \ + -d /opt/questdb/lib + +sudo chown -R root:root /opt/questdb`} + +)} +/> + + + +The native libraries are installed under `/opt/questdb/lib` so that QuestDB can +load them directly instead of extracting them to the system temporary directory. + + + + + +For QuestDB Enterprise, extract the runtime archive for your architecture to +`/opt/questdb`. Run these commands from the directory containing the archive: + + + + + +```bash +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 +``` + + + + + +```bash +sudo install -d -o root -g root -m 0755 /opt/questdb +sudo tar -xzf questdb-enterprise-*-rt-linux-aarch64.tar.gz \ + -C /opt/questdb \ + --strip-components 1 +sudo chown -R root:root /opt/questdb ``` -The example below is a recommended starting point. Note the default QuestDB -service configuration and system paths in line with the above example. Next, -open the `questdb.service` file and add the following: + + + + +### SELinux + +If you have SELinux enabled, apply the default SELinux labels after extracting +QuestDB: + +```bash +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](/docs/configuration/overview/) 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. + + + + + + + + ```shell [Unit] Description=QuestDB -Documentation=https://www.questdb.com/docs/ -After=network.target +Documentation=https://questdb.com/docs/deployment/systemd/ [Service] -Type=simple +Type=exec +User=questdb +Group=questdb Restart=always RestartSec=2 -# Adjust java path to match requirements of a given distro -ExecStart=/usr/lib/jvm/java-25-openjdk-amd64/bin/java \ --XX:+UnlockExperimentalVMOptions \ --XX:+AlwaysPreTouch \ --XX:+UseParallelGC \ --DQuestDB-Runtime-66535 \ --Dcontainerized=false \ --ea -Dnoebug \ ---add-exports java.base/jdk.internal.math=io.questdb \ ---add-exports java.base/jdk.internal.vm=io.questdb \ --p /home/[USER_NAME]/bin/questdb.jar \ --m io.questdb/io.questdb.ServerMain \ --d /home/[USER_NAME]/var/lib/questdb - -ExecReload=/bin/kill -s HUP $MAINPID - -# Raise the open-files limit +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 -# Prevent writes to /usr, /boot, and /etc ProtectSystem=full -StandardError=syslog +StandardOutput=journal +StandardError=journal SyslogIdentifier=questdb [Install] WantedBy=multi-user.target ``` -For QuestDB Enterprise, launch the enterprise module -(`com.questdb/com.questdb.EntServerMain`) and target both `io.questdb` and -`com.questdb` on the module flags. The corresponding `ExecStart` is: +The unit above uses the bundled x86-64 runtime. On ARM64, replace its +`ExecStart` directive with the following one: ```shell -ExecStart=/home/[USER_NAME]/questdb-enterprise/bin/java \ --XX:+UnlockExperimentalVMOptions \ --XX:+AlwaysPreTouch \ --XX:+UseParallelGC \ --ea -Dnoebug \ ---sun-misc-unsafe-memory-access=allow \ ---enable-native-access=io.questdb,com.questdb \ ---add-opens=java.base/java.lang=io.questdb,com.questdb \ ---add-opens=java.base/java.lang.reflect=io.questdb,com.questdb \ ---add-opens=java.base/java.nio=io.questdb,com.questdb \ ---add-opens=java.base/java.time.zone=io.questdb,com.questdb \ ---add-exports=java.base/jdk.internal.vm=io.questdb,com.questdb \ --m com.questdb/com.questdb.EntServerMain \ --d /home/[USER_NAME]/var/lib/questdb +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} ``` -The Enterprise package is a self-contained runtime image: the `io.questdb` and -`com.questdb` modules are built into `bin/java`, so no `--module-path` / `-p` is -required. - -`LimitNOFILE=1048576` raises the open-files limit above systemd's default of -`524288`, which is below what QuestDB recommends. The kernel `vm.max_map_count` -limit cannot be set from a unit file; configure it separately. See -[OS configuration](/docs/getting-started/capacity-planning/#os-configuration) for -both. + -Next, move your `questdb.service` file into your user's `systemd` config: + ```shell -mv questdb.service ~/.config/systemd/user/questdb.service -``` - -Enable the service: - -```shell -systemctl --user enable questdb.service -``` - -Start the service: +[Unit] +Description=QuestDB Enterprise +Documentation=https://questdb.com/docs/deployment/systemd/ -```shell -systemctl --user start questdb -``` +[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,com.questdb \ + --add-opens=java.base/java.lang=io.questdb,com.questdb \ + --add-opens=java.base/java.lang.reflect=io.questdb,com.questdb \ + --add-opens=java.base/java.nio=io.questdb,com.questdb \ + --add-opens=java.base/java.time.zone=io.questdb,com.questdb \ + --add-exports=java.base/jdk.internal.vm=io.questdb,com.questdb \ + -m com.questdb/com.questdb.EntServerMain \ + -d ${QDB_ROOT} + +# Raise the open-files limit to QuestDB's recommended value +LimitNOFILE=1048576 -Check out the service status: +ProtectSystem=full +StandardOutput=journal +StandardError=journal +SyslogIdentifier=questdb -```shell -systemctl --user status questdb.service +[Install] +WantedBy=multi-user.target ``` -Your QuestDB instance should now be accessible at localhost, with services -available at the following default ports: + -- [Web Console](/docs/getting-started/web-console/overview/) & REST API is available on port `9000` -- PostgreSQL wire protocol available on `8812` -- InfluxDB line protocol `9009` (TCP and UDP) -- Health monitoring & Prometheus `/metrics` `9003` + -## User vs. System +`-XX:ErrorFile` writes JVM crash logs beneath `QDB_ROOT/db`; `%%p` is +intentional. -As an operator, you can decide whether to run systemd as the "system" from root -permissions, or a user with its own privileges. At the system level, root is -required to make changes to the `systemctl` application. Services created this -way will start and stop when the system is restarted. +`SuccessExitStatus=143` records `systemctl stop` as a successful orderly +shutdown. -Unlike at the system level, user services will start & stop as the user session -is activated or de-activated. You also do not need to apply `sudo` to make -changes to the services. +Configure `vm.max_map_count` and other recommended OS settings separately. See +[OS configuration](/docs/getting-started/capacity-planning/#os-configuration). -Consistent with the examples on this page, we recommend scoped users. +Install the unit: +```shell +sudo install -o root -g root -m 0644 \ + questdb.service \ + /etc/systemd/system/questdb.service +``` -## Daily timers +Reload systemd, enable QuestDB at boot, and start it now: -If running QuestDB on a `systemd` based Linux (for example, `Ubuntu`) you may find that, by default, there are a number of daily upgrade timers enabled. +```shell +sudo systemctl daemon-reload +sudo systemctl enable --now questdb.service +``` -When executed, these tasks restart `systemd` services, which can cause interruptions to QuestDB. It will appear -that QuestDB restarted with no errors or apparent trigger. +Check the service status: -To resolve it, either: +```shell +sudo systemctl status questdb.service +``` -- Force services to be listed for restart, but not restarted automatically. - - Modify `/etc/needrestart/needrestart.conf` to contain `$nrconf{restart} = 'l'`. -- Disable the auto-upgrade services entirely: +View its journal: -```bash -sudo systemctl disable --now apt-daily-upgrade.timer -sudo systemctl disable --now apt-daily.timer -sudo systemctl disable --now unattended-upgrades.service +```shell +sudo journalctl --unit=questdb.service --follow ``` -You can check the status of the timers using: +## Unexpected restarts -```bash -systemctl list-timers --all | grep apt +If QuestDB restarts without an error, check the systemd journal: + +```shell +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](https://ubuntu.com/server/docs/how-to/software/automatic-updates/#service-restarts) +for configuration options.