Neo4j 2026
Videos
Overview: Neo4j 2026 Community Ubuntu 24.04 on Azure: overview (watch on YouTube)
Launch and log in: Neo4j 2026 Community Ubuntu 24.04 on Azure: launch and log in (watch on YouTube)
Deep Dive: Neo4j 2026 Community Ubuntu 24.04 on Azure: deep dive (watch on YouTube)
Overview
Neo4j is a native graph database. It stores data as nodes, relationships and properties, and you query it with the Cypher query language. Teams use it for knowledge graphs, fraud detection, recommendations, network and IT topology, identity and access graphs, and as the graph store behind retrieval-augmented generation (GraphRAG).
This guide covers deploying and using Neo4j 2026 Community on Ubuntu 24.04 from SecureAnyCloud on Microsoft Azure. The image ships Neo4j Community Edition 2026.10.1, which is licensed under the GNU General Public License version 3.
What you get:
- Neo4j Browser (the web query interface), the HTTP API and the Bolt protocol used by every official Neo4j driver, plus
cypher-shell. - No default login. Neo4j normally starts with the user
neo4jand the passwordneo4j. On this image, the database is created on first boot with a 24-character password that is unique to the VM. The password is set before Neo4j ever starts, so the default login never exists. Nothing listens until that password and the certificate exist. - Encrypted from the first boot. A certificate generated on the VM for its own address protects Neo4j Browser and the HTTP API (HTTPS on port 7473) and the Bolt protocol (port 7687). Bolt requires TLS, so plain
bolt://connections are refused. The unencrypted HTTP port 7474 is turned off, and every other Neo4j listener is off or bound to loopback. The only ports the VM listens on are 22, 7473 and 7687. - A sandboxed database service. Neo4j runs as an unprivileged service account in a systemd sandbox. It can write only its data, log and run directories, and it cannot read the credentials file, SSH keys,
/rootor/etc/shadow.LOAD CSVfile URLs are confined to the import directory. - Blocked from the Azure metadata service. The Neo4j service and its first-boot setup cannot reach the Azure Instance Metadata Service (169.254.169.254) or the Azure wire server (168.63.129.16). A
LOAD CSV FROM 'http://...'therefore cannot read VM metadata. The Azure Linux Agent and cloud-init keep their access, so provisioning and extensions work as usual. - No plugins. The Neo4j package also carries the APOC, Graph Data Science and GenAI plugin jars. None is installed on this image, the plugins directory is empty, and upgrades do not restore them. Usage reporting to Neo4j is turned off.
- Fully patched Ubuntu 24.04 at build time, Neo4j from Neo4j's official signed package repository, OpenJDK 25 from Ubuntu, and the SecureAnyCloud security defaults.
- On the image: Ubuntu 24.04 LTS, OpenJDK 25 (Java runtime, from Ubuntu), Neo4j 2026.10.1 Community and cypher-shell from debian.neo4j.com, the configuration in /etc/neo4j/, the data directory /var/lib/neo4j/data (empty until first boot creates the databases), and the SecureAnyCloud first-boot service.
Connecting to your VM
Item Value
SSH user the administrator you choose at deployment (for example azureuser)
Neo4j Browser https://<vm-ip>:7473/browser/
Bolt (drivers, cypher-shell) neo4j+s://<vm-ip>:7687 (or neo4j+ssc:// with the self-signed certificate)
Neo4j user neo4j, password in /root/neo4j-credentials.txt
Open ports 22 (SSH), 7473 (HTTPS), 7687 (Bolt, TLS). Port 7474 is not used.
Prerequisites
- An Azure subscription, an SSH public key, and a virtual network in the target region
- A network security group that allows TCP 22 from your own address. It must also allow TCP 7473 (Neo4j Browser and the HTTP API, HTTPS) and TCP 7687 (Bolt, TLS) from the clients and applications that will use the database. Expose 7473 and 7687 only to the networks that need them. You can also keep them closed and use an SSH tunnel (Step 7).
- Recommended virtual machine size:
Standard_B2s(2 vCPU, 4 GB RAM) for development and small graphs. Neo4j sizes its heap and page cache from the VM's memory at start-up. For production graphs, choose a memory-optimized size such asStandard_E4s_v5(4 vCPU, 32 GB RAM) or larger. See Step 9 for tuning.
Deploy from the Azure Portal
Search for Neo4j 2026 in the Azure Marketplace. Select the SecureAnyCloud entry and choose Create.
In Networking, allow SSH (22) from your address. Add inbound rules for TCP 7473 and TCP 7687 from your client networks.
First boot takes one to two minutes after the VM is running. During this time, the VM generates its certificate and password, creates the databases and starts Neo4j.
Deploy from the Azure CLI
RG="neo4j-prod"; LOCATION="eastus"; VM_NAME="neo4j-01" IMAGE_URN="sac1647283583153:neo4j-2026-ubuntu-24-04:default:latest" CLIENT_CIDR="<your-mgmt-cidr>" az group create --name "$RG" --location "$LOCATION" az network nsg create -g "$RG" --name neo4j-nsg az network nsg rule create -g "$RG" --nsg-name neo4j-nsg --name allow-ssh --priority 100 \
--source-address-prefixes "$CLIENT_CIDR" --destination-port-ranges 22 --access Allow --protocol Tcp az network nsg rule create -g "$RG" --nsg-name neo4j-nsg --name allow-neo4j --priority 110 \
--source-address-prefixes "$CLIENT_CIDR" --destination-port-ranges 7473 7687 --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/id_rsa.pub \
--nsg neo4j-nsg --public-ip-sku StandardFirst boot takes a minute or two. If you connect as soon as the VM shows as running, wait for the per-VM setup to finish before you continue:
bash sudo cloud-init status --wait
The command prints status: done. Then systemctl is-active neo4j-firstboot.service reports active.
Connect via SSH and check the service
ssh azureuser@<vm-ip>The login banner shows the Neo4j Browser and Bolt addresses for this VM. Confirm that Neo4j is running and listening only on the HTTPS and Bolt ports:
systemctl is-active neo4j.service neo4j-firstboot.service
sudo ss -Htln '( sport = :7473 or sport = :7474 or sport = :7687 )'Both services report active. Neo4j listens on port 7473 (HTTPS) and port 7687 (Bolt with TLS) on all addresses. Nothing listens on 7474.
Read the per-VM credentials
The neo4j password is unique to this VM. It is written to a root-only file (mode 0600) at first boot. Print only the field names, never the password itself:
sudo grep -oE '^[A-Z0-9_]+=' /root/neo4j-credentials.txtThe command lists these fields:
NEO4J_HOST: the address Neo4j advertises, which is the VM's public IP, or its private IP when it has noneNEO4J_USER:neo4jNEO4J_PASSWORD: the per-VM passwordNEO4J_BROWSER_URL,NEO4J_HTTPS_URLandNEO4J_BOLT_URI
Read the password with sudo sed -n 's/^NEO4J_PASSWORD=//p' /root/neo4j-credentials.txt when you need it. Keep it safe, because it is the database administrator's password.
The VM's certificate covers its public and private IP addresses, its host name, localhost and 127.0.0.1.
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. Each gets 401 Unauthorized.
Save the VM's certificate so curl can verify the connection:
sudo cat /var/lib/neo4j/certificates/sac/public.crt > /tmp/neo4j.crt
H=$(sudo sed -n 's/^NEO4J_HOST=//p' /root/neo4j-credentials.txt) Q='{"statement":"RETURN 1 AS one"}' curl -s --cacert /tmp/neo4j.crt --resolve "$H:7473:127.0.0.1" -o /dev/null -w 'anonymous: HTTP %{http_code}\n' -H 'Content-Type: application/json' -d "$Q" "https://$H:7473/db/neo4j/query/v2" curl -s --cacert /tmp/neo4j.crt --resolve "$H:7473:127.0.0.1" -u 'neo4j:wrong-password' -o /dev/null -w 'wrong password: HTTP %{http_code}\n' -H 'Content-Type: application/json' -d "$Q" "https://$H:7473/db/neo4j/query/v2" curl -s --cacert /tmp/neo4j.crt --resolve "$H:7473:127.0.0.1" -u 'neo4j:neo4j' -o /dev/null -w 'neo4j/neo4j: HTTP %{http_code}\n' -H 'Content-Type: application/json' -d "$Q" "https://$H:7473/db/neo4j/query/v2"Each request 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. With the per-VM password, the query runs:
sleep 6
H=$(sudo sed -n 's/^NEO4J_HOST=//p' /root/neo4j-credentials.txt) printf 'user = "neo4j:%s"\n' "$(sudo sed -n 's/^NEO4J_PASSWORD=//p' /root/neo4j-credentials.txt)" | \
curl -s --cacert /tmp/neo4j.crt --resolve "$H:7473:127.0.0.1" -K - -w '\nHTTP %{http_code}\n' \
-H 'Content-Type: application/json' -d '{"statement":"RETURN 1 AS one"}' "https://$H:7473/db/neo4j/query/v2"The response is HTTP 202 with "data":{"fields":["one"],"values":[[1]]}. The password is passed to curl on standard input, so it does not appear in the process list.
Use cypher-shell over TLS
cypher-shell reads the password from the NEO4J_PASSWORD environment variable. Set it in each new shell, as below.
Bolt requires TLS, so use the bolt+ssc:// scheme on the VM itself. The connection is encrypted, but the self-signed certificate is not checked:
export NEO4J_PASSWORD="$(sudo sed -n 's/^NEO4J_PASSWORD=//p' /root/neo4j-credentials.txt)" echo "CALL dbms.components() YIELD name, versions, edition RETURN name, versions[0] AS version, edition;" | \
cypher-shell -a bolt+ssc://localhost:7687 -u neo4j --format plainThe command prints "Neo4j Kernel", "2026.10.1", "community". A plain, unencrypted connection is refused:
export NEO4J_PASSWORD="$(sudo sed -n 's/^NEO4J_PASSWORD=//p' /root/neo4j-credentials.txt)" echo "RETURN 1;" | cypher-shell -a bolt://localhost:7687 -u neo4j --format plain 2>&1 | head -3 || trueCreate a small graph and query it:
export NEO4J_PASSWORD="$(sudo sed -n 's/^NEO4J_PASSWORD=//p' /root/neo4j-credentials.txt)" cat <<'EOF' | cypher-shell -a bolt+ssc://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; EOFThe query returns Bob and Carol. Carol is reached through Bob, which is a two-hop traversal.
Open Neo4j Browser
With TCP 7473 and 7687 open to your address in the network security group, open https://<vm-ip>:7473/browser/ in your browser.
If you prefer to keep those ports closed, use an SSH tunnel and open https://localhost:7473/browser/ instead. The VM's certificate also covers localhost:
ssh -N -L 7473:localhost:7473 -L 7687:localhost:7687 azureuser@<vm-ip>The certificate is self-signed and unique to the VM, so your browser warns once. Accept it for this host. For production, see Step 9.
In the Connect to instance dialog, choose neo4j+s:// as the protocol. Enter the VM's address and port 7687 as the connection URL (localhost:7687 through the tunnel). Keep neo4j as the database user, and enter the per-VM password:
If the connection fails with a security or certificate message, your browser has not yet accepted the certificate for the Bolt port. Open https://<vm-ip>:7687 (or https://localhost:7687) once in a new tab and accept the warning. The page itself then shows an error, which is expected. Connect again.
Once connected, type Cypher in the editor at the top and choose Run. The graph from Step 6 is drawn as nodes and relationships, with a summary of the labels and relationship types:
Queries that return values are shown as a table, here the two-hop traversal from Alice:
:sysinfo lists the databases (neo4j and system), the address they are served on and their status:
Connect from an application
Every Neo4j driver (Python, Java, JavaScript, .NET, Go) connects over Bolt on port 7687 with TLS.
With the self-signed certificate, use the neo4j+ssc:// scheme. The connection is encrypted, but the certificate is not checked.
To verify the server, copy /var/lib/neo4j/certificates/sac/public.crt from the VM and add it to the client's trust store. Alternatively, replace the certificate with one from your own certificate authority. Then use neo4j+s://.
For example, in Python (pip install neo4j):
from neo4j import GraphDatabase driver = GraphDatabase.driver("neo4j+ssc://<vm-ip>:7687", auth=("neo4j", "<NEO4J_PASSWORD>")) with driver.session() as session: print(session.run("MATCH (n) RETURN count(n) AS nodes").single()["nodes"]) driver.close()Create a separate user for each application instead of sharing the neo4j administrator. Community Edition users all have full access, so keep the list short.
For example, run this in cypher-shell or Neo4j Browser connected to the system database: CREATE USER app SET PASSWORD 'a-long-random-password' CHANGE NOT REQUIRED;
To change the neo4j password, run ALTER CURRENT USER SET PASSWORD FROM 'current-password' TO 'new-password'; in Neo4j Browser or cypher-shell. Then update /root/neo4j-credentials.txt yourself, because the file is not rewritten.
Serve under your own DNS name, and tune memory
Neo4j advertises one address to its clients. The Bolt routing table and Neo4j Browser use it. On first boot, the address is the VM's public IP address from the Azure metadata service, or its private IP when the VM has no public IP.
After you point a DNS record at the VM, set the name and issue a new certificate for it:
sudo neo4j-set-hostname neo4j.<your-domain>The command regenerates the self-signed certificate, records the name in /etc/sac/neo4j-hostname and restarts Neo4j.
For production, replace the self-signed certificate with your own CA-issued certificate. Put private.key and public.crt in /var/lib/neo4j/certificates/sac/ and restart Neo4j.
Print Neo4j's memory recommendation for this VM size with:
sudo -u neo4j 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. Then run sudo systemctl restart neo4j.
Security notes
LOAD CSV and the metadata service. LOAD CSV reads data from files and URLs on the server. On this image, a file:/// URL is resolved inside /var/lib/neo4j/import, so a query cannot read other files on the VM. Copy your CSV files there with sudo cp data.csv /var/lib/neo4j/import/.
Try to read a file outside the import directory to see the restriction:
export NEO4J_PASSWORD="$(sudo sed -n 's/^NEO4J_PASSWORD=//p' /root/neo4j-credentials.txt)" echo "LOAD CSV FROM 'file:///etc/shadow' AS row RETURN row LIMIT 1;" | \
cypher-shell -a bolt+ssc://localhost:7687 -u neo4j --format plain 2>&1 | head -2 || trueNeo4j refuses it (22N43: ... unable to load external resource).
A systemd IPAddressDeny rule also denies the Neo4j service access to the Azure Instance Metadata Service and the wire server. A LOAD CSV FROM 'http://169.254.169.254/...' therefore never reaches it.
You can prove this from inside the service's own control group. The Azure Linux Agent is not in that group, so it keeps its access:
CG=$(systemctl show -p ControlGroup --value neo4j.service)
sudo bash -c "echo \$\$ > /sys/fs/cgroup${CG}/cgroup.procs; exec sac-egress-probe neo4j.service"It prints verdict=BLOCKED, with loopback reachable and the metadata addresses timing out:
Plugins. No plugin ships, and /etc/dpkg/dpkg.cfg.d/sac-neo4j-no-plugins keeps package upgrades from restoring the APOC, Graph Data Science and GenAI jars.
Adding a plugin is your own security decision. Plugins run inside the database with its permissions, and procedures such as APOC's apoc.load.* read files and URLs. To add one, follow these steps:
- Download the plugin version that matches Neo4j 2026.10.1 from its official release page.
- Copy the jar into
/var/lib/neo4j/plugins/(owned byneo4j). - Allow only the procedures you need with
dbms.security.procedures.allowlistin/etc/neo4j/neo4j.conf. - Restart Neo4j.
The service sandbox and the metadata block still apply to a plugin.
The Neo4j package signing key expires on 31 December 2026. Neo4j's repository is signed with key 1EEF B876 7D49 24B8 6EAD 08A4 59D7 00E4 D37F 5F19 (Neo4j Admins), which expires on 2026-12-31.
Nothing on this image needs the repository to boot or to run Neo4j, and Ubuntu's own security updates are unaffected. After that date, apt-get update reports an error for the Neo4j repository and exits non-zero. Ubuntu's package lists still refresh, and unattended security upgrades keep running, until you load Neo4j's renewed key.
When Neo4j publishes the renewed key, refresh it and check its fingerprint and expiry:
curl -fsSL https://debian.neo4j.com/neotechnology.gpg.key -o /tmp/neo4j.key gpg --show-keys --with-colons /tmp/neo4j.key | awk -F: '/^fpr:/{print "fingerprint " $10; exit} /^pub:/{system("date -u -d @" $7 " +\"expires %Y-%m-%d\"")}'If the fingerprint is the one above, install the key with sudo gpg --dearmor --yes -o /usr/share/keyrings/neo4j-archive-keyring.gpg /tmp/neo4j.key. Then run sudo apt-get update.
If Neo4j announces a different key, verify it against the instructions on https://debian.neo4j.com before you install it.
When you have finished with the example graph, remove it:
export NEO4J_PASSWORD="$(sudo sed -n 's/^NEO4J_PASSWORD=//p' /root/neo4j-credentials.txt)" echo "MATCH (n) WHERE n:Person OR n:Topic DETACH DELETE n RETURN count(*) AS removed;" | \
cypher-shell -a bolt+ssc://localhost:7687 -u neo4j --format plain rm -f /tmp/neo4j.crt /tmp/neo4j.keyGeneral recommendations:
- Keep your VM patched with
sudo apt-get update && sudo apt-get upgrade. Neo4j updates come from the same official repository. - Back up your databases with
neo4j-admin database dumpwhile Neo4j is stopped. - Keep the
neo4jpassword safe. - Expose ports 7473 and 7687 only to the networks that need them.
Server components
Component Path
Configuration /etc/neo4j/neo4j.conf
Data directory /var/lib/neo4j/data
Import directory (LOAD CSV) /var/lib/neo4j/import
Plugins directory (empty) /var/lib/neo4j/plugins
Certificate and key /var/lib/neo4j/certificates/sac/
Logs /var/log/neo4j/
Credentials file /root/neo4j-credentials.txt (mode 0600)
First-boot service neo4j-firstboot.service (/usr/local/sbin/neo4j-firstboot.sh)
Hostname and certificate helper /usr/local/sbin/neo4j-set-hostname
Support and licensing
Neo4j Community Edition is licensed under the GNU General Public License version 3. This image ships Community only. Neo4j Enterprise requires a commercial license from Neo4j, Inc.
SecureAnyCloud provides 24/7 technical support for this image by email, 365 days a year, with a 24-hour response SLA: sales@secureanycloud.com.
Neo4j is a registered trademark of Neo4j, Inc. SecureAnyCloud is not affiliated with or endorsed by Neo4j, Inc.
Deploy on Azure
Launch Neo4j 2026 Community 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
Overview
Neo4j is a native graph database. It stores data as nodes, relationships and properties, and you query it with the Cypher query language. Teams use it for knowledge graphs, fraud detection, recommendations, network and IT topology, identity and access graphs, and as the graph store behind retrieval-augmented generation (GraphRAG).
This guide covers launching and using the Neo4j 2026.10.1 Community AMI from SecureAnyCloud on Amazon EC2. It is one version of the SecureAnyCloud Hardened Neo4j & Graph and RDF Databases AMIs listing on AWS Marketplace. You pick it as the software version when you subscribe and launch. Every product in the listing is described at /guides/graph-databases-aws/.
What you get:
- Neo4j Community Edition 2026.10.1, licensed under the GNU General Public License version 3, with Neo4j Browser (the web query interface), the HTTP API and the Bolt protocol used by every official Neo4j driver, plus
cypher-shell. - No default login. Neo4j normally starts with the user
neo4jand the passwordneo4j. On this image, the database is created on first boot with a 24-character password that is unique to the instance. The password is set before Neo4j ever starts, so the default login never exists. Nothing listens until that password and the certificate exist. - Encrypted from the first boot. A certificate generated on the instance for its own hostname protects Neo4j Browser and the HTTP API (HTTPS on port 7473) and the Bolt protocol (port 7687). Bolt requires TLS, so plain
bolt://connections are refused. The unencrypted HTTP port 7474 is turned off, and every other Neo4j listener is off or bound to loopback. - A sandboxed database service. Neo4j runs as an unprivileged service account in a systemd sandbox. It can write only its data, log and run directories, and it cannot read the credentials file, SSH keys,
/rootor/etc/shadow.LOAD CSVfile URLs are confined to the import directory. The service cannot reach the EC2 instance metadata service, so aLOAD CSV FROM 'http://...'cannot read instance credentials. - No plugins. The Neo4j package also carries the APOC, Graph Data Science and GenAI plugin jars. None is installed on this image, and upgrades do not restore them. Usage reporting to Neo4j is turned off.
- Data on its own disk. The databases and transaction logs live on a separate EBS volume mounted at
/var/lib/neo4j/data. You can grow the volume independently of the operating system disk. - Fully patched Ubuntu 24.04 at build time, from Neo4j's official signed package repository, with the SecureAnyCloud security defaults.
- On the image: Ubuntu 24.04 LTS, OpenJDK 25 (Java runtime), Neo4j 2026.10.1 Community and cypher-shell from debian.neo4j.com, the configuration in /etc/neo4j/, the data directory /var/lib/neo4j/data on its own volume (empty until first boot creates the databases), and the SecureAnyCloud first-boot service.
Connecting to your instance
Version SSH user Neo4j Browser Bolt (drivers, cypher-shell)
Neo4j 2026 Community on Ubuntu 24.04 ubuntu https://<public-dns>:7473/browser/ neo4j+s://<public-dns>:7687
Prerequisites
- An AWS account and permission to launch EC2 instances
- An EC2 key pair in the Region you launch in
- A security group that allows TCP 22 from your own address. It must also allow TCP 7473 (Neo4j Browser and the HTTP API, HTTPS) and TCP 7687 (Bolt, TLS) from the clients and applications that will use the database. Port 7474 is not used, because plain HTTP is turned off.
- Recommended instance type:
m5.large(2 vCPU, 8 GiB). Neo4j sizes its heap and page cache from the instance memory at start-up. For big graphs, choose a memory-optimized instance (for exampler5.largeor larger). See Step 9 for tuning.
Launch the instance
Option A: AWS Marketplace console
- Open the SecureAnyCloud Hardened Neo4j & Graph and RDF Databases AMIs listing on AWS Marketplace. Choose View purchase options, then Subscribe. One subscription covers every version in the listing.
- Choose Launch your software. In Version, choose Neo4j 2026 Community on Ubuntu 24.04 - YYYY-MM-DD, and choose your Region.
- Instance type:
m5.largeis recommended. - Key pair: choose your EC2 key pair.
- Security group: allow TCP 22 from your own address, and TCP 7473 and 7687 from your clients.
- Choose Launch. First boot takes one to two minutes after the instance is reachable. During this time, the instance generates its certificate and password, creates the databases and starts Neo4j.
Option B: AWS CLI
Run this command on your own workstation. Replace the AMI ID with the one shown for your Region on the Marketplace launch page. Replace the key pair, security group and subnet with your own:
aws ec2 run-instances \
--image-id ami-0123456789abcdef0 \
--instance-type m5.large \
--key-name my-key-pair \
--security-group-ids sg-0123456789abcdef0 \
--subnet-id subnet-0123456789abcdef0 \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=neo4j}]'The AMI already requires IMDSv2, so you do not need --metadata-options. The data volume is part of the AMI and is created with the instance.
Connect via SSH
ssh -i my-key-pair.pem ubuntu@<vm-ip>The login banner shows the Neo4j Browser and Bolt addresses for this instance.
Check the service and its listeners
Confirm that Neo4j is running and listening only on the HTTPS and Bolt ports:
systemctl is-active neo4j.service
sudo ss -Htln '( sport = :7473 or sport = :7474 or sport = :7687 )'The service reports active. Neo4j listens on 0.0.0.0:7473 (HTTPS) and 0.0.0.0:7687 (Bolt with TLS). Nothing listens on 7474.
The data volume is mounted at /var/lib/neo4j/data:
findmnt -no SOURCE,FSTYPE,SIZE /var/lib/neo4j/dataRead the per-instance credentials
The neo4j password is unique to this instance. It is written to a root-only file at first boot. Print only the field names, never the password itself:
sudo grep -oE '^[A-Z0-9_]+=' /root/neo4j-credentials.txtThe command lists these fields:
NEO4J_HOST: the hostname Neo4j advertisesNEO4J_USER:neo4jNEO4J_PASSWORD: the per-instance passwordNEO4J_BROWSER_URL,NEO4J_HTTPS_URLandNEO4J_BOLT_URI
Read the password with sudo sed -n 's/^NEO4J_PASSWORD=//p' /root/neo4j-credentials.txt when you need it. Keep it safe, because it is the database administrator's password.
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. Each gets 401 Unauthorized.
Save the instance's certificate so curl can verify the connection:
sudo cat /var/lib/neo4j/certificates/sac/public.crt > /tmp/neo4j.crt
H=$(sudo sed -n 's/^NEO4J_HOST=//p' /root/neo4j-credentials.txt) Q='{"statement":"RETURN 1 AS one"}' curl -s --cacert /tmp/neo4j.crt --resolve "$H:7473:127.0.0.1" -o /dev/null -w 'anonymous: HTTP %{http_code}\n' -H 'Content-Type: application/json' -d "$Q" "https://$H:7473/db/neo4j/query/v2" curl -s --cacert /tmp/neo4j.crt --resolve "$H:7473:127.0.0.1" -u 'neo4j:wrong-password' -o /dev/null -w 'wrong password: HTTP %{http_code}\n' -H 'Content-Type: application/json' -d "$Q" "https://$H:7473/db/neo4j/query/v2" curl -s --cacert /tmp/neo4j.crt --resolve "$H:7473:127.0.0.1" -u 'neo4j:neo4j' -o /dev/null -w 'neo4j/neo4j: HTTP %{http_code}\n' -H 'Content-Type: application/json' -d "$Q" "https://$H:7473/db/neo4j/query/v2"Each request 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. With the per-instance password, the query runs:
sleep 6
H=$(sudo sed -n 's/^NEO4J_HOST=//p' /root/neo4j-credentials.txt) printf 'user = "neo4j:%s"\n' "$(sudo sed -n 's/^NEO4J_PASSWORD=//p' /root/neo4j-credentials.txt)" | \
curl -s --cacert /tmp/neo4j.crt --resolve "$H:7473:127.0.0.1" -K - -w '\nHTTP %{http_code}\n' \
-H 'Content-Type: application/json' -d '{"statement":"RETURN 1 AS one"}' "https://$H:7473/db/neo4j/query/v2"The response is HTTP 202 with "data":{"fields":["one"],"values":[[1]]}. The password is passed to curl on standard input, so it does not appear in the process list.
Use cypher-shell over TLS
cypher-shell reads the password from the NEO4J_PASSWORD environment variable. Set it in each new shell, as below.
Bolt requires TLS, so use the bolt+ssc:// scheme on the instance itself. The connection is encrypted, but the self-signed certificate is not checked:
export NEO4J_PASSWORD="$(sudo sed -n 's/^NEO4J_PASSWORD=//p' /root/neo4j-credentials.txt)" echo "CALL dbms.components() YIELD name, versions, edition RETURN name, versions[0] AS version, edition;" | \
cypher-shell -a bolt+ssc://localhost:7687 -u neo4j --format plainThe command prints "Neo4j Kernel", "2026.10.1", "community". A plain, unencrypted connection is refused:
export NEO4J_PASSWORD="$(sudo sed -n 's/^NEO4J_PASSWORD=//p' /root/neo4j-credentials.txt)" echo "RETURN 1;" | cypher-shell -a bolt://localhost:7687 -u neo4j --format plain 2>&1 | head -3 || trueCreate a small graph and query it:
export NEO4J_PASSWORD="$(sudo sed -n 's/^NEO4J_PASSWORD=//p' /root/neo4j-credentials.txt)" cat <<'EOF' | cypher-shell -a bolt+ssc://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; EOFThe query returns Bob and Carol. Carol is reached through Bob, which is a two-hop traversal.
Open Neo4j Browser
Open https://<public-dns>:7473/browser/ in your browser. The certificate is self-signed and unique to the instance, so your browser warns once. Accept it for this host. For production, see Step 9.
The Connect to instance dialog already shows this instance's address (the hostname Neo4j advertises) and port 7687. Choose neo4j+s:// as the protocol. Keep neo4j as the database user, and enter the per-instance password:
If the connection fails with a security or certificate message, your browser has not yet accepted the certificate for the Bolt port. Open https://<public-dns>:7687 once in a new tab and accept the warning. The page itself then shows an error, which is expected. Connect again.
Once connected, type Cypher in the editor at the top and choose Run. The graph from Step 6 is drawn as nodes and relationships, with a summary of the labels and relationship types:
Queries that return values are shown as a table, here the two-hop traversal from Alice:
:sysinfo lists the databases (neo4j and system), the address they are served on and their status:
Connect from an application
Every Neo4j driver (Python, Java, JavaScript, .NET, Go) connects over Bolt on port 7687 with TLS.
With the self-signed certificate, use the neo4j+ssc:// scheme. The connection is encrypted, but the certificate is not checked.
To verify the server, copy /var/lib/neo4j/certificates/sac/public.crt from the instance and add it to the client's trust store. Alternatively, replace the certificate with one from your own certificate authority. Then use neo4j+s://.
For example, in Python (pip install neo4j):
from neo4j import GraphDatabase driver = GraphDatabase.driver("neo4j+ssc://<public-dns>:7687", auth=("neo4j", "<NEO4J_PASSWORD>")) with driver.session() as session: print(session.run("MATCH (n) RETURN count(n) AS nodes").single()["nodes"]) driver.close()Create a separate user for each application instead of sharing the neo4j administrator. Community Edition users all have full access, so keep the list short.
For example, run this in cypher-shell or Neo4j Browser connected to the system database: CREATE USER app SET PASSWORD 'a-long-random-password' CHANGE NOT REQUIRED;
To change the neo4j password, run ALTER CURRENT USER SET PASSWORD FROM 'current-password' TO 'new-password'; in Neo4j Browser or cypher-shell. Then update /root/neo4j-credentials.txt yourself, because the file is not rewritten.
Serve under your own DNS name, and tune memory
Neo4j advertises one hostname to its clients. The Bolt routing table and Neo4j Browser use it. On first boot, the hostname is the instance's public DNS name from the EC2 metadata service.
After you point a DNS record at the instance, set the name and issue a new certificate for it:
sudo neo4j-set-hostname neo4j.example.comThe command regenerates the self-signed certificate, records the name in /etc/sac/neo4j-hostname and restarts Neo4j.
For production, replace the self-signed certificate with your own CA-issued certificate. Put private.key and public.crt in /var/lib/neo4j/certificates/sac/ and restart Neo4j.
Print Neo4j's memory recommendation for this instance size with:
sudo -u neo4j 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. Then run sudo systemctl restart neo4j.
To grow the data disk, enlarge its EBS volume in the EC2 console. Then run sudo resize2fs on the device that findmnt /var/lib/neo4j/data shows.
Security notes
LOAD CSV reads data from files and URLs on the server. On this image, a file:/// URL is resolved inside /var/lib/neo4j/import, so a query cannot read other files on the instance. Copy your CSV files there with sudo cp data.csv /var/lib/neo4j/import/. The Neo4j service also cannot reach the instance metadata service.
Try to read a file outside the import directory to see the restriction:
export NEO4J_PASSWORD="$(sudo sed -n 's/^NEO4J_PASSWORD=//p' /root/neo4j-credentials.txt)" echo "LOAD CSV FROM 'file:///etc/shadow' AS row RETURN row LIMIT 1;" | \
cypher-shell -a bolt+ssc://localhost:7687 -u neo4j --format plain 2>&1 | head -2 || trueNeo4j refuses it (22N43: ... unable to load external resource). The file:/// paths are resolved inside the import directory, so /etc/shadow is never reached.
When you have finished with the example graph, remove it:
export NEO4J_PASSWORD="$(sudo sed -n 's/^NEO4J_PASSWORD=//p' /root/neo4j-credentials.txt)" echo "MATCH (n) WHERE n:Person OR n:Topic DETACH DELETE n RETURN count(*) AS removed;" | \
cypher-shell -a bolt+ssc://localhost:7687 -u neo4j --format plain rm -f /tmp/neo4j.crtThe service's sandbox is visible in its systemd unit, and the plugins folder holds no plugin. Check both:
systemctl show neo4j.service -p User -p IPAddressDeny -p ProtectHome -p ProtectSystem -p NoNewPrivileges echo "plugins folder: $(sudo ls -A /var/lib/neo4j/plugins | tr '\n' ' ')" echo "plugin jars: $(sudo find /var/lib/neo4j/plugins -name '*.jar' | wc -l)"The output shows:
User=neo4j,ProtectHome=yes,ProtectSystem=strictandNoNewPrivileges=yes- An
IPAddressDenylist that holds the instance metadata addresses (169.254.169.254/32andfd00:ec2::254/128) - A plugins folder with only
README.txt, andplugin jars: 0
To prove the metadata block, run the same request from your shell and from inside the Neo4j service's own cgroup:
CG=$(systemctl show -p ControlGroup --value neo4j.service)
curl -s -m 5 -o /dev/null -w 'metadata, from your shell: HTTP %{http_code}\n' -X PUT -H 'X-aws-ec2-metadata-token-ttl-seconds: 60' http://169.254.169.254/latest/api/token
sudo bash -c "echo \$\$ > /sys/fs/cgroup$CG/cgroup.procs curl -s -m 5 -o /dev/null -w 'metadata, from neo4j.service: HTTP %{http_code}\n' -X PUT -H 'X-aws-ec2-metadata-token-ttl-seconds: 60' http://169.254.169.254/latest/api/token curl -sk -m 5 -o /dev/null -w 'loopback, from neo4j.service: HTTP %{http_code}\n' https://127.0.0.1:7473/"Your shell gets HTTP 200; from inside the service the metadata request gets no answer (HTTP 000), while loopback still answers HTTP 200.
To back up a database, stop Neo4j, dump it with neo4j-admin, and start it again:
sudo systemctl stop neo4j
sudo install -d -o neo4j -g neo4j /var/lib/neo4j/data/dumps
sudo -u neo4j neo4j-admin database dump neo4j --to-path=/var/lib/neo4j/data/dumps 2>&1 | tail -2 sudo systemctl start neo4j
sudo ls -lh /var/lib/neo4j/data/dumpsThe output ends with Dump completed successfully and a neo4j.dump file. Copy the file off the instance, for example to Amazon S3.
General recommendations:
- Keep your instance patched with
sudo apt-get update && sudo apt-get upgrade. Neo4j updates come from the same official repository. - Back up your databases with
neo4j-admin database dumpwhile Neo4j is stopped. - Keep the
neo4jpassword safe. - Expose ports 7473 and 7687 only to the networks that need them.
Support
SecureAnyCloud provides 24/7 technical support for every version in this listing by email and live chat, 365 days a year, with a 24-hour response SLA: sales@secureanycloud.com.
Trademarks
Neo4j is a registered trademark of Neo4j, Inc. SecureAnyCloud is not affiliated with or endorsed by Neo4j, Inc. This image packages Neo4j Community Edition, which is open-source software licensed under the GNU General Public License version 3.
Deploy on AWS
Launch Neo4j 2026 Community on Ubuntu 24.04 with 24/7 support from SecureAnyCloud.
View on Marketplace
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com