LightRAG on Ubuntu 24.04 on Azure User Guide
Overview
This guide covers the deployment and configuration of LightRAG on Ubuntu 24.04 on Azure using cloudimg Azure Marketplace images. LightRAG is a graph based retrieval augmented generation server from the HKU Data Intelligence Lab. You upload documents; LightRAG uses your chosen language model to extract the entities in them and the relationships between those entities into a knowledge graph, while embedding the text into a vector index. Questions are then answered from both at once, so answers are grounded in how the facts in your corpus connect rather than in isolated similar looking paragraphs.
The bundled web interface lets you upload and track documents, watch the indexing pipeline, explore the extracted knowledge graph visually, edit entities and relationships by hand, and query in naive, local, global, hybrid or mix retrieval modes. Everything is also available over a documented REST API, and the server additionally speaks the Ollama chat protocol so existing chat clients can point straight at it.
LightRAG is a front end to your models, not a model host. It calls an OpenAI compatible endpoint for generation and an embedding endpoint for indexing, so it runs comfortably on a small CPU only VM and needs no GPU. Point it at OpenAI, Azure OpenAI, Google Gemini, AWS Bedrock, Anthropic, or a private Ollama, vLLM, LM Studio or TGI server on your own network.
The cloudimg image ships the free and open source, MIT licensed LightRAG as the official upstream container pinned by image digest. No model provider key is ever baked into the image. Storage is deliberately file based — a JSON key/value store, a NetworkX graph and a NanoVectorDB vector index, all on your own VM — so there is no database server to secure, patch or licence. A unique 32 character access credential is generated for each VM on first boot, and the gateway in front of LightRAG will not start until first boot has proved that an unauthenticated request is answered with 401. Backed by 24/7 cloudimg support.
LightRAG is an independent open source project. This image is produced by cloudimg and is not affiliated with, endorsed by, or sponsored by the LightRAG team or the University of Hong Kong. It ships the free and open source MIT licensed software, unmodified.

