Databases Azure

Neo4j 5 Community Edition on Rocky Linux 8 on Azure User Guide

| Product: Neo4j 5 Community Edition on Rocky Linux 8 on Azure

Overview

This guide covers deploying and using Neo4j 5 Community Edition on Rocky Linux 8 from cloudimg on Microsoft Azure.

Neo4j is a native graph database: data is stored as nodes, relationships and properties, and queried with the Cypher query language. It is used for knowledge graphs, fraud detection, recommendations, and network and IT topology. This image ships Neo4j Community Edition 5.26 (the Neo4j 5 long-term support line; image version 1.0.1 carries 5.26.32) with Neo4j Browser (the web query interface), the HTTP API and the Bolt protocol used by every official Neo4j driver, plus cypher-shell. Neo4j Community Edition is licensed under the GNU General Public License version 3.

Every command and every output in this guide was run on a virtual machine deployed from the public Marketplace image (image version 1.0.1), as the azureuser account a customer gets.

What cloudimg adds to the upstream packages:

  • No default login. Neo4j normally starts with the user neo4j and the password neo4j. On this image the database is created on first boot with a 24-character password that is unique to the VM, set before Neo4j ever starts, so the default login never exists.
  • Localhost only. Neo4j listens on 127.0.0.1 only: Neo4j Browser and the HTTP API on port 7474, and Bolt on port 7687. Nothing from the network reaches the database until you decide how it should. You reach Neo4j Browser through an SSH tunnel (Step 7).
  • Data on its own disk. The database lives on a separate Azure data disk mounted at /var/lib/neo4j, apart from the operating system disk.
  • Rocky Linux 8 with SELinux enforcing, OpenJDK 17 from Rocky Linux, and Neo4j and cypher-shell from Neo4j's official signed package repository (yum.neo4j.com/stable/5), so dnf upgrade keeps Neo4j on the latest 5.26 release.

What's included

  • Neo4j Community Edition 5.26 (5.26.32 on image version 1.0.1) and cypher-shell, from yum.neo4j.com/stable/5
  • OpenJDK 17 (java-17-openjdk) from Rocky Linux AppStream
  • Rocky Linux 8 (8.10 on image version 1.0.1), SELinux enforcing
  • Azure Linux Agent (waagent) and cloud-init for Azure provisioning, and Python 3
  • A 10 GB Azure data disk for the database, mounted at /var/lib/neo4j
  • The cloudimg first-boot service that sets the per-VM neo4j password
  • 24/7 cloudimg support

The Azure CLI is not installed on the image. If you want it on the VM, install it with Microsoft's instructions for RHEL-based distributions.

Connecting to your VM

Item Value
SSH user the administrator you choose at deployment (for example azureuser)
Neo4j Browser http://localhost:7474/browser/ through an SSH tunnel (Step 7)
Bolt (drivers, cypher-shell) neo4j://localhost:7687 or bolt://localhost:7687, on the VM or through the tunnel
Neo4j user neo4j, password in /root/neo4j-credentials.txt
Open ports 22 (SSH) only. Neo4j's ports 7474 and 7687 listen on localhost.

Prerequisites

  1. An Azure subscription and an SSH public key
  2. The Azure CLI on your workstation, signed in with az login
  3. A network security group that allows TCP 22 from your own address only. Neo4j needs no inbound rule.

Choose a virtual machine size that suits your workload. Neo4j sizes its heap and page cache from the VM's memory when it starts (Step 9).

Step 1: Deploy from the Azure CLI

The image carries a Marketplace purchase plan, so accept its terms once per subscription, then create the virtual machine. The offer and the plan are both named by the same identifier, which is why it appears twice in the image URN; the plan's Gen2 image adds -gen2. Replace <your-vm-size> with the size you chose:

az vm image terms accept --urn cloudimg1647283583153:899b6cd4-46fb-436f-a23a-09c0724c831f:899b6cd4-46fb-436f-a23a-09c0724c831f-gen2:latest

az vm create \
  --resource-group myResourceGroup \
  --name my-neo4j-vm \
  --image cloudimg1647283583153:899b6cd4-46fb-436f-a23a-09c0724c831f:899b6cd4-46fb-436f-a23a-09c0724c831f-gen2:latest \
  --size <your-vm-size> \
  --admin-username azureuser \
  --ssh-key-values ~/.ssh/id_ed25519.pub \
  --nsg my-ssh-only-nsg \
  --public-ip-sku Standard

The data disk for /var/lib/neo4j comes with the image, so there is nothing to attach. A Gen1 image of the same release is published under the plan identifier without -gen2, for sizes that do not support Gen2 virtual machines.

