Dg
Artificial Intelligence (AI) Azure

DB-GPT on Ubuntu 24.04 on Azure User Guide

| Product: DB-GPT on Ubuntu 24.04 LTS on Azure

Overview

This guide covers the deployment and configuration of DB-GPT on Ubuntu 24.04 on Azure using cloudimg Azure Marketplace images. DB-GPT is an open source AI data assistant. You connect it to your databases and ask questions in plain language; it reads the schema, writes the SQL, runs it and shows the result as a table or chart, with the SQL it used one click away. It also builds knowledge bases from your documents and answers questions from them with citations (retrieval augmented generation), and it includes agents, reusable skills and a visual workflow designer (AWEL) for more involved data tasks.

The cloudimg image ships DB-GPT v0.8.2 under the MIT licence and works with no API key on arrival: a local open source language model (Qwen2.5 7B Instruct, Apache 2.0) and a local embedding model (BGE-M3, MIT) are served by Ollama on the CPU, so your data and questions never leave the VM unless you choose a hosted provider. A small sample database (customers, products, orders) is registered on first boot so you can try text to SQL straight away. Backed by 24/7 cloudimg support.

DB-GPT is an independent open source project by the eosphoros-ai community. This image is produced by cloudimg and is not affiliated with, endorsed by, or sponsored by the DB-GPT project or its maintainers. It ships the free and open source MIT licensed software from the upstream release.

The six units active, and only ports 22, 80 and 443 reachable from the network

What is included:

  • DB-GPT v0.8.2, installed from the upstream release tag with every Python dependency checked against the upstream lock file hashes, on a pinned Python 3.11 runtime
  • The DB-GPT web interface from the same release, with its code editor and icons served from the VM itself instead of public CDNs, and English as the default language
  • Ollama v0.40.5 (MIT) with the CPU backend only, serving Qwen2.5 7B Instruct (Apache 2.0) and BGE-M3 embeddings (MIT), both pinned by SHA-256 digest and cached in the image, so first boot downloads nothing
  • Database drivers for MySQL and MariaDB, PostgreSQL, Microsoft SQL Server, ClickHouse, Oracle, DuckDB and SQLite
  • nginx on port 443 with a TLS certificate generated for each VM; port 80 only redirects to HTTPS
  • A unique 24 character password and a unique API key generated on first boot, required on every page and API call
  • DB-GPT and the model server listening on 127.0.0.1 only
  • A network guard that keeps DB-GPT away from the Azure metadata service and your private networks, with a one line command to allow your own databases

Prerequisites

  • Active Azure subscription, an SSH public key, and a VNet and subnet in your target region
  • A subscription to the DB-GPT listing on Azure Marketplace
  • Recommended size Standard_B4ms (4 vCPU, 16 GiB). The two bundled models need about 7 GiB of memory while loaded.

Be realistic about the bundled CPU model. It is there so the appliance is useful, private and free of API keys from the first minute, not to be fast. Measured on Standard_B4ms: a text to SQL question about the sample database took 25 to 80 seconds (the first question after boot is the slowest), and a question answered from a knowledge base took about 30 seconds. A 7B model is good at simple aggregations and lookups but can misread complex schemas or invent values, so always check the SQL it shows you before relying on an answer. B-series VMs are burstable, so sustained use can exhaust CPU credits and slow things down further; for steady use pick a non-burstable size such as Standard_D4s_v5 or larger, or switch to a hosted model provider (Step 11), which answers in seconds and is considerably more accurate. No GPU is required.

Step 1: Deploy from the Azure Portal

  1. In the Azure Portal, search the Marketplace for DB-GPT by cloudimg and select Create.
  2. Choose your subscription, resource group and region, and set the VM name.
  3. Select size Standard_B4ms, authentication type SSH public key, and paste your key.
  4. Under Inbound port rules, allow SSH (22) and HTTPS (443). Port 80 is optional; it only redirects to HTTPS. Restrict the source of 443 to your own network (see Security hardening).
  5. Leave the OS disk defaults, then Review + create.

