diff --git a/ansible/group_vars/all/settings.yml.example b/ansible/group_vars/all/settings.yml.example
index b5e08491e872f38a286ed35c61ddf4b7b4f4c0fe..51b2984df49020e3e0f75f7c2f206629247a552c 100644
--- a/ansible/group_vars/all/settings.yml.example
+++ b/ansible/group_vars/all/settings.yml.example
@@ -19,3 +19,20 @@ helmfiles:
   - 10-nginx
   - 15-monitoring
   - 20-nextcloud
+
+# Optional, custom rke config.
+# I.e. you can set the desired Kubernetes version but please be aware of
+# the [every rke release has only a few supported kubernetes versions](https://rancher.com/docs/rke/latest/en/config-options/#kubernetes-version).
+#
+# rke_custom_config:
+#   kubernetes_version: "v1.14.3-rancher1-1"
+#
+# Another example is allowing to disable ipv6 in pods by
+# passing adding an additional argument to the kubelet:
+# `--allowed-unsafe-sysctls net.ipv6.conf.all.disable_ipv6`
+#
+# rke_custom_config:
+#   services:
+#     kubelet:
+#       extra_args:
+#         allowed-unsafe-sysctls: 'net.ipv6.conf.all.disable_ipv6'
diff --git a/ansible/roles/rke_configuration/defaults/main.yml b/ansible/roles/rke_configuration/defaults/main.yml
deleted file mode 100644
index ad9de7c102005628cbd3a1ebb76e35284c90ac2d..0000000000000000000000000000000000000000
--- a/ansible/roles/rke_configuration/defaults/main.yml
+++ /dev/null
@@ -1,6 +0,0 @@
-rke_configuration_location: "{{ data_directory }}/rke/cluster.yml"
-rke_ssh_key_path: "{{ data_directory }}/ssh/ssh_key"
-rke_ssh_agent_auth: "false"
-# Whether to support customer flexvolume driver plugins, by mounting the path
-# /usr/libexec/kubernetes/kubelet-plugins/volume/exec into kubelet.
-flexvolume_plugins: false
diff --git a/ansible/roles/rke_configuration/files/cluster-defaults.yml b/ansible/roles/rke_configuration/files/cluster-defaults.yml
new file mode 100644
index 0000000000000000000000000000000000000000..4e3f9b50aeb01783c183e48a75120eda52538fd9
--- /dev/null
+++ b/ansible/roles/rke_configuration/files/cluster-defaults.yml
@@ -0,0 +1,72 @@
+addon_job_timeout: 0
+addons: ''
+addons_include: []
+authentication:
+  options: {}
+  sans: []
+  strategy: x509
+authorization:
+  mode: rbac
+  options: {}
+bastion_host:
+  address: ''
+  port: ''
+  ssh_key: ''
+  ssh_key_path: ''
+  user: ''
+cloud_provider:
+  name: ''
+cluster_name: ''
+ignore_docker_version: false
+ingress:
+  extra_args: {}
+  node_selector: {}
+  options: {}
+  # Set this to none, so we can install nginx ourselves.
+  provider: none
+kubernetes_version: 'v1.14.3-rancher1-1'
+monitoring:
+  options: {}
+  provider: ''
+network:
+  options: {}
+  plugin: canal
+prefix_path: ''
+private_registries: []
+services:
+  etcd:
+    ca_cert: ''
+    cert: ''
+    creation: ''
+    external_urls: []
+    image: ''
+    key: ''
+    path: ''
+    retention: ''
+    snapshot: false
+  kube-api:
+    image: ''
+    pod_security_policy: false
+    service_cluster_ip_range: 10.43.0.0/16
+    service_node_port_range: ''
+  kube-controller:
+    cluster_cidr: 10.42.0.0/16
+    image: ''
+    service_cluster_ip_range: 10.43.0.0/16
+  kubelet:
+    cluster_dns_server: 10.43.0.10
+    cluster_domain: cluster.local
+    extra_args:
+      containerized: 'true'
+    extra_binds:
+    # Make local storage work with persistent volumes that use `subpath`
+    # see https://open.greenhost.net/openappstack/openappstack/issues/236
+    - /:/rootfs:rshared
+    fail_swap_on: false
+    image: ''
+    infra_container_image: ''
+  kubeproxy:
+    image: ''
+  scheduler:
+    image: ''
+ssh_agent_auth: false
diff --git a/ansible/roles/rke_configuration/tasks/main.yml b/ansible/roles/rke_configuration/tasks/main.yml
index 8dbac5beb167783029b9910467a8a748b0f4dc51..54a7859ad37ec0b85956427bacfc6ec991df25f2 100644
--- a/ansible/roles/rke_configuration/tasks/main.yml
+++ b/ansible/roles/rke_configuration/tasks/main.yml
@@ -29,8 +29,24 @@
   become: true
 
 
