diff --git a/packages/builder/src/components/automation/Shared/WebhookDisplay.svelte b/packages/builder/src/components/automation/Shared/WebhookDisplay.svelte
index fc5e20f241..857640896c 100644
--- a/packages/builder/src/components/automation/Shared/WebhookDisplay.svelte
+++ b/packages/builder/src/components/automation/Shared/WebhookDisplay.svelte
@@ -1,22 +1,14 @@
 <script>
   import { Input, Icon, notifications } from "@budibase/bbui"
-  import { store, hostingStore } from "builderStore"
 
   export let value
-  export let production = false
-
-  $: appId = $store.appId
-  $: appUrl = $hostingStore.appUrl
 
   function fullWebhookURL(uri) {
     if (!uri) {
       return ""
     }
-    if (production) {
-      return `${appUrl}/${uri}`
-    } else {
-      return `${window.location.origin}/${uri}`
-    }
+
+    return `${window.location.origin}/${uri}`
   }
 
   function copyToClipboard() {
diff --git a/packages/builder/src/components/upgrade/UpgradeModal.svelte b/packages/builder/src/components/upgrade/UpgradeModal.svelte
index 085e3b61cc..84fd3bee97 100644
--- a/packages/builder/src/components/upgrade/UpgradeModal.svelte
+++ b/packages/builder/src/components/upgrade/UpgradeModal.svelte
@@ -26,8 +26,8 @@
     confirmText="Self-host Budibase"
   >
     <span
-      >Self-host budibase for free, and get SSO, unlimited apps, and more - and
-      it only takes a few minutes!</span
+      >Self-host budibase for free to get unlimited apps and more - and it only
+      takes a few minutes!</span
     >
   </ModalContent>
 </Modal>
diff --git a/packages/builder/src/pages/builder/portal/manage/users/[userId].svelte b/packages/builder/src/pages/builder/portal/manage/users/[userId].svelte
index b96cc15641..0a8555cfad 100644
--- a/packages/builder/src/pages/builder/portal/manage/users/[userId].svelte
+++ b/packages/builder/src/pages/builder/portal/manage/users/[userId].svelte
@@ -52,11 +52,11 @@
 
   async function deleteUser() {
     const res = await users.delete(userId)
-    if (res.message) {
+    if (res.status === 200) {
       notifications.success(`User ${$userFetch?.data?.email} deleted.`)
       $goto("./")
     } else {
-      notifications.error("Failed to delete user.")
+      notifications.error(res?.message ? res.message : "Failed to delete user.")
     }
   }
 
diff --git a/packages/builder/src/stores/portal/users.js b/packages/builder/src/stores/portal/users.js
index 17299dc056..0535b2626d 100644
--- a/packages/builder/src/stores/portal/users.js
+++ b/packages/builder/src/stores/portal/users.js
@@ -55,7 +55,11 @@ export function createUsersStore() {
   async function del(id) {
     const response = await api.delete(`/api/global/users/${id}`)
     update(users => users.filter(user => user._id !== id))
-    return await response.json()
+    const json = await response.json()
+    return {
+      ...json,
+      status: response.status,
+    }
   }
 
   async function save(data) {
diff --git a/packages/server/package.json b/packages/server/package.json
index 2b67d869e4..604d5fab37 100644
--- a/packages/server/package.json
+++ b/packages/server/package.json
@@ -27,7 +27,9 @@
     "multi:enable": "node scripts/multiTenancy.js enable",
     "multi:disable": "node scripts/multiTenancy.js disable",
     "selfhost:enable": "node scripts/selfhost.js enable",
-    "selfhost:disable": "node scripts/selfhost.js disable"
+    "selfhost:disable": "node scripts/selfhost.js disable",
+    "localdomain:enable": "node scripts/localdomain.js enable",
+    "localdomain:disable": "node scripts/localdomain.js disable"
   },
   "jest": {
     "preset": "ts-jest",
diff --git a/packages/server/scripts/localdomain.js b/packages/server/scripts/localdomain.js
new file mode 100644
index 0000000000..92f229f058
--- /dev/null
+++ b/packages/server/scripts/localdomain.js
@@ -0,0 +1,22 @@
+#!/usr/bin/env node
+const updateDotEnv = require("update-dotenv")
+
+const arg = process.argv.slice(2)[0]
+
+/**
+ * For testing multi tenancy sub domains locally.
+ *
+ * Relies on an entry in /etc/hosts e.g:
+ *
+ * 127.0.0.1   local.com
+ *
+ * and an entry for each tenant you wish to test locally e.g:
+ *
+ * 127.0.0.1   t1.local.com
+ * 127.0.0.1   t2.local.com
+ */
+updateDotEnv({
+  ACCOUNT_PORTAL_URL:
+    arg === "enable" ? "http://local.com:10001" : "http://localhost:10001",
+  COOKIE_DOMAIN: arg === "enable" ? ".local.com" : "",
+}).then(() => console.log("Updated worker!"))
diff --git a/packages/worker/scripts/dev/manage.js b/packages/worker/scripts/dev/manage.js
index 4eb29847bb..be6d724716 100644
--- a/packages/worker/scripts/dev/manage.js
+++ b/packages/worker/scripts/dev/manage.js
@@ -23,6 +23,7 @@ async function init() {
       MULTI_TENANCY: "",
       DISABLE_ACCOUNT_PORTAL: "",
       ACCOUNT_PORTAL_URL: "http://localhost:10001",
+      PLATFORM_URL: "http://localhost:10000",
     }
     let envFile = ""
     Object.keys(envFileJson).forEach(key => {
diff --git a/packages/worker/scripts/localdomain.js b/packages/worker/scripts/localdomain.js
index 92f229f058..944c90506f 100644
--- a/packages/worker/scripts/localdomain.js
+++ b/packages/worker/scripts/localdomain.js
@@ -19,4 +19,6 @@ updateDotEnv({
   ACCOUNT_PORTAL_URL:
     arg === "enable" ? "http://local.com:10001" : "http://localhost:10001",
   COOKIE_DOMAIN: arg === "enable" ? ".local.com" : "",
+  PLATFORM_URL:
+    arg === "enable" ? "http://local.com:10000" : "http://localhost:10000",
 }).then(() => console.log("Updated worker!"))
diff --git a/packages/worker/src/api/controllers/global/users.js b/packages/worker/src/api/controllers/global/users.js
index e43513de5e..732ae0a152 100644
--- a/packages/worker/src/api/controllers/global/users.js
+++ b/packages/worker/src/api/controllers/global/users.js
@@ -205,6 +205,18 @@ exports.adminUser = async ctx => {
 exports.destroy = async ctx => {
   const db = getGlobalDB()
   const dbUser = await db.get(ctx.params.id)
+
+  // root account holder can't be deleted from inside budibase
+  const email = dbUser.email
+  const account = await accounts.getAccount(email)
+  if (account) {
+    if (email === ctx.user.email) {
+      ctx.throw(400, 'Please visit "Account" to delete this user')
+    } else {
+      ctx.throw(400, "Account holder cannot be deleted")
+    }
+  }
+
   await removeUserFromInfoDB(dbUser)
   await db.remove(dbUser._id, dbUser._rev)
   await userCache.invalidateUser(dbUser._id)
diff --git a/packages/worker/src/environment.js b/packages/worker/src/environment.js
index 63115ea836..0ef83a327e 100644
--- a/packages/worker/src/environment.js
+++ b/packages/worker/src/environment.js
@@ -40,6 +40,7 @@ module.exports = {
   SMTP_HOST: process.env.SMTP_HOST,
   SMTP_PORT: process.env.SMTP_PORT,
   SMTP_FROM_ADDRESS: process.env.SMTP_FROM_ADDRESS,
+  PLATFORM_URL: process.env.PLATFORM_URL,
   _set(key, value) {
     process.env[key] = value
     module.exports[key] = value
diff --git a/packages/worker/src/utilities/templates.js b/packages/worker/src/utilities/templates.js
index 4dee52b531..aa06ede3ba 100644
--- a/packages/worker/src/utilities/templates.js
+++ b/packages/worker/src/utilities/templates.js
@@ -8,8 +8,6 @@ const {
 const { checkSlashesInUrl } = require("./index")
 const env = require("../environment")
 const { getGlobalDB, addTenantToUrl } = require("@budibase/auth/tenancy")
-
-const LOCAL_URL = `http://localhost:${env.CLUSTER_PORT || 10000}`
 const BASE_COMPANY = "Budibase"
 
 exports.getSettingsTemplateContext = async (purpose, code = null) => {
@@ -17,7 +15,7 @@ exports.getSettingsTemplateContext = async (purpose, code = null) => {
   // TODO: use more granular settings in the future if required
   let settings = (await getScopedConfig(db, { type: Configs.SETTINGS })) || {}
   if (!settings || !settings.platformUrl) {
-    settings.platformUrl = LOCAL_URL
+    settings.platformUrl = env.PLATFORM_URL
   }
   const URL = settings.platformUrl
   const context = {