diff --git a/README.md b/README.md
index d5b0e51ec2a0eb74f69f1718a2e81fe395278e7b..f7b4959eb46d8e00c4ec1f33c2c0f731a1ac0687 100644
--- a/README.md
+++ b/README.md
@@ -67,9 +67,10 @@ These need to be available locally, because Kratos wants to run on the same
 domain as the front-end that serves the login interface.
 
 ### Setup
+Before you start, make sure your machine has the required software installed, as per official documentation: https://docs.stackspin.net/en/v2/installation/install_cli.html#preparing-the-provisioning-machine.
 
 Please read through all subsections to set up your environment before
-attempting to run the dashboard locally.
+attempting to run the dashboard locally. 
 
 #### 1. Stackspin cluster
 
diff --git a/backend/areas/users/users.py b/backend/areas/users/users.py
index baaa9003538da7858ff3d47cd15d7e9626898722..25d906e593b405cb9a6a19f21a44f123194c181a 100644
--- a/backend/areas/users/users.py
+++ b/backend/areas/users/users.py
@@ -1,7 +1,7 @@
 from flask import jsonify, request
-from flask_jwt_extended import get_jwt, jwt_required
 from flask_cors import cross_origin
 from flask_expects_json import expects_json
+from flask_jwt_extended import get_jwt, jwt_required
 
 from areas import api_v1
 from helpers import KratosApi
diff --git a/backend/config.py b/backend/config.py
index 1972c59497b1229589837c66ca6973bb1e7fd408..6e5d37ac1221925e8403612674225bd0ccf5314d 100644
--- a/backend/config.py
+++ b/backend/config.py
@@ -21,3 +21,5 @@ SQLALCHEMY_TRACK_MODIFICATIONS = False
 # running in a Kubernetes pod. Set it to "false" to load the config from the
 # `KUBECONFIG` environment variable.
 LOAD_INCLUSTER_CONFIG = os.environ.get("LOAD_INCLUSTER_CONFIG").lower() == "true"
+
+DEMO_INSTANCE = os.environ.get("DASHBOARD_DEMO_INSTANCE", "False").lower() in ('true', '1')
diff --git a/backend/web/login/login.py b/backend/web/login/login.py
index 12d4ff1aecaa1aa69fc960ff9033aa30b09006bf..25f09a006ace2a225fdf17d3f674a810a6a64fa4 100644
--- a/backend/web/login/login.py
+++ b/backend/web/login/login.py
@@ -16,7 +16,7 @@ from ory_hydra_client.models import AcceptConsentRequest, AcceptLoginRequest, Co
 import ory_hydra_client.exceptions as hydra_exceptions
 import ory_kratos_client
 from ory_kratos_client.api import frontend_api, identity_api
-from flask import abort, redirect, render_template, request, current_app
+from flask import abort, current_app, jsonify, redirect, render_template, request
 
 from database import db
 from helpers import KratosUser
@@ -24,6 +24,8 @@ from config import *
 from web import web
 from areas.apps import AppRole, App, OAuthClientApp
 from areas.roles import RoleService
+from areas.roles.models import Role
+from areas.users.user_service import UserService
 
 
 # This is a circular import and should be solved differently
@@ -159,7 +161,7 @@ def login():
     # or `not identity`
     #     User is not logged in yet.
     # In either case, we present the login screen now.
-    return render_template("login.html", api_url=KRATOS_PUBLIC_URL, dashboard_url=DASHBOARD_URL, refresh=refresh)
+    return render_template("login.html", api_url=KRATOS_PUBLIC_URL, dashboard_url=DASHBOARD_URL, refresh=refresh, demo=DEMO_INSTANCE)
 
 
 @web.route("/auth", methods=["GET", "POST"])
@@ -543,3 +545,14 @@ def logout():
             ex)
     return redirect(kratos_api_response.logout_url)
 