-- name: Copy rke cluster configuration file
-  template:
-    src: "cluster.yml.j2"
-    dest: "{{ rke_configuration_location }}"
+- name: Deploy rke cluster configuration file
+  tags:
+    - tmp
+    - rke
+  vars:
+    additional_config:
+      nodes:
+        - address: "{{ ansible_host }}"
+          hostname_override: "{{ inventory_hostname }}"
+          role:
+            - controlplane
+            - etcd
+            - worker
+          ssh_key_path: '/var/lib/OpenAppStack/ssh/ssh_key'
+          user: "{{ ansible_user }}"
+    # Allow undefined rke_custom_config variable
+    custom_config: "{{ rke_custom_config | default({}) }}"
+  copy:
+    content: "{{ lookup('file', 'cluster-defaults.yml') | from_yaml | combine(additional_config, custom_config, recursive=True) | to_nice_yaml(indent=2) }}"
+    dest: "{{ data_directory }}/rke/cluster.yml"
   become: true
diff --git a/ansible/roles/rke_configuration/templates/cluster.yml.j2 b/ansible/roles/rke_configuration/templates/cluster.yml.j2
deleted file mode 100644
index 07d90dccbb5d258c2af1131eb80817dd021bb858..0000000000000000000000000000000000000000
--- a/ansible/roles/rke_configuration/templates/cluster.yml.j2
+++ /dev/null
@@ -1,102 +0,0 @@
-nodes:
-{% for node in groups['all'] %}
-- address: {{ hostvars[node]['ansible_host'] }}
-  # port: "22"
-  # internal_address: ""
-  role:
-{% if hostvars[node]['inventory_hostname'] in groups.master %}
-  - controlplane
-  - etcd
-{% endif %}
-{% if hostvars[node]['inventory_hostname'] in groups.worker %}
-  - worker
-{% endif %}
-  hostname_override: {{ hostvars[node]['inventory_hostname'] }}
-  user: {{ hostvars[node]['ansible_user'] }}
-  # docker_socket: /var/run/docker.sock
-  # ssh_key: ""
-{% if rke_ssh_key_path is defined %}
-  ssh_key_path: {{ rke_ssh_key_path }}
-{% else %}
-  # ssh_key_path: ""
-{% endif %}
-  # labels: {}
-{% endfor %}
-services:
-  etcd:
-    image: ""
-    external_urls: []
-    ca_cert: ""
-    cert: ""
-    key: ""
-    path: ""
-    snapshot: false
-    retention: ""
-    creation: ""
-  kube-api:
-    image: ""
-    service_cluster_ip_range: 10.43.0.0/16
-    service_node_port_range: ""
-    pod_security_policy: false
-  kube-controller:
-    image: ""
-    cluster_cidr: 10.42.0.0/16
-    service_cluster_ip_range: 10.43.0.0/16
-  scheduler:
-    image: ""
-  kubelet:
-    image: ""
-    extra_args:
-      containerized: "true"
-{% if flexvolume_plugins %}
-      volume-plugin-dir: /usr/libexec/kubernetes/kubelet-plugins/volume/exec
-{% endif %}
-    extra_binds:
-    # Make local storage work with persistent volumes that use `subpath`
-    # see https://open.greenhost.net/openappstack/openappstack/issues/236
-    - "/:/rootfs:rshared"
-{% if flexvolume_plugins %}
-    - /usr/libexec/kubernetes/kubelet-plugins/volume/exec:/usr/libexec/kubernetes/kubelet-plugins/volume/exec
-{% endif %}
-    cluster_domain: cluster.local
-    infra_container_image: ""
-    cluster_dns_server: 10.43.0.10
-    fail_swap_on: false
-  kubeproxy:
-    image: ""
-network:
-  plugin: canal
-  options: {}
-authentication:
-  strategy: x509
-  options: {}
-  sans: []
-addons: ""
-addons_include: []
-ssh_agent_auth: {{ rke_ssh_agent_auth }}
-authorization:
-  mode: rbac
-  options: {}
-ignore_docker_version: false
-kubernetes_version: {{ kubernetes_version }}
-private_registries: []
-ingress:
-  # Set this to none, so we can install nginx ourselves.
-  provider: none
-  options: {}
-  node_selector: {}
-  extra_args: {}
-cluster_name: ""
-cloud_provider:
-  name: ""
-prefix_path: ""
-addon_job_timeout: 0
-bastion_host:
-  address: ""
-  port: ""
-  user: ""
-  ssh_key: ""
-  ssh_key_path: ""
-monitoring:
-  provider: ""
-  options: {}