Dgraph
Overview
This guide shows you how to deploy and use the SecureAnyCloud Dgraph 25.5.1 image on Microsoft Azure. Dgraph is a distributed, horizontally scalable, native graph database. It stores data as nodes and typed edges, and it answers deep graph traversals plus full-text, regular-expression, geo and vector-indexed queries.
Dgraph speaks two query languages: DQL (Dgraph Query Language) over HTTP and gRPC, and GraphQL, generated from a schema you upload. One dgraph binary runs two services. Zero coordinates the cluster, and Alpha stores the data and serves queries. Dgraph is licensed under the Apache License, Version 2.0. Since version 25, its access control lists (ACL), multi-tenancy, backup and restore features are open source too.
What you get:
- No default login. Dgraph ACL is switched on. On first boot, the image generates a unique 32-character password for the
grootadministrator. It also generates a unique 256-bit key that signs Dgraph's access tokens. Dgraph's documented default (groot/password) is changed before the API is reachable from the network, and it is refused from then on. Dgraph reads the key from a file, never from a command line. - Nothing runs without a login. Dgraph runs with
anonymous=none. A caller who has not logged in may call only/loginand/health. Every query, mutation, schema change, GraphQL request and admin call needs an access token. - HTTPS from first boot. nginx serves the Dgraph HTTP and GraphQL APIs on port 443 with a certificate generated on the VM for its own address. Port 80 only redirects to HTTPS, and requests for any other hostname are dropped.
- Loopback-only Dgraph ports. Zero (5080, 6080) and Alpha (7080, 8080, 9080) listen on
127.0.0.1. Only SSH, 80 and 443 are reachable. nginx publishes only the API paths, so Dgraph's/debugprofiling endpoints and Zero's admin endpoints are never exposed. - Sandboxed services. Zero and Alpha run as an unprivileged
dgraphuser in a systemd sandbox. The sandbox can write only/var/lib/dgraph. It cannot read system secrets such as/etc/shadow, the credentials file or the TLS key. It also cannot reach the Azure Instance Metadata Service or the Azure wire server. Exports and backups can therefore be written only under/var/lib/dgraph. - A fully patched Ubuntu 24.04 base at build time, with per-VM secrets and the SecureAnyCloud security defaults.
The image contains Ubuntu 24.04 LTS, Dgraph 25.5.1 (the official release binary, checksum-verified) in /opt/dgraph, nginx, and the SecureAnyCloud first-boot service. All Dgraph data lives on a dedicated 30 GiB data disk at /var/lib/dgraph. First boot also loads a tiny demo graph of three Person nodes joined by friend edges, so your first query returns data. A swap file is created on each boot on the VM's temporary resource disk (/mnt), never on the OS disk.
Coming from the earlier image? Earlier versions of this offer (Dgraph 25.3.8) used nginx basic authentication and an admin token. If your VM has /root/dgraph-info.txt instead of /root/dgraph-credentials.txt, it was deployed from that image. Its basic authentication user, password and admin token are in that file. Such a VM keeps its design until you replace it. To migrate, deploy a new VM from this image, export your data from the old VM and import it into the new one.
Prerequisites
- An Azure subscription and permission to create virtual machines.
- An SSH key pair.
- A network security group that allows TCP 22 from your own address. It must also allow TCP 443 from the clients that will use the API, and optionally TCP 80, which only redirects. Ports 5080, 6080, 7080, 8080 and 9080 are never exposed because Dgraph listens on them only on loopback.
Recommended VM size: Standard_B2s (2 vCPU, 4 GiB) for evaluation and small graphs. Use Standard_D4s_v5 or larger for production. Dgraph Alpha keeps hot data in memory, so choose more memory for bigger graphs. Resize the data disk to suit your dataset.
Deploy from the Azure Portal
Search the Azure Marketplace for Dgraph on Ubuntu 24.04 and choose Create. Pick your VM size and SSH key.
Attach a network security group that allows TCP 22 from your management network. Allow TCP 443 from the networks and applications that will query Dgraph. Port 80 only issues an HTTPS redirect.
Azure creates the data disk from the image automatically. First boot takes about a minute after the VM is reachable. During that time it generates this VM's certificate, signing key and groot password, and it loads the demo graph.
Deploy from the Azure CLI
Run these commands on your own workstation:
RG="dgraph-prod"; LOCATION="eastus"; VM_NAME="dgraph-01" IMAGE_URN="sac1647283583153:dgraph-ubuntu-24-04:default:latest" SSH_KEY="$(cat ~/.ssh/id_rsa.pub)" az group create --name "$RG" --location "$LOCATION" az network vnet create -g "$RG" --name dgraph-vnet --address-prefix 10.90.0.0/16 --subnet-name dgraph-subnet --subnet-prefix 10.90.1.0/24 az network nsg create -g "$RG" --name dgraph-nsg az network nsg rule create -g "$RG" --nsg-name dgraph-nsg --name allow-ssh --priority 100 \
--source-address-prefixes "<your-mgmt-cidr>" --destination-port-ranges 22 --access Allow --protocol Tcp az network nsg rule create -g "$RG" --nsg-name dgraph-nsg --name allow-https --priority 110 \
--source-address-prefixes "<your-mgmt-cidr>" --destination-port-ranges 443 --access Allow --protocol Tcp
# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn "$IMAGE_URN"
az vm create -g "$RG" --name "$VM_NAME" --image "$IMAGE_URN" \
--size Standard_B2s \
--admin-username azureuser --ssh-key-values "$SSH_KEY" \
--vnet-name dgraph-vnet --subnet dgraph-subnet --nsg dgraph-nsg --public-ip-sku StandardConnect via SSH
ssh azureuser@<vm-ip>The login banner shows the API and GraphQL URLs for this VM.
Check the services and health
Confirm that Zero, Alpha and nginx are running and that first boot has finished. Confirm that the health endpoint answers over HTTPS and that the installed version is 25.5.1:
systemctl is-active dgraph-zero.service dgraph-alpha.service nginx.service test -f /var/lib/sac/data/dgraph-firstboot.done && echo first-boot-done curl -sk -o /dev/null -w 'healthz: HTTP %{http_code}\n' https://localhost/healthz /opt/dgraph/bin/dgraph version 2>/dev/null | grep -E 'Dgraph version|Go version'All three services report active, and the first-boot marker is present. /healthz returns HTTP 200, and the binary reports v25.5.1 built with go1.27.3.
Every Dgraph port is on loopback, and nginx owns the public ports:
sudo ss -tlnp | grep -E ':(5080|6080|7080|8080|9080|80|443) 'The output shows dgraph on 127.0.0.1 ports 5080 and 6080 (Zero) and 7080, 8080 and 9080 (Alpha). It shows nginx on ports 80 and 443.
Read the per-VM credentials
The groot password is unique to this VM. First boot writes it to a root-only file. Print only the field names, never the password itself:
sudo stat -c '%a %U:%G %n' /root/dgraph-credentials.txt
sudo grep -oE '^[A-Z_]+=' /root/dgraph-credentials.txtThe file is mode 600 and owned by root. It holds DGRAPH_HOST, DGRAPH_URL, DGRAPH_GRAPHQL_URL, DGRAPH_ADMIN_URL, DGRAPH_GROOT_USER (groot) and DGRAPH_GROOT_PASSWORD.
Read the password with sudo sed -n 's/^DGRAPH_GROOT_PASSWORD=//p' /root/dgraph-credentials.txt when you need it. Keep it safe, because groot is the Dgraph administrator (a member of the guardians group). Dgraph stores only a bcrypt hash of the password.
The authentication gate
Dgraph answers a refused request with HTTP 200 and an errors body, so read the message. A query without a token is refused. A wrong password and Dgraph's documented default password are refused too:
curl -sk -H 'Content-Type: application/dql' -X POST https://localhost/query \
-d '{ q(func: has(name)) { uid } }' | grep -o 'requires an identified caller' printf '{"userid":"groot","password":"%s"}' 'wrong-password' | curl -sk -X POST --data-binary @- https://localhost/login | grep -o 'invalid username or password' printf '{"userid":"groot","password":"%s"}' 'password' | curl -sk -X POST --data-binary @- https://localhost/login | grep -o 'invalid username or password'Each line prints the refusal. Now log in with the per-VM password to get an access token. The password is sent on standard input, so it never appears in the process list or your shell history:
PW=$(sudo sed -n 's/^DGRAPH_GROOT_PASSWORD=//p' /root/dgraph-credentials.txt)
JWT=$(printf '{"userid":"groot","password":"%s"}' "$PW" | curl -sk -X POST --data-binary @- https://localhost/login \
| sed -n 's/.*"accessJWT":"\([^"]*\)".*/\1/p')
echo "access token received: ${#JWT} characters"Send the token as the X-Dgraph-AccessToken header on every call. Access tokens last 6 hours. The /login response also carries a refreshJWT, which you can exchange for a new access token.
Query the demo graph with DQL
PW=$(sudo sed -n 's/^DGRAPH_GROOT_PASSWORD=//p' /root/dgraph-credentials.txt)
JWT=$(printf '{"userid":"groot","password":"%s"}' "$PW" | curl -sk -X POST --data-binary @- https://localhost/login \
| sed -n 's/.*"accessJWT":"\([^"]*\)".*/\1/p')
curl -sk -H "X-Dgraph-AccessToken: $JWT" -H 'Content-Type: application/dql' -X POST https://localhost/query \
-d '{ people(func: type(Person), orderasc: name) { name age friend { name } } }' \
| python3 -c 'import json,sys; print(json.dumps(json.load(sys.stdin)["data"], indent=1))'The answer lists Alice (31), Bob (27) and Carol (35). Each entry includes the friend that its friend edge points to.
Write your own data
Add to the schema, write nodes with an RDF mutation, and query them back. /alter changes the schema, and /mutate?commitNow=true writes and commits in one call:
PW=$(sudo sed -n 's/^DGRAPH_GROOT_PASSWORD=//p' /root/dgraph-credentials.txt)
JWT=$(printf '{"userid":"groot","password":"%s"}' "$PW" | curl -sk -X POST --data-binary @- https://localhost/login \
| sed -n 's/.*"accessJWT":"\([^"]*\)".*/\1/p')
curl -sk -H "X-Dgraph-AccessToken: $JWT" -X POST https://localhost/alter \
-d 'title: string @index(term) . directed_by: [uid] .'; echo
curl -sk -H "X-Dgraph-AccessToken: $JWT" -H 'Content-Type: application/rdf' -X POST 'https://localhost/mutate?commitNow=true' \
-d '{ set { _:film <title> "The Graph Story" . _:film <directed_by> _:director . _:director <name> "Dana Director" . } }' | grep -o '"code":"Success"'
curl -sk -H "X-Dgraph-AccessToken: $JWT" -H 'Content-Type: application/dql' -X POST https://localhost/query \
-d '{ films(func: anyofterms(title, "graph")) { title directed_by { name } } }' \
| python3 -c 'import json,sys; print(json.dumps(json.load(sys.stdin)["data"], indent=1))'The schema change returns "code":"Success", and the mutation commits. The query finds the film by a word in its title and follows the directed_by edge to its director.
GraphQL
Dgraph generates a complete GraphQL API from a GraphQL schema. Upload a schema to /admin/schema. Then query and mutate at /graphql with the same access token:
PW=$(sudo sed -n 's/^DGRAPH_GROOT_PASSWORD=//p' /root/dgraph-credentials.txt)
JWT=$(printf '{"userid":"groot","password":"%s"}' "$PW" | curl -sk -X POST --data-binary @- https://localhost/login \
| sed -n 's/.*"accessJWT":"\([^"]*\)".*/\1/p')
curl -sk -H "X-Dgraph-AccessToken: $JWT" -X POST https://localhost/admin/schema \
--data-binary 'type Task { id: ID! title: String! @search(by: [term]) done: Boolean }' | grep -o '"code":"Success"' sleep 3
curl -sk -H "X-Dgraph-AccessToken: $JWT" -H 'Content-Type: application/json' -X POST https://localhost/graphql \
-d '{"query":"mutation { addTask(input: [{title: \"Try Dgraph GraphQL\", done: false}]) { task { title done } } }"}'; echo
curl -sk -H "X-Dgraph-AccessToken: $JWT" -H 'Content-Type: application/json' -X POST https://localhost/graphql \
-d '{"query":"{ queryTask { title done } }"}'; echoThe schema upload returns "code":"Success". The mutation and the query both return the Try Dgraph GraphQL task. GraphQL subscriptions work over WebSocket at the same /graphql path for same-origin clients.
Query from your workstation
From your own machine, call https://<vm-ip>/. Open TCP 443 to your address in the network security group first.
The certificate is self-signed and unique to this VM. Either pass -k, or copy /etc/ssl/dgraph/dgraph.crt to your workstation and trust it with --cacert. Log in first, then send the token:
read -rs -p 'groot password: ' PW; echo
JWT=$(printf '{"userid":"groot","password":"%s"}' "$PW" | curl -sk -X POST --data-binary @- https://<vm-ip>/login \
| sed -n 's/.*"accessJWT":"\([^"]*\)".*/\1/p')
curl -sk -H "X-Dgraph-AccessToken: $JWT" -H 'Content-Type: application/dql' -X POST https://<vm-ip>/query \
-d '{ people(func: type(Person)) { name } }'The gRPC port (9080) used by the official clients (dgo, pydgraph and dgraph-js) stays on loopback. Reach it, and Alpha's HTTP port, through an SSH tunnel from your workstation:
ssh -N -L 9080:127.0.0.1:9080 -L 8080:127.0.0.1:8080 azureuser@<vm-ip>Point a client at localhost:9080 and log in as groot with the per-VM password. ACL applies on gRPC too.
Dgraph's Ratel query UI is a separate project and is not installed. If you run Ratel on your workstation, connect it to http://localhost:8080 through the same tunnel.
Where things live
These are the locations of the main components. Each line gives the component, then its path or command.
Dgraph binary (read-only, root-owned): /opt/dgraph/bin/dgraph
Units: dgraph-zero.service and dgraph-alpha.service, in /etc/systemd/system/
ACL signing key (per VM, mode 0640, owned by root:dgraph): /etc/dgraph/acl-secret
Data disk: /var/lib/dgraph
Zero write-ahead log: /var/lib/dgraph/zw
Alpha postings, write-ahead log and temporary files: /var/lib/dgraph/p, /var/lib/dgraph/w and /var/lib/dgraph/t
Exports: /var/lib/dgraph/export
Logs: journalctl -u dgraph-alpha -u dgraph-zero
Credentials file (mode 0600): /root/dgraph-credentials.txt
Per-VM certificate: /etc/ssl/dgraph/
nginx site: /etc/nginx/sites-available/sac-dgraph
License: /usr/share/doc/dgraph/LICENSE.txt
The data disk is mounted by filesystem UUID:
findmnt /var/lib/dgraph df -h /var/lib/dgraphTo change a Dgraph flag (for example Alpha's cache size), run sudo systemctl edit dgraph-alpha.service. Override ExecStart= and restart the service.
Keep --bindall=false, --acl "secret-file=/etc/dgraph/acl-secret" and --security "whitelist=127.0.0.1; anonymous=none" in place. They keep Dgraph on loopback with ACL enforced.
Exports and backups
Export the whole database as RDF (or json) into /var/lib/dgraph/export:
PW=$(sudo sed -n 's/^DGRAPH_GROOT_PASSWORD=//p' /root/dgraph-credentials.txt)
JWT=$(printf '{"userid":"groot","password":"%s"}' "$PW" | curl -sk -X POST --data-binary @- https://localhost/login \
| sed -n 's/.*"accessJWT":"\([^"]*\)".*/\1/p')
curl -sk -H "X-Dgraph-AccessToken: $JWT" -H 'Content-Type: application/json' -X POST https://localhost/admin \
-d '{"query":"mutation { export(input: {format: \"rdf\"}) { response { code message } } }"}'; echo
sudo ls /var/lib/dgraph/exportThe call returns "code":"Success", and a dgraph.r... directory appears with the RDF and schema files. Copy exports off the VM, for example to Azure Blob Storage.
Take Azure snapshots of the /var/lib/dgraph data disk for point-in-time backups. Dgraph's backup mutation (full and incremental binary backups) also writes only under /var/lib/dgraph on this image, or to an S3-compatible or MinIO destination that you configure.
Create an application user
Use a dedicated user with only the permissions it needs instead of groot. Create a user and a group, and give the group read access to the name predicate. Replace the password with a strong one of your own:
PW=$(sudo sed -n 's/^DGRAPH_GROOT_PASSWORD=//p' /root/dgraph-credentials.txt)
JWT=$(printf '{"userid":"groot","password":"%s"}' "$PW" | curl -sk -X POST --data-binary @- https://localhost/login \
| sed -n 's/.*"accessJWT":"\([^"]*\)".*/\1/p')
curl -sk -H "X-Dgraph-AccessToken: $JWT" -H 'Content-Type: application/json' -X POST https://localhost/admin \
-d '{"query":"mutation { addGroup(input: [{name: \"readers\", rules: [{predicate: \"name\", permission: 4}]}]) { group { name } } }"}'; echo
curl -sk -H "X-Dgraph-AccessToken: $JWT" -H 'Content-Type: application/json' -X POST https://localhost/admin \
-d '{"query":"mutation { addUser(input: [{name: \"app\", password: \"your-strong-password\", groups: [{name: \"readers\"}]}]) { user { name } } }"}'; echoPermission 4 is read, 2 is write and 1 is modify (schema). Add the values together for combined rights.
Change the groot password
Rotate the administrator password whenever you need to. The command generates a new random password and updates the credentials file. It sends the password to Dgraph in a request body written to a root-only file in memory, never on a command line:
PW=$(sudo sed -n 's/^DGRAPH_GROOT_PASSWORD=//p' /root/dgraph-credentials.txt)
JWT=$(printf '{"userid":"groot","password":"%s"}' "$PW" | curl -sk -X POST --data-binary @- https://localhost/login \
| sed -n 's/.*"accessJWT":"\([^"]*\)".*/\1/p')
NEW=$(head -c 600 /dev/urandom | LC_ALL=C tr -dc 'A-Za-z0-9' | head -c 32)
REQ=$(mktemp -p /dev/shm); chmod 600 "$REQ" printf '{"query":"mutation { updateUser(input: {filter: {name: {eq: \\"groot\\"}}, set: {password: \\"%s\\"}}) { user { name } } }"}' "$NEW" > "$REQ" curl -sk -H "X-Dgraph-AccessToken: $JWT" -H 'Content-Type: application/json' -X POST --data-binary @"$REQ" https://localhost/admin; echo shred -u "$REQ" printf 'DGRAPH_GROOT_PASSWORD=%s\n' "$NEW" | sudo sh -c 'C=/root/dgraph-credentials.txt; { grep -v "^DGRAPH_GROOT_PASSWORD=" "$C"; cat; } > "$C.new" && chmod 600 "$C.new" && mv -f "$C.new" "$C"' printf '{"userid":"groot","password":"%s"}' "$PW" | curl -sk -X POST --data-binary @- https://localhost/login | grep -o 'invalid username or password' unset PW NEW JWTDgraph answers {"data":{"updateUser":{"user":[{"name":"groot"}]}}}. The credentials file now holds the new password, and the old password is refused. Access tokens issued before the change stay valid until they expire.
Serve under your own DNS name
Point a DNS record at the VM, for example an Azure DNS A record or the VM's public IP DNS label. Then regenerate the certificate and pin the served hostname:
sudo dgraph-set-hostname dgraph.example.comThis issues a new self-signed certificate for that name and makes nginx answer only for it. For production, replace it with your own CA-issued certificate.
For a public, browser-trusted certificate, you can also terminate TLS at Azure Application Gateway or Azure Front Door in front of the VM. Then open port 443 only to that front end.
Security notes
Dgraph 25.5.1 is the latest release at the time of writing. It includes the fix for the unauthenticated Zero admin endpoint advisory (GHSA-qj98-gp63-54xj) and every earlier Dgraph security fix. On top of that, this image hardens the deployment in these ways:
- It switches on Dgraph ACL with a per-VM signing key and groot password, and it sets
anonymous=none. Nothing except/loginand/healthworks without a token. - It keeps every Dgraph port on loopback and publishes only the API paths through nginx.
/debugreturns 403, and Zero's admin endpoints (/state,/removeNode,/assignand/moveTablet) are never exposed. - It runs Zero and Alpha as an unprivileged user in a systemd sandbox. They can write only
/var/lib/dgraph. They cannot see/root,/etc/shadow,/etc/ssh, the Azure agent's state, the credentials file or the TLS key. - It blocks the Azure Instance Metadata Service (169.254.169.254) and the Azure wire server (168.63.129.16) for Zero, Alpha, nginx and the first-boot service. A URL in a GraphQL
@customresolver, a lambda URL or a backup destination can therefore never reach the VM's managed identity tokens or agent channel. The Azure VM agent and cloud-init keep their normal access. - It refuses cross-origin state-changing requests and WebSocket upgrades at nginx, and it logs the real client address.
The debug and Zero endpoints are not published, and the metadata block is part of each service's unit:
curl -sk -o /dev/null -w 'debug endpoint via nginx: HTTP %{http_code}\n' https://localhost/debug/vars
curl -sk -o /dev/null -w 'zero removeNode via nginx: HTTP %{http_code}\n' https://localhost/removeNode systemctl show -p IPAddressDeny dgraph-zero.service dgraph-alpha.service nginx.servicenginx answers HTTP 403 and HTTP 404. All three units deny 169.254.169.254 and 168.63.129.16, plus their IPv6 and IPv4-mapped forms.
The sandbox refuses an export into a system directory:
PW=$(sudo sed -n 's/^DGRAPH_GROOT_PASSWORD=//p' /root/dgraph-credentials.txt)
JWT=$(printf '{"userid":"groot","password":"%s"}' "$PW" | curl -sk -X POST --data-binary @- https://localhost/login \
| sed -n 's/.*"accessJWT":"\([^"]*\)".*/\1/p')
curl -sk -H "X-Dgraph-AccessToken: $JWT" -H 'Content-Type: application/json' -X POST https://localhost/admin \
-d '{"query":"mutation { export(input: {format: \"rdf\", destination: \"/root/stolen\"}) { response { code } } }"}' \
| grep -o 'resolving export failed because task failed'
sudo test -e /root/stolen || echo 'nothing was written to /root'Dgraph reports that the export task failed and nothing is written.
Keep the VM patched with sudo apt-get update && sudo apt-get upgrade. Unattended security upgrades are enabled. Keep the groot password safe, and export or snapshot /var/lib/dgraph regularly. Expose only ports 22 and 443, and only to the networks that need them.
Support
Every SecureAnyCloud deployment includes 24/7 support with a 24-hour response SLA. Contact sales@secureanycloud.com for help with deployment, configuration or scaling.
This is a repackaged open-source software product with additional charges for SecureAnyCloud support services. Dgraph is a trademark of its respective owner. All product and company names are trademarks or registered trademarks of their respective holders. Use of them does not imply any affiliation with or endorsement by them.
Deploy on Azure
Launch Dgraph on Ubuntu 24.04 LTS on Azure, with 24/7 support from SecureAnyCloud.
View this image
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com
This guide shows you how to deploy and use the SecureAnyCloud Dgraph AMI from AWS Marketplace. Dgraph is a distributed, open-source graph database written in Go. It stores data as a graph of nodes and typed relationships. It answers deeply joined traversals plus full-text, geo and regular-expression queries through its own DQL query language and a native GraphQL API, over HTTP and gRPC.
The SecureAnyCloud image runs Dgraph as two coordinated systemd services from a single binary: a cluster coordinator (dgraph-zero) and a data node (dgraph-alpha). Both sit behind an nginx TLS reverse proxy on port 443. Open-source Dgraph ships with no built-in access control, so this image never exposes an open database. Every instance generates a unique HTTP password and a unique admin token on first boot, and the database ports bind to loopback only.
Connecting to your instance
Connect over SSH with the key pair you selected at launch. The login user depends on the OS variant you subscribed to. For Ubuntu 24.04, the SSH login user is ubuntu.
ssh -i /path/to/your-key.pem ubuntu@<public-ip>Retrieve your per-instance credentials
On first boot, the instance generates its own nginx HTTP basic-auth username and password. It also generates its own Dgraph admin security token. Both are written to a root-only file. Read them with:
sudo cat /root/dgraph-info.txtThe file looks like this. The values are unique to your instance:
DGRAPH_HTTP_USER=dgraph_ab12cd DGRAPH_HTTP_PASSWORD=<64-hex-characters> DGRAPH_SECURITY_TOKEN=<64-hex-characters> DGRAPH_URL=https://203.0.113.24/ DGRAPH_HEALTH_URL=https://203.0.113.24/healthDGRAPH_HTTP_USER/DGRAPH_HTTP_PASSWORD: the nginx HTTP basic-auth credentials. Every request to the HTTP API needs them.DGRAPH_SECURITY_TOKEN: required, in addition to basic-auth, for any administrative operation. Administrative operations include altering the schema,/admin, export and backup. Send the token in theX-Dgraph-AuthTokenheader.
The TLS certificate is self-signed per instance, so the examples below use curl -k. For production, front the instance with your own domain and a CA-signed certificate.
Check the service health
Confirm that the two Dgraph services and nginx are running and that the endpoints respond. The unauthenticated /healthz probe is a static nginx response for load balancers. The Dgraph /health endpoint is behind basic-auth.
systemctl is-active dgraph-zero dgraph-alpha nginx echo "--- static LB probe (no auth) ---" curl -ks -o /dev/null -w '/healthz -> %{http_code}\n' https://127.0.0.1/healthz echo "--- Dgraph /health requires basic-auth ---" curl -ks -o /dev/null -w '/health without auth -> %{http_code} (expect 401)\n' https://127.0.0.1/health
U=$(sudo grep '^DGRAPH_HTTP_USER=' /root/dgraph-info.txt | cut -d= -f2-)
P=$(sudo grep '^DGRAPH_HTTP_PASSWORD=' /root/dgraph-info.txt | cut -d= -f2-)
curl -ks -o /dev/null -w '/health with auth -> %{http_code} (expect 200)\n' -u "$U:$P" https://127.0.0.1/healthThe expected output resembles this:
active active active --- static LB probe (no auth) --- /healthz -> 200 --- Dgraph /health requires basic-auth --- /health without auth -> 401 (expect 401) /health with auth -> 200 (expect 200)Run your first query
This example sets a schema, inserts a node and queries it back, which is a complete graph round trip. Setting the schema is an administrative operation, so the request carries the X-Dgraph-AuthToken header in addition to basic-auth. Mutations and queries need basic-auth only.
U=$(sudo grep '^DGRAPH_HTTP_USER=' /root/dgraph-info.txt | cut -d= -f2-)
P=$(sudo grep '^DGRAPH_HTTP_PASSWORD=' /root/dgraph-info.txt | cut -d= -f2-)
T=$(sudo grep '^DGRAPH_SECURITY_TOKEN=' /root/dgraph-info.txt | cut -d= -f2-) BASE=https://127.0.0.1 echo "1) set the schema (admin op: basic-auth + token)" curl -ks -u "$U:$P" -H "X-Dgraph-AuthToken: $T" -X POST $BASE/alter -d 'name: string @index(exact) .' echo echo "2) insert a node (RDF mutation)" curl -ks -u "$U:$P" -H 'Content-Type: application/rdf' -X POST "$BASE/mutate?commitNow=true" \
-d '{ set { _:city <name> "Reykjavik" . } }' echo echo "3) query it back (DQL)" curl -ks -u "$U:$P" -H 'Content-Type: application/dql' -X POST $BASE/query \
-d '{ q(func: eq(name, "Reykjavik")) { name } }' echoThe query returns the node you just inserted:
1) set the schema (admin op: basic-auth + token) {"data":{"code":"Success","message":"Done"}} 2) insert a node (RDF mutation) {"data":{"code":"Success","message":"Done","uids":{"city":"0x4e21"}},...} 3) query it back (DQL) {"data":{"q":[{"name":"Reykjavik"}]},...}To reach the API from your own machine, use the instance public IP and the same credentials. The certificate is self-signed, so keep -k or trust the certificate:
curl -k -u USER:PASS -H 'Content-Type: application/dql' -X POST https://<public-ip>/query \
-d '{ q(func: has(name)) { name } }'Dgraph also serves a native GraphQL API at /graphql, with the admin surface at /admin. Both are reached through the same authenticated proxy.
Security model
The image is hardened so the database is never open:
- nginx HTTP basic-auth gates every request to the HTTP API. Without the per-instance username and password, the API returns
401. - A per-instance admin token is required for every administrative operation. A request that authenticates with basic-auth but omits the
X-Dgraph-AuthTokenheader is refused for administrative operations. - Loopback binding.
dgraph-zeroanddgraph-alphastart with--bindall=false, so ports 5080, 6080, 7080, 8080 and 9080 listen on127.0.0.1only. nginx on port 443 is the sole network-facing surface, and/debug/is blocked.
Confirm that both layers are enforced:
echo "admin op with NO basic-auth is rejected:" curl -ks -o /dev/null -w ' POST /alter (no auth) -> %{http_code} (expect 401)\n' -X POST https://127.0.0.1/alter -d 'x: string .'
U=$(sudo grep '^DGRAPH_HTTP_USER=' /root/dgraph-info.txt | cut -d= -f2-)
P=$(sudo grep '^DGRAPH_HTTP_PASSWORD=' /root/dgraph-info.txt | cut -d= -f2-)
echo "admin op authenticated but WITHOUT the token is rejected:" curl -ks -u "$U:$P" -X POST https://127.0.0.1/alter -d 'y: string .' | grep -o 'No Auth Token found' || echo " (token missing -> refused)"The default security group opens only ports 22, 80 and 443. Restrict port 443 ingress to trusted networks. Enable EBS encryption on the data volume at launch for encryption at rest.
Dedicated data volume
All Dgraph state lives on a dedicated EBS volume mounted at /var/lib/dgraph. That state includes the Zero raft write-ahead log and the Alpha postings, WAL and temp directories. The volume is separate from the OS root volume, so you can resize or snapshot it independently.
findmnt -no SOURCE,TARGET,FSTYPE,SIZE /var/lib/dgraphThe mount is pinned by filesystem UUID in /etc/fstab, so it survives reboots and relaunches. To grow storage, expand the EBS volume in the AWS console. Then extend the filesystem with resize2fs.
Rotating the credentials
To regenerate the per-instance HTTP password, admin token and TLS certificate, remove the first-boot sentinel and re-run the first-boot service. This changes the running instance, so run it only when you intend to rotate:
sudo rm -f /var/lib/sac/data/dgraph-firstboot.done
sudo /usr/local/sbin/dgraph-firstboot.sh
sudo systemctl restart dgraph-alpha nginxProduction TLS with your own domain
The per-instance certificate is self-signed. For production, point a DNS record at the instance and install a CA-signed certificate, for example with certbot and your-domain.example. Then replace the certificate and key referenced by the nginx site at /etc/nginx/sites-available/sac-dgraph, and reload nginx.
Support
SecureAnyCloud includes 24/7 technical support with this product. Contact sales@secureanycloud.com or use live chat for help with Dgraph deployment, schema and index design, TLS and reverse-proxy configuration, credential rotation and performance tuning.
Deploy on AWS
Launch Dgraph on AWS, with 24/7 support from SecureAnyCloud.
View on Marketplace
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com