Step 2: Connect via SSH

Run these on your own workstation. Find the public IP, then connect:

az vm show --resource-group myResourceGroup --name my-neo4j-vm --show-details --query publicIps -o tsv
ssh azureuser@<vm-ip>

First boot takes a minute or two after the VM is running, while it sets the VM's password and starts Neo4j. If you connect straight away, wait for it:

sudo cloud-init status --wait

It prints status: done.

Step 3: Check the service

systemctl is-active neo4j.service cloudimg-firstboot-neo4j.service
sudo ss -Htln '( sport = :7474 or sport = :7687 )'

Both services report active, and Neo4j listens on 127.0.0.1 only (Java prints the address as [::ffff:127.0.0.1]), on 7474 and 7687. The release and the Java runtime:

grep PRETTY_NAME /etc/os-release
rpm -q neo4j cypher-shell java-17-openjdk-headless

Step 4: Read the per-VM credentials

The neo4j password is unique to this VM and is written at first boot to a root-only file (mode 0600):

sudo stat -c '%a %U:%G %n' /root/neo4j-credentials.txt

It prints 600 root:root /root/neo4j-credentials.txt. The file holds the user (neo4j), the password, and the Bolt and Browser addresses. When you need the password, read it into a variable rather than onto the screen. cypher-shell reads it from the NEO4J_PASSWORD environment variable, so set that in each new shell like this.

export NEO4J_PASSWORD="$(sudo sed -n 's/^Neo4j password: //p' /root/neo4j-credentials.txt)"

Keep it safe: it is the database administrator's password.

Step 5: The authentication gate

Neo4j's HTTP API (the Query API at /db/neo4j/query/v2) refuses an anonymous request, a wrong password and the documented default neo4j/neo4j:

Q='{"statement":"RETURN 1 AS one"}'
curl -s -o /dev/null -w 'anonymous:   HTTP %{http_code}\n' -H 'Content-Type: application/json' -d "$Q" http://127.0.0.1:7474/db/neo4j/query/v2
curl -s -u 'neo4j:not-the-real-one' -o /dev/null -w 'wrong login: HTTP %{http_code}\n' -H 'Content-Type: application/json' -d "$Q" http://127.0.0.1:7474/db/neo4j/query/v2
curl -s -u 'neo4j:neo4j' -o /dev/null -w 'neo4j/neo4j: HTTP %{http_code}\n' -H 'Content-Type: application/json' -d "$Q" http://127.0.0.1:7474/db/neo4j/query/v2

Each returns HTTP 401. Neo4j locks an account for a few seconds after three failed logins in a row, so wait a moment before you use the real password.

Step 6: Use cypher-shell

With NEO4J_PASSWORD set (Step 4), ask Neo4j for its version and edition:

echo "CALL dbms.components() YIELD name, versions, edition RETURN name, versions[0] AS version, edition;" | \
  cypher-shell -a bolt://localhost:7687 -u neo4j --format plain

It prints "Neo4j Kernel", "5.26.32", "community". Create a small graph and query it:

cat <<'EOF' | cypher-shell -a bolt://localhost:7687 -u neo4j --format plain
MERGE (alice:Person {name: 'Alice'})
MERGE (bob:Person {name: 'Bob'})
MERGE (carol:Person {name: 'Carol'})
MERGE (graphs:Topic {name: 'Graph databases'})
MERGE (alice)-[:KNOWS]->(bob)
MERGE (bob)-[:KNOWS]->(carol)
MERGE (alice)-[:INTERESTED_IN]->(graphs)
MERGE (carol)-[:INTERESTED_IN]->(graphs);
MATCH (p:Person)-[:KNOWS*1..2]->(friend:Person)
WHERE p.name = 'Alice'
RETURN friend.name AS reachable_from_alice ORDER BY reachable_from_alice;
EOF

The query returns Bob and Carol: Carol is reached through Bob, a two-hop traversal.

Step 7: Open Neo4j Browser through an SSH tunnel

Neo4j listens on localhost, so reach Neo4j Browser through SSH. On your workstation:

ssh -N -L 7474:localhost:7474 -L 7687:localhost:7687 azureuser@<vm-ip>

Leave it running and open http://localhost:7474/browser/ in your browser. The traffic travels inside the encrypted SSH connection. In the Connect to instance dialog keep the protocol neo4j:// and the connection URL localhost:7687, keep neo4j as the database user, enter the per-VM password and choose Connect.

Type Cypher in the editor at the top and choose Run. MATCH (n)-[r]->(m) RETURN n, r, m draws the graph from Step 6 as nodes and relationships, and a query that returns values, such as the two-hop traversal from Alice, is shown as a table.

