# Seeding Neo4j using a Backup on Docker

**URL:** <https://community.neo4j.com/t/seeding-neo4j-using-a-backup-on-docker/14937>\
**Category:** Community Content & Blogs\
**Created:** [February 20, 2020, 1:06pm UTC](https://community.neo4j.com/t/seeding-neo4j-using-a-backup-on-docker/14937 "2020-02-20T13:06:31Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![adam\_cowley](https://sea1.discourse-cdn.com/flex021/user_avatar/community.neo4j.com/adam_cowley/32/145_2.png) [@adam\_cowley](https://community.neo4j.com/u/adam_cowley)\
**Post date:** [February 20, 2020, 1:06pm UTC](https://community.neo4j.com/t/seeding-neo4j-using-a-backup-on-docker/14937/1 "2020-02-20T13:06:31Z")

</div>

20/02/2020 02:20

In this post, I’ll walk through how you can take a backup of an existing database and use it to seed an [instance of Neo4j inside a Docker container](https://hub.docker.com/neo4j). This could be useful if you are looking to fire up a development server using real data. I’ll show you how how to launch an instance of Neo4j using `docker-compose` and then extend the official Docker image by creating a custom `Dockerfile`.

## Neo4j on Docker

You can find Neo4j images going back to 3.4 on [Docker hub](https://hub.docker.com/neo4j) all named as `x.y.z` for community and with `-enterprise` appended for enterprise edition. You can get up and running quickly by running the `docker run` command.

In order to run Enterprise Edition, you need to accept the [Neo4j Licensing Agreement](https://neo4j.com/licensing/). You do this with Docker by setting the `NEO4J_ACCEPT_LICENSE_AGREEMENT` variable to `yes`.

```
docker run --env=NEO4J_ACCEPT_LICENSE_AGREEMENT=yes
    neo4j:4.0.0-enterprise
```

## Taking a Backup `neo4j-admin backup`

The `neo4j-admin` tool located in the `$NEO4J_HOME/bin` folder allows you to run a number of administation commands including [backup](https://neo4j.com/docs/operations-manual/current/backup/performing/), [restore](https://neo4j.com/docs/operations-manual/current/backup/restoring/) and an [import tool for imports of over 1M rows](https://neo4j.com/docs/operations-manual/current/tools/import/).

There are two types of exports - `dump` and `export`. The `dump` command creates an archive that can be easily shared and is great for smaller databases. For larger databases, the `export` command allows you to do an incremental backup. If you run a backup on a directory that already has a backup in there, it will take the difference and append it to the store files rather than starting from transaction id 0. This is great for larger databases.

The backup is enabled by default, but by default it will only listen on the backup port on requests from localhost. Because we’ll be taking a backup from a local machine, we’ll need to enable remote backups by setting `dbms.backup.listen_address` to `0.0.0.0:6362`.

neo4j.conf

```
# Enable online backups to be taken from this database.
dbms.backup.enabled=true
# By default the backup service will only listen on localhost.
# To enable remote backups you will have to bind to an external
# network interface (e.g. 0.0.0.0 for all interfaces).
# The protocol running varies depending on deployment. In a Causal Clustering environment this is the
# same protocol that runs on causal_clustering.transaction_listen_address.
dbms.backup.listen_address=0.0.0.0:6362
```

To run the backup you can run the following command:

```
bin/neo4j-admin backup \
    --from=neo4jurl:7687 \ # hostname or ip and port for neo4j server
    --backup-dir=/path/to/backups \ # directory to store the backup in
    --database=neo4j # The name of the database to backup
```

A consistency check runs as part of the backup to make sure that the backup files are OK, but this can take a while on a large database. You can disable this by adding `--check-consistency=false` and check the consitency at a later time.

## Automating the Backup using Docker

One of the nice things about Docker is that you can build or _extend_ `Dockerfile`s to create an image. These can also be published to the Docker Hub but I won’t cover that here. The `FROM` keyword allows you to choose an image to build on top of, in this case we want the latest version of Neo4j Enterprise.

Dockerfile

The neo4j images all automatically start up the neo4j instance. In this case, we want to run the backup on the _production_ server and restore it before the neo4j server starts. We can do this by replacing the the `ENTRYPOINT` with one of our own. There’s a lot of complicated stuff going on in [in the docker-entrypoint.sh file](https://github.com/neo4j/docker-neo4j-publish/blob/master/4.0.0/enterprise/docker-entrypoint.sh) that I don’t really want to be replicating and maintaining, so instead we can just create a new shell file which performs the backup and restore before calling the original `docker-entrypoint.sh` file.

my-entrypoint.sh

```
#!/bin/bash
echo "Running Backup & Restore"
neo4j-admin backup --from=$PRODUCTION --backup-dir=/backup 
neo4j-admin restore --from=/backup/neo4j --database=neo4j --force
```

The script runs the `neo4j-admin backup` command and places the backup in the `/backup` directory before `restore`ing it into [the default `neo4j` database](https://adamcowley.co.uk/neo4j/multi-tenancy-neo4j-4.0/). The introduction of the `$PRODUCTION` environment variable to the call means that the address of the neo4j server can be set as an `--env` flag when the container is created. The `--force` command will overwrite any files if they already exist, perfect for if we’re mounting a volume for the data.

### File Ownership

The file ownership caused me a few issues when developing this script, the neo4j process is run by a user called `neo4j` whereas this entrypoint script is ran by root. Originally, this caused a `Neo.TransientError.Database.DatabaseUnavailable` error complaining that `Database 'neo4j' is unavailable`. This was because the neo4j user couldn’t write to the directory. `chown`ing the /data directory to `neo4j:neo4j` fixes this issue.

my-entrypoint.sh

```
chown -R neo4j:neo4j /data
```

After that, the original `docker-entrypoint.sh` script can be run to work it’s magic and bring the database up.

my-entrypoint.sh

```
/docker-entrypoint.sh neo4j
```

### Modifying the `Dockerfile`

Back in `Dockerfile`, a few commands are needed to clean things up. Firstly, we’ll need to accept the license agreement.

Dockerfile

```
ENV NEO4J_ACCEPT_LICENSE_AGREEMENT yes
```

Next, setting the `dbms.directories.data` directory to a folder in the root will make it easier to mount a volume.

Dockerfile

```
ENV NEO4J_dbms_directories_data /data
```

Then, `my-entrypoint.sh` needs to be copied to the docker container. By default the file will not have execute permissions, so the `RUN` command will allow us to run `chmod` to add execution permission on the file.

Dockerfile

```
WORKDIR /
COPY my-entrypoint.sh /my-entrypoint.sh
RUN chmod +x /my-entrypoint.sh
```

Finally, we can overwrite the `ENTRYPOINT` to run `my-entrypoint.sh` (and subsequently the original `docker-entrypoint.sh`) before running the `neo4j` command to start neo4j.

Dockerfile

```
ENTRYPOINT ["/sbin/tini", "-g", "--", "/my-entrypoint.sh"]
CMD ["neo4j"]
```

### Building the image

The `docker build` command creates an image that can be used when creating containers.

To make life easier, I have tagged the new image as `dev` using the `-t dev` flag, otherwise it would generate a random hash and the whole thing couldn’t be automated.

### Creating a Container

Containers with the newly created `dev` image can be created using the `docker run` command. I have mapped the HTTP and Bolt ports using `-p` so I can access the Neo4j Browser and query the data via bolt. As mentioned before, running a backup on a directory with an existing backup will trigger an incremental backup so I will mount the backup directory as a [volume](https://docs.docker.com/storage/volumes/) on the docker container. The same goes for the data directory. The local path to the volumes need to be absolute so I have created a `$HERE` environment variable to make things a bit easier.

```
docker run --name=dev \
    -p 17474:7474 \ # Map HTTP port from container to 17474
    -p 17687:7687 \ # Map Bolt port from container to 17687
    --env="PRODUCTION=prod.databases.adamcowley.co.uk:6463" # Env var for server
    --volume="$HERE/backup:/backup" \ # Mount backup directory volume to /backup
    --volume="$HERE/data:/data" \ # Mount data directory volume to /data
    dev # Use the newly built dev image
```

## Conclusion

Being fairly inexperienced with Docker, this took me a while to figure out. But once I realised that I can just _extend_ an existing image, my life became a lot easier. This process works well for a single instance, but could also be used to automate the seeding and deployment of [Read Replicas](https://neo4j.com/docs/operations-manual/current/clustering/introduction/#causal-clustering-read-replicas). Downloading a copy of a previous backup and mounting it as a volume will speed up the startup process on larger databases.

I’ve put the [code up on Github](https://github.com/adam-cowley/seed-neo4j-docker) - feel free to pull, clone or submit a PR.

* * *
This is a companion discussion topic for the original entry at [https://adamcowley.co.uk/neo4j/neo4j-docker-seed-backup/](https://adamcowley.co.uk/neo4j/neo4j-docker-seed-backup/)
