openGemini on Ubuntu 24.04 LTS on Azure
This image ships openGemini 1.4.1 on Ubuntu 24.04 LTS, configured and ready to accept authenticated writes and queries from the first boot of every deployed virtual machine.
openGemini is an open source distributed time series database purpose built for metrics, observability and IoT workloads. It ingests and queries high volumes of time stamped measurements over a simple HTTP API, stores them efficiently with columnar compression, and speaks a familiar InfluxQL style query language. It runs perfectly well as a single node, which is how this image ships, and scales out to a distributed cluster when you need one.
What makes this image different
Authentication is enforced, not optional. Out of the box, openGemini ships with HTTP authentication disabled: every write and query is permitted without credentials. This image never runs that way. The server is configured with auth-enabled = true, and a random administrator password unique to your virtual machine is generated on first boot. An unauthenticated query is refused with 401.
No credential is baked into the image. The entire openGemini data, metadata and write ahead log tree is destroyed before the image is captured, so no user, database or build time password can ride into your virtual machine. A first boot service creates a pristine store, generates the per VM administrator credential, creates the default cloudimg database, and writes the credential to a root only file. There is no default login anywhere in the image.
Internal ports stay private. Only the HTTP query and write API on port 8086 is reachable off the machine. The meta, store, RPC and internal service ports are all bound to 127.0.0.1, and the Marketplace plan opens port 22 only. Section 7 shows exactly how to reach the API safely and how to open it to your own virtual network when you need to.
1. Deploy the virtual machine
Deploy from the Azure Marketplace listing, or from the gallery image with the Azure CLI. The recommended size is Standard_B2s or larger.
az vm create \
--resource-group my-resource-group \
--name my-opengemini-vm \
--image "openGemini on Ubuntu 24.04 LTS by cloudimg" \
--size Standard_B2s \
--admin-username azureuser \
--generate-ssh-keys \
--public-ip-sku Standard
2. Connect to the virtual machine
ssh azureuser@<vm-ip>
3. Confirm openGemini is running
systemctl status opengemini.service --no-pager
The service is a native systemd unit and starts automatically on boot. A companion first boot unit, opengemini-firstboot.service, is what generates the per VM administrator credential described above.

Confirm the version:
ts-server version 2>&1 | grep -a single
single: 1.4.1
The HTTP API also answers an unauthenticated liveness probe, which is convenient for a load balancer or a health check:
curl -sS -o /dev/null -w 'ping returns HTTP %{http_code}\n' http://localhost:8086/ping
ping returns HTTP 204
4. Retrieve your credential
First boot generates a random administrator password and writes it to a file readable only by root.
sudo cat /root/opengemini-credentials.txt
Expected output, with the password value unique to your virtual machine:
# openGemini — Per-VM Credentials (generated on first boot; unique to this VM).
# Stored in plain text ONLY here (0600 root:root). Keep it safe.
OPENGEMINI_USER=admin
OPENGEMINI_PASSWORD=<OPENGEMINI_PASSWORD>
OPENGEMINI_HTTP_ENDPOINT=http://<vm-ip>:8086
OPENGEMINI_DEFAULT_DATABASE=cloudimg
5. Run your first query
openGemini exposes an HTTP query API that speaks an InfluxQL style language and returns JSON. Every query must authenticate.
curl -sS -u 'admin:<OPENGEMINI_PASSWORD>' -G 'http://localhost:8086/query' \
--data-urlencode 'q=SHOW DATABASES' | jq .
{
"results": [
{
"statement_id": 0,
"series": [
{
"name": "databases",
"columns": ["name"],
"values": [["cloudimg"]]
}
]
}
]
}
Confirm that an unauthenticated request is genuinely refused:
curl -sS -o /dev/null -w 'anonymous query returns HTTP %{http_code}\n' \
-G 'http://localhost:8086/query' --data-urlencode 'q=SHOW DATABASES'
anonymous query returns HTTP 401

6. Write and read time series data
Writes use the line protocol and go to the /write endpoint. A point is a measurement, optional tags, one or more fields and an optional timestamp in nanoseconds. Here we write a few weather readings into the default cloudimg database.
NOW=$(date +%s000000000)
curl -sS -o /dev/null -w 'write returns HTTP %{http_code}\n' \
-u 'admin:<OPENGEMINI_PASSWORD>' \
-XPOST 'http://localhost:8086/write?db=cloudimg' \
--data-binary "weather,location=london temperature=17.4,humidity=71 ${NOW}"
write returns HTTP 204
Read the point back. Written points become queryable within a few seconds:
curl -sS -u 'admin:<OPENGEMINI_PASSWORD>' -G 'http://localhost:8086/query' \
--data-urlencode 'db=cloudimg' \
--data-urlencode 'q=SELECT * FROM weather' | jq .
{
"results": [
{
"statement_id": 0,
"series": [
{
"name": "weather",
"columns": ["time", "humidity", "location", "temperature"],
"values": [["2026-07-19T05:31:56Z", 71, "london", 17.4]]
}
]
}
]
}
openGemini supports aggregation, grouping and time bucketing. Write a small series and run a grouped aggregate over it:
NOW=$(date +%s000000000)
curl -sS -o /dev/null -w 'batch write HTTP %{http_code}\n' \
-u 'admin:<OPENGEMINI_PASSWORD>' \
-XPOST 'http://localhost:8086/write?db=cloudimg' \
--data-binary "weather,location=paris temperature=19.1,humidity=64 ${NOW}
weather,location=berlin temperature=15.8,humidity=80 ${NOW}"
curl -sS -u 'admin:<OPENGEMINI_PASSWORD>' -G 'http://localhost:8086/query' \
--data-urlencode 'db=cloudimg' \
--data-urlencode 'q=SELECT MEAN(temperature) AS mean_temp, MAX(humidity) AS max_humidity FROM weather' | jq '.results[0].series'