+
+if DEMO_INSTANCE:
+    @web.route("/demo-user", methods=["POST"])
+    def demo_user():
+        data = request.get_json()
+        defaults = {
+            "name": "",
+            "app_roles": [{"name": "dashboard", "role_id": Role.ADMIN_ROLE_ID}],
+        }
+        UserService.post_user({**defaults, **data})
+        return jsonify("User created successfully. You should receive an email to confirm your address and set a password.")
diff --git a/backend/web/static/base.js b/backend/web/static/base.js
index 566f8db7cfac424c70e9290ab45ff35dc383b57a..e7cab4a0d962dec9018d14fe703cb784a1a612da 100644
--- a/backend/web/static/base.js
+++ b/backend/web/static/base.js
@@ -59,6 +59,9 @@ function flow_login() {
 
       var messages_html = render_messages(data);
       $('#contentMessages').html(messages_html);
+
+      $('#totp_code').focus();
+      $('#identifier').focus();
     },
     complete: function (obj) {
       // If we get a 410, the flow is expired, need to refresh the flow
diff --git a/backend/web/templates/login.html b/backend/web/templates/login.html
index 515472f1103544e17d36b44d9d67665c09db8c0d..11d9f8a5315dfb97662604ad906c3022e2729971 100644
--- a/backend/web/templates/login.html
+++ b/backend/web/templates/login.html
@@ -24,5 +24,63 @@
     <div id="contentHelp">
         <a href='recovery'>Set new password</a> | <a href='https://stackspin.net'>About stackspin</a>
     </div>
+{% if demo %}
+  <br>
+  <script>
+    function submitSignup() {
+      let result = document.querySelector('#signup-result');
+      let email = document.querySelector('#signup-email');
+      let xhr = new XMLHttpRequest();
+      xhr.responseType = 'json';
+      let url = "/web/demo-user";
+      xhr.open("POST", url, true);
+      xhr.setRequestHeader("Content-Type", "application/json");
+      xhr.onreadystatechange = function () {
+        if (xhr.readyState === 4) {
+          // In the success case, we get a plain (json) string; in the error
+          // case, we get an object with `errorMessage` property.
+          if (typeof(this.response) == 'object' && 'errorMessage' in this.response) {
+            window.console.log("Error in sign-up request.");
+            result.classList.remove('alert-success');
+            result.classList.add('alert-danger');
+            result.innerHTML = this.response.errorMessage;
+          } else {
+            result.classList.add('alert-success');
+            result.classList.remove('alert-danger');
+            result.innerHTML = this.response;
+          }
+          result.style.visibility = 'visible';
+        }
+      };
+      // Converting JSON data to string
+      var data = JSON.stringify({"email": email.value });
+      // Sending data with the request
+      xhr.send(data);
+      }
+  </script>
+  <h4>Sign up for this demo instance</h4>
+  Enter your email address here to create an account on this Stackspin
+  instance.
+  <div class="alert alert-warning" style="margin-top: 1em;">
+    Warning: this is a demo instance! That means that:
+    <ul>
+      <li>Anyone can create an account on this same instance, like yourself,
+        and will share the same set of users and data. So any data you create
+        or upload, including the email address you enter here, becomes
+        essentially public information.</li>
+      <li>Every night (Europe/Amsterdam time), this instance gets automatically
+        reset to an empty state, so any data you create or upload will be
+        destroyed.</li>
+    </ul>
+  </div>
+  <div class="form-group">
+    <label for="signup-email">Email address</label>
+    <input type="email" class="form-control" id="signup-email" name="signup-email" placeholder="Your email address to sign up with.">
+  </div>
+  <div class="form-group">
+    <button class="btn btn-primary" onclick="submitSignup()">Sign up</button>
+    <div id="signup-result" class="alert" style="visibility: hidden; margin-top: 1em;"></div>
+  </div>
+{% endif %}
 
 {% endblock %}
diff --git a/docker-compose.yml b/docker-compose.yml
index d355fdb7103926167085d674b0df9a0a1623c0f5..655be3e58c31e6d70fefdab2b1f40398e6fee636 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -56,7 +56,7 @@ services:
       - kube_port_mysql
     entrypoint: ["bash", "-c", "flask run --host $$(hostname -i)"]
   kube_port_kratos_admin:
-    image: bitnami/kubectl:1.26.1
+    image: bitnami/kubectl:1.26.2
     user: "${KUBECTL_UID}:${KUBECTL_GID}"
     expose:
       - 8000
@@ -64,7 +64,7 @@ services:
       - "$KUBECONFIG:/.kube/config"
     entrypoint: ["bash", "-c", "kubectl -n stackspin port-forward --address $$(hostname -i) service/kratos-admin 8000:80"]
   kube_port_hydra_admin:
-    image: bitnami/kubectl:1.26.1
+    image: bitnami/kubectl:1.26.2
     user: "${KUBECTL_UID}:${KUBECTL_GID}"
     expose:
       - 4445
@@ -72,7 +72,7 @@ services:
       - "$KUBECONFIG:/.kube/config"
     entrypoint: ["bash", "-c", "kubectl -n stackspin port-forward --address $$(hostname -i) service/hydra-admin 4445:4445"]
   kube_port_kratos_public:
-    image: bitnami/kubectl:1.26.1
+    image: bitnami/kubectl:1.26.2
     user: "${KUBECTL_UID}:${KUBECTL_GID}"
     ports:
       - "8080:8080"
@@ -82,7 +82,7 @@ services:
       - "$KUBECONFIG:/.kube/config"
     entrypoint: ["bash", "-c", "kubectl -n stackspin port-forward --address 0.0.0.0 service/kratos-public 8080:80"]
   kube_port_mysql:
-    image: bitnami/kubectl:1.26.1
+    image: bitnami/kubectl:1.26.2
     user: "${KUBECTL_UID}:${KUBECTL_GID}"
     expose:
       - 3306
diff --git a/frontend/src/components/UserModal/UserModal.tsx b/frontend/src/components/UserModal/UserModal.tsx
index 900ef7aee10a0d8b8b84a1b92f043eee0c906c26..b6ceed73710f45f3bda1e4218224c85fbec575fd 100644
--- a/frontend/src/components/UserModal/UserModal.tsx
+++ b/frontend/src/components/UserModal/UserModal.tsx
@@ -236,6 +236,11 @@ export const UserModal = ({ open, onClose, userId, setUserId }: UserModalProps)
                         </select>
                       </div>
                     </div>
+                    {userId && (
+                      <div className="sm:col-span-6">
+                        <Input control={control} name="id" label="UUID" required={false} disabled />
+                      </div>
+                    )}
                   </>
                 )}
               </div>
