diff --git a/map.jinja b/map.jinja
index 7e8e23a..9644bbc 100644
--- a/map.jinja
+++ b/map.jinja
@@ -1,230 +1,230 @@
 {% set dirs = salt['grains.filter_by']({
     'Debian': {
         'etc': '/etc',
         'bin': '/usr/bin',
         'home': '/home',
         'include': '/usr/include',
         'lib': '/usr/lib',
         'man': '/usr/share/man',
         'sbin': '/usr/sbin',
         'share': '/usr/share',
     },
     'FreeBSD' : {
         'etc': '/usr/local/etc',
         'bin': '/usr/local/bin',
         'home': '/usr/home',
         'include': '/usr/local/include',
         'lib': '/usr/local/lib',
         'man': '/usr/local/man',
         'sbin': '/usr/local/sbin',
         'share': '/usr/local/share',
     },
 }, default='Debian') %}
 
 {% set services = salt['grains.filter_by']({
     'Debian': {
         'manager': 'systemd',
         'firewall': 'iptables',
     },
     'RedHat': {
         'manager': 'systemd',
         'firewall': 'firewalld',
     },
     'FreeBSD' : {
         'manager': 'rc',
         'firewall': 'pf',
     },
 }, default='Debian') %}
 
 {% set shells = salt['grains.filter_by']({
     'Debian': {
         'bash': '/bin/bash',
         'fish': '/usr/bin/fish',
         'nologin': '/usr/sbin/nologin',
         'tcsh': '/usr/bin/tcsh',
         'zsh': '/bin/zsh',
     },
     'FreeBSD' : {
         'bash': '/usr/local/bin/bash',
         'fish': '/usr/local/bin/fish',
         'nologin': '/sbin/nologin',
         'tcsh': '/bin/tcsh',
         'zsh': '/usr/local/bin/zsh',
     },
     'Arch': {
         'bash': '/bin/bash',
         'fish': '/usr/bin/fish',
         'nologin': '/sbin/nologin',
         'tcsh': '/usr/bin/tcsh',
         'zsh': '/bin/zsh',
     },
 }, default='Debian') %}
 
 {% set paths = salt['grains.filter_by']({
     'FreeBSD': {
         'sshd': '/usr/sbin/sshd',
         'sftp': '/usr/libexec/sftp-server',
     },
     'Debian': {
         'sshd': '/usr/sbin/sshd',
         'sftp': '/usr/lib/openssh/sftp-server',
     },
     'RedHat': {
         'sshd': '/sbin/sshd',
         'sftp': '/usr/libexec/openssh/sftp-server',
     },
     'Arch': {
         'sshd': '/usr/sbin/sshd',
         'sftp': '/usr/lib/ssh/sftp-server',
     },
 }, default='FreeBSD') %}
 
 {% set packages_prefixes = salt['grains.filter_by']({
     'Debian': {
         'pecl': 'php-',
         'php': 'php7.4-',
         'python2': '',
         'python3': 'python3-',
         'rubygem': '',
     },
     'RedHat': {
         'pecl': 'php-pecl-',
         'python2': 'python-',
         'python3': 'python3-',
         'rubygem': 'rubygem-',
     },
     'FreeBSD' : {
         'pecl': 'php81-pecl-',
         'php': 'php81-',
         'python2': 'py27-',
         'python3': 'py39-',
         'rubygem': 'rubygem-',
     },
 }, default='Debian') %}
 
 {% set packages = salt['grains.filter_by']({
     'Debian' : {
         'ag': 'silversearcher-ag',
         'aspell-fr': 'aspell-fr',
         'aspell-en': 'aspell-en',
         'bats': 'bats',
         'boost': 'libboost-all-dev',
         'certbot': 'certbot',
         'composer': 'composer',
         'cppunit': 'libcppunit-dev',
         'djvulibre': 'djvulibre-bin',
         'exiftool': 'libimage-exiftool-perl',
         'gpg': 'gpg',
         'imagemagick': 'imagemagick',
         'jpeg-turbo' : 'libjpeg-turbo',
         'librabbitmq': 'librabbitmq-dev',
         'lua': 'lua5.1',
         'mariadb': 'mariadb-server',
         'netcat': 'netcat-openbsd',
         'node': 'nodejs',
         'pear': 'php-pear',
         'phpcs': 'php-codesniffer',
         'postgresql': 'postgresql-15',
         'sphinx': 'python3-sphinx',
         'tcl': 'tcl8.6-dev',
         'tcltls': 'tcl-tls',
         'tdom': 'tdom',
         'varnish': 'varnish',
         'verbiste': 'verbiste',
         'youtube-dl': 'youtube-dl',
         'yubico-pam': 'libpam-yubico',
     },
     'RedHat': {
         'ag': 'the_silver_searcher',
         'aspell-fr': 'aspell-fr',
         'certbot': 'python3-certbot',
         'cppunit': 'cppunit-devel',
         'djvulibre': 'djvulibre',
         'exiftool': 'perl-Image-ExifTool',
         'jpeg-turbo' : 'libjpeg-turbo',
         'librabbitmq': 'librabbitmq',
         'lua': 'lua',
         'mariadb': 'mariadb-server',
         'netcat': 'nmap-ncat',
         'node': 'nodejs',
         'pear': 'php-pear',
         'phpcs': 'php-pear-PHP-CodeSniffer',
         'sphinx': 'python3-sphinx',
         'tcl': 'tcl',
         'tcltls': 'tcltls',
         'varnish': 'varnish',
         'youtube-dl': 'youtube-dl',
         'yubico-pam': 'pam_yubico',
     },
     'Arch': {
         'ag': 'the_silver_searcher',
         'aspell-fr': 'aspell-fr',
         'certbot': 'certbot',
         'cppunit': 'cppunit',
         'mariadb': 'mariadb',
         'sphinx': 'python-sphinx',
         'tcltls': 'tcltls',
         'varnish': 'varnish',
         'youtube-dl': 'youtube-dl',
         'yubico-pam': 'yubico-pam',
     },
     'FreeBSD' : {
         'ag': 'the_silver_searcher',
         'aspell-fr': 'fr-aspell',
         'aspell-en': 'en-aspell',
         'bats': 'bats-core',
         'boost': 'boost-all',
         'certbot': 'py39-certbot',
-        'composer': 'php-composer',
+        'composer': 'php82-composer2',
         'cppunit': 'cppunit',
         'djvulibre': 'djvulibre',
         'exiftool': 'p5-Image-ExifTool-devel',
         'gpg': 'gnupg',
         'imagemagick': 'ImageMagick6-nox11',
         'jpeg-turbo' : 'jpeg-turbo',
         'librabbitmq': 'rabbitmq-c-devel',
         'lua': 'lua51',
         'mariadb': 'mariadb1011-server',
         'node': 'node',
         'pear': 'pear',
         'phpcs': 'pear-PHP_CodeSniffer',
         'postgresql': 'postgresql15-server',
         'postgresql-contrib': 'postgresql15-contrib',
         'sphinx': 'py36-sphinx',
         'tcl': 'tcl86',
         'tcltls': 'tcltls',
         'tdom': 'tDOM',
         'varnish': 'varnish5',
         'verbiste': 'fr-verbiste',
         'youtube-dl': 'youtube_dl',
         'yubico-pam': 'pam_yubico',
     },
 }, default='Debian') %}
 
 {% set utilities = salt['grains.filter_by']({
     'FreeBSD': {
         'gmake': 'gmake',
     },
     'Debian': {
         'gmake': 'make',
     },
 }, default='Debian') %}
 
 {#  -------------------------------------------------------------
     Capabilities of OS and distributions
 
       :: MOTD-printed-at-login
           Login mechanism, through PAM or dotfiles,
           prints the MOTD when a session is opened.
 
           When at False, OpenSSH will take care of it.
     - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #}
 
 {% set capabilities = salt['grains.filter_by']({
   'Debian': {
     'MOTD-printed-at-login': True,
   },
   'FreeBSD' : {
     'MOTD-printed-at-login': False,
   },
 }, default='Debian') %}
diff --git a/roles/webserver-alkane/alkane/files/alkane.conf b/roles/webserver-alkane/alkane/files/alkane.conf
new file mode 100644
index 0000000..4b08923
--- /dev/null
+++ b/roles/webserver-alkane/alkane/files/alkane.conf
@@ -0,0 +1,21 @@
+#   -------------------------------------------------------------
+#   Alkane :: Configuration
+#   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#   Project:        Nasqueron
+#   License:        BSD-2-Clause
+#   Source file:    roles/webserver-alkane/alkane/files/alkane.conf
+#   -------------------------------------------------------------
+#
+#   <auto-generated>
+#       This file is managed by our rOPS SaltStack repository.
+#
+#       Changes to this file may cause incorrect behavior
+#       and will be lost if the state is redeployed.
+#   </auto-generated>
+
+roots:
+  db: /var/db/alkane
+  sites: /var/wwwroot
+  recipes: /usr/local/libexec/alkane
+
+site_directory_template: "%domain%.%tld%/%subdomain%"
diff --git a/roles/webserver-alkane/alkane/files/alkane.rc b/roles/webserver-alkane/alkane/files/alkane.rc
new file mode 100644
index 0000000..eac33eb
--- /dev/null
+++ b/roles/webserver-alkane/alkane/files/alkane.rc
@@ -0,0 +1,18 @@
+#   -------------------------------------------------------------
+#   Alkane :: Nasqueron PaaS for static and PHP sites
+#   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#   Project:        Nasqueron
+#   License:        Trivial work, not eligible to copyright
+#   Source file:    roles/webserver-alkane/alkane/files/alkane.rc
+#   -------------------------------------------------------------
+#
+#   <auto-generated>
+#       This file is managed by our rOPS SaltStack repository.
+#
+#       Changes to this file may cause incorrect behavior
+#       and will be lost if the state is redeployed.
+#   </auto-generated>
+
+alkane_enable=YES
+alkane_address={{ address }}
+alkane_log_level=info
diff --git a/roles/webserver-alkane/alkane/files/recipes/_lib/git-clone.sh b/roles/webserver-alkane/alkane/files/recipes/_lib/git-clone.sh
new file mode 100755
index 0000000..fe3f7c4
--- /dev/null
+++ b/roles/webserver-alkane/alkane/files/recipes/_lib/git-clone.sh
@@ -0,0 +1,61 @@
+#!/bin/sh
+
+#   -------------------------------------------------------------
+#   Nasqueron PaaS :: Alkane :: Recipe for deployment
+#   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#   Project:        Nasqueron
+#   License:        Trivial work, not eligible to copyright
+#   Source file:    roles/webserver-alkane/alkane/files/recipes/_lib/git-clone.sh
+#   Action:         init
+#   -------------------------------------------------------------
+#
+#   <auto-generated>
+#       This file is managed by our rOPS SaltStack repository.
+#
+#       Changes to this file may cause incorrect behavior
+#       and will be lost if the state is redeployed.
+#   </auto-generated>
+
+set -e
+
+GIT_DEFAULT_BRANCH=main
+
+#   -------------------------------------------------------------
+#   Parse context
+#     - URL
+#     - branch
+#
+#   Formats:
+#     - JSON payload {"url": "...", "branch": "production
+#     - String, will only parse it as URL
+#   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+if [ "$(printf %.1s "$ALKANE_SITE_CONTEXT")" = "{" ]; then
+    # Parses JSON object
+    GIT_URL=$(echo "$ALKANE_SITE_CONTEXT" | jq .url)
+    GIT_BRANCH=$(echo "$ALKANE_SITE_CONTEXT" | jq .branch)
+
+    if [ "$GIT_BRANCH" = "null" ]; then
+        GIT_BRANCH=$GIT_DEFAULT_BRANCH
+    fi
+else
+    GIT_URL=$ALKANE_SITE_CONTEXT
+    GIT_BRANCH=$GIT_DEFAULT_BRANCH
+fi
+
+#   -------------------------------------------------------------
+#   Ensure directory doesn't exist
+#   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+if [ -d "$ALKANE_SITE_PATH/.git" ]; then
+    echo "$ALKANE_SITE_PATH repository already exists." >&2
+    exit 1
+fi
+
+#   -------------------------------------------------------------
+#   Update Git repository
+#   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+git clone "$GIT_URL" "$ALKANE_SITE_PATH"
+cd "$ALKANE_SITE_PATH"
+git switch "$GIT_BRANCH"
diff --git a/roles/webserver-alkane/alkane/files/recipes/_lib/git-pull.sh b/roles/webserver-alkane/alkane/files/recipes/_lib/git-pull.sh
new file mode 100755
index 0000000..5e34d95
--- /dev/null
+++ b/roles/webserver-alkane/alkane/files/recipes/_lib/git-pull.sh
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+#   -------------------------------------------------------------
+#   Nasqueron PaaS :: Alkane :: Recipe for deployment
+#   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#   Project:        Nasqueron
+#   License:        Trivial work, not eligible to copyright
+#   Source file:    roles/webserver-alkane/alkane/files/recipes/_lib/git-pull.sh
+#   Action:         update
+#   -------------------------------------------------------------
+#
+#   <auto-generated>
+#       This file is managed by our rOPS SaltStack repository.
+#
+#       Changes to this file may cause incorrect behavior
+#       and will be lost if the state is redeployed.
+#   </auto-generated>
+
+set -e
+
+#   -------------------------------------------------------------
+#   Update Git repository
+#   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+cd "$ALKANE_SITE_PATH"
+git diff-index --quiet HEAD && git pull
diff --git a/roles/webserver-alkane/alkane/files/recipes/_lib/install-packages.sh b/roles/webserver-alkane/alkane/files/recipes/_lib/install-packages.sh
new file mode 100755
index 0000000..ef926c7
--- /dev/null
+++ b/roles/webserver-alkane/alkane/files/recipes/_lib/install-packages.sh
@@ -0,0 +1,39 @@
+#!/bin/sh
+
+#   -------------------------------------------------------------
+#   Nasqueron PaaS :: Alkane :: Recipe for deployment
+#   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#   Project:        Nasqueron
+#   License:        Trivial work, not eligible to copyright
+#   Source file:    roles/webserver-alkane/alkane/files/recipes/_lib/install-package.sh
+#   Action:         init
+#   -------------------------------------------------------------
+#
+#   <auto-generated>
+#       This file is managed by our rOPS SaltStack repository.
+#
+#       Changes to this file may cause incorrect behavior
+#       and will be lost if the state is redeployed.
+#   </auto-generated>
+
+set -e
+
+cd "$ALKANE_SITE_PATH"
+
+if [ -f "composer.json" ]; then
+    if [ -d "$ALKANE_SITE_PATH/vendor" ]; then
+        echo "$ALKANE_SITE_PATH/vendor directory already exists." >&2
+        exit 1
+    fi
+
+    composer install
+fi
+
+if [ -f "package.json" ]; then
+    if [ -d "$ALKANE_SITE_PATH/node_modules" ]; then
+        echo "$ALKANE_SITE_PATH/node_modules directory already exists." >&2
+        exit 1
+    fi
+
+    yarn install
+fi
diff --git a/roles/webserver-alkane/alkane/files/recipes/_lib/standard-init.sh b/roles/webserver-alkane/alkane/files/recipes/_lib/standard-init.sh
new file mode 100755
index 0000000..2de323c
--- /dev/null
+++ b/roles/webserver-alkane/alkane/files/recipes/_lib/standard-init.sh
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+#   -------------------------------------------------------------
+#   Nasqueron PaaS :: Alkane :: Recipe for deployment
+#   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#   Project:        Nasqueron
+#   License:        Trivial work, not eligible to copyright
+#   Source file:    roles/webserver-alkane/alkane/files/recipes/_lib/standard-init.sh
+#   Action:         init
+#   -------------------------------------------------------------
+#
+#   <auto-generated>
+#       This file is managed by our rOPS SaltStack repository.
+#
+#       Changes to this file may cause incorrect behavior
+#       and will be lost if the state is redeployed.
+#   </auto-generated>
+
+set -e
+
+sh "$ALKANE_RECIPES_PATH/_lib/git-clone.sh"
+sh "$ALKANE_RECIPES_PATH/_lib/install-packages.sh"
diff --git a/roles/webserver-alkane/alkane/files/recipes/_lib/standard-update.sh b/roles/webserver-alkane/alkane/files/recipes/_lib/standard-update.sh
new file mode 100755
index 0000000..6680abc
--- /dev/null
+++ b/roles/webserver-alkane/alkane/files/recipes/_lib/standard-update.sh
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+#   -------------------------------------------------------------
+#   Nasqueron PaaS :: Alkane :: Recipe for deployment
+#   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#   Project:        Nasqueron
+#   License:        Trivial work, not eligible to copyright
+#   Source file:    roles/webserver-alkane/alkane/files/recipes/_lib/standard-update.sh
+#   Action:         update
+#   -------------------------------------------------------------
+#
+#   <auto-generated>
+#       This file is managed by our rOPS SaltStack repository.
+#
+#       Changes to this file may cause incorrect behavior
+#       and will be lost if the state is redeployed.
+#   </auto-generated>
+
+set -e
+
+sh "$ALKANE_RECIPES_PATH/_lib/git-pull.sh"
+sh "$ALKANE_RECIPES_PATH/_lib/update-packages.sh"
diff --git a/roles/webserver-alkane/alkane/files/recipes/_lib/update-packages.sh b/roles/webserver-alkane/alkane/files/recipes/_lib/update-packages.sh
new file mode 100755
index 0000000..383231c
--- /dev/null
+++ b/roles/webserver-alkane/alkane/files/recipes/_lib/update-packages.sh
@@ -0,0 +1,39 @@
+#!/bin/sh
+
+#   -------------------------------------------------------------
+#   Nasqueron PaaS :: Alkane :: Recipe for deployment
+#   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#   Project:        Nasqueron
+#   License:        Trivial work, not eligible to copyright
+#   Source file:    roles/webserver-alkane/alkane/files/recipes/_lib/update-package.sh
+#   Action:         update
+#   -------------------------------------------------------------
+#
+#   <auto-generated>
+#       This file is managed by our rOPS SaltStack repository.
+#
+#       Changes to this file may cause incorrect behavior
+#       and will be lost if the state is redeployed.
+#   </auto-generated>
+
+set -e
+
+cd "$ALKANE_SITE_PATH"
+
+if [ -f "composer.json" ]; then
+    if [ ! -d "$ALKANE_SITE_PATH/vendor" ]; then
+        echo "$ALKANE_SITE_PATH/vendor directory doesn't exist." >&2
+        exit 2
+    fi
+
+    composer update
+fi
+
+if [ -f "package.json" ]; then
+    if [ ! -d "$ALKANE_SITE_PATH/node_modules" ]; then
+        echo "$ALKANE_SITE_PATH/node_modules directory doesn't exist." >&2
+        exit 2
+    fi
+
+    yarn install
+fi
diff --git a/roles/webserver-alkane/alkane/init.sls b/roles/webserver-alkane/alkane/init.sls
new file mode 100644
index 0000000..36d2fc7
--- /dev/null
+++ b/roles/webserver-alkane/alkane/init.sls
@@ -0,0 +1,78 @@
+#   -------------------------------------------------------------
+#   Salt :: Alkane :: Nasqueron PaaS for static and PHP sites
+#   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#   Project:        Nasqueron
+#   License:        Trivial work, not eligible to copyright
+#   -------------------------------------------------------------
+
+{% from "map.jinja" import dirs, packages, services with context %}
+{% set network = salt['node.resolve_network']() %}
+
+#   -------------------------------------------------------------
+#   Software
+#   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+alkane_software:
+  pkg.installed:
+    - name: alkane
+
+{{ dirs.etc }}/alkane.conf:
+  file.managed:
+    - source: salt://roles/webserver-alkane/alkane/files/alkane.conf
+
+#   -------------------------------------------------------------
+#   Recipes
+#
+#   The _lib/ directoy offers ready-to-use solution for init or update
+#   You can use them with:
+#
+#   alkane_recipes:
+#     foo.domain.tld:
+#       init: git-clone.sh
+#       update: git-pull.sh
+#   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+recipes_dependencies:
+  pkg.installed:
+    - pkgs:
+      - {{ packages.composer }}
+      - git
+      - jq
+      - yarn
+
+/usr/local/libexec/alkane:
+  file.recurse:
+    - source: salt://roles/webserver-alkane/alkane/files/recipes
+    - dir_mode: 755
+    - file_mode: 555
+
+{% for site_name, recipes in pillar.get("alkane_recipes", {}).items() %}
+/usr/local/libexec/alkane/{{ site_name }}:
+  file.directory
+
+{% for action, recipe in recipes.items() %}
+/usr/local/libexec/alkane/{{ site_name }}/{{ action }}:
+  file.symlink:
+    - target: /usr/local/libexec/alkane/_lib/{{ recipe }}
+{% endfor %}
+
+{% endfor %}
+
+#   -------------------------------------------------------------
+#   Service
+#   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+{% if services.manager == "rc" %}
+
+/etc/rc.conf.d/alkane:
+  file.managed:
+    - source: salt://roles/webserver-alkane/alkane/files/alkane.rc
+    - template: jinja
+    - context:
+        address: {{ network["private_ipv4_address"] | default("localhost") }}
+
+alkane_service:
+  service.running:
+    - name: alkane
+
+{% endif %}
diff --git a/roles/webserver-alkane/init.sls b/roles/webserver-alkane/init.sls
new file mode 100644
index 0000000..68351f4
--- /dev/null
+++ b/roles/webserver-alkane/init.sls
@@ -0,0 +1,9 @@
+#   -------------------------------------------------------------
+#   Salt :: Alkane :: Nasqueron PaaS for static and PHP sites
+#   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#   Project:        Nasqueron
+#   License:        Trivial work, not eligible to copyright
+#   -------------------------------------------------------------
+
+include:
+  - .alkane
diff --git a/top.sls b/top.sls
index 1993e80..71552ec 100644
--- a/top.sls
+++ b/top.sls
@@ -1,45 +1,47 @@
 #   -------------------------------------------------------------
 #   Salt configuration for Nasqueron servers
 #   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 #   Project:        Nasqueron
 #   Created:        2016-04-10
 #   License:        Trivial work, not eligible to copyright
 #   -------------------------------------------------------------
 
 base:
   '*':
     - roles/core
     - roles/webserver-content
   'local':
     - roles/salt-primary
   'ysul':
     - roles/builder
     - roles/dbserver-mysql
     - roles/devserver
     - roles/viperserv
     - roles/webserver-core
     - roles/webserver-legacy
     - roles/webserver-varnish
   'windriver':
     - roles/builder
     - roles/dbserver-mysql
     - roles/dbserver-pgsql
     - roles/devserver
+    - roles/webserver-alkane
     - roles/webserver-core
     - roles/webserver-legacy
   'cloudhugger':
     - roles/opensearch
   'db-A-001':
     - roles/dbserver-pgsql
   'db-B-001':
     - roles/dbserver-mysql
   'docker-002':
     - roles/paas-docker
   'dwellers':
     - roles/paas-docker/docker
     - roles/paas-lxc/lxc
   'eglide':
     - roles/webserver-core
     - roles/shellserver
   'web-001':
     - roles/webserver-core
+    - roles/webserver-alkane