First boot takes a few minutes. It generates this VM's password, API key, encryption key and certificate, starts the services on the loopback address, loads both models into memory (they stay loaded), registers the sample database, proves that authentication and cross site request protection are enforced, and only then opens nginx. If anything in that sequence fails, nothing is left listening.

Step 2: Deploy from the Azure CLI

Replace the placeholder values with your own. This block is illustrative and is not executed by the walk through.

az vm image terms accept --urn cloudimg1647283583153:db-gpt-ubuntu-24-04:default:latest
az vm create \
  --resource-group my-resource-group \
  --name my-dbgpt-vm \
  --image cloudimg1647283583153:db-gpt-ubuntu-24-04:default:latest \
  --size Standard_B4ms \
  --admin-username azureuser \
  --ssh-key-values ~/.ssh/id_rsa.pub \
  --public-ip-sku Standard \
  --os-disk-delete-option Delete --nic-delete-option Delete

Then allow HTTPS from your own network only:

az network nsg rule create \
  --resource-group my-resource-group \
  --nsg-name my-dbgpt-vmNSG \
  --name allow-https-from-office \
  --priority 1010 --access Allow --protocol Tcp \
  --destination-port-ranges 443 --source-address-prefixes 203.0.113.0/24

Step 3: Connect to your VM

ssh azureuser@<vm-ip>

Step 4: Confirm the services are running

Six units make up the appliance: dbgpt-netguard (the network guard), dbgpt-firstboot (per VM secrets and the security proof), ollama (the local model server, in its own private network namespace), ollama-proxy.socket (the only door into it), dbgpt (DB-GPT itself) and nginx (HTTPS and sign in).

systemctl is-active dbgpt-netguard dbgpt-firstboot ollama ollama-proxy.socket dbgpt nginx

Expected output:

active
active
active
active
active
active

Step 5: Read the per instance credentials

Every VM generates its own credentials on first boot. Nothing is shared between instances and nothing is baked into the image.

sudo cat /root/dbgpt-credentials.txt

Expected output (your address, password and key will differ):

# DB-GPT — per-VM credentials (generated at first boot on 2026-10-16T18:43:20Z)
DBGPT_URL=https://20.25.91.179/
DBGPT_USERNAME=admin
DBGPT_PASSWORD=<unique per VM>
DBGPT_API_KEY=<unique per VM>
DBGPT_LLM=bundled local model (Ollama, CPU): qwen2.5:7b-instruct-q4_K_M; see the guide to use your own provider key

DB-GPT itself has no sign in of its own (its upstream documentation says so), so the image puts one in front of it: nginx asks for the user name admin and this password on every page, static file and API call. API clients can present the API key instead (Step 8).

The per VM credentials file (password and key redacted here), with anonymous, wrong password and cross site requests refused

Step 6: Open the web interface

Browse to https://<vm-ip>/. The certificate is self signed and unique to this VM, so your browser shows a warning the first time. To confirm you are talking to your own VM, compare the fingerprint your browser shows with the one on the VM:

openssl x509 -in /etc/ssl/certs/dbgpt-vm.crt -noout -fingerprint -sha256

Your browser then asks for a user name and password: enter admin and the password from Step 5. You land on the home page, with the bundled model selected.

The DB-GPT home page with the bundled model selected

The sample database is already registered. Open Datasources, then the Sqlite card, to see it:

Datasources, with the bundled sample_sales database

To ask it a question, open https://<vm-ip>/chat?scene=chat_with_db_execute&select_param=sample_sales, type a question and press Sent. For one of your own data sources, put its name after select_param=. DB-GPT writes the SQL, runs it and shows the result; the SQL tab shows exactly what it ran.

A question about the sample database answered by running SQL: customers per country

Knowledge Base turns your documents into a searchable knowledge base; questions are answered from it with numbered references to the passages used (Step 9 builds one).

A question answered from a knowledge base, with a reference to the source passage

Two of the four Recommended examples on the home page (Walmart sales and the financial report analysis) rely on sample files that upstream distributes but this image does not include, because their redistribution terms are unclear. Use the bundled sample_sales database, or your own data, instead.

Step 7: Check the security posture

The image ships a read only self check. Each probe is paired with a control so that a pass means something: for example, the metadata service test first proves that root can reach it, then proves DB-GPT cannot.