7. Network posture, and opening openGemini to your virtual network
The HTTP API listens on all interfaces on port 8086, while every internal port is bound to loopback only:
ss -tln | grep -E ':(8086|8087|8088|8091|8092|8400|8401) '
LISTEN 0 4096 0.0.0.0:8086 0.0.0.0:*
LISTEN 0 4096 127.0.0.1:8087 0.0.0.0:*
LISTEN 0 4096 127.0.0.1:8088 0.0.0.0:*
LISTEN 0 4096 127.0.0.1:8091 0.0.0.0:*
LISTEN 0 4096 127.0.0.1:8092 0.0.0.0:*
LISTEN 0 4096 127.0.0.1:8400 0.0.0.0:*
LISTEN 0 4096 127.0.0.1:8401 0.0.0.0:*
Port 8086 is the query and write API and it is authenticated. The meta port 8091, the RPC port 8092, the store ports 8400 and 8401 and the flight port 8087 are all on 127.0.0.1 and are not reachable from outside the machine. The Marketplace plan opens port 22 only.

Reaching openGemini from your workstation without opening anything
The simplest safe path is an SSH tunnel. Nothing is exposed to the network:
ssh -L 8086:localhost:8086 azureuser@<vm-ip>
Then point any client at http://localhost:8086 on your own machine.
Opening the API to your own virtual network
The HTTP API already listens on all interfaces, so to let another host in your virtual network reach it you only need to open the port in the network security group, to your virtual network's address range only. Never open a database port to 0.0.0.0/0.
az network nsg rule create --resource-group my-resource-group --nsg-name my-nsg \
--name allow-opengemini-vnet --priority 1001 --access Allow --protocol Tcp \
--destination-port-ranges 8086 --source-address-prefixes 10.0.0.0/16
Because authentication is already enforced, the API is authenticated from the moment you expose it. For traffic that crosses a network, enable HTTPS by setting https-enabled = true with a certificate and key in the [http] section of /etc/opengemini/openGemini.conf, then restart the service.
8. Managing users and databases
Create an additional database:
curl -sS -u 'admin:<OPENGEMINI_PASSWORD>' -G 'http://localhost:8086/query' \
--data-urlencode 'q=CREATE DATABASE metrics' | jq .
Create a non administrator user and grant it read and write on a single database:
curl -sS -u 'admin:<OPENGEMINI_PASSWORD>' -G 'http://localhost:8086/query' \
--data-urlencode "q=CREATE USER app WITH PASSWORD 'Str0ng!AppPass2026'" | jq .
curl -sS -u 'admin:<OPENGEMINI_PASSWORD>' -G 'http://localhost:8086/query' \
--data-urlencode 'q=GRANT ALL ON metrics TO app' | jq .
openGemini enforces password complexity and rejects weak passwords, so choose a strong value. List the users to confirm:
curl -sS -u 'admin:<OPENGEMINI_PASSWORD>' -G 'http://localhost:8086/query' \
--data-urlencode 'q=SHOW USERS' | jq .
9. Configuration and data locations
The single node configuration lives at /etc/opengemini/openGemini.conf. The data, metadata and write ahead log live under /var/lib/opengemini, and logs are written to /var/log/opengemini.
sudo systemctl show -p FragmentPath opengemini.service
ls -1 /var/lib/opengemini
After editing the configuration, restart the service:
sudo systemctl restart opengemini
10. Keeping openGemini patched
The operating system and every apt managed component on this image patch normally with apt-get update && apt-get upgrade, and unattended upgrades run exactly as they do on stock Ubuntu.
openGemini itself is not an apt package. This image installs the official upstream release binary, pinned to version 1.4.1 and verified against its published checksum before installation. To move to a newer openGemini release, download the official tarball for that version from the openGemini releases page, verify its checksum, install the ts-server binary over /usr/local/bin/ts-server, and restart the service. Alternatively, take the republished cloudimg image, which is rebuilt on a freshly patched base.
11. Licence
openGemini is licensed under the Apache License 2.0. The full licence text is on the image:
cat /usr/share/doc/cloudimg/opengemini-LICENSE
Support
This image is supported by cloudimg. If you hit a problem with the image, contact support@cloudimg.co.uk. For questions about openGemini itself, the upstream project documentation is at docs.opengemini.org.