Skip to main content

Neo4j Community Edition 5.x (Amazon Linux 2023) AMI Administrator Guide

1. Quick Start Information

Connection Methods:

  • Access the instance via SSH using the ec2-user user. Use sudo to run commands requiring root privileges. To switch to the root user, use sudo su - root.

Install Information:

  • OS: Amazon Linux 2023
  • Neo4j edition: Community Edition 5.x
  • Java: Amazon Corretto 17 (AWS-optimized OpenJDK 17)
  • Web UI: http://YOUR_PUBLIC_IP:7474
  • Bolt endpoint: bolt://YOUR_PUBLIC_IP:7687
  • Config file: /etc/neo4j/neo4j.conf
  • Data directory: /var/lib/neo4j/data
  • Log directory: /var/log/neo4j/

Default Credentials:

  • Username: neo4j
  • Password: Your AWS Instance ID (e.g., i-0abc123def456789)
  • How to find: Read the file /home/ec2-user/readme after the instance starts
cat /home/ec2-user/readme

Neo4j Service Management:

  • Start Neo4j: sudo systemctl start neo4j
  • Stop Neo4j: sudo systemctl stop neo4j
  • Restart Neo4j: sudo systemctl restart neo4j
  • Check status: sudo systemctl status neo4j
  • Enable auto-start: sudo systemctl enable neo4j

Required Ports (Security Group):

PortProtocolPurposeRequired
22TCPSSH accessYes
7474TCPNeo4j Web Browser (HTTP)Yes
7687TCPBolt protocol (drivers/code)Yes
7473TCPNeo4j Web Browser (HTTPS)Optional

2. First Launch & Verification

Step 1: Configure Security Group

Before accessing Neo4j, open the required ports in your AWS EC2 security group:

  1. Go to EC2 Console → Security Groups
  2. Select the security group attached to your instance
  3. Add inbound rules:
    • Port 7474 (TCP) — Neo4j Web Browser
    • Port 7687 (TCP) — Bolt Protocol
    • Source: Your IP or 0.0.0.0/0 (for public access)

Step 2: Retrieve Your Credentials

Connect via SSH and read the auto-generated credentials file:

ssh -i your-key.pem ec2-user@YOUR_PUBLIC_IP
cat /home/ec2-user/readme

Expected Output:

========================================================================
Neo4j Credentials (Auto-configured)
========================================================================
Login URL: http://YOUR_PUBLIC_IP:7474
Username : neo4j
Password : i-0abc123def456789
(This is your AWS Instance ID)
========================================================================

Note: The password initialization script runs automatically on first boot via cloud-init. It may take 1–2 minutes after launch for the readme file to appear and Neo4j to be fully ready.

Step 3: Access the Neo4j Browser

Open a web browser and navigate to:

http://YOUR_PUBLIC_IP:7474

You will see the Neo4j Browser login page.

Step 4: Log In

Enter your credentials:

  • Username: neo4j
  • Password: Your AWS Instance ID (from ~/readme)

After successful login, you will be connected to the Neo4j database and can start running Cypher queries.

Step 5: Verify Neo4j is Running

Check service status via SSH:

sudo systemctl status neo4j --no-pager

Expected Output:

● neo4j.service - Neo4j Graph Database
Loaded: loaded (/usr/lib/systemd/system/neo4j.service; enabled; ...)
Active: active (running) since ...

Run a test Cypher query via cypher-shell:

cypher-shell -u neo4j -p YOUR_INSTANCE_ID "RETURN 'Neo4j is working!' AS message;"

Expected Output:

message
"Neo4j is working!"

3. Architecture & Detailed Configuration

This AMI runs Neo4j Community Edition 5.x on Amazon Linux 2023, with a secure auto-credential system that sets each instance's password to its unique AWS Instance ID on first boot.

Deployment Architecture:

[Amazon Corretto 17]