diff --git a/frontend/src/services/auth/redux/selectors.ts b/frontend/src/services/auth/redux/selectors.ts
index 0e7d26b18e69382629cd6e315e628b7efa1a82db..0feaae547d0ed851a9a8b1b5d3308a2ea6633f87 100644
--- a/frontend/src/services/auth/redux/selectors.ts
+++ b/frontend/src/services/auth/redux/selectors.ts
@@ -10,7 +10,6 @@ export const getAuthToken = (state: State) => state.auth.token;
 export const getCurrentUser = (state: State) => state.auth.userInfo;
 
 export const getIsAdmin = (state: State) => {
-  window.console.log(state.auth.userInfo);
   // check since old users wont have this
   if (state.auth.userInfo) {
     if (!state.auth.userInfo.app_roles) {
diff --git a/renovate.json b/renovate.json
index 70fbf6501a77c71f7f5faa476bbc18c566fc08fc..3644c8c9361cc137031cbd352145bb7f4dade9be 100644
--- a/renovate.json
+++ b/renovate.json
@@ -5,5 +5,12 @@
     ],
     "npm": {
         "enabled": false
-    }
+    },
+    "packageRules": [
+        {
+            "matchDepNames": ["node"],
+            "matchFiles": ["frontend/Dockerfile", ".gitlab-ci.yml"],
+            "allowedVersions": "!/^\d*[13579](-.*)?$/"
+        }
+    ]
 }