diff --git a/DEMO.md b/DEMO.md
index 80a58fceb23502a9854ccdc6eaa0e23e5e8d6d33..9f955cce5714b21f341f18deda0bd3709bcae60b 100644
--- a/DEMO.md
+++ b/DEMO.md
@@ -25,7 +25,7 @@ cp db.demo.sqlite3 db.sqlite3
 tar -cJvf demo_media.tar.xz ./demo_media
 docker compose -f docker-compose.demo.yml up -d
 docker compose -f docker-compose.demo.yml exec web python manage.py migrate --noinput
-docker compose -f docker-compose.prod.yml exec web python manage.py collectstatic --no-input --clear
+docker compose -f docker-compose.demo.yml exec web python manage.py collectstatic --no-input --clear
 docker compose -f docker-compose.demo.yml exec web python manage.py opensearch index --force create
 docker compose -f docker-compose.demo.yml exec web python manage.py opensearch document --force index
 ```
@@ -43,7 +43,7 @@ tar -xJvf demo_media.tar.xz ./demo_media
 # Start the web container
 docker compose -f docker-compose.demo.yml up -d
 docker compose -f docker-compose.demo.yml exec web python manage.py migrate --noinput
-docker compose -f docker-compose.prod.yml exec web python manage.py collectstatic --no-input --clear
+docker compose -f docker-compose.demo.yml exec web python manage.py collectstatic --no-input --clear
 docker compose -f docker-compose.demo.yml exec web python manage.py opensearch document --force delete
 docker compose -f docker-compose.demo.yml exec web python manage.py opensearch document --force index
 ```