sudo dbgpt-selfcheck

Expected output:

PASS  network listeners are exactly 22 80 443
PASS  port 5670 bound to 127.0.0.1 only
PASS  port 11434 bound to 127.0.0.1 only
PASS  port 80 only redirects to HTTPS (301)
PASS  anonymous / refused (401)
PASS  anonymous /api/v1/chat/db/list refused (401)
PASS  anonymous /favicon.ico refused (401)
PASS  DB-GPT (in its service) cannot reach IMDS or the WireServer (root control 200)
PASS  DB-GPT user cannot reach 127.0.0.1:443/
PASS  DB-GPT user cannot reach 127.0.0.1:22/
PASS  DB-GPT user cannot reach 10.0.0.1:5432/
PASS  DB-GPT user cannot reach 192.168.0.1/
PASS  DB-GPT user cannot reach 172.16.0.1/
PASS  model server reachable by DB-GPT/root only (other user 000, root 200)
Allowed private destinations: 0 (sudo dbgpt-allow-network list)
SELFCHECK OK

The self check: listeners, anonymous refusal, metadata service and private networks blocked, model server answering DB-GPT only

What the image enforces, and why:

Control Detail
Sign in on every route nginx requires HTTP Basic authentication (admin and the per VM password, stored as a bcrypt hash) for every page, static file, API route and streaming response, or this VM's API key as a bearer token.
HTTPS only nginx terminates TLS with a per VM certificate; port 80 only redirects. Any cookie the application sets is forced to Secure, HttpOnly and SameSite=Strict.
Cross site requests refused A browser remembers Basic credentials, so nginx checks where each request comes from: any API call another site makes (judged by the Origin, Referer and Sec-Fetch-Site headers) is refused with 403, even though the browser would attach your password. Cross origin (CORS) headers from the application are removed. A link from another site to the interface opens the home page, without passing on any parameters.
Loopback only DB-GPT (5670) and the model server (11434) listen on 127.0.0.1 only. DB-GPT's code execution workers would otherwise open a port on every interface; a small preload library (source in /usr/local/src/cloudimg-loopback-bind) keeps every listener the service opens on loopback.
Server side request forgery DB-GPT connects to databases and fetches URLs you give it. At the network layer the dbgpt service account cannot reach the instance metadata service (169.254.169.254), the wire server (168.63.129.16), link local, private (10/8, 172.16/12, 192.168/16, 100.64/10) or reserved networks, or anything on the loopback interface except the DNS resolver, the model server and its own ports. This is enforced by nftables per user and by systemd per service, independently of DB-GPT, so a host name that resolves to an internal address, or a redirect to one, is refused too. Databases on the public internet work as normal; private ones are allowed one by one (Step 10).
Model server isolated Ollama has no authentication of its own, so it runs in a private network namespace with no network access at all; the socket on 127.0.0.1:11434 that leads into it may only be opened by the dbgpt account and root.
Secrets The password, API key, the key that encrypts stored database passwords, and the TLS key are generated per VM. None of them is ever placed on a command line, and DB-GPT logs at warning level so database connection details are not written to the journal.
Fail closed The services refuse to start until first boot has written this VM's secrets, and nginx refuses to start until first boot has proven the sign in and cross site protection work.

Step 8: Use the API

Everything in the interface is available over DB-GPT's REST API, through the same nginx front door. On the VM, the commands below read the password from the credentials file and hand it to curl through standard input, so it never appears in a command line. Requests that change something must say which site they come from (Origin); requests without it are refused as a cross site request protection.

List the registered data sources:

sudo sed -n 's/^DBGPT_PASSWORD=\(.*\)/user = "admin:\1"/p' /root/dbgpt-credentials.txt \
  | curl -s -K - --cacert /etc/ssl/certs/dbgpt-vm.crt https://127.0.0.1/api/v1/chat/db/list \
  | python3 -c 'import json,sys; [print(d["db_name"], d["db_type"]) for d in json.load(sys.stdin)["data"]]'

Expected output:

sample_sales sqlite

Ask the sample database a question. DB-GPT answers as a stream of server sent events; the last one carries the SQL it ran and the rows it got back:

