Hasura GraphQL Engine (CE v2) on Ubuntu 24.04 on Azure User Guide
Overview
Hasura GraphQL Engine gives you an instant, realtime GraphQL API over a relational database, plus a web console for exploring your schema, composing queries and managing row and column permissions. The cloudimg image ships the free and open source Community Edition (the Apache-2.0 v2 engine, hasura/graphql-engine), run the officially supported way as the upstream container alongside a bundled PostgreSQL, orchestrated by Docker Compose under systemd and fronted by nginx. Both images are pinned by digest and captured into the VM, so your instance starts in seconds. A unique admin secret and a unique database password are generated for each VM on first boot, before the port is reachable, so the console and the GraphQL endpoint are locked down from the very first request. Backed by 24/7 cloudimg support.
Hasura is a trademark of its respective owner. This image is produced by cloudimg and is not affiliated with, endorsed by, or sponsored by Hasura. It ships only the free and open source Apache-2.0 v2 Community Edition engine; it does not ship Hasura v3 / DDN.

What is included:
- Hasura GraphQL Engine Community Edition v2.49.4 (the Apache-2.0 v2 engine), pinned by image digest
- A bundled PostgreSQL 16 database, pinned by image digest, reachable only inside a private Docker network (never published to a host port)
- Docker Engine (Docker CE) with the engine published to the loopback interface only, fronted by nginx on port
80 hasura.service,hasura-firstboot.serviceandnginx.serviceas systemd units, enabled and active on boot- A unique
HASURA_GRAPHQL_ADMIN_SECRETand a unique PostgreSQL password generated per VM on first boot, never baked into the image - A clean, empty database on first boot: no default account, no shipped secret, no prior data
- 24/7 cloudimg support
Prerequisites
An active Azure subscription, an SSH key pair, and a VNet plus subnet in the target region. Standard_B2s (2 vCPU / 4 GiB RAM) is a sensible starting point; increase the size for heavier workloads. NSG inbound: allow 22/tcp from your management network and 80/tcp (and 443/tcp once you add TLS) for the console and the GraphQL API. The engine serves plain HTTP on port 80; for production, put it behind TLS with your own domain (see the final section).
Step 1 - Deploy from the Azure Marketplace
Sign in to the Azure Portal, choose Create a resource, search the Marketplace for Hasura GraphQL Engine by cloudimg, and select Create. On Basics pick your subscription, resource group, region and size; under Administrator account choose SSH public key and paste your key; under Inbound port rules allow SSH (22) and HTTP (80). Then Review + create and Create.
Step 2 - Deploy from the Azure CLI
az vm create \
--resource-group <your-rg> \
--name hasura \
--image <marketplace-image-urn> \
--size Standard_B2s \
--admin-username azureuser \
--ssh-key-values ~/.ssh/id_ed25519.pub \
--vnet-name <your-vnet> --subnet <your-subnet> \
--public-ip-sku Standard
az vm open-port --resource-group <your-rg> --name hasura --port 80 --priority 1010
Step 3 - Connect to your VM
ssh azureuser@<vm-public-ip>
Step 4 - Confirm the services are running
On first boot the image generates a unique admin secret and database password, initialises a clean PostgreSQL database, and starts the engine. Confirm the systemd services are active and that both containers (the engine and the bundled PostgreSQL) are healthy:
systemctl is-active docker hasura nginx
docker ps --format 'table {{.Names}}\t{{.Image}}\t{{.Status}}'
All three services report active, and both hasura-graphql-engine-1 and hasura-postgres-1 report healthy.

The engine is published to the loopback interface only and fronted by nginx; the bundled PostgreSQL is never exposed on a host port. The public liveness endpoint returns 200 with no credentials:
curl -s -o /dev/null -w 'health: HTTP %{http_code}\n' http://127.0.0.1/healthz
Step 5 - Secure by default: the admin secret gates everything
The engine ships locked down. Any request to an admin endpoint (metadata, run SQL, the console) without the exact per-VM admin secret is rejected with 401. Confirm it yourself - this request sends no secret:
curl -s -o /dev/null -w 'no secret: HTTP %{http_code}\n' \
-X POST http://127.0.0.1/v1/metadata \
-H 'Content-Type: application/json' \
-d '{"type":"export_metadata","args":{}}'
It returns HTTP 401. The same is true for the GraphQL endpoint and the console: nothing is readable or writable without your admin secret.

Your unique admin secret is written to /root/hasura-notes.txt, readable only by root:
sudo stat -c '%a %U:%G' /root/hasura-notes.txt
It reports 600 root:root. View the notes (which include your admin secret, the console URL and the GraphQL endpoint) with:
sudo cat /root/hasura-notes.txt

Step 6 - Open the console
Browse to http://<vm-public-ip>/console. The console prompts for your admin secret before it loads anything - this is the gate that protects your database.

Paste the admin secret from /root/hasura-notes.txt and select Enter. The console opens on the API tab with GraphiQL, where you can compose and run GraphQL queries, mutations and subscriptions against your data, and browse the auto-generated schema in the Explorer panel.

The Data tab manages your database: connect schemas, create and track tables, define relationships and set permissions. The bundled database is reported here as PostgreSQL 16.

Step 7 - Call the GraphQL API from the command line
Every request to the GraphQL endpoint must carry your admin secret in the x-hasura-admin-secret header. The block below reads the secret from your notes file (so it never appears on screen) and runs a GraphQL query that confirms the endpoint is authenticated and serving:
S=$(sudo grep '^HASURA_ADMIN_SECRET=' /root/hasura-notes.txt | cut -d= -f2-)
curl -s -X POST http://127.0.0.1/v1/graphql \
-H "x-hasura-admin-secret: $S" \
-H 'Content-Type: application/json' \
-d '{"query":"query { __typename }"}'
It returns {"data":{"__typename":"query_root"}}, proving an authenticated GraphQL round trip against the bundled PostgreSQL. Once you create and track a table (for example a products table) in the Data tab, Hasura instantly exposes it as GraphQL. From your own machine, substitute your VM public IP and your admin secret:
curl -X POST http://<vm-public-ip>/v1/graphql \
-H 'x-hasura-admin-secret: <HASURA_ADMIN_SECRET>' \
-H 'Content-Type: application/json' \
-d '{"query":"query { products { id name category price in_stock } }"}'

Step 8 - Rotate the admin secret
The admin secret is your master key. To set your own, edit the environment file and restart the engine:
sudo sed -i 's/^HASURA_GRAPHQL_ADMIN_SECRET=.*/HASURA_GRAPHQL_ADMIN_SECRET=<your-new-secret>/' /etc/hasura/hasura.env
sudo systemctl restart hasura
Step 9 - Production: your own domain with TLS
For production, front the engine with your own domain and TLS. Point a DNS record at the VM public IP, then install a certificate with your preferred tool (for example Certbot with the nginx plugin) and reload nginx. Restrict inbound access in your NSG to 443/tcp (and 22/tcp from your management network) once TLS is in place, and keep the admin secret confidential - it grants full read and write access to your database.
Support
This image is supported 24/7 by cloudimg. For help with deployment or configuration, contact support through cloudimg.co.uk.