[Neo4j Community Edition 5.x]
/etc/neo4j/neo4j.conf → configuration (remote access enabled)
/var/lib/neo4j/data/ → graph database storage
/var/log/neo4j/ → logs

[Systemd Service]
neo4j.service → Auto-start on boot

[Cloud-Init (per-instance, first boot only)]
/var/lib/cloud/scripts/per-instance/set_neo4j_password.sh

[Password = AWS Instance ID]

[README at /home/ec2-user/readme]
Login URL + credentials for the customer

Key Design Decisions:

  1. Password = Instance ID: Each deployed instance has a unique, cryptographically distinct password — no shared credentials across instances
  2. Cloud-init per-instance: The password script runs exactly once per instance lifecycle, not on every reboot
  3. IMDSv2 support: The script uses the secure token-based metadata API (IMDSv2) with fallback to IMDSv1
  4. 15-minute retry loop: Neo4j 5.x takes time to initialize on first boot — the script retries for up to 15 minutes before timing out
  5. Fallback password: If Instance ID cannot be retrieved, a random hex string is used as a fallback
  6. Remote access enabled: server.default_listen_address=0.0.0.0 configured so customers can access the web UI immediately

3.1. Neo4j Configuration File

File Location: /etc/neo4j/neo4j.conf

Key Modified Setting:

# Allow connections from any IP address (required for remote web UI access)
server.default_listen_address=0.0.0.0

How This Works:

By default, Neo4j binds only to localhost, making it inaccessible from outside the server. Setting server.default_listen_address=0.0.0.0 tells Neo4j to listen on all network interfaces, allowing customers to connect via browser or Bolt drivers from their machines.

Access control is enforced through:

  1. AWS Security Groups (firewall — only open ports 7474 and 7687)
  2. Neo4j authentication (username + password required)

3.2. Password Initialization Script

File Location: /opt/neo4j/init_password.sh

Complete Contents:

#!/bin/bash
# /opt/neo4j/init_password.sh
# Purpose: Auto-set Neo4j password to AWS Instance ID on first boot (AL2023)
# Logic: V5 High Availability (15min timeout) + Simple README format.

LOG_FILE="/var/log/neo4j_init.log"
echo "Starting Neo4j password initialization..." > "$LOG_FILE"