\ No newline at end of file
diff --git a/demo_reset.sh b/demo_reset.sh
new file mode 100755
index 0000000000000000000000000000000000000000..a307985c93e21e3c92592e37ced94181e96873f3
--- /dev/null
+++ b/demo_reset.sh
@@ -0,0 +1,67 @@
+#!/bin/bash
+
+wait_for_container() {
+  STRING_IN_NAME=$1
+  CONTAINER=$(docker compose -f docker-compose.demo.yml ps | grep "$STRING_IN_NAME" | cut -f1 -d' ')
+  timeout=500
+
+  counter=0
+
+  echo "Waiting for $CONTAINER to be ready (${counter}/${timeout})"
+
+  until [[ $(docker inspect --format '{{json .State.Running}}' "$CONTAINER") == true ]]; do
+
+    if [[ $timeout -lt $counter ]]; then
+      echo "ERROR: Timed out waiting for $CONTAINER to come up."
+      exit 1
+    fi
+
+    if (( $counter % 5 == 0 )); then
+      echo -e "\e[1A\e[KWaiting for $CONTAINER to be ready (${counter}/${timeout})"
+    fi
+
+    sleep 1s
+    ((counter++))
+
+  done
+}
+
+get_ip_address() {
+  STRING_IN_NAME=$1
+  CONTAINER=$(docker compose -f docker-compose.demo.yml ps | grep "$STRING_IN_NAME" | cut -f1 -d' ')
+  docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$CONTAINER" | head -n 1
+}
+
+# Stop the containers
+docker compose -f docker-compose.demo.yml stop web
+
+# Reset the database
+rm db.sqlite3
+cp db.demo.sqlite3 db.sqlite3
+
+# Reset the media
+rm -rd demo_media/*
+tar -xJvf demo_media.tar.xz ./demo_media
+
+# Start the containers
+docker compose -f docker-compose.demo.yml up -d
+
+# Wait for web container to be ready
+wait_for_container "web"
+wait_for_container "opensearch"
+
+# Wait until we can reach opensearch
+os_ip=$(get_ip_address "opensearch")
+echo "$os_ip"
+until curl --output /dev/null --silent --head --fail "https://$os_ip:9200" -ku "admin:VeryInsecurePassword1!"; do
+    echo "Waiting for Opensearch"
+    sleep 5
+done
+sleep 5
+
+# Load the data
+docker compose -f docker-compose.demo.yml exec web python manage.py opensearch document --force delete
+docker compose -f docker-compose.demo.yml exec web python manage.py opensearch document --force index
+
+# Done
+echo Done!
\ No newline at end of file
diff --git a/demo_start.sh b/demo_start.sh
new file mode 100755
index 0000000000000000000000000000000000000000..768e04222443b48eb8cbf873fae87888af49f803
--- /dev/null
+++ b/demo_start.sh
@@ -0,0 +1,62 @@
+#!/bin/bash
+
+wait_for_container() {
+  STRING_IN_NAME=$1
+  CONTAINER=$(docker compose -f docker-compose.demo.yml ps | grep "$STRING_IN_NAME" | cut -f1 -d' ')
+  timeout=500
+
+  counter=0
+
+  echo "Waiting for $CONTAINER to be ready (${counter}/${timeout})"
+
+  until [[ $(docker inspect --format '{{json .State.Running}}' "$CONTAINER") == true ]]; do
+
+    if [[ $timeout -lt $counter ]]; then
+      echo "ERROR: Timed out waiting for $CONTAINER to come up."
+      exit 1
+    fi
+
+    if (( $counter % 5 == 0 )); then
+      echo -e "\e[1A\e[KWaiting for $CONTAINER to be ready (${counter}/${timeout})"
+    fi
+
+    sleep 1s
+    ((counter++))
+
+  done
+}
+
+get_ip_address() {
+  STRING_IN_NAME=$1
+  CONTAINER=$(docker compose -f docker-compose.demo.yml ps | grep "$STRING_IN_NAME" | cut -f1 -d' ')
+  docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$CONTAINER" | head -n 1
+}
+
+# Get database ready
+cp db.demo.sqlite3 db.sqlite3
+
+# Backup media
+tar -cJvf demo_media.tar.xz ./demo_media
+
+# Start the containers
+docker compose -f docker-compose.demo.yml up -d
+
+# Wait for web container to be ready
+wait_for_container "web"
+wait_for_container "opensearch"
+
+# Wait until we can reach opensearch
+os_ip=$(get_ip_address "opensearch")
+echo "$os_ip"
+until curl --output /dev/null --silent --head --fail "https://$os_ip:9200" -ku "admin:VeryInsecurePassword1!"; do
+    echo "Waiting for Opensearch"
+    sleep 5
+done
+sleep 5
+
+# Load the data
+docker compose -f docker-compose.demo.yml exec web python manage.py opensearch index --force create
+docker compose -f docker-compose.demo.yml exec web python manage.py opensearch document --force index
+
+# Done
+echo Done!
\ No newline at end of file
diff --git a/docker-compose.demo.yml b/docker-compose.demo.yml
index 130961efd01b2dfa83beaf6eff18fdb31f820282..c1e0a18b5b883e3c55530fa3f759f7314025a4b4 100644
--- a/docker-compose.demo.yml
+++ b/docker-compose.demo.yml
@@ -4,6 +4,7 @@ services:
     command: gunicorn heyheyLibrary.wsgi:application --bind 0.0.0.0:8000
     environment:
       - DJANGO_ALLOWED_HOSTS=librarydemo.rb9.xyz
+      - OPENSEARCH_HOST=opensearch:9200
       - OPENSEARCH_USERNAME=admin
       - OPENSEARCH_PASSWORD=VeryInsecurePassword1!
       - SECRET_KEY=VeryInsecureSecretKey
@@ -20,6 +21,7 @@ services:
       - librarydemo-internal
     links:
       - nginx-googleapisproxy:www.googleapis.com
+      - opensearch:opensearch
 
   opensearch:
     image: opensearchproject/opensearch:latest
@@ -57,11 +59,14 @@ services:
       - demo_static:/home/app/web/staticfiles
       - ./demo_media:/home/app/web/mediafiles
     ports:
-      - 1337:80
+      - "1337:80"
     depends_on:
       - web
+    links:
+      - web:web
     networks:
       - librarydemo-internal
+      - librarydemo-external
 
 volumes:
   demo_static:
@@ -71,4 +76,4 @@ networks:
   librarydemo-internal:
     # Block all external traffic to the network
     internal: true
-  librarydemo-external: {}
\ No newline at end of file
+  librarydemo-external: {}