diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 1e53802cf015a62aac49125751b618890e1c74d7..45ab8679c1bc931ff185d08409fc6e1cb0464880 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -31,3 +31,45 @@ publish:
     - yarn install
     - yarn run build
     - yarn run publish
+
+.deploy_defaults: &deploy_defaults
+  except:
+    - schedules
+  stage: deploy
+  script:
+    # Add ssh key
+    - mkdir -p ~/.ssh
+    - echo "${DEPLOY_KEY}" | tr -d '\r' > ~/.ssh/id_rsa
+    - chmod 700 ~/.ssh && chmod 600 ~/.ssh/id_rsa
+    - ssh-keyscan -t rsa "${DEPLOY_HOST}" >> ~/.ssh/known_hosts
+    # Deploy
+    - dep deploy "${CI_ENVIRONMENT_NAME}"
+    - echo "Deployed to ${CI_ENVIRONMENT_URL}"
+    # Simple health check
+    - curl --max-time 10 --retry 3 --output /dev/null --silent --show-error --fail --location "${CI_ENVIRONMENT_URL}"
+
+deploy_demo:
+  only:
+    refs:
+      - demo
+  environment:
+    name: demo
+    url: https://frontend-demo.tugraz.at/apps/demo
+  variables:
+    DEPLOY_HOST: mw01-dev.tugraz.at
+    DEPLOY_KEY: "$DEPLOY_SSH_KEY"
+  <<: *deploy_defaults
+
+deploy_development:
+  only:
+    refs:
+      - master
+  environment:
+    name: development
+    url: https://mw-frontend-dev.tugraz.at/apps/demo
+    url: https://mw-frontend-dev.tugraz.at/apps/demo
+  variables:
+    DEPLOY_HOST: mw01-dev.tugraz.at
+    DEPLOY_KEY: "$DEPLOY_SSH_KEY"
+  <<: *deploy_defaults
+
diff --git a/toolkit-showcase/deploy.php b/toolkit-showcase/deploy.php
new file mode 100644
index 0000000000000000000000000000000000000000..89f9901297c77d2a8b2da114eb9ff11db7175ba8
--- /dev/null
+++ b/toolkit-showcase/deploy.php
@@ -0,0 +1,69 @@
+<?php
+namespace Deployer;
+
+require 'recipe/common.php';
+require 'recipe/rsync.php';
+
+// Global config
+set('allow_anonymous_stats', false);
+
+set('rsync',[
+    'exclude'      => [
+        '.git',
+        'deploy.php',
+    ],
+    'exclude-file' => false,
+    'include'      => [],
+    'include-file' => false,
+    'filter'       => [],
+    'filter-file'  => false,
+    'filter-perdir'=> false,
+    'flags'        => 'rz',
+    'options'      => ['delete'],
+    'timeout'      => 60,
+]);
+
+set('rsync_src', __DIR__ . '/dist');
+set('rsync_dest','{{release_path}}');
+
+// Hosts
+host('demo')
+    ->stage('demo')
+    ->hostname('mw@mw01-dev.tugraz.at')
+    ->set('deploy_path', '/home/mw/demo/deploy/apps/demo');
+
+host('development')
+    ->stage('development')
+    ->hostname('mw@mw01-dev.tugraz.at')
+    ->set('deploy_path', '/home/mw/dev/deploy/apps/demo');
+
+// Demo build task
+task('build-demo', function () {
+    runLocally("yarn install");
+    runLocally("yarn run build-demo");
+})->onStage('demo');
+
+// Demo dev task
+task('build-development', function () {
+    runLocally("yarn install");
+    runLocally("yarn run build-dev");
+})->onStage('development');
+
+
+// Deploy task
+task('deploy', [
+    'deploy:info',
+    'build-demo',
+    'build-development',
+    'build-production',
+    'deploy:prepare',
+    'deploy:lock',
+    'deploy:release',
+    'rsync',
+    'deploy:shared',
+    'deploy:symlink',
+    'deploy:unlock',
+    'cleanup',
+    'success',
+]);
+after('deploy:failed', 'deploy:unlock');
diff --git a/toolkit-showcase/rollup.config.js b/toolkit-showcase/rollup.config.js
index 2c3c7f59596ded932cbbef164ac75b75b539f656..6036a60b73011254b01fa646afb402cf636405c7 100644
--- a/toolkit-showcase/rollup.config.js
+++ b/toolkit-showcase/rollup.config.js
@@ -62,7 +62,7 @@ switch (build) {
     pdfAsQualifiedlySigningServer = 'sig-dev.tugraz.at';
     break;
   case 'development':
-    basePath = '/apps/toolkit-showcase/';
+    basePath = '/apps/demo/';
     entryPointURL = 'https://mw-dev.tugraz.at';
     // "/pers" can't go here because it's not allowed in the "Content-Security-Policy"
     nextcloudBaseURL = 'https://nc-dev.tugraz.at';
@@ -74,6 +74,7 @@ switch (build) {
     keyCloakClientId = 'auth-dev-mw-frontend';
     pdfAsQualifiedlySigningServer = 'sig-dev.tugraz.at';
     break;
+
   default:
     console.error('Unknown build environment: ' + build);
     process.exit(1);