In this blog post Create a Blank Neo4j Instance Safely on Docker, VM, or Kubernetes we will walk through how to spin up a clean, secure Neo4j deployment on Docker, a Linux VM, or Kubernetes, and why each step matters.
Create a Blank Neo4j Instance Safely on Docker, VM, or Kubernetes starts with a simple goal: a fresh Neo4j you can rely on. Teams sometimes say “black Neo4j instance” when they really mean a pristine or blank graph with no sample data, safe defaults, and repeatable setup. That’s what we’ll build.
What is Neo4j and why it fits this job
Neo4j is a native graph database built on the labeled property graph model. Data lives as nodes and relationships, both carrying key-value properties, which makes connected queries fast and expressive. Cypher is Neo4j’s query language, designed to describe patterns, not just rows, so reading relationships like KNOWS or PURCHASED feels natural. Under the hood Neo4j uses a transactional storage engine with a write-ahead log and a page cache for hot data. Clients talk to Neo4j via the Bolt protocol (port 7687) and a lightweight HTTP/HTTPS API (port 7474) used by Neo4j Browser and tools.
When we say “blank instance,” we mean a new server with authentication enabled, persistent storage, and zero user data or sample datasets. In Community edition you get one database (named neo4j
); Enterprise adds multiple databases and clustering. We’ll keep everything portable and secure-by-default so you can promote from laptop to cloud with minimal churn.
What you will build
- A clean, empty Neo4j instance
- Authentication enabled and an admin password set
- Persistent volumes so data survives restarts
- Network exposure limited to what you actually need
- Optional TLS and a quick backup routine
Prerequisites
- Neo4j 5.x (Docker image or native packages)
- Docker Desktop (for the container path) or Ubuntu 22.04+ (for the VM path) or a Kubernetes cluster (for the K8s path)
- Ports: 7474 (HTTP/Browser) and 7687 (Bolt)
Option 1 — Docker quick start
This is the fastest path for local development or a POC.
# Create persistent volumes
docker volume create neo4j_data
docker volume create neo4j_logs
# Run Neo4j Community 5.x
docker run \
--name neo4j \
--detach \
--publish 127.0.0.1:7474:7474 \
--publish 127.0.0.1:7687:7687 \
--volume neo4j_data:/data \
--volume neo4j_logs:/logs \
--env NEO4J_AUTH=neo4j/ChangeMeNow! \
--env NEO4J_dbms_memory_pagecache_size=1G \
--env NEO4J_server_memory_heap_initial__size=512m \
--env NEO4J_server_memory_heap_max__size=2G \
--env NEO4JLABS_PLUGINS='["apoc"]' \
neo4j:5-community
Notes:
- We bind ports to
127.0.0.1
to keep the database local-only. Use a reverse proxy or VPN to expose it later. NEO4J_AUTH
sets an initial password; change it after your first login.- Volumes mount
/data
and/logs
so the graph persists.
Test it:
- Open http://localhost:7474 (Neo4j Browser)
- Login with
neo4j
/ChangeMeNow!
- Run:
SHOW DATABASES;
— you should see the defaultneo4j
database.
Keeping it blank
The Community edition starts with an empty neo4j
database. If you ever loaded sample data and want to clear it:
// Remove all nodes and relationships
MATCH (n) DETACH DELETE n;
// Optionally drop indexes and constraints (v5 syntax)
SHOW INDEXES YIELD name; // Inspect first
// DROP INDEX index_name;
SHOW CONSTRAINTS YIELD name; // Inspect first
// DROP CONSTRAINT constraint_name;
Enterprise users can create a brand-new database:
// Enterprise only
CREATE DATABASE clean;
WAIT FOR DATABASE clean ONLINE;
Optional TLS on Docker
For encrypted Bolt, generate a certificate and mount it under /var/lib/neo4j/certificates
, then configure TLS:
# Example: generate self-signed certs (adjust CN/SANs to your hostnames)
openssl req -x509 -newkey rsa:4096 -sha256 -days 365 -nodes \
-keyout private.key -out public.crt -subj "/CN=localhost"
# Create expected directory structure and mount to the container
# /var/lib/neo4j/certificates/bolt/...
# Then set environment variables like:
NEO4J_server_bolt_tls__level=REQUIRED
In production, use certificates issued by your organization instead of self-signed.
Option 2 — Linux VM install (Ubuntu)
This suits small servers or when you want systemd-managed services.
# Add Neo4j repository (5.x)
wget -O - https://debian.neo4j.com/neotechnology.gpg.key | sudo gpg --dearmor -o /usr/share/keyrings/neo4j.gpg
echo "deb [signed-by=/usr/share/keyrings/neo4j.gpg] https://debian.neo4j.com stable 5" | \
sudo tee /etc/apt/sources.list.d/neo4j.list
sudo apt update
sudo apt install neo4j
# Enable and start
sudo systemctl enable neo4j
sudo systemctl start neo4j
Configure security and memory:
# /etc/neo4j/neo4j.conf (key lines)
server.default_listen_address=0.0.0.0 # Or a specific NIC/IP
server.bolt.listen_address=:7687
server.http.listen_address=:7474
# Enable auth (default true)
server.auth.enabled=true
# Heap and page cache sizing
server.memory.heap.initial_size=512m
server.memory.heap.max_size=2g
dbms.memory.pagecache.size=1g
Restrict network access with a firewall:
sudo ufw allow from 203.0.113.10 to any port 7687 proto tcp
sudo ufw allow from 203.0.113.10 to any port 7474 proto tcp
sudo ufw enable
Set the initial password (first login) using Neo4j Browser or the command line:
cypher-shell -u neo4j -p neo4j 'ALTER CURRENT USER SET PASSWORD FROM "neo4j" TO "ChangeMeNow!";'
Option 3 — Kubernetes quick start
Kubernetes gives you repeatability and easy upgrades. Here’s a minimal StatefulSet with a persistent volume. Access via port-forward to keep it private.
kubectl create namespace graphs
cat <<'YAML' | kubectl apply -n graphs -f -
apiVersion: v1
kind: Service
metadata:
name: neo4j
spec:
selector:
app: neo4j
ports:
- name: http
port: 7474
- name: bolt
port: 7687
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: neo4j
spec:
serviceName: neo4j
replicas: 1
selector:
matchLabels:
app: neo4j
template:
metadata:
labels:
app: neo4j
spec:
containers:
- name: neo4j
image: neo4j:5-community
ports:
- containerPort: 7474
- containerPort: 7687
env:
- name: NEO4J_AUTH
value: "neo4j/ChangeMeNow!"
- name: NEO4J_server_memory_heap_initial__size
value: "512m"
- name: NEO4J_server_memory_heap_max__size
value: "2G"
- name: NEO4J_dbms_memory_pagecache_size
value: "1G"
volumeMounts:
- name: data
mountPath: /data
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 10Gi
YAML
# Port-forward for local access
kubectl -n graphs port-forward svc/neo4j 7474:7474 7687:7687
Secure-by-default checklist
- Change the initial password immediately and use a vault/secret manager.
- Restrict network exposure. Prefer localhost, VPN, or private subnets.
- Enable TLS for Bolt when crossing untrusted networks.
- Use least-privilege OS users and non-root containers.
- Size memory: heap for query processing, page cache for graph store.
- Persist
/data
and back it up on a schedule.
Backups and restore
Always practice restores. Two common approaches:
# Online dump (requires database to be offline for full consistency on older versions; consult docs for your version)
neo4j-admin database dump --to-path /backups neo4j
# Restore
neo4j-admin database load --from-path /backups neo4j --overwrite-destination
In containers, bind-mount a host directory to /backups
or use an object storage sync job.
Why these steps matter under the hood
- Authentication prevents anonymous writes via Bolt or HTTP.
- Persistent volumes keep the store files and transaction logs safe across restarts.
- Memory settings split work: heap for query planning/execution, page cache for fast graph traversal. Oversizing heap starves the page cache and slows reads.
- TLS protects Bolt traffic that would otherwise expose credentials and data.
- Limiting network surfaces reduces attack paths to the Bolt port you actually use.
Automate for repeatability
- Docker Compose for local: encode volumes, env, and ports in code.
- Helm or Kustomize for Kubernetes: keep values in Git and promote through environments.
- Cloud VM with Terraform and cloud-init: provision OS, firewall, and Neo4j in one plan.
Troubleshooting tips
- Port already in use: stop old containers or change host ports.
- Can’t write to /data: check volume permissions; container user must own the path.
- Browser can’t connect to Bolt: verify 7687 is reachable and not blocked by a firewall.
- High GC pauses: reduce heap or tune queries; monitor with
SHOW TRANSACTIONS
and logs. - ARM vs x86: use an image tag that supports your architecture; official images support both.
Next steps
- Add role-based access control (Enterprise) and separate app/service accounts.
- Define schema for speed and safety: unique constraints on ids, indexes for lookups.
- Automate imports with
neo4j-admin database import
or APOC procedures. - Introduce monitoring: metrics to Prometheus and logs to your SIEM.
- Consider Neo4j Enterprise for multi-database, clustering, and advanced security.
With these steps, you have a reliable, blank Neo4j ready for development or to serve as the foundation for a production rollout. Start small, keep it secure, and automate the path from laptop to cloud.
Discover more from CPI Consulting
Subscribe to get the latest posts sent to your email.