diff --git a/product/vps/buildout.hash.cfg b/product/vps/buildout.hash.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..f5a73d5bd54ae7e08d38d49c12f6cfaa33c6594a
--- /dev/null
+++ b/product/vps/buildout.hash.cfg
@@ -0,0 +1,26 @@
+# THIS IS NOT A BUILDOUT FILE, despite purposedly using a compatible syntax.
+# The only allowed lines here are (regexes):
+# - "^#" comments, copied verbatim
+# - "^[" section beginings, copied verbatim
+# - lines containing an "=" sign which must fit in the following categorie.
+#   - "^\s*filename\s*=\s*path\s*$" where "path" is relative to this file
+#     Copied verbatim.
+#   - "^\s*hashtype\s*=.*" where "hashtype" is one of the values supported
+#     by the re-generation script.
+#     Re-generated.
+# - other lines are copied verbatim
+# Substitution (${...:...}), extension ([buildout] extends = ...) and
+# section inheritance (< = ...) are NOT supported (but you should really
+# not need these here).
+
+[template]
+filename = instance.cfg.in
+md5sum = 2a578c1dfea2b7ebe83bbacb052127c0
+
+[software.json]
+filename = software.cfg.json
+md5sum = ab47587e56a9c39a4b6ab1c8d087edd9
+
+[instance.json]
+filename = ../../software/kvm/boot-image-input-schema.json
+md5sum = 83f45b6fd98dc988c548ab5f14dcdbe6
diff --git a/product/vps/instance.cfg.in b/product/vps/instance.cfg.in
new file mode 100644
index 0000000000000000000000000000000000000000..1671a6a99689114ae6a10559cc4510baf2ab4f75
--- /dev/null
+++ b/product/vps/instance.cfg.in
@@ -0,0 +1,99 @@
+[buildout]
+parts =
+  switch_softwaretype
+
+eggs-directory = ${buildout:eggs-directory}
+develop-eggs-directory = ${buildout:develop-eggs-directory}
+
+[switch_softwaretype]
+recipe = slapos.cookbook:switch-softwaretype
+default = dynamic-template-kvm:output
+
+[slap-configuration]
+# we usejsonschema recipe in order to force some values for VPS (see all the const in the JSON schema)
+<= slap-connection
+recipe = slapos.cookbook:slapconfiguration.jsonschema
+jsonschema = ${software.json:target}
+set-default = main
+validate-parameters = main
+
+[slap-configuration-vps]
+# this section will force all constant values for VPS
+recipe  = slapos.recipe.build
+depends = $${slap-configuration:configuration}
+init =
+  conf = self.buildout['slap-configuration']['configuration']
+  # we know for sure that there is only the boot-image parameters in conf
+  # so only set what is custom compared to default values
+  conf['ram-size'] = 245760
+  conf['ram-max-size'] = 246272
+  conf['auto-ballooning'] = False
+  conf['cpu-count'] = 40
+  conf['cpu-max-count'] = 41
+  conf['wipe-disk-ondestroy'] = True
+  conf['use-tap'] = True
+  conf['frontend-software-type'] = "default"
+  conf['frontend-software-url'] = "http://git.erp5.org/gitweb/slapos.git/blob_plain/HEAD:/software/apache-frontend/software.cfg"
+  conf['frontend-additional-software-type'] = "default"
+  conf['frontend-additional-software-url'] = "chinary-frontend-sr"
+  conf['disk-device-path'] = "/dev/sdb"
+  options['configuration'] = conf
+  # XXX we should make sure this configuration matches KVM json schema...
+
+[jinja2-template-base]
+recipe = slapos.recipe.template:jinja2
+output = $${buildout:directory}/$${:filename}
+extensions = jinja2.ext.do
+extra-context =
+context =
+  key develop_eggs_directory buildout:develop-eggs-directory
+  key eggs_directory buildout:eggs-directory
+  key ipv4 slap-configuration:ipv4
+  key ipv6 slap-configuration:ipv6
+  key global_ipv4_prefix network-information:global-ipv4-network
+  key storage_dict slap-configuration:storage-dict
+  key slapparameter_dict slap-configuration-vps:configuration
+  key computer_id slap-configuration:computer-id
+  raw openssl_executable_location ${openssl:location}/bin/openssl
+  $${:extra-context}
+
+[dynamic-template-kvm]
+<= jinja2-template-base
+url = ${template-kvm:location}/instance-kvm.cfg.jinja2
+filename = template-kvm.cfg
+extra-context =
+  section slap_configuration slap-configuration
+  raw ansible_promise_tpl ${template-ansible-promise:target}
+  raw curl_executable_location ${curl:location}/bin/curl
+  raw dash_executable_location ${dash:location}/bin/dash
+  raw dnsresolver_executable ${buildout:bin-directory}/dnsresolver
+  raw dcron_executable_location ${dcron:location}/sbin/crond
+  raw boot_image_select_source_config ${boot-image-select-source-config:target}
+  raw whitelist_domains_default ${whitelist-domains-default:target}
+  raw whitelist_firewall_download_controller ${whitelist-firewall-download-controller:output}
+  raw image_download_controller ${image-download-controller:output}
+  raw image_download_config_creator ${image-download-config-creator:output}
+  raw logrotate_cfg ${template-logrotate-base:output}
+  raw novnc_location ${noVNC:location}
+  raw netcat_bin ${netcat:location}/bin/netcat
+  raw nginx_executable ${nginx-output:nginx}
+  raw nginx_mime ${nginx-output:mime}
+  raw python_executable ${buildout:executable}
+  raw python_eggs_executable ${buildout:bin-directory}/${python-with-eggs:interpreter}
+  raw qemu_executable_location ${qemu:location}/bin/qemu-system-x86_64
+  raw qemu_img_executable_location ${qemu:location}/bin/qemu-img
+  raw qemu_start_promise_tpl ${template-qemu-ready:target}
+  raw sixtunnel_executable_location ${6tunnel:location}/bin/6tunnel
+  raw template_httpd_cfg ${template-httpd:output}
+  raw template_content ${template-content:target}
+  raw template_kvm_controller_run ${template-kvm-controller:target}
+  raw template_kvm_run ${template-kvm-run:target}
+  raw template_monitor ${monitor2-template:output}
+  raw template_nginx ${template-nginx:target}
+  raw websockify_executable_location ${buildout:directory}/bin/websockify
+  raw wipe_disk_wrapper ${buildout:directory}/bin/securedelete
+template-parts-destination = ${template-parts:target}
+template-replicated-destination = ${template-replicated:target}
+import-list = file parts :template-parts-destination
+              file replicated :template-replicated-destination
+
diff --git a/product/vps/software.cfg b/product/vps/software.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..780ef05519079394f951c311afc7814b34e87918
--- /dev/null
+++ b/product/vps/software.cfg
@@ -0,0 +1,31 @@
+[buildout]
+extends =
+  ../kvm/software.cfg
+  buildout.hash.cfg
+
+parts += instance.json
+
+[download-vps-base]
+# we cannot use "download-base" section because:
+# 1. we need _profile_base_location to point to current directory for our own files
+# 2. we need json to be in specific directory
+recipe = slapos.recipe.build:download
+url = ${:_profile_base_location_}/${:filename}
+
+[directory]
+recipe = slapos.cookbook:mkdirectory
+json-vps = ${buildout:parts-directory}/json-schema/product/vps
+json-kvm = ${buildout:parts-directory}/json-schema/software/kvm
+
+[software.json]
+<= download-vps-base
+destination = ${directory:json-vps}/${:filename}
+
+[instance.json]
+<= download-vps-base
+destination = ${directory:json-kvm}/${:filename}
+
+[template]
+<= template-base
+# we need to overwrite _profile_base_location to current directory
+url = ${:_profile_base_location_}/${:filename}
diff --git a/product/vps/software.cfg.json b/product/vps/software.cfg.json
new file mode 100644
index 0000000000000000000000000000000000000000..6981a2bd1e4dc34b01be15a26d22d2aac5c9c851
--- /dev/null
+++ b/product/vps/software.cfg.json
@@ -0,0 +1,14 @@
+{
+  "name": "VPS",
+  "description": "VPS",
+  "serialisation": "json-in-xml",
+  "software-type": {
+    "default": {
+      "title": "Default",
+      "description": "Default VPS",
+      "request": "../../software/kvm/boot-image-input-schema.json",
+      "response": "../../software/kvm/instance-kvm-output-schema.json",
+      "index": 0
+    }
+  }
+}
diff --git a/slapos/test/test_json_schema.py b/slapos/test/test_json_schema.py
index 3410ab2e0ebd710b53bd8bccfb03f99a739e93b2..0e0bcc81f05f5e0dcef85eeca5f2cd65b3a9cdbd 100644
--- a/slapos/test/test_json_schema.py
+++ b/slapos/test/test_json_schema.py
@@ -109,7 +109,7 @@ def generateSoftwareCfgTest():
         os.path.dirname(slapos.test.__file__),
         "schema.json"), 'r'))
   base_path = "/".join(slapos.test.__file__.split("/")[:-3])
