diff --git a/deploy/.gitignore b/deploy/.gitignore
new file mode 100644
index 0000000..97199cc
--- /dev/null
+++ b/deploy/.gitignore
@@ -0,0 +1,3 @@
+.registry.env
+
+.app.env
diff --git a/deploy/.registry.env.example b/deploy/.registry.env.example
new file mode 100644
index 0000000..6ac4ee0
--- /dev/null
+++ b/deploy/.registry.env.example
@@ -0,0 +1,10 @@
+# ENV for registry operations
+
+# Bond to use
+REGISTRY_BOND_ID=230cfedda15e78edc8986dfcb870e1b618f65c56e38d2735476d2a8cb3f25e38
+
+# Target deployer LRN
+DEPLOYER_LRN=lrn://vaasl-provider/deployers/webapp-deployer-api.apps.vaasl.io
+
+# Authority to deploy the app under
+AUTHORITY=laconic
diff --git a/deploy/Dockerfile b/deploy/Dockerfile
new file mode 100644
index 0000000..a120b22
--- /dev/null
+++ b/deploy/Dockerfile
@@ -0,0 +1,40 @@
+ARG VARIANT=20-bullseye
+FROM node:${VARIANT}
+
+ARG USERNAME=node
+ARG NPM_GLOBAL=/usr/local/share/npm-global
+
+# Add NPM global to PATH.
+ENV PATH=${NPM_GLOBAL}/bin:${PATH}
+
+RUN \
+ # Configure global npm install location, use group to adapt to UID/GID changes
+ if ! cat /etc/group | grep -e "^npm:" > /dev/null 2>&1; then groupadd -r npm; fi \
+ && usermod -a -G npm ${USERNAME} \
+ && umask 0002 \
+ && mkdir -p ${NPM_GLOBAL} \
+ && touch /usr/local/etc/npmrc \
+ && chown ${USERNAME}:npm ${NPM_GLOBAL} /usr/local/etc/npmrc \
+ && chmod g+s ${NPM_GLOBAL} \
+ && npm config -g set prefix ${NPM_GLOBAL} \
+ && su ${USERNAME} -c "npm config -g set prefix ${NPM_GLOBAL}" \
+ # Install eslint
+ && su ${USERNAME} -c "umask 0002 && npm install -g eslint" \
+ && npm cache clean --force > /dev/null 2>&1
+
+RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
+ && apt-get -y install --no-install-recommends jq bash
+
+# laconic-so
+RUN curl -LO https://git.vdb.to/cerc-io/stack-orchestrator/releases/download/latest/laconic-so && \
+chmod +x ./laconic-so && \
+mv ./laconic-so /usr/bin/laconic-so
+
+# Configure the npm registry
+RUN npm config set @cerc-io:registry https://git.vdb.to/api/packages/cerc-io/npm/
+
+# DEBUG, remove
+RUN yarn info @cerc-io/laconic-registry-cli
+
+# Globally install the cli package
+RUN yarn global add @cerc-io/laconic-registry-cli
diff --git a/deploy/README.md b/deploy/README.md
new file mode 100644
index 0000000..2194333
--- /dev/null
+++ b/deploy/README.md
@@ -0,0 +1,94 @@
+# Deploy
+
+## Setup
+
+- Clone the repo and run the next set of steps inside cloned repo directory
+
+
+- Build registry CLI image:
+
+ ```bash
+ docker build -t cerc/laconic-registry-cli .
+
+ # Builds image cerc/laconic-registry-cli:latest
+ ```
+
+- Configure `userKey` in the [registry CLI config](./config.yml):
+
+ - User key should be of the account that owns the `laconic-deploy` authority (owner account address: `laconic1kwx2jm6vscz38qlyujvq6msujmk8l3zangqahs`)
+
+ - Account should also own the bond `5d82586d156fb6671a9170d92f930a72a49a29afb45e30e16fff2100e30776e2`
+
+ ```bash
+ nano config.yml
+ ```
+
+- Add configuration for registry operations:
+
+ ```bash
+ cp .registry.env.example .registry.env
+
+ # Update values if required
+ nano .registry.env
+ ```
+
+- Add configuration for the app:
+
+ ```bash
+ # Create env for deployment from example env
+ cp ../env.example .app.env
+
+ # Fill in the required values
+ nano .app.env
+ ```
+
+## Run
+
+- Deploy `mtm-vpn-dashboard` App:
+
+ ```bash
+ # In mtm-vpn-dashboard/deploy dir
+ docker run -it \
+ -v ./:/app/deploy -w /app/deploy \
+ -e DEPLOYMENT_DNS=mtm-vpn-dashboard \
+ cerc/laconic-registry-cli:latest \
+ ./deploy.sh
+ ```
+
+- Check deployment logs on deployer UI:
+
+- Visit deployed app:
+
+### Remove deployment
+
+- Remove deployment:
+
+ ```bash
+ # In gor-deploy/deploy dir
+ docker run -it \
+ -v ./:/app/deploy -w /app/deploy \
+ -e DEPLOYMENT_RECORD_ID= \
+ cerc/laconic-registry-cli:latest \
+ ./remove-deployment.sh
+ ```
+
+## Troubleshoot
+
+- Check records in [registry console app](https://console.laconic.com/#/registry).
+
+- If deployment fails due to low bond balance
+ - Check balances
+
+ ```bash
+ # Account balance
+ ./laconic-cli.sh account get
+
+ # Bond balance
+ ./laconic-cli.sh bond get --id 5d82586d156fb6671a9170d92f930a72a49a29afb45e30e16fff2100e30776e2
+ ```
+
+ - Command to refill bond
+
+ ```bash
+ ./laconic-cli.sh bond refill --id 5d82586d156fb6671a9170d92f930a72a49a29afb45e30e16fff2100e30776e2 --type alnt --quantity 10000000
+ ```
diff --git a/deploy/config.yml b/deploy/config.yml
new file mode 100644
index 0000000..9866814
--- /dev/null
+++ b/deploy/config.yml
@@ -0,0 +1,9 @@
+# Registry CLI config
+services:
+ registry:
+ rpcEndpoint: 'https://laconicd-mainnet-1.laconic.com'
+ gqlEndpoint: 'https://laconicd-mainnet-1.laconic.com/api'
+ userKey:
+ bondId: 230cfedda15e78edc8986dfcb870e1b618f65c56e38d2735476d2a8cb3f25e38
+ chainId: laconic-mainnet
+ gasPrice: 0.001alnt
diff --git a/deploy/deploy.sh b/deploy/deploy.sh
new file mode 100755
index 0000000..74dafa2
--- /dev/null
+++ b/deploy/deploy.sh
@@ -0,0 +1,132 @@
+#!/bin/bash
+
+# Fail on error
+set -e
+
+source .registry.env
+echo "Using REGISTRY_BOND_ID: $REGISTRY_BOND_ID"
+echo "Using DEPLOYER_LRN: $DEPLOYER_LRN"
+echo "Using AUTHORITY: $AUTHORITY"
+
+# Repository URL
+REPO_URL="https://github.com/deep-stack/mtm-vpn-dashboard"
+
+# Get the latest commit hash for a branch
+BRANCH_NAME="ng-deploy-laconic"
+LATEST_HASH=$(git ls-remote $REPO_URL refs/heads/$BRANCH_NAME | awk '{print $1}')
+
+# Gitea
+# PACKAGE_VERSION=$(curl -s $REPO_URL/raw/branch/$BRANCH_NAME/package.json | jq -r .version)
+
+# GitHub
+PACKAGE_VERSION=$(curl -s $REPO_URL/raw/refs/heads/$BRANCH_NAME/package.json | jq -r .version)
+
+APP_NAME=mtm-vpn-dashboard
+
+echo "Repo: ${REPO_URL}"
+echo "Latest hash: ${LATEST_HASH}"
+echo "App version: ${PACKAGE_VERSION}"
+echo "Deployment DNS: ${DEPLOYMENT_DNS}"
+
+# Current date and time for note
+CURRENT_DATE_TIME=$(date -u)
+
+CONFIG_FILE=config.yml
+
+# Reference: https://git.vdb.to/cerc-io/test-progressive-web-app/src/branch/main/scripts
+
+# Get latest version from registry and increment application-record version
+NEW_APPLICATION_VERSION=$(laconic -c $CONFIG_FILE registry record list --type ApplicationRecord --all --name "$APP_NAME" 2>/dev/null | jq -r -s ".[] | sort_by(.createTime) | reverse | [ .[] | select(.bondId == \"$REGISTRY_BOND_ID\") ] | .[0].attributes.version" | awk -F. -v OFS=. '{$NF += 1 ; print}')
+
+if [ -z "$NEW_APPLICATION_VERSION" ] || [ "1" == "$NEW_APPLICATION_VERSION" ]; then
+ # Set application-record version if no previous records were found
+ NEW_APPLICATION_VERSION=0.0.1
+fi
+
+# Generate application-record.yml with incremented version
+mkdir -p records
+RECORD_FILE=./records/application-record.yml
+
+cat >$RECORD_FILE < /dev/null; then
+ echo "Error: Docker is not installed or not in PATH"
+ exit 1
+fi
+
+# Check if the cerc/laconic-registry-cli image exists
+if ! docker image inspect cerc/laconic-registry-cli &> /dev/null; then
+ echo "Error: cerc/laconic-registry-cli Docker image not found"
+ echo "Please build the image first: docker build -t cerc/laconic-registry-cli ."
+ exit 1
+fi
+
+# Get current directory (should be deploy directory)
+CURRENT_DIR="$(pwd)"
+PROJECT_ROOT="$(dirname "$CURRENT_DIR")"
+
+# Verify we're in the deploy directory
+if [ ! -f "config.yml" ] || [ ! -f "laconic-cli.sh" ]; then
+ echo "Error: This script must be run from the deploy directory"
+ echo "Current directory: $CURRENT_DIR"
+ echo "Please cd to the deploy directory and run: ./laconic-cli.sh"
+ exit 1
+fi
+
+# Set up volume mounts
+DEPLOY_MOUNT="-v $CURRENT_DIR:/app/deploy"
+OUT_MOUNT=""
+
+# Create out directory if it doesn't exist and always mount it
+if [ ! -d "out" ]; then
+ mkdir -p "out"
+fi
+OUT_MOUNT="-v $CURRENT_DIR/out:/app/out"
+
+# Run the Docker command with processed arguments
+docker run --rm \
+ --add-host=host.docker.internal:host-gateway \
+ $DEPLOY_MOUNT \
+ $OUT_MOUNT \
+ -w /app/deploy \
+ cerc/laconic-registry-cli \
+ laconic registry -c config.yml \
+ "$@"
diff --git a/deploy/records/.gitkeep b/deploy/records/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/deploy/remove-deployment.sh b/deploy/remove-deployment.sh
new file mode 100755
index 0000000..5c9d000
--- /dev/null
+++ b/deploy/remove-deployment.sh
@@ -0,0 +1,63 @@
+#!/bin/bash
+
+set -e
+
+if [[ -z $DEPLOYMENT_RECORD_ID ]]; then
+ echo "Error: please pass the deployment record ID" >&2
+ exit 1
+fi
+
+source .registry.env
+echo "Using DEPLOYER_LRN: $DEPLOYER_LRN"
+
+echo "Deployment record ID: $DEPLOYMENT_RECORD_ID"
+
+# Generate application-deployment-removal-request.yml
+REMOVAL_REQUEST_RECORD_FILE=./records/application-deployment-removal-request.yml
+
+cat > $REMOVAL_REQUEST_RECORD_FILE <