What is included:
- LightRAG v1.5.4 (the MIT licensed upstream container
ghcr.io/hkuds/lightrag), pinned by image digest, not by a moving tag - Docker Engine and the Compose plugin from the official Docker APT repository
- An nginx access gateway on port
80, installed as a host package so unattended security upgrades keep the internet facing component patched - File based storage —
JsonKVStorage,JsonDocStatusStorage,NetworkXStorageandNanoVectorDBStorage— with no database server of any kind on the instance - A unique 32 character access credential, a unique API key and a unique token signing secret generated per VM on first boot, never baked into the image
- Fail closed guards: both the application service and the gateway refuse to start unless this VM's own credentials are in place, and the gateway additionally refuses to start until first boot has proved the gate denies
- LightRAG's own account authentication configured (it is optional upstream, and unconfigured it accepts every request), with the path whitelist narrowed so no model spending route is ever exempt
- The model provider keys shipped empty — you always supply your own
- A shipped dependency licence inventory at
/usr/share/lightrag/dependency-licences.txt - Ubuntu 24.04 LTS base with latest security patches applied at build time
- Azure Linux Agent for seamless cloud integration and SSH key injection
- 24/7 cloudimg support with guaranteed 24 hour response SLA
Prerequisites
- Active Azure subscription, SSH public key, VNet + subnet in target region
- Subscription to the LightRAG listing on Azure Marketplace
- A model provider LightRAG can reach. LightRAG needs two things from you: a chat/completions endpoint to extract the knowledge graph and write answers, and an embeddings endpoint to build the vector index. The image ships pre-filled for OpenAI with the key left empty, and carries commented examples for Azure OpenAI, Ollama and any OpenAI compatible server. cloudimg does not supply a key and never bundles one.
- Recommended size Standard_B2ms (2 vCPU / 8 GiB). LightRAG holds its knowledge graph and vector index in memory while serving and both grow with your corpus, so 8 GiB is comfortable where 4 GiB is tight. No GPU is required.
Step 1: Deploy from the Azure Portal
- In the Azure Portal, search the Marketplace for LightRAG by cloudimg and select Create.
- Choose your subscription, resource group and region, and set the VM name.
- Select size Standard_B2ms, authentication type SSH public key, and paste your key.
- Under Inbound port rules, allow SSH (22) and HTTP (80). Restrict the source of port 80 to your own network — see Security hardening below.
- Leave OS disk defaults, then Review + create.
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 create \
--resource-group my-resource-group \
--name my-lightrag-vm \
--image cloudimg:lightrag-ubuntu-24-04:default:latest \
--size Standard_B2ms \
--admin-username azureuser \
--ssh-key-values ~/.ssh/id_rsa.pub \
--public-ip-sku Standard \
--os-disk-delete-option Delete --nic-delete-option Delete
Then open port 80 to your own network only:
az network nsg rule create \
--resource-group my-resource-group \
--nsg-name my-lightrag-vmNSG \
--name allow-http-from-office \
--priority 1010 --access Allow --protocol Tcp \
--destination-port-ranges 80 --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
Four units make up the appliance: docker, lightrag-firstboot (which generates this VM's secrets and proves the gate on the very first boot), lightrag (the application container), and nginx (the access gateway).
sudo systemctl is-active docker.service lightrag-firstboot.service lightrag.service nginx.service
Expected output:
active
active
active
active
The application container itself is pinned by digest and published on the loopback address only:
sudo docker compose -f /var/lib/lightrag/docker-compose.yml ps

You can confirm the exact artifact this VM is running, and that it is the MIT licensed upstream release:
sudo docker image inspect $(sudo docker ps --format '{{.Image}}' | head -1) --format 'licence={{index .Config.Labels "org.opencontainers.image.licenses"}} version={{index .Config.Labels "org.opencontainers.image.version"}} source={{index .Config.Labels "org.opencontainers.image.source"}}'
Expected output:
licence=MIT version=v1.5.4 source=https://github.com/HKUDS/LightRAG
The licences of every Python dependency inside that image were scanned at build time and the inventory ships with the appliance:
sudo head -n 3 /usr/share/lightrag/dependency-licences.txt
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/lightrag-credentials.txt

The file gives you three values:
| Value | What it is for |
|---|---|
LIGHTRAG_USERNAME |
The account name for both the gateway and LightRAG's own sign in |
LIGHTRAG_PASSWORD |
The 32 character password for both |
LIGHTRAG_APIKEY |
A 32 character key for scripts. Sent as the X-API-Key header, it satisfies both layers in one header |
Step 6: Open the web interface
Browse to http://<vm-ip>/.
Your browser asks for a username and password first. That is the gateway, and it is what stops anyone who finds this address from spending your model provider credit. Enter the username and password from Step 5. The gateway then sets a cookie, so it only asks once.
LightRAG's own sign in page appears next. Enter the same username and password.

Once signed in you land on Document Management, which lists everything you have ingested and its indexing status.

Step 7: Understand the two layer access model
LightRAG's own account authentication is optional upstream, and it fails open: with no accounts configured the server accepts every request. Worse, its default path whitelist exempts /api/generate and /api/chat — the two routes that actually spend your model provider credit. This image closes that from both sides.
Layer one — the gateway. nginx owns port 80 and denies by default. It accepts a request only if it carries this VM's gate cookie, this VM's API key, or this VM's HTTP Basic credential. Prove it refuses an anonymous caller:
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1/
Expected output:
401
The same is true of the routes that would spend your credit:
curl -s -o /dev/null -w '%{http_code}\n' -X POST -H 'Content-Type: application/json' -d '{}' http://127.0.0.1/api/chat
Expected output:
401

A wrong password is refused too, not merely a missing one:
curl -s -o /dev/null -w '%{http_code}\n' -u '<LIGHTRAG_USERNAME>:definitely-not-the-password' http://127.0.0.1/
Expected output:
401
Layer two — LightRAG's own accounts. Getting past the gateway is not enough. An application route still needs an application credential:
curl -s -o /dev/null -w '%{http_code}\n' -u '<LIGHTRAG_USERNAME>:<LIGHTRAG_PASSWORD>' http://127.0.0.1/documents/pipeline_status
Expected output:
401
The API key satisfies both layers in a single header, which is what you use from scripts:
curl -s -H 'X-API-Key: <LIGHTRAG_APIKEY>' http://127.0.0.1/graph/label/list
The gateway cannot run ungated. nginx.service carries two ConditionPathExists directives — this VM's credential file, and a marker that first boot writes only after it has proved, against a throwaway internal listener, that the gate answers an unauthenticated request with 401. If that proof ever fails, first boot tears the stack down and deletes both files, so nginx can never start. You can see both conditions:
sudo systemctl cat nginx.service | grep ConditionPathExists
The application is never reachable directly — it is published on the loopback address only, so every request must pass the gateway:
sudo ss -lntH | awk '{print $4}' | sort -u
Step 8: Add your own model provider
LightRAG does not host a model. Until you give it a provider it can serve the interface and show you the appliance, but it cannot index a document or answer a question.
The configuration file is /var/lib/lightrag/lightrag.env. It ships pre-filled for OpenAI with both keys empty:
sudo grep -E '^(LLM_BINDING|LLM_MODEL|EMBEDDING_BINDING|EMBEDDING_MODEL|EMBEDDING_DIM)=' /var/lib/lightrag/lightrag.env
Edit the file and set your own keys — this step is yours to perform and is not executed by the walk through:
sudo nano /var/lib/lightrag/lightrag.env
Set LLM_BINDING_API_KEY= and EMBEDDING_BINDING_API_KEY= to your own key, then restart and wait for the service to come back:
sudo systemctl restart lightrag.service
for i in $(seq 1 30); do
[ "$(curl -s -o /dev/null -w '%{http_code}' --max-time 5 -H 'X-API-Key: <LIGHTRAG_APIKEY>' http://127.0.0.1/health)" = "200" ] && break
sleep 2
done
sudo systemctl is-active lightrag.service
The file carries commented blocks for the common alternatives:
- Azure OpenAI — set
LLM_BINDING=azure_openai,LLM_BINDING_HOST=https://<your-resource>.openai.azure.com/, and use your deployment names forLLM_MODELandEMBEDDING_MODEL. - Ollama on this VM or your network — set
LLM_BINDING=ollamaandLLM_BINDING_HOST=http://host.docker.internal:11434. The container is already configured to reach the VM's own host address. - Any OpenAI compatible server (vLLM, LM Studio, TGI, OpenRouter, Together) — keep
LLM_BINDING=openaiand pointLLM_BINDING_HOSTat its/v1URL.
Your key stays on this VM. cloudimg never ships a model provider credential, and the image is built and tested with both key fields empty.
Step 9: Ingest a document and query it
Upload through the web interface with Documents → Upload, or over the API. Indexing is asynchronous: LightRAG chunks the document, asks your model to extract entities and relationships, embeds the passages, and merges the result into the knowledge graph.
Watch the pipeline:
curl -s -H 'X-API-Key: <LIGHTRAG_APIKEY>' http://127.0.0.1/documents/pipeline_status | head -c 300
List the entities currently in the knowledge graph:
curl -s -H 'X-API-Key: <LIGHTRAG_APIKEY>' http://127.0.0.1/graph/label/list
The Knowledge Graph tab draws what was extracted. Entities are nodes and the relationships your model found between them are edges; click any node to inspect or edit its description.

Ask a question from the Retrieval tab, or over the API. mode selects how much of the graph is used: naive is plain vector search, local and global walk the graph from different directions, hybrid combines them and mix uses everything.

Note that LightRAG refuses to ingest the same file name twice — delete the existing record first if you want to re-index a changed document.
Step 10: Where your data lives
Storage is file based by design. There is no database server on this instance, so there is nothing extra to secure, patch or licence.
sudo ls -la /var/lib/lightrag/data/rag_storage/
| File pattern | What it holds | Backend |
|---|---|---|
graph_*.graphml |
The entity and relationship graph | NetworkX (BSD-3-Clause) |
vdb_*.json |
The vector indexes for entities, relations and chunks | NanoVectorDB (MIT) |
kv_store_*.json |
Documents, chunk text and indexing status | JSON key/value store |
Your uploaded originals live alongside them in /var/lib/lightrag/data/inputs. Both directories are 0700 root:root, and the gateway serves no file from disk at all — it only proxies to the application — so nothing you ingest is reachable over HTTP except through LightRAG's own authenticated API.
sudo stat -c '%n %a %U:%G' /var/lib/lightrag/data /var/lib/lightrag/data/inputs /var/lib/lightrag/data/rag_storage
Expected output:
/var/lib/lightrag/data 700 root:root
/var/lib/lightrag/data/inputs 700 root:root
/var/lib/lightrag/data/rag_storage 700 root:root
Backing up that one directory backs up your entire knowledge base:
sudo tar czf /var/backups/lightrag-kb-$(date +%Y%m%d).tar.gz -C /var/lib/lightrag data
Step 11: Day to day operation
sudo systemctl restart lightrag.service
sudo docker compose -f /var/lib/lightrag/docker-compose.yml logs --tail 20
Configuration changes always take a service restart, because the file is mounted read only into the container.
Security hardening
- Restrict port 80 in the network security group to the networks that need it. The gateway is strong, but there is no reason to expose it to the whole internet.
- Put TLS in front before exposing the instance beyond your own network. Terminate on an Azure Application Gateway, an Azure Front Door, or a reverse proxy of your own, and forward to port 80 on this VM.
- The gate cookie is deliberately not marked
Secure, because the appliance is reached overhttp://on a VM IP by default and browsers refuse to store aSecurecookie over plain HTTP. Once you have TLS in front you may add that attribute yourself. - Rotate the credentials by editing
/etc/nginx/lightrag.htpasswd(withhtpasswd -B), the matching entries in/etc/nginx/conf.d/lightrag-gate-map.conf, andAUTH_ACCOUNTS/LIGHTRAG_API_KEYin/var/lib/lightrag/lightrag.env. - Do not widen
WHITELIST_PATHS. It is deliberately narrowed to/health. LightRAG's upstream default also exempts/api/*, which would leave the model spending routes unauthenticated. - Unattended security upgrades are enabled and keep the gateway and the base OS patched.
Troubleshooting
The web interface asks for a password twice. That is expected and correct — the gateway asks once, then LightRAG's own sign in asks once. Both take the same username and password. The gateway's cookie means it will not ask again.
Indexing never completes. LightRAG needs a working model provider. Check the container log for provider errors:
sudo docker compose -f /var/lib/lightrag/docker-compose.yml logs --tail 30
Confirm your keys are set and the endpoint is reachable from the VM. An empty LLM_BINDING_API_KEY is the shipped state and will fail every extraction.
The gateway will not start. It is fail closed by design. Check the guard's own reason:
sudo /usr/local/sbin/lightrag-preflight.sh --nginx || true
A query returns "no context". Nothing in the knowledge base matched. Confirm a document finished indexing (Completed in the Documents tab) and that entities exist via /graph/label/list.
Support
cloudimg provides 24/7 support with a guaranteed 24 hour response SLA for this image. Contact support through the Azure Marketplace listing.
LightRAG itself is an independent open source project licensed under the MIT licence. Questions about the software's own behaviour are best raised with the upstream project; questions about the image, its packaging, its security model or its operation on Azure are ours.