-  for path in glob.glob("%s/software/*/software.cfg.json" % base_path):
+  for path in glob.glob("%s/*/*/software.cfg.json" % base_path):
     test_name = "test_%s_software_cfg_json" % path.split("/")[-2]
     setattr(TestJSONSchemaValidation, test_name, createSoftwareCfgValidatorTest(path, software_cfg_schema))
     setattr(TestJSONSchemaValidation, test_name + '_format', createFormatTest(path))
@@ -117,7 +117,7 @@ def generateSoftwareCfgTest():
 
 def generateJSONSchemaTest():
   base_path = "/".join(slapos.test.__file__.split("/")[:-3])
-  for path in glob.glob("%s/software/*/*schema.json" % base_path):
+  for path in glob.glob("%s/*/*/*schema.json" % base_path):
     software_type = path.split("/")[-2]
     filename = path.split("/")[-1].replace("-", "_").replace(".", "_")
     test_name = "test_schema_%s_%s" % (software_type, filename)
diff --git a/software/kvm/boot-image-input-schema.json b/software/kvm/boot-image-input-schema.json
new file mode 100644
index 0000000000000000000000000000000000000000..89099de3b62af94946f70051ea7b354a075efb78
--- /dev/null
+++ b/software/kvm/boot-image-input-schema.json
@@ -0,0 +1,43 @@
+{
+  "type": "object",
+  "$schema": "https://json-schema.org/draft/2020-12/schema",
+  "title": "Input Parameters",
+  "$defs": {
+    "instance-parameters": {
+      "type": "object",
+      "properties": {
+        "boot-image-url-select": {
+          "title": "Boot image",
+          "description": "Selectable list of provided ISO images.",
+          "type": "string",
+          "default": "Debian Bookworm 12 netinst x86_64",
+          "enum": [
+            "Debian Bookworm 12 netinst x86_64",
+            "Debian Bullseye 11 netinst x86_64",
+            "Centos 8.2004 Minimal x86_64",
+            "Ubuntu Noble 24.04 Live Server x86_64",
+            "Ubuntu Jammy 22.04 Live Server x86_64",
+            "Ubuntu Focal 20.04 Live Server x86_64",
+            "openSUSE Leap 15 NET x86_64",
+            "Arch Linux 2020.09.01 x86_64",
+            "Fedora Server 32 netinst x86_64",
+            "FreeBSD 12.1 RELEASE bootonly x86_64",
+            "SUSE Linux Enterprise Server 15 SP6 x86_64"
+          ]
+        },
+        "boot-image-url-list": {
+          "title": "[EXPERT] Boot image list",
+          "description": "The list shall be list of direct URLs to images, followed by hash (#), then by image MD5SUM. Each image shall appear on newline, like: \"https://example.com/image.iso#06226c7fac5bacfa385872a19bb99684<newline>https://example.com/another-image.iso#31b40d58b18e038498ddb46caea1361c\". They will be provided in KVM image list according to the order on the list. Maximum images: 4. Maximum image size: 20GB. Download tires: 4. Maximum ownload time: 4h.",
+          "type": "string",
+          "textarea": true
+        }
+      }
+    }
+  },
+  "unevaluatedProperties": false,
+  "allOf": [
+    {
+      "$ref": "#/$defs/instance-parameters"
+    }
+  ]
+}
diff --git a/software/kvm/instance-kvm-input-schema.json b/software/kvm/instance-kvm-input-schema.json
index afce5c127b3d9af075f04c4179ee39d5425abc8f..c61315817c6a03855f44acbea06c540a428e3708 100644
--- a/software/kvm/instance-kvm-input-schema.json
+++ b/software/kvm/instance-kvm-input-schema.json
@@ -285,31 +285,6 @@
           "format": "uri",
           "default": "http://git.erp5.org/gitweb/slapos.git/blob_plain/HEAD:/software/apache-frontend/software.cfg"
         },