sudo sed -n 's/^DBGPT_PASSWORD=\(.*\)/user = "admin:\1"/p' /root/dbgpt-credentials.txt \
  | curl -sN -K - --cacert /etc/ssl/certs/dbgpt-vm.crt https://127.0.0.1/api/v1/chat/completions \
      -H 'Origin: https://127.0.0.1' -H 'Content-Type: application/json' \
      -d '{"chat_mode":"chat_with_db_execute","select_param":"sample_sales","model_name":"qwen2.5:7b-instruct-q4_K_M","temperature":0,"user_input":"How many customers are there in each country?"}' \
  | python3 -c '
import html, json, re, sys
last = [l for l in sys.stdin if l.startswith("data:")][-1][5:]
content = json.loads(last)["choices"][0]["message"]["content"]
view = json.loads(html.unescape(re.search(r"<chart-view content=\"([^\"]*)\"", content).group(1)))
print("SQL:", view["sql"])
for row in sorted(view["data"], key=lambda r: list(r.values())[0]):
    print(*row.values())
'

Expected output (the SQL wording can vary slightly between runs):

SQL: SELECT country, COUNT(customer_id) AS customer_count FROM customers GROUP BY country LIMIT 50;
Canada 13
France 9
Germany 7
Ireland 15
Netherlands 16
Spain 17
United Kingdom 22
United States 21

Check it against the database directly:

sudo sqlite3 -readonly /var/lib/dbgpt/sample/sample_sales.db \
  "SELECT country, COUNT(*) FROM customers GROUP BY country ORDER BY country;"

Expected output:

Canada|13
France|9
Germany|7
Ireland|15
Netherlands|16
Spain|17
United Kingdom|22
United States|21

Scripts and integrations can use the API key instead of the password. A bearer key is not a browser credential, so no Origin header is needed. On the VM (the key reaches curl as a header on standard input):

sudo sed -n 's/^DBGPT_API_KEY=\(.*\)/Authorization: Bearer \1/p' /root/dbgpt-credentials.txt \
  | curl -s -H @- --cacert /etc/ssl/certs/dbgpt-vm.crt https://127.0.0.1/api/v1/chat/db/list \
  | python3 -c 'import json,sys; [print(d["db_name"], d["db_type"]) for d in json.load(sys.stdin)["data"]]'

Expected output:

sample_sales sqlite

From another machine, copy the certificate (/etc/ssl/certs/dbgpt-vm.crt) and send the key the same way:

curl -s --cacert dbgpt-vm.crt -H "Authorization: Bearer <DBGPT_API_KEY>" https://<vm-ip>/api/v1/chat/db/list

Without credentials, every route is refused:

curl -s -o /dev/null -w '%{http_code}\n' --cacert /etc/ssl/certs/dbgpt-vm.crt https://127.0.0.1/api/v1/chat/db/list

Expected output:

401

Step 9: Build a knowledge base

Create a knowledge base, add a document to it, index it, and ask a question about it (indexing a short document takes about fifteen seconds; answering takes around thirty):

auth() { sudo sed -n 's/^DBGPT_PASSWORD=\(.*\)/user = "admin:\1"/p' /root/dbgpt-credentials.txt; }
api() { auth | curl -s -K - --cacert /etc/ssl/certs/dbgpt-vm.crt -H 'Origin: https://127.0.0.1' -H 'Content-Type: application/json' "https://127.0.0.1/api/v1/$1" -d "$2"; }
api knowledge/space/add '{"name":"handbook","vector_type":"Chroma","domain_type":"Normal","desc":"Staff handbook","owner":"dbgpt"}' >/dev/null
api knowledge/handbook/document/add '{"doc_name":"leave-policy","doc_type":"TEXT","content":"Harbor Robotics staff receive 27 days of annual leave. Leave requests go to the team lead at least two weeks in advance. Unused leave of up to five days can be carried into the next year."}' >/dev/null
DOC=$(api knowledge/handbook/document/list '{"page":1,"page_size":20}' | python3 -c 'import json,sys; d=json.load(sys.stdin)["data"]; d=d.get("data",d) if isinstance(d,dict) else d; print(d[0]["id"])')
api knowledge/handbook/document/sync "{\"doc_ids\":[$DOC]}" >/dev/null
for i in $(seq 1 60); do
  ST=$(api knowledge/handbook/document/list '{"page":1,"page_size":20}' | python3 -c 'import json,sys; d=json.load(sys.stdin)["data"]; d=d.get("data",d) if isinstance(d,dict) else d; print(d[0]["status"])')
  [ "$ST" = FINISHED ] && break; sleep 5
