DB-GPT
Overview
This guide covers deploying and configuring DB-GPT on Ubuntu 24.04 on Azure, using SecureAnyCloud 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). Agents, reusable skills and a visual workflow designer (AWEL) cover more involved data tasks.
The SecureAnyCloud image ships DB-GPT v0.8.2 under the MIT licence and works with no API key on arrival. Ollama serves a local open source language model (Qwen2.5 7B Instruct, Apache 2.0) and a local embedding model (BGE-M3, MIT) 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.
DB-GPT is an independent open source project by the eosphoros-ai community. This image is produced by SecureAnyCloud 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.
What you get:
- DB-GPT v0.8.2, installed from the upstream release tag on a pinned Python 3.11 runtime, with every Python dependency checked against the upstream lock file hashes
- 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 are 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
443with a TLS certificate generated for each VM. Port80only 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.1only - 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
- 24/7 SecureAnyCloud support
Prerequisites
- An 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
Know what to expect from the bundled CPU model. It makes the appliance useful, private and free of API keys from the first minute. It is not built 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. A question answered from a knowledge base took about 30 seconds.
A 7B model is good at simple aggregations and lookups, but it can misread complex schemas or invent values. Always check the SQL it shows you before you rely 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). A hosted provider answers in seconds and is considerably more accurate. No GPU is required.
Deploy from the Azure Portal
- In the Azure Portal, search the Marketplace for DB-GPT by SecureAnyCloud and select Create.
- Choose your subscription, resource group and region, and set the VM name.
- Select size Standard_B4ms and authentication type SSH public key, then paste your key.
- Under Inbound port rules, allow SSH (22) and HTTPS (443). Port 80 is optional, because it only redirects to HTTPS. Restrict the source of 443 to your own network (see Security hardening).
- Leave the OS disk defaults, then select Review + create.
First boot takes a few minutes. It generates this VM's password, API key, encryption key and certificate. It starts the services on the loopback address, loads both models into memory (they stay loaded) and registers the sample database. It then 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.
Deploy from the Azure CLI
Replace the example values in the following command with your own.
az vm image terms accept --urn sac1647283583153:db-gpt-ubuntu-24-04:default:latest
az vm create \
--resource-group my-resource-group \
--name my-dbgpt-vm \
--image sac1647283583153: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 DeleteThen 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/24Connect to your VM
ssh azureuser@<vm-ip>Confirm the services are running
Six units make up the appliance:
dbgpt-netguard: the network guarddbgpt-firstboot: per-VM secrets and the security proofollama: the local model server, in its own private network namespaceollama-proxy.socket: the only door into the model serverdbgpt: DB-GPT itselfnginx: HTTPS and sign-in
Check that all six are active:
systemctl is-active dbgpt-netguard dbgpt-firstboot ollama ollama-proxy.socket dbgpt nginxExpected output:
active active active active active activeRead 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.txtExpected 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 keyDB-GPT has no sign-in of its own, as its upstream documentation says. 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).
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 -sha256Your 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 sample database is already registered. Open Datasources, then the Sqlite card, to see it:
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.
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.
Two of the four Recommended examples on the home page, Walmart sales and the financial report analysis, rely on sample files that upstream distributes. This image does not include them, because their redistribution terms are unclear. Use the bundled sample_sales database, or your own data, instead.
Check the security posture
The image ships a read-only self-check. Each probe is paired with a control, so a pass means something. For example, the metadata service test first proves that root can reach the service, then proves that DB-GPT cannot.
sudo dbgpt-selfcheckExpected 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 OKThe image enforces these controls:
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. This VM's API key works as a bearer token instead.
HTTPS only. nginx terminates TLS with a per-VM certificate, and 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, so a small preload library (source in /usr/local/src/sac-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), or link-local, private (10/8, 172.16/12, 192.168/16, 100.64/10) or reserved networks. It also cannot reach anything on the loopback interface except the DNS resolver, the model server and its own ports.
nftables enforces this per user and systemd enforces it per service, independently of DB-GPT. 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, and 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. Only the dbgpt account and root may open the socket on 127.0.0.1:11434 that leads into it.
Secrets. The password, the 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. 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. nginx refuses to start until first boot has proven that sign-in and cross-site protection work.
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 following commands read the password from the credentials file and pass 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 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 sqliteAsk the sample database a question. DB-GPT answers as a stream of server-sent events. The last event 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 21Check 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|21Scripts 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 sqliteFrom 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/listWithout 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/listExpected output:
401Build 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, and 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. There you can upload PDF, Word, PowerPoint, Markdown and text files. Chat with it at https://<vm-ip>/chat?scene=chat_knowledge&select_param=handbook, and put your knowledge base's name after select_param=.
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 work as they are. Examples are an Azure Database for PostgreSQL or MySQL flexible server, or Azure SQL Database, reached through its public endpoint and firewall rules.
Databases on a private address are blocked by default, so nobody can point DB-GPT at your internal network unasked. Examples are a private endpoint, a database VM in the same or a peered VNet, or a database on this VM itself. Allow each one explicitly, by address and port:
sudo dbgpt-allow-network add 10.1.2.3:5432That 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 listExpected output (on a new VM):
(no private destinations allowed)sudo dbgpt-allow-network remove 10.1.2.3:5432Give DB-GPT a database account with read-only permissions on the data it should analyse. The model writes SQL from your question, and read-only access means a misunderstood question cannot change your data.
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. Edit /etc/dbgpt/dbgpt.toml (readable by root and the service only) and replace the [[models.llms]] block. Keep the local embedding model, because 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 with an 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 dbgptIf your provider endpoint has a private address, such as 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 the model. Add the model as another [[models.llms]] block with provider = "proxy/ollama" and api_base = "http://127.0.0.1:11434", then restart DB-GPT. Larger models need more memory.
Once you no longer use local models, free their memory with sudo systemctl disable --now ollama-proxy.socket ollama.
Back up and restore
All of DB-GPT's data lives under /var/lib/dbgpt. That covers data source definitions, conversations, knowledge bases and their vectors. 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.gzCopy the archive off the VM, for example to Azure Blob Storage.
To restore onto a new VM from this image, stop dbgpt and extract the archive over /, keeping /var/lib/dbgpt owned by dbgpt. Then start it again.
Logs and day-to-day operation
sudo journalctl -u dbgpt -n 20 --no-pagerUseful commands:
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
To see exactly what is installed and where it came from, read the provenance file:
cat /usr/share/dbgpt/PROVENANCESecurity hardening
- Restrict the source of port 443 in your network security group to the networks that need it. 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.txtif 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.confand runningsudo systemctl reload nginx. - Replace the self-signed certificate with your own. Put the certificate and key at
/etc/dbgpt/tls/dbgpt.crtand/etc/dbgpt/tls/dbgpt.key, and a copy of the certificate at/etc/ssl/certs/dbgpt-vm.crt. Then runsudo systemctl reload nginx. - DB-GPT's agents, skills and AWEL code operators can run Python code on the VM, as the unprivileged
dbgptaccount 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).
- Ubuntu security updates 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). Also check that 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. This is expected with the bundled CPU model. See the measurements under Prerequisites.
- A knowledge base answers "Collection ... does not exist." This happens after you delete a knowledge base and create 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
Originheader naming this VM (Step 8). Alternatively, use the API key. - The browser shows a certificate warning. This is 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, because 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
SecureAnyCloud provides 24/7 support for this image with a guaranteed 24-hour response. Contact sales@secureanycloud.com and include your VM's region and the output of sudo dbgpt-selfcheck.
Deploy on Azure
Launch DB-GPT on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.
View on Marketplace
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com