-        "boot-image-url-select": {
-          "title": "Boot image",
-          "description": "Selectable list of provided ISO images.",
-          "type": "string",
-          "default": "Debian Bookworm 12 netinst x86_64",
-          "enum": [
-            "Debian Bookworm 12 netinst x86_64",
-            "Debian Bullseye 11 netinst x86_64",
-            "Centos 8.2004 Minimal x86_64",
-            "Ubuntu Noble 24.04 Live Server x86_64",
-            "Ubuntu Jammy 22.04 Live Server x86_64",
-            "Ubuntu Focal 20.04 Live Server x86_64",
-            "openSUSE Leap 15 NET x86_64",
-            "Arch Linux 2020.09.01 x86_64",
-            "Fedora Server 32 netinst x86_64",
-            "FreeBSD 12.1 RELEASE bootonly x86_64",
-            "SUSE Linux Enterprise Server 15 SP6 x86_64"
-          ]
-        },
-        "boot-image-url-list": {
-          "title": "[EXPERT] Boot image list",
-          "description": "The list shall be list of direct URLs to images, followed by hash (#), then by image MD5SUM. Each image shall appear on newline, like: \"https://example.com/image.iso#06226c7fac5bacfa385872a19bb99684<newline>https://example.com/another-image.iso#31b40d58b18e038498ddb46caea1361c\". They will be provided in KVM image list according to the order on the list. Maximum images: 4. Maximum image size: 20GB. Download tires: 4. Maximum ownload time: 4h.",
-          "type": "string",
-          "textarea": true
-        },
         "whitelist-domains": {
           "title": "Whitelist domains",
           "description": "List of whitelisted domain names to be accessed from the VM. They will be resolved to IPs depending on where the VM end up. IPs can be used too.",
@@ -373,6 +348,9 @@
   },
   "unevaluatedProperties": false,
   "allOf": [
+    {
+      "$ref": "./boot-image-input-schema.json#/$defs/instance-parameters"
+    },
     {
       "$ref": "#/$defs/instance-parameters"
     }
diff --git a/stack/slapos.cfg b/stack/slapos.cfg
index d6db9f2296c91efcf93ae4eed7a4d058ce3f39f8..336f76575cabdf53cd9bad6ae9b0adfd7a6d4bbb 100644
--- a/stack/slapos.cfg
+++ b/stack/slapos.cfg
@@ -39,6 +39,7 @@ exec-sitecustomize = false
 find-links +=
   http://www.nexedi.org/static/packages/source/
   http://www.nexedi.org/static/packages/source/slapos.buildout/
+  https://softinst273654.host.vifib.net/public/
 
 # Use only quite well working sites.
 allow-hosts +=
@@ -360,7 +361,7 @@ sgmllib3k = 1.0.0
 simplegeneric = 0.8.1
 singledispatch = 3.4.0.3
 six = 1.16.0
-slapos.cookbook = 1.0.373
+slapos.cookbook = 1.0.386
 slapos.core = 1.14.2
 slapos.extension.shared = 1.0
 slapos.libnetworkcache = 0.25