done
echo "document: $ST"
api chat/completions '{"chat_mode":"chat_knowledge","select_param":"handbook","model_name":"qwen2.5:7b-instruct-q4_K_M","temperature":0,"user_input":"How many days of annual leave do Harbor Robotics staff get?"}' \
  | python3 -c 'import json,sys; last=[l for l in sys.stdin if l.startswith("data:")][-1][5:]; print(json.loads(last)["choices"][0]["message"]["content"].split("<references")[0].strip())'

Expected output:

document: FINISHED
Harbor Robotics staff get 27 days of annual leave. [1]

In the interface the same knowledge base appears under Knowledge Base, where you can upload PDF, Word, PowerPoint, Markdown and text files, and chat with it at https://<vm-ip>/chat?scene=chat_knowledge&select_param=handbook (put your knowledge base's name after select_param=).

Step 10: Connect your own databases

In the interface, open Datasources, choose the database type, and fill in the host, port, database, user and password. DB-GPT stores the password encrypted with a key unique to this VM.

Databases on the public internet (for example an Azure Database for PostgreSQL or MySQL flexible server, or Azure SQL Database, reached through its public endpoint and firewall rules) work as they are.

Databases on a private address (a private endpoint, a database VM in the same or a peered VNet, or a database on this VM itself) are blocked by default, so that nobody can point DB-GPT at your internal network unasked. Allow each one explicitly, by address and port:

sudo dbgpt-allow-network add 10.1.2.3:5432

That allows exactly one host and port. A whole subnet on one port is 10.20.0.0/16:1433; a host on every port is just 10.1.2.3; a database running on this VM is 127.0.0.1:5432. The change takes effect immediately and survives reboots; the Azure metadata service and wire server can never be allowed. Review or undo what you allowed:

sudo dbgpt-allow-network list

Expected output (on a new VM):

(no private destinations allowed)
sudo dbgpt-allow-network remove 10.1.2.3:5432

Give DB-GPT a database account with read only permissions on the data it should analyse. The model writes SQL from your question; read only access means a misunderstood question cannot change your data.

Step 11: Switch to your own model provider (optional)

The bundled model keeps everything on the VM. For faster and more accurate answers, point DB-GPT at a hosted provider by editing /etc/dbgpt/dbgpt.toml (readable by root and the service only) and replacing the [[models.llms]] block. Keep the local embedding model: changing it means re-indexing your knowledge bases and data sources.

OpenAI, or any OpenAI compatible endpoint:

[[models.llms]]
name = "gpt-4o-mini"
provider = "proxy/openai"
api_base = "https://api.openai.com/v1"
api_key = "sk-your-openai-key"

Azure OpenAI (API key; managed identity is not available because DB-GPT is deliberately blocked from the instance metadata service):

[[models.llms]]
name = "your-deployment-name"
provider = "proxy/openai"
api_type = "azure"
api_base = "https://your-resource.openai.azure.com"
api_version = "2024-12-01-preview"
api_key = "your-azure-openai-key"

DeepSeek is also built in (provider = "proxy/deepseek"). Then restart DB-GPT:

sudo systemctl restart dbgpt

If your provider endpoint has a private address (an Azure OpenAI private endpoint, or a model server on another VM), allow it first with sudo dbgpt-allow-network add <address>:443.

To use a different local model instead, download it with sudo dbgpt-ollama-pull <model:tag> (Ollama itself has no network access, so this helper fetches it), add it as another [[models.llms]] block with provider = "proxy/ollama" and api_base = "http://127.0.0.1:11434", and restart DB-GPT. Larger models need more memory. Once you no longer use local models you can stop them to free memory with sudo systemctl disable --now ollama-proxy.socket ollama.

Step 12: Back up and restore