Step 8: Connect from an application

Every Neo4j driver (Python, Java, JavaScript, .NET, Go) connects over Bolt on port 7687. An application on the VM itself connects to neo4j://localhost:7687. From another machine, the simplest secure route is the SSH tunnel from Step 7. If your applications must reach Neo4j over the network, follow Neo4j's operations manual to configure TLS for Bolt and HTTPS (SSL framework) before you change server.default_listen_address in /etc/neo4j/neo4j.conf, and open 7687 in the network security group only to the networks that need it.

Create a separate user for each application instead of sharing the neo4j administrator, for example in cypher-shell or Neo4j Browser: CREATE USER app SET PASSWORD 'a-long-random-password' CHANGE NOT REQUIRED;. Community Edition users all have full access, so keep the list short.

To change the neo4j password, run ALTER CURRENT USER SET PASSWORD FROM 'current-password' TO 'new-password';, then update /root/neo4j-credentials.txt yourself (it is not rewritten).

Step 9: Data disk, backups and memory

The database is on its own Azure data disk:

findmnt /var/lib/neo4j

It shows the data disk (an ext4 device such as /dev/sdc; the device name can differ from one VM to another) mounted at /var/lib/neo4j. To grow it, resize the data disk in Azure, then grow the file system with sudo resize2fs "$(findmnt -n -o SOURCE /var/lib/neo4j)".

Community Edition takes a backup with neo4j-admin database dump while Neo4j is stopped:

sudo mkdir -p /var/lib/neo4j/backups && sudo chown neo4j:neo4j /var/lib/neo4j/backups
sudo systemctl stop neo4j
sudo -u neo4j neo4j-admin database dump neo4j --to-path=/var/lib/neo4j/backups --overwrite-destination=true
sudo systemctl start neo4j

It ends with Dump completed successfully and writes /var/lib/neo4j/backups/neo4j.dump. Copy the dump off the VM (for example to Azure Blob Storage), and consider Azure Backup or disk snapshots for the whole VM as well.

Neo4j's memory recommendation for this VM's size can be printed with:

sudo neo4j-admin server memory-recommendation 2>/dev/null | grep -E '^server\.memory'

Copy the server.memory.heap.initial_size, server.memory.heap.max_size and server.memory.pagecache.size lines into /etc/neo4j/neo4j.conf and run sudo systemctl restart neo4j.

Step 10: Keep it updated

The image was patched when it was built. Updates published since then are not applied automatically, so update a new VM before you put it into service, and regularly afterwards:

sudo dnf -y upgrade

This updates Rocky Linux and, from Neo4j's repository, Neo4j and cypher-shell within the 5.26 line. Reboot if a new kernel was installed.

Security notes

  • Firewall. firewalld is not installed on this image. The network security group is the firewall: allow SSH only from the networks you manage from.
  • rpcbind. The image includes the NFS client tools, so rpcbind listens on port 111. If you do not mount NFS shares, turn it off with sudo systemctl disable --now rpcbind.socket rpcbind.service, and keep port 111 closed in the network security group either way.
  • SELinux is enforcing (getenforce prints Enforcing). Keep it on.
  • LOAD CSV file URLs are resolved inside /var/lib/neo4j/import (server.directories.import), so copy CSV files there with sudo cp data.csv /var/lib/neo4j/import/.

When you have finished with the example graph, remove it:

echo "MATCH (n) WHERE n:Person OR n:Topic DETACH DELETE n RETURN count(*) AS removed;" | \
  cypher-shell -a bolt://localhost:7687 -u neo4j --format plain

Server components

Component Path
Configuration /etc/neo4j/neo4j.conf
Data directory (Azure data disk) /var/lib/neo4j/data
Import directory (LOAD CSV) /var/lib/neo4j/import
Plugins directory /var/lib/neo4j/plugins
Logs /var/log/neo4j/
Credentials file /root/neo4j-credentials.txt (mode 0600)
First-boot service cloudimg-firstboot-neo4j.service
Data disk service cloudimg-datadisk.service (/etc/cloudimg/datadisk.conf)

Support and licensing

Neo4j Community Edition is licensed under the GNU General Public License version 3. This image ships Community Edition only; Neo4j Enterprise requires a commercial licence from Neo4j, Inc. cloudimg provides round-the-clock technical support for this image by email, with a guaranteed 24-hour response time: support@cloudimg.co.uk.

Neo4j is a registered trademark of Neo4j, Inc. Rocky Linux is a trademark of the Rocky Enterprise Software Foundation. cloudimg is not affiliated with or endorsed by either of them.