# --- 1. Retrieve AWS Instance ID ---
TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600" -s)
if [ -z "$TOKEN" ]; then
INSTANCE_ID=$(curl -s http://169.254.169.254/latest/meta-data/instance-id)
else
INSTANCE_ID=$(curl -H "X-aws-ec2-metadata-token: $TOKEN" -s http://169.254.169.254/latest/meta-data/instance-id)
fi

if [ -z "$INSTANCE_ID" ]; then
INSTANCE_ID=$(openssl rand -hex 8)
fi

echo "Target Password: $INSTANCE_ID" >> "$LOG_FILE"

# --- 2. Change Password Loop (15 min timeout) ---
MAX_RETRIES=300
COUNT=0
SUCCESS=0

echo "Attempting to set password on 'system' database..." >> "$LOG_FILE"

while [ $COUNT -lt $MAX_RETRIES ]; do
# Try to change password using 'ALTER CURRENT USER'
echo "ALTER CURRENT USER SET PASSWORD FROM 'neo4j' TO '$INSTANCE_ID';" | cypher-shell -u neo4j -p neo4j -d system >> "$LOG_FILE" 2>&1

if [ $? -eq 0 ]; then
echo "Success: Password changed." >> "$LOG_FILE"
SUCCESS=1
break
else
# Wait 3 seconds and retry
sleep 3
let COUNT=COUNT+1
fi
done

if [ $SUCCESS -eq 0 ]; then
echo "Error: Timed out after 15 minutes." >> "$LOG_FILE"
exit 1
fi

# --- 3. Generate README (Simple Format) ---
PUBLIC_IP=$(curl -s http://checkip.amazonaws.com || echo "<Your-Public-IP>")

cat > /home/ec2-user/readme <<EOF
========================================================================
Neo4j Credentials (Auto-configured)
========================================================================
Login URL: http://${PUBLIC_IP}:7474
Username : neo4j
Password : $INSTANCE_ID
(This is your AWS Instance ID)
========================================================================
EOF

chown ec2-user:ec2-user /home/ec2-user/readme
chmod 644 /home/ec2-user/readme

How This Works:

  • IMDSv2 token: Uses the secure AWS metadata API (IMDSv2) with a 6-hour token; falls back to IMDSv1 if the token request fails
  • Instance ID as password: Each EC2 instance has a globally unique Instance ID — using it as the password means no two instances share the same credentials
  • Retry loop: Neo4j 5.x requires the system database to be fully initialized before accepting password changes. The loop retries every 3 seconds for up to 15 minutes (300 × 3s)
  • cypher-shell -d system: Password changes in Neo4j 5.x must target the system database explicitly
  • README generation: After success, creates a human-readable credentials file owned by ec2-user

3.3. Cloud-Init Deployment

Script Location: /var/lib/cloud/scripts/per-instance/set_neo4j_password.sh

This is a symlink/copy of the initialization script placed in cloud-init's per-instance directory.

How Cloud-Init Works:

  • Scripts in /var/lib/cloud/scripts/per-instance/ run exactly once per instance — on first boot after launch
  • They do NOT run on subsequent reboots (unlike per-boot scripts)
  • This ensures the password is set once when a customer first launches the AMI, not reset on every restart

Cloud-Init Execution Timeline:

Instance launches (first boot)

cloud-init starts

Neo4j systemd service starts (auto-start)

set_neo4j_password.sh runs (per-instance)

Neo4j initializes system database (~10-20 seconds)

Script successfully changes password

/home/ec2-user/readme created with credentials

Customer reads readme → logs in to Neo4j Browser

4. How-To-Create: Reproduce This Environment

This section explains exactly how this AMI was built.

Step 1: Update System and Install Java 17

sudo dnf update -y
sudo dnf install java-17-amazon-corretto-devel -y

Verify:

java -version

Expected Output:

openjdk version "17.0.x" 2024-xx-xx LTS
OpenJDK Runtime Environment Corretto-17.x.x.x (build 17.0.x+x-LTS)

Step 2: Add Neo4j Official Repository

Import the GPG key:

sudo rpm --import https://debian.neo4j.com/neotechnology.gpg.key

Create the repository file:

sudo tee /etc/yum.repos.d/neo4j.repo > /dev/null << 'EOF'
[neo4j]
name=Neo4j RPM Repository
baseurl=https://yum.neo4j.com/stable/5
enabled=1
gpgcheck=1
EOF

How This Works:

  • rpm --import: Registers Neo4j's GPG signing key so packages can be verified
  • The repo points to yum.neo4j.com/stable/5 — the official Neo4j 5.x RPM channel
  • gpgcheck=1: Ensures every package is verified against the imported key

Step 3: Install Neo4j

sudo dnf install neo4j -y

This installs:

  • neo4j server binary
  • cypher-shell CLI tool
  • Default configuration at /etc/neo4j/neo4j.conf
  • Systemd service unit
  • Data and log directories

Step 4: Enable Remote Access

sudo sed -i 's/#server.default_listen_address=0.0.0.0/server.default_listen_address=0.0.0.0/' /etc/neo4j/neo4j.conf

Verify:

grep "server.default_listen_address" /etc/neo4j/neo4j.conf

Expected Output:

server.default_listen_address=0.0.0.0

Step 5: Start Neo4j and Verify

sudo systemctl enable --now neo4j
sudo systemctl status neo4j --no-pager

Wait 10–20 seconds for the first-time database initialization to complete.

Step 6: Create the Password Initialization Script

sudo mkdir -p /opt/neo4j
sudo tee /opt/neo4j/init_password.sh > /dev/null << 'SCRIPT'
#!/bin/bash
LOG_FILE="/var/log/neo4j_init.log"
echo "Starting Neo4j password initialization..." > "$LOG_FILE"

TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600" -s)
if [ -z "$TOKEN" ]; then
INSTANCE_ID=$(curl -s http://169.254.169.254/latest/meta-data/instance-id)
else
INSTANCE_ID=$(curl -H "X-aws-ec2-metadata-token: $TOKEN" -s http://169.254.169.254/latest/meta-data/instance-id)
fi

if [ -z "$INSTANCE_ID" ]; then
INSTANCE_ID=$(openssl rand -hex 8)
fi

echo "Target Password: $INSTANCE_ID" >> "$LOG_FILE"

MAX_RETRIES=300
COUNT=0
SUCCESS=0

echo "Attempting to set password on 'system' database..." >> "$LOG_FILE"

while [ $COUNT -lt $MAX_RETRIES ]; do
echo "ALTER CURRENT USER SET PASSWORD FROM 'neo4j' TO '$INSTANCE_ID';" | cypher-shell -u neo4j -p neo4j -d system >> "$LOG_FILE" 2>&1
if [ $? -eq 0 ]; then
echo "Success: Password changed." >> "$LOG_FILE"
SUCCESS=1
break
else
sleep 3
let COUNT=COUNT+1
fi
done

if [ $SUCCESS -eq 0 ]; then
echo "Error: Timed out after 15 minutes." >> "$LOG_FILE"
exit 1
fi

PUBLIC_IP=$(curl -s http://checkip.amazonaws.com || echo "<Your-Public-IP>")

cat > /home/ec2-user/readme <<EOF
========================================================================
Neo4j Credentials (Auto-configured)
========================================================================
Login URL: http://${PUBLIC_IP}:7474
Username : neo4j
Password : $INSTANCE_ID
(This is your AWS Instance ID)
========================================================================
EOF

chown ec2-user:ec2-user /home/ec2-user/readme
chmod 644 /home/ec2-user/readme
SCRIPT

sudo chmod +x /opt/neo4j/init_password.sh

Step 7: Deploy to Cloud-Init and Clean Up for AMI

# Stop Neo4j
sudo systemctl stop neo4j

# Reset database to default state (removes any test data and resets password to 'neo4j')
sudo rm -rf /var/lib/neo4j/data/dbms/auth
sudo rm -rf /var/lib/neo4j/data/databases/system
sudo rm -rf /var/lib/neo4j/data/transactions/system

# Fix ownership
sudo chown -R neo4j:neo4j /var/lib/neo4j/data

# Register the script with cloud-init
sudo mkdir -p /var/lib/cloud/scripts/per-instance
sudo cp /opt/neo4j/init_password.sh /var/lib/cloud/scripts/per-instance/set_neo4j_password.sh
sudo chmod +x /var/lib/cloud/scripts/per-instance/set_neo4j_password.sh

# Clean cloud-init state so it runs fresh on next launch
sudo systemctl stop cloud-init
sudo cloud-init clean --logs

# Remove instance-specific files
sudo rm -f /home/ec2-user/readme
sudo rm -f /var/log/neo4j_init.log

# Reset machine ID (important for AMI uniqueness)
sudo rm -f /etc/machine-id && sudo touch /etc/machine-id

How This Works:

  • Removing data/dbms/auth deletes the stored password hash — Neo4j will use the default neo4j/neo4j on next start
  • Removing data/databases/system and data/transactions/system forces Neo4j to reinitialize the system database on next boot — required for the password change script to work
  • cloud-init clean --logs resets cloud-init's "already run" marker so the per-instance script executes on the next instance launch
  • Removing /etc/machine-id ensures each launched instance gets a unique system ID

5. Credentials and Security

How Credentials Work

PhaseDetails
AMI stateDefault neo4j/neo4j password (reset during AMI prep)
First bootcloud-init runs set_neo4j_password.sh
After ~1-2 minPassword changed to Instance ID; ~/readme created
Customer accessReads ~/readme, logs in with Instance ID as password

Retrieve Your Password

cat /home/ec2-user/readme

Or directly find your Instance ID:

# From inside the instance
curl -s http://169.254.169.254/latest/meta-data/instance-id

# Or from AWS CLI (outside the instance)
aws ec2 describe-instances --instance-ids YOUR_INSTANCE_ID --query 'Reservations[0].Instances[0].InstanceId'

Change Your Password

After logging in to the Neo4j Browser, go to the top-right user menu and select Change Password, or use cypher-shell:

cypher-shell -u neo4j -p YOUR_INSTANCE_ID -d system \
"ALTER CURRENT USER SET PASSWORD FROM 'YOUR_INSTANCE_ID' TO 'NewStrongPassword!';"

Security Recommendations

  1. Change the default password after first login — do not keep the Instance ID as a permanent password
  2. Restrict security group access — limit port 7474 and 7687 to trusted IP ranges rather than 0.0.0.0/0
  3. Use HTTPS — configure Neo4j with an SSL certificate and use port 7473 for production
  4. Enable Neo4j authentication — authentication is enabled by default; do not disable dbms.security.auth_enabled

6. Using Neo4j

6.1. Neo4j Browser (Web UI)

Access at http://YOUR_PUBLIC_IP:7474

The Neo4j Browser provides:

  • Interactive Cypher query editor
  • Visual graph visualization
  • Schema explorer
  • Query history

6.2. Cypher Queries (Getting Started)

Connect via cypher-shell:

cypher-shell -u neo4j -p YOUR_PASSWORD

Create nodes:

CREATE (:Person {name: 'Alice', age: 30});
CREATE (:Person {name: 'Bob', age: 25});

Create relationships:

MATCH (a:Person {name: 'Alice'}), (b:Person {name: 'Bob'})
CREATE (a)-[:KNOWS]->(b);

Query the graph:

MATCH (p:Person)-[:KNOWS]->(q:Person)
RETURN p.name, q.name;

Count nodes:

MATCH (n) RETURN count(n);

6.3. Connecting with Drivers

Python (neo4j driver):

from neo4j import GraphDatabase

driver = GraphDatabase.driver(
"bolt://YOUR_PUBLIC_IP:7687",
auth=("neo4j", "YOUR_PASSWORD")
)

with driver.session() as session:
result = session.run("RETURN 'Hello, Neo4j!' AS message")
print(result.single()["message"])

driver.close()

JavaScript (neo4j-driver):

const neo4j = require('neo4j-driver');

const driver = neo4j.driver(
'bolt://YOUR_PUBLIC_IP:7687',
neo4j.auth.basic('neo4j', 'YOUR_PASSWORD')
);

const session = driver.session();
session.run("RETURN 'Hello!' AS msg")
.then(result => console.log(result.records[0].get('msg')))
.finally(() => driver.close());

7. Important File Locations

File PathPurpose
/etc/neo4j/neo4j.confMain Neo4j configuration file
/var/lib/neo4j/data/Graph database data directory
/var/log/neo4j/Neo4j log files
/var/log/neo4j/neo4j.logMain application log
/var/log/neo4j/debug.logDetailed debug log
/opt/neo4j/init_password.shPassword initialization script
/var/lib/cloud/scripts/per-instance/set_neo4j_password.shCloud-init deployment of init script
/var/log/neo4j_init.logPassword initialization log
/home/ec2-user/readmeAuto-generated credentials file
/etc/yum.repos.d/neo4j.repoNeo4j RPM repository configuration
/usr/bin/cypher-shellNeo4j command-line query tool
/usr/lib/systemd/system/neo4j.serviceSystemd service file

8. Troubleshooting

Issue 1: ~/readme File Not Found After Launch

Symptoms:

$ cat /home/ec2-user/readme
cat: /home/ec2-user/readme: No such file or directory

Cause:

The password initialization script is still running — Neo4j needs 1–2 minutes to fully start and accept password changes.

Solution:

Wait 2 minutes and check the initialization log:

cat /var/log/neo4j_init.log

If the script is still running, you will see retry attempts. Wait for Success: Password changed.


Issue 2: Cannot Access Neo4j Browser

Symptoms:

Browser shows "Connection refused" or times out on http://YOUR_IP:7474.

Diagnosis:

Check Neo4j is running:

sudo systemctl status neo4j

Check port is listening:

sudo ss -tlnp | grep 7474

Solutions:

  1. Verify port 7474 is open in your AWS security group
  2. Start Neo4j if not running: sudo systemctl start neo4j
  3. Check logs for errors: sudo tail -50 /var/log/neo4j/neo4j.log

Issue 3: Login Fails with Correct Password

Symptoms:

Neo4j Browser shows "Invalid username or password" even with the Instance ID.

Diagnosis:

Check initialization log:

cat /var/log/neo4j_init.log

Solution:

If the script failed (shows "Error: Timed out"), run it manually:

sudo bash /opt/neo4j/init_password.sh

Then read the newly generated readme:

cat /home/ec2-user/readme

Issue 4: Neo4j Service Fails to Start

Symptoms:

$ sudo systemctl status neo4j
Active: failed

Diagnosis:

sudo journalctl -u neo4j -n 50 --no-pager
sudo tail -50 /var/log/neo4j/neo4j.log

Common Causes:

  1. Java not found or wrong version:
java -version

Ensure it shows Corretto-17. If not, reinstall:

sudo dnf install java-17-amazon-corretto-devel -y
  1. Port already in use:
sudo lsof -i :7474
sudo lsof -i :7687
  1. Data directory permission issue:
sudo chown -R neo4j:neo4j /var/lib/neo4j/
sudo chown -R neo4j:neo4j /var/log/neo4j/
sudo systemctl start neo4j

Issue 5: Forgot Password

Solution:

Stop Neo4j, reset the auth database, and let cloud-init set a new password:

sudo systemctl stop neo4j
sudo rm -rf /var/lib/neo4j/data/dbms/auth
sudo rm -rf /var/lib/neo4j/data/databases/system
sudo rm -rf /var/lib/neo4j/data/transactions/system
sudo chown -R neo4j:neo4j /var/lib/neo4j/data
sudo rm -f /home/ec2-user/readme
sudo systemctl start neo4j
sudo bash /opt/neo4j/init_password.sh
cat /home/ec2-user/readme

9. Final Notes

Key Takeaways

  1. Neo4j Community Edition 5.x running on Amazon Linux 2023 with Java 17 (Corretto)
  2. Password = AWS Instance ID — unique per instance, auto-configured on first boot
  3. Read ~/readme for credentials immediately after launch
  4. Open ports 7474 and 7687 in your security group to access the web UI and Bolt protocol
  5. The installation is production-ready and AMI-optimized

Neo4j Use Cases

  • Knowledge Graphs: Connect entities and relationships for AI/ML applications
  • Fraud Detection: Trace transaction networks and suspicious patterns
  • Recommendation Engines: "Customers who bought X also bought Y"
  • Network & IT Operations: Map infrastructure dependencies
  • Social Networks: Model user connections and communities
WorkloadInstanceReason
Development / Testingt3.medium2 vCPU, 4GB RAM minimum for Neo4j
Small productiont3.large8GB RAM, good for moderate graphs
Medium productionm5.xlarge16GB RAM, better for large datasets
Analytics workloadsr5.xlarge+Memory-optimized for large graphs

Note: Neo4j Community Edition requires at least 2GB RAM. t3.small (2GB) is the absolute minimum; t3.medium (4GB) is recommended for comfortable operation.

Additional Resources


For support or questions, please contact the Easycloud team.