All of DB-GPT's data (data source definitions, conversations, knowledge bases and their vectors) lives under /var/lib/dbgpt. The stored database passwords are encrypted with the key in /etc/dbgpt/dbgpt.toml, so back that file up too; the archive contains secrets, so it is created readable by root only. Stop DB-GPT for a consistent copy:

sudo systemctl stop dbgpt
sudo tar czf /var/backups/dbgpt-backup.tar.gz -C / var/lib/dbgpt etc/dbgpt
sudo chmod 600 /var/backups/dbgpt-backup.tar.gz
sudo systemctl start dbgpt
sudo ls -l /var/backups/dbgpt-backup.tar.gz | awk '{print $1, $3, $9}'

Expected output:

-rw------- root /var/backups/dbgpt-backup.tar.gz

Copy the archive off the VM, for example to Azure Blob Storage. To restore onto a new VM from this image, stop dbgpt, extract the archive over / (keeping /var/lib/dbgpt owned by dbgpt), and start it again.

Step 13: Logs and day to day operation

sudo journalctl -u dbgpt -n 20 --no-pager

Useful commands:

Task Command
Restart DB-GPT sudo systemctl restart dbgpt
Model server logs sudo journalctl -u ollama -n 50
First boot log sudo journalctl -u dbgpt-firstboot
Re check security sudo dbgpt-selfcheck
Allowed private databases sudo dbgpt-allow-network list

Exactly what is installed, and where it came from:

cat /usr/share/dbgpt/PROVENANCE

Pinned versions, model digests, the dependency licence scan results and the CPU only model server

Security hardening

  • Restrict the source of port 443 in your network security group to the networks that need it, and close port 22 to everything except your management network.
  • Change the password: run sudo htpasswd -B -C 10 /etc/nginx/dbgpt.htpasswd admin, type the new password twice, and update /root/dbgpt-credentials.txt if you keep it there. Add a sign in for another person the same way with a different user name. All sign ins share the same DB-GPT workspace.
  • Rotate the API key by editing the key in /etc/nginx/conf.d/dbgpt-api-key.conf and running sudo systemctl reload nginx.
  • Replace the self signed certificate with your own: put the certificate and key at /etc/dbgpt/tls/dbgpt.crt and /etc/dbgpt/tls/dbgpt.key (and a copy of the certificate at /etc/ssl/certs/dbgpt-vm.crt) and run sudo systemctl reload nginx.
  • DB-GPT's agents, skills and AWEL code operators can run Python code on the VM, as the unprivileged dbgpt account inside its sandboxed service. Treat the sign in as administrator access and share it accordingly.
  • Use read only database accounts for the data DB-GPT analyses (Step 10).
  • Security updates for Ubuntu are installed automatically by unattended upgrades.

Troubleshooting

  • The browser keeps asking for a password: the user name is admin, and the password is the one in /root/dbgpt-credentials.txt (Step 5).
  • A connection to my database fails: if the database has a private address, allow it with sudo dbgpt-allow-network add <address>:<port> (Step 10). Check the database's own firewall allows this VM's address.
  • An answer looks wrong: open the SQL tab to see what DB-GPT ran. Rephrase the question with the exact table or column names, or switch to a hosted model (Step 11) for better accuracy.
  • Answers are slow: expected with the bundled CPU model; see the measurements under Prerequisites.
  • A knowledge base answers "Collection ... does not exist": this happens after deleting a knowledge base and creating a new one with the same name; restart DB-GPT with sudo systemctl restart dbgpt, then sync the documents again.
  • An API call returns 403: a request that changes something needs an Origin header naming this VM (Step 8), or use the API key.
  • The browser shows a certificate warning: expected with the per VM self signed certificate; compare the fingerprint (Step 6) or install your own certificate.
  • Nothing answers on 443 after deployment: first boot may still be running (loading the models from disk takes a few minutes on a new VM); check sudo journalctl -u dbgpt-firstboot. If first boot failed it stops every service on purpose.

Support

cloudimg provides 24/7 support for this image with a guaranteed 24 hour response. Contact support@cloudimg.co.uk with your VM's region and the output of sudo dbgpt-selfcheck.