DodoApp: Support dev virtual machines

Change-Id: Ib7641adb5be477bdde7cd9a06df4b45aa65a1c01
diff --git a/core/installer/values-tmpl/appmanager.cue b/core/installer/values-tmpl/appmanager.cue
index aad8f52..24d0d8d 100644
--- a/core/installer/values-tmpl/appmanager.cue
+++ b/core/installer/values-tmpl/appmanager.cue
@@ -29,57 +29,59 @@
 _domain: "\(_subdomain).\(input.network.domain)"
 url: "https://\(_domain)"
 
-ingress: {
-	appmanager: {
-		auth: {
-			enabled: true
-			groups: input.authGroups
-		}
-		network: input.network
-		subdomain: _subdomain
-		service: {
-			name: "appmanager"
-			port: name: _httpPortName
-		}
-	}
-}
-
-images: {
-	appmanager: {
-		repository: "giolekva"
-		name: "pcloud-installer"
-		tag: "latest"
-		pullPolicy: "Always"
-	}
-}
-
-charts: {
-	appmanager: {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/appmanager"
-	}
-}
-
-helm: {
-	appmanager: {
-		chart: charts.appmanager
-		values: {
-			repoAddr: input.repoAddr
-			sshPrivateKey: base64.Encode(null, input.sshPrivateKey)
-			headscaleAPIAddr: "http://headscale-api.\(global.namespacePrefix)app-headscale.svc.cluster.local"
-			ingress: {
-				className: input.network.ingressClass
-				domain: _domain
-				certificateIssuer: ""
+out: {
+	ingress: {
+		appmanager: {
+			auth: {
+				enabled: true
+				groups: input.authGroups
 			}
-			clusterRoleName: "\(global.id)-appmanager"
-			portName: _httpPortName
-			image: {
-				repository: images.appmanager.fullName
-				tag: images.appmanager.tag
-				pullPolicy: images.appmanager.pullPolicy
+			network: input.network
+			subdomain: _subdomain
+			service: {
+				name: "appmanager"
+				port: name: _httpPortName
+			}
+		}
+	}
+
+	images: {
+		appmanager: {
+			repository: "giolekva"
+			name: "pcloud-installer"
+			tag: "latest"
+			pullPolicy: "Always"
+		}
+	}
+
+	charts: {
+		appmanager: {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/appmanager"
+		}
+	}
+
+	helm: {
+		appmanager: {
+			chart: charts.appmanager
+			values: {
+				repoAddr: input.repoAddr
+				sshPrivateKey: base64.Encode(null, input.sshPrivateKey)
+				headscaleAPIAddr: "http://headscale-api.\(global.namespacePrefix)app-headscale.svc.cluster.local"
+				ingress: {
+					className: input.network.ingressClass
+					domain: _domain
+					certificateIssuer: ""
+				}
+				clusterRoleName: "\(global.id)-appmanager"
+				portName: _httpPortName
+				image: {
+					repository: images.appmanager.fullName
+					tag: images.appmanager.tag
+					pullPolicy: images.appmanager.pullPolicy
+				}
 			}
 		}
 	}
diff --git a/core/installer/values-tmpl/cert-manager.cue b/core/installer/values-tmpl/cert-manager.cue
index 0a89102..66e21af 100644
--- a/core/installer/values-tmpl/cert-manager.cue
+++ b/core/installer/values-tmpl/cert-manager.cue
@@ -3,104 +3,106 @@
 name: "cert-manager"
 namespace: "cert-manager"
 
-images: {
-	certManager: {
-		registry: "quay.io"
-		repository: "jetstack"
-		name: "cert-manager-controller"
-		tag: "v1.12.2"
-		pullPolicy: "IfNotPresent"
+out: {
+	images: {
+		certManager: {
+			registry: "quay.io"
+			repository: "jetstack"
+			name: "cert-manager-controller"
+			tag: "v1.12.2"
+			pullPolicy: "IfNotPresent"
+		}
+		cainjector: {
+			registry: "quay.io"
+			repository: "jetstack"
+			name: "cert-manager-cainjector"
+			tag: "v1.12.2"
+			pullPolicy: "IfNotPresent"
+		}
+		webhook: {
+			registry: "quay.io"
+			repository: "jetstack"
+			name: "cert-manager-webhook"
+			tag: "v1.12.2"
+			pullPolicy: "IfNotPresent"
+		}
+		dnsChallengeSolver: {
+			repository: "giolekva"
+			name: "dns-challenge-solver"
+			tag: "latest"
+			pullPolicy: "Always"
+		}
 	}
-	cainjector: {
-		registry: "quay.io"
-		repository: "jetstack"
-		name: "cert-manager-cainjector"
-		tag: "v1.12.2"
-		pullPolicy: "IfNotPresent"
-	}
-	webhook: {
-		registry: "quay.io"
-		repository: "jetstack"
-		name: "cert-manager-webhook"
-		tag: "v1.12.2"
-		pullPolicy: "IfNotPresent"
-	}
-	dnsChallengeSolver: {
-		repository: "giolekva"
-		name: "dns-challenge-solver"
-		tag: "latest"
-		pullPolicy: "Always"
-	}
-}
 
-charts: {
-	certManager: {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/cert-manager"
+	charts: {
+		certManager: {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/cert-manager"
+		}
+		dnsChallengeSolver: {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/cert-manager-webhook-pcloud"
+		}
 	}
-	dnsChallengeSolver: {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/cert-manager-webhook-pcloud"
-	}
-}
 
-helm: {
-	"cert-manager": {
-		chart: charts.certManager
-		dependsOn: [{
-			name: "ingress-public"
-			namespace: "\(global.pcloudEnvName)-ingress-public"
-		}]
-		values: {
-			fullnameOverride: "\(global.pcloudEnvName)-cert-manager"
-			installCRDs: true
-			dns01RecursiveNameserversOnly: true
-			dns01RecursiveNameservers: "1.1.1.1:53,8.8.8.8:53"
-			image: {
-				repository: images.certManager.fullName
-				tag: images.certManager.tag
-				pullPolicy: images.certManager.pullPolicy
-			}
-			cainjector: {
+	helm: {
+		"cert-manager": {
+			chart: charts.certManager
+			dependsOn: [{
+				name: "ingress-public"
+				namespace: "\(global.pcloudEnvName)-ingress-public"
+			}]
+			values: {
+				fullnameOverride: "\(global.pcloudEnvName)-cert-manager"
+				installCRDs: true
+				dns01RecursiveNameserversOnly: true
+				dns01RecursiveNameservers: "1.1.1.1:53,8.8.8.8:53"
 				image: {
-					repository: images.cainjector.fullName
-					tag: images.cainjector.tag
-					pullPolicy: images.cainjector.pullPolicy
+					repository: images.certManager.fullName
+					tag: images.certManager.tag
+					pullPolicy: images.certManager.pullPolicy
 				}
-			}
-			webhook: {
-				image: {
-					repository: images.webhook.fullName
-					tag: images.webhook.tag
-					pullPolicy: images.webhook.pullPolicy
+				cainjector: {
+					image: {
+						repository: images.cainjector.fullName
+						tag: images.cainjector.tag
+						pullPolicy: images.cainjector.pullPolicy
+					}
+				}
+				webhook: {
+					image: {
+						repository: images.webhook.fullName
+						tag: images.webhook.tag
+						pullPolicy: images.webhook.pullPolicy
+					}
 				}
 			}
 		}
-	}
-	"cert-manager-webhook-pcloud": {
-		chart: charts.dnsChallengeSolver
-		dependsOn: [{
-			name: "cert-manager"
-			namespace: release.namespace
-		}]
-		values: {
-			fullnameOverride: "\(global.pcloudEnvName)-cert-manager-webhook-pcloud"
-			certManager: {
-				name: "\(global.pcloudEnvName)-cert-manager"
-				namespace: "\(global.pcloudEnvName)-cert-manager"
+		"cert-manager-webhook-pcloud": {
+			chart: charts.dnsChallengeSolver
+			dependsOn: [{
+				name: "cert-manager"
+				namespace: release.namespace
+			}]
+			values: {
+				fullnameOverride: "\(global.pcloudEnvName)-cert-manager-webhook-pcloud"
+				certManager: {
+					name: "\(global.pcloudEnvName)-cert-manager"
+					namespace: "\(global.pcloudEnvName)-cert-manager"
+				}
+				image: {
+					repository: images.dnsChallengeSolver.fullName
+					tag: images.dnsChallengeSolver.tag
+					pullPolicy: images.dnsChallengeSolver.pullPolicy
+				}
+				logLevel: 2
+				apiGroupName: "dodo.cloud"
+				resolverName: "dns-resolver-pcloud"
 			}
-			image: {
-				repository: images.dnsChallengeSolver.fullName
-				tag: images.dnsChallengeSolver.tag
-				pullPolicy: images.dnsChallengeSolver.pullPolicy
-			}
-			logLevel: 2
-			apiGroupName: "dodo.cloud"
-			resolverName: "dns-resolver-pcloud"
 		}
 	}
 }
diff --git a/core/installer/values-tmpl/certificate-issuer-custom.cue b/core/installer/values-tmpl/certificate-issuer-custom.cue
index 0b1bc6e..8721e7f 100644
--- a/core/installer/values-tmpl/certificate-issuer-custom.cue
+++ b/core/installer/values-tmpl/certificate-issuer-custom.cue
@@ -7,8 +7,6 @@
 	domain: string
 }
 
-images: {}
-
 name: "Network"
 namespace: "ingress-custom"
 readme: "Configure custom public domain"
@@ -36,29 +34,31 @@
   </g>
 </svg>"""
 
-charts: {
-	"certificate-issuer": {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/certificate-issuer-public"
+out: {
+	charts: {
+		"certificate-issuer": {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/certificate-issuer-public"
+		}
 	}
-}
 
-helm: {
-	"certificate-issuer": {
-		chart: charts["certificate-issuer"]
-		dependsOn: [{
-			name: "ingress-nginx"
-			namespace: "\(global.namespacePrefix)ingress-private"
-		}]
-		values: {
-			issuer: {
-				name: input.name
-				server: "https://acme-v02.api.letsencrypt.org/directory"
-				domain: input.domain
-				contactEmail: global.contactEmail
-				ingressClass: networks.public.ingressClass
+	helm: {
+		"certificate-issuer": {
+			chart: charts["certificate-issuer"]
+			dependsOn: [{
+				name: "ingress-nginx"
+				namespace: "\(global.namespacePrefix)ingress-private"
+			}]
+			values: {
+				issuer: {
+					name: input.name
+					server: "https://acme-v02.api.letsencrypt.org/directory"
+					domain: input.domain
+					contactEmail: global.contactEmail
+					ingressClass: networks.public.ingressClass
+				}
 			}
 		}
 	}
diff --git a/core/installer/values-tmpl/certificate-issuer-private.cue b/core/installer/values-tmpl/certificate-issuer-private.cue
index c67702b..66dc53c 100644
--- a/core/installer/values-tmpl/certificate-issuer-private.cue
+++ b/core/installer/values-tmpl/certificate-issuer-private.cue
@@ -3,34 +3,34 @@
 name: "certificate-issuer-private"
 namespace: "ingress-private"
 
-images: {}
-
-charts: {
-	"certificate-issuer-private": {
-		path: "charts/certificate-issuer-private"
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
+out: {
+	charts: {
+		"certificate-issuer-private": {
+			path: "charts/certificate-issuer-private"
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+		}
 	}
-}
 
-helm: {
-	"certificate-issuer-private": {
-		chart: charts["certificate-issuer-private"]
-		dependsOn: [{
-			name: "ingress-nginx"
-			namespace: "\(global.namespacePrefix)ingress-private"
-		}]
-		values: {
-			issuer: {
-				name: "\(global.id)-private"
-				server: "https://acme-v02.api.letsencrypt.org/directory"
-				domain: global.privateDomain
-				contactEmail: global.contactEmail
-			}
-			config: {
-				createTXTAddr: "http://dns-api.\(global.id)-dns.svc.cluster.local/create-txt-record"
-				deleteTXTAddr: "http://dns-api.\(global.id)-dns.svc.cluster.local/delete-txt-record"
+	helm: {
+		"certificate-issuer-private": {
+			chart: charts["certificate-issuer-private"]
+			dependsOn: [{
+				name: "ingress-nginx"
+				namespace: "\(global.namespacePrefix)ingress-private"
+			}]
+			values: {
+				issuer: {
+					name: "\(global.id)-private"
+					server: "https://acme-v02.api.letsencrypt.org/directory"
+					domain: global.privateDomain
+					contactEmail: global.contactEmail
+				}
+				config: {
+					createTXTAddr: "http://dns-api.\(global.id)-dns.svc.cluster.local/create-txt-record"
+					deleteTXTAddr: "http://dns-api.\(global.id)-dns.svc.cluster.local/delete-txt-record"
+				}
 			}
 		}
 	}
diff --git a/core/installer/values-tmpl/certificate-issuer-public.cue b/core/installer/values-tmpl/certificate-issuer-public.cue
index 15f2d11..04a6e50 100644
--- a/core/installer/values-tmpl/certificate-issuer-public.cue
+++ b/core/installer/values-tmpl/certificate-issuer-public.cue
@@ -2,30 +2,30 @@
 	network: #Network
 }
 
-images: {}
-
 name: "certificate-issuer-public"
 namespace: "ingress-private"
 
-charts: {
-	"certificate-issuer-public": {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/certificate-issuer-public"
+out: {
+	charts: {
+		"certificate-issuer-public": {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/certificate-issuer-public"
+		}
 	}
-}
 
-helm: {
-	"certificate-issuer-public": {
-		chart: charts["certificate-issuer-public"]
-		values: {
-			issuer: {
-				name: input.network.certificateIssuer
-				server: "https://acme-v02.api.letsencrypt.org/directory"
-				domain: input.network.domain
-				contactEmail: global.contactEmail
-				ingressClass: input.network.ingressClass
+	helm: {
+		"certificate-issuer-public": {
+			chart: charts["certificate-issuer-public"]
+			values: {
+				issuer: {
+					name: input.network.certificateIssuer
+					server: "https://acme-v02.api.letsencrypt.org/directory"
+					domain: input.network.domain
+					contactEmail: global.contactEmail
+					ingressClass: input.network.ingressClass
+				}
 			}
 		}
 	}
diff --git a/core/installer/values-tmpl/coder.cue b/core/installer/values-tmpl/coder.cue
index 7f98189..4365830 100644
--- a/core/installer/values-tmpl/coder.cue
+++ b/core/installer/values-tmpl/coder.cue
@@ -12,125 +12,127 @@
 description: readme
 icon: "<svg xmlns='http://www.w3.org/2000/svg' width='50px' height='50px' viewBox='0 0 16 16'><path fill='currentColor' fill-rule='evenodd' d='M11.573.275a1.203 1.203 0 0 0-.191.073c-.039.021-1.383 1.172-2.986 2.558C6.792 4.291 5.462 5.424 5.44 5.424c-.022 0-.664-.468-1.427-1.04c-.762-.571-1.428-1.057-1.48-1.078c-.15-.063-.468-.05-.613.024C1.754 3.416.189 4.975.094 5.15a.741.741 0 0 0 .04.766c.041.057.575.557 1.185 1.11c.611.553 1.107 1.015 1.102 1.026c-.004.012-.495.442-1.091.957c-.596.514-1.122.981-1.168 1.036a.746.746 0 0 0-.069.804c.096.175 1.659 1.734 1.827 1.821c.166.087.497.089.653.005c.059-.031.7-.502 1.424-1.046l1.318-.988l.109.1l2.73 2.473c1.846 1.671 2.666 2.396 2.772 2.453l.15.08h1.348l1.631-.814c1.5-.748 1.64-.823 1.748-.942c.213-.237.197.241.197-5.738c0-5.821.009-5.468-.151-5.699c-.058-.084-.41-.331-1.634-1.148c-.857-.572-1.613-1.065-1.68-1.095c-.1-.045-.187-.056-.482-.063c-.237-.005-.401.004-.48.027m1.699 2.305l1.233.82l.001 4.82l.001 4.82l-1.205.6l-1.204.6h-.569L8.66 11.644c-1.578-1.428-2.912-2.616-2.963-2.641c-.199-.094-.5-.101-.661-.014c-.034.018-.651.475-1.372 1.015c-.721.541-1.322.983-1.335.983c-.03 0-.477-.448-.461-.462c.673-.577 2.078-1.794 2.182-1.891c.086-.081.169-.192.21-.28c.057-.127.065-.174.054-.343c-.01-.158-.028-.223-.091-.324c-.053-.086-.454-.466-1.229-1.167l-1.15-1.04l.231-.233a1.83 1.83 0 0 1 .256-.234c.013 0 .644.465 1.4 1.033c1.496 1.123 1.537 1.148 1.81 1.116a.968.968 0 0 0 .253-.069c.062-.029.503-.39.979-.802L7.96 5.265a5929.2 5929.2 0 0 0 2.187-1.89a191.687 191.687 0 0 1 1.879-1.614c.008-.001.568.368 1.246.819M11.64 4.257a1.5 1.5 0 0 0-.16.051c-.059.021-1.079.738-2.267 1.593C6.867 7.59 6.92 7.547 6.851 7.854a.556.556 0 0 0 0 .292c.068.307.017.264 2.362 1.953c1.188.855 2.214 1.576 2.28 1.601c.347.133.743-.029.929-.38l.071-.133V4.813l-.071-.133a.76.76 0 0 0-.369-.356c-.127-.056-.324-.088-.413-.067m-.66 4.5l-.007.757l-1.046-.75A41.313 41.313 0 0 1 8.881 8c0-.007.471-.351 1.046-.764l1.046-.75l.007.757a95.51 95.51 0 0 1 0 1.514'/></svg>"
 
-ingress: {
-	coder: {
-		auth: enabled: false
-		network: input.network
-		subdomain: input.subdomain
-		service: {
+out: {
+	ingress: {
+		coder: {
+			auth: enabled: false
+			network: input.network
+			subdomain: input.subdomain
+			service: {
+				name: "coder"
+				port: name: "http"
+			}
+		}
+	}
+
+	images: {
+		postgres: {
+			repository: "library"
+			name: "postgres"
+			tag: "15.3"
+			pullPolicy: "IfNotPresent"
+		}
+		coder: {
+			registry: "ghcr.io"
+			repository: "coder"
 			name: "coder"
-			port: name: "http"
+			tag: "latest"
+			pullPolicy: "IfNotPresent"
 		}
 	}
-}
 
-images: {
-	postgres: {
-		repository: "library"
-		name: "postgres"
-		tag: "15.3"
-		pullPolicy: "IfNotPresent"
-	}
-	coder: {
-		registry: "ghcr.io"
-		repository: "coder"
-		name: "coder"
-		tag: "latest"
-		pullPolicy: "IfNotPresent"
-	}
-}
-
-charts: {
-	postgres: {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/postgresql"
-	}
-	coder: {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/coder"
-	}
-	oauth2Client: {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/oauth2-client"
-	}
-}
-
-_oauth2ClientSecretName: "oauth2-credentials"
-
-helm: {
-	"oauth2-client": {
-		chart: charts.oauth2Client
-		values: {
-			name: "\(release.namespace)-coder"
-			secretName: _oauth2ClientSecretName
-			grantTypes: ["authorization_code"]
-			responseTypes: ["code"]
-			scope: "openid profile email"
-			redirectUris: ["\(url)/api/v2/users/oidc/callbackzot"]
-			hydraAdmin: "http://hydra-admin.\(global.namespacePrefix)core-auth.svc.cluster.local"
+	charts: {
+		postgres: {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/postgresql"
+		}
+		coder: {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/coder"
+		}
+		oauth2Client: {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/oauth2-client"
 		}
 	}
-	postgres: {
-		chart: charts.postgres
-		values: {
-			fullnameOverride: "postgres"
-			image: {
-				registry: images.postgres.registry
-				repository: images.postgres.imageName
-				tag: images.postgres.tag
-				pullPolicy: images.postgres.pullPolicy
-			}
-			auth: {
-				username: "coder"
-				password: "coder"
-				database: "coder"
+
+	_oauth2ClientSecretName: "oauth2-credentials"
+
+	helm: {
+		"oauth2-client": {
+			chart: charts.oauth2Client
+			values: {
+				name: "\(release.namespace)-coder"
+				secretName: _oauth2ClientSecretName
+				grantTypes: ["authorization_code"]
+				responseTypes: ["code"]
+				scope: "openid profile email"
+				redirectUris: ["\(url)/api/v2/users/oidc/callbackzot"]
+				hydraAdmin: "http://hydra-admin.\(global.namespacePrefix)core-auth.svc.cluster.local"
 			}
 		}
-	}
-	coder: {
-		chart: charts.coder
-		values: coder: {
-			image: {
-				repo: images.coder.fullName
-				tag: images.coder.tag
-				pullPolicy: images.coder.pullPolicy
-			}
-			envUseClusterAccessURL: false
-			env: [{
-				name: "CODER_ACCESS_URL"
-				value: url
-			}, {
-				name: "CODER_PG_CONNECTION_URL"
-				value: "postgres://coder:coder@postgres.\(release.namespace).svc.cluster.local:5432/coder?sslmode=disable"
-			}, {
-				name: "CODER_OIDC_ISSUER_URL"
-				value: "https://hydra.\(networks.public.domain)"
-			}, {
-				name: "CODER_OIDC_EMAIL_DOMAIN"
-				value: networks.public.domain
-			}, {
-				name: "CODER_OIDC_CLIENT_ID"
-				valueFrom: {
-					secretKeyRef: {
-						name: _oauth2ClientSecretName
-						key: "client_id"
-					}
+		postgres: {
+			chart: charts.postgres
+			values: {
+				fullnameOverride: "postgres"
+				image: {
+					registry: images.postgres.registry
+					repository: images.postgres.imageName
+					tag: images.postgres.tag
+					pullPolicy: images.postgres.pullPolicy
 				}
-			}, {
-				name: "CODER_OIDC_CLIENT_SECRET"
-				valueFrom: {
-					secretKeyRef: {
-						name: _oauth2ClientSecretName
-						key: "client_secret"
-					}
+				auth: {
+					username: "coder"
+					password: "coder"
+					database: "coder"
 				}
-			}]
+			}
+		}
+		coder: {
+			chart: charts.coder
+			values: coder: {
+				image: {
+					repo: images.coder.fullName
+					tag: images.coder.tag
+					pullPolicy: images.coder.pullPolicy
+				}
+				envUseClusterAccessURL: false
+				env: [{
+					name: "CODER_ACCESS_URL"
+					value: url
+				}, {
+					name: "CODER_PG_CONNECTION_URL"
+					value: "postgres://coder:coder@postgres.\(release.namespace).svc.cluster.local:5432/coder?sslmode=disable"
+				}, {
+					name: "CODER_OIDC_ISSUER_URL"
+					value: "https://hydra.\(networks.public.domain)"
+				}, {
+					name: "CODER_OIDC_EMAIL_DOMAIN"
+					value: networks.public.domain
+				}, {
+					name: "CODER_OIDC_CLIENT_ID"
+					valueFrom: {
+						secretKeyRef: {
+							name: _oauth2ClientSecretName
+							key: "client_id"
+						}
+					}
+				}, {
+					name: "CODER_OIDC_CLIENT_SECRET"
+					valueFrom: {
+						secretKeyRef: {
+							name: _oauth2ClientSecretName
+							key: "client_secret"
+						}
+					}
+				}]
+			}
 		}
 	}
 }
diff --git a/core/installer/values-tmpl/config-repo.cue b/core/installer/values-tmpl/config-repo.cue
index f56da11..26ada75 100644
--- a/core/installer/values-tmpl/config-repo.cue
+++ b/core/installer/values-tmpl/config-repo.cue
@@ -7,41 +7,40 @@
 name: "config-repo"
 namespace: "config-repo"
 
-images: {
-	softserve: {
-		repository: "charmcli"
-		name: "soft-serve"
-		tag: "v0.7.1"
-		pullPolicy: "IfNotPresent"
+out: {
+	images: {
+		softserve: {
+			repository: "charmcli"
+			name: "soft-serve"
+			tag: "v0.7.1"
+			pullPolicy: "IfNotPresent"
+		}
 	}
-}
 
-charts: {
-	softserve: {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/soft-serve"
+	charts: {
+		softserve: {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/soft-serve"
+		}
 	}
-}
 
-helm: {
-	softserve: {
-		chart: charts.softserve
-		values: {
-			serviceType: "ClusterIP"
-			addressPool: ""
-			reservedIP: ""
-			adminKey: input.adminKey
-			privateKey: input.privateKey
-			publicKey: input.publicKey
-			ingress: {
-				enabled: false
-			}
-			image: {
-				repository: images.softserve.fullName
-				tag: images.softserve.tag
-				pullPolicy: images.softserve.pullPolicy
+	helm: {
+		softserve: {
+			chart: charts.softserve
+			values: {
+				serviceType: "ClusterIP"
+				addressPool: ""
+				reservedIP: ""
+				adminKey: input.adminKey
+				privateKey: input.privateKey
+				publicKey: input.publicKey
+				image: {
+					repository: images.softserve.fullName
+					tag: images.softserve.tag
+					pullPolicy: images.softserve.pullPolicy
+				}
 			}
 		}
 	}
diff --git a/core/installer/values-tmpl/core-auth.cue b/core/installer/values-tmpl/core-auth.cue
index 079da27..d535c97 100644
--- a/core/installer/values-tmpl/core-auth.cue
+++ b/core/installer/values-tmpl/core-auth.cue
@@ -36,344 +36,353 @@
 }
 """###
 
-images: {
-	kratos: {
-		repository: "oryd"
-		name: "kratos"
-		tag: "v1.1.0-distroless"
-		pullPolicy: "IfNotPresent"
+out: {
+	images: {
+		kratos: {
+			repository: "oryd"
+			name: "kratos"
+			tag: "v1.1.0-distroless"
+			pullPolicy: "IfNotPresent"
+		}
+		hydra: {
+			repository: "oryd"
+			name: "hydra"
+			tag: "v2.2.0-distroless"
+			pullPolicy: "IfNotPresent"
+		}
+		ui: {
+			repository: "giolekva"
+			name: "auth-ui"
+			tag: "latest"
+			pullPolicy: "Always"
+		}
+		postgres: {
+			repository: "library"
+			name: "postgres"
+			tag: "15.3"
+			pullPolicy: "IfNotPresent"
+		}
 	}
-	hydra: {
-		repository: "oryd"
-		name: "hydra"
-		tag: "v2.2.0-distroless"
-		pullPolicy: "IfNotPresent"
-	}
-	ui: {
-		repository: "giolekva"
-		name: "auth-ui"
-		tag: "latest"
-		pullPolicy: "Always"
-	}
-	postgres: {
-		repository: "library"
-		name: "postgres"
-		tag: "15.3"
-		pullPolicy: "IfNotPresent"
-	}
-}
 
-charts: {
-	auth: {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/auth"
+	charts: {
+		auth: {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/auth"
+		}
+		postgres: {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/postgresql"
+		}
 	}
-	postgres: {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/postgresql"
-	}
-}
 
-helm: {
-	postgres: {
-		chart: charts.postgres
-		values: {
-			fullnameOverride: "postgres"
-			image: {
-				registry: images.postgres.registry
-				repository: images.postgres.imageName
-				tag: images.postgres.tag
-				pullPolicy: images.postgres.pullPolicy
-			}
-			service: {
-				type: "ClusterIP"
-				port: 5432
-			}
-			primary: {
-				initdb: {
-					scripts: {
-						"init.sql": """
-						CREATE USER kratos WITH PASSWORD 'kratos';
-						CREATE USER hydra WITH PASSWORD 'hydra';
-						CREATE DATABASE kratos WITH OWNER = kratos;
-						CREATE DATABASE hydra WITH OWNER = hydra;
-						"""
+	helm: {
+		postgres: {
+			chart: charts.postgres
+			values: {
+				fullnameOverride: "postgres"
+				image: {
+					registry: images.postgres.registry
+					repository: images.postgres.imageName
+					tag: images.postgres.tag
+					pullPolicy: images.postgres.pullPolicy
+				}
+				service: {
+					type: "ClusterIP"
+					port: 5432
+				}
+				primary: {
+					initdb: {
+						scripts: {
+							"init.sql": """
+							CREATE USER kratos WITH PASSWORD 'kratos';
+							CREATE USER hydra WITH PASSWORD 'hydra';
+							CREATE DATABASE kratos WITH OWNER = kratos;
+							CREATE DATABASE hydra WITH OWNER = hydra;
+							"""
+						}
+					}
+					persistence: {
+						size: "1Gi"
+					}
+					securityContext: {
+						enabled: true
+						fsGroup: 0
+					}
+					containerSecurityContext: {
+						enabled: true
+						runAsUser: 0
 					}
 				}
-				persistence: {
-					size: "1Gi"
-				}
-				securityContext: {
-					enabled: true
-					fsGroup: 0
-				}
-				containerSecurityContext: {
-					enabled: true
-					runAsUser: 0
-				}
-			}
-			volumePermissions: {
-				securityContext: {
-					runAsUser: 0
+				volumePermissions: {
+					securityContext: {
+						runAsUser: 0
+					}
 				}
 			}
 		}
-	}
-	auth: {
-		chart: charts.auth
-		dependsOn: [{
-			name: "postgres"
-			namespace: release.namespace
-		}]
-		values: {
-			kratos: {
-				fullnameOverride: "kratos"
-				image: {
-					repository: images.kratos.fullName
-					tag: images.kratos.tag
-					pullPolicy: images.kratos.pullPolicy
-				}
-				service: {
-					admin: {
-						enabled: true
-						type: "ClusterIP"
-						port: 80
-						name: "http"
-					}
-					public: {
-						enabled: true
-						type: "ClusterIP"
-						port: 80
-						name: "http"
-					}
-				}
-				ingress: {
-					admin: enabled: false
-					public: {
-						enabled: true
-						className: input.network.ingressClass
-						annotations: {
-							"acme.cert-manager.io/http01-edit-in-place": "true"
-							"cert-manager.io/cluster-issuer": input.network.certificateIssuer
-						}
-						hosts: [{
-							host: "accounts.\(input.network.domain)"
-							paths: [{
-								path: "/"
-								pathType: "Prefix"
-							}]
-						}]
-						tls: [{
-							hosts: ["accounts.\(input.network.domain)"]
-							secretName: "cert-accounts.\(input.network.domain)"
-						}]
-					}
-				}
-				secret: {
-					enabled: true
-				}
+		auth: {
+			chart: charts.auth
+			dependsOn: [{
+				name: "postgres"
+				namespace: release.namespace
+			}]
+			values: {
 				kratos: {
-					automigration: {
+					fullnameOverride: "kratos"
+					image: {
+						repository: images.kratos.fullName
+						tag: images.kratos.tag
+						pullPolicy: images.kratos.pullPolicy
+					}
+					service: {
+						admin: {
+							enabled: true
+							type: "ClusterIP"
+							port: 80
+							name: "http"
+						}
+						public: {
+							enabled: true
+							type: "ClusterIP"
+							port: 80
+							name: "http"
+						}
+					}
+					ingress: {
+						admin: enabled: false
+						public: {
+							enabled: true
+							className: input.network.ingressClass
+							annotations: {
+								"acme.cert-manager.io/http01-edit-in-place": "true"
+								"cert-manager.io/cluster-issuer": input.network.certificateIssuer
+							}
+							hosts: [{
+								host: "accounts.\(input.network.domain)"
+								paths: [{
+									path: "/"
+									pathType: "Prefix"
+								}]
+							}]
+							tls: [{
+								hosts: ["accounts.\(input.network.domain)"]
+								secretName: "cert-accounts.\(input.network.domain)"
+							}]
+						}
+					}
+					secret: {
 						enabled: true
 					}
-					development: false
-					courier: {
-						enabled: false
-					}
-					config: {
-						version: "v0.7.1-alpha.1"
-						dsn: "postgres://kratos:kratos@postgres.\(global.namespacePrefix)core-auth.svc:5432/kratos?sslmode=disable&max_conns=20&max_idle_conns=4"
-						serve: {
-							public: {
-								base_url: "https://accounts.\(input.network.domain)"
-								cors: {
-									enabled: true
-									debug: false
-									allow_credentials: true
-									allowed_origins: [
-										"https://\(input.network.domain)",
-										"https://*.\(input.network.domain)",
-								]
-								}
-							}
-							admin: {
-								base_url: "https://kratos-admin.\(global.namespacePrefix)core-auth.svc.cluster.local"
-							}
+					kratos: {
+						automigration: {
+							enabled: true
 						}
-						selfservice: {
-							default_browser_return_url: "https://accounts-ui.\(input.network.domain)"
-							allowed_return_urls: [
-								"https://*.\(input.network.domain)/",
-								// TODO(gio): replace with input.network.privateSubdomain
-								"https://*.\(global.privateDomain)",
-						    ]
-							methods: {
-								password: {
-									enabled: true
-								}
-							}
-							flows: {
-								error: {
-									ui_url: "https://accounts-ui.\(input.network.domain)/error"
-								}
-								settings: {
-									ui_url: "https://accounts-ui.\(input.network.domain)/settings"
-									privileged_session_max_age: "15m"
-								}
-								recovery: {
-									enabled: false
-								}
-								verification: {
-									enabled: false
-								}
-								logout: {
-									after: {
-										default_browser_return_url: "https://accounts-ui.\(input.network.domain)/login"
-									}
-								}
-								login: {
-									ui_url: "https://accounts-ui.\(input.network.domain)/login"
-									lifespan: "10m"
-									after: {
-										password: {
-											default_browser_return_url: "https://accounts-ui.\(input.network.domain)/"
-										}
-									}
-								}
-								registration: {
-									lifespan: "10m"
-									ui_url: "https://accounts-ui.\(input.network.domain)/register"
-									after: {
-										password: {
-											hooks: [{
-												hook: "session"
-											}]
-											default_browser_return_url: "https://accounts-ui.\(input.network.domain)/"
-										}
-									}
-								}
-							}
-						}
-						log: {
-							level: "debug"
-							format: "text"
-							leak_sensitive_values: true
-						}
-						cookies: {
-							path: "/"
-							same_site: "None"
-							domain: input.network.domain
-						}
-						secrets: {
-							cookie: ["PLEASE-CHANGE-ME-I-AM-VERY-INSECURE"]
-						}
-						hashers: {
-							argon2: {
-								parallelism: 1
-								memory: "128MB"
-								iterations: 2
-								salt_length: 16
-								key_length: 16
-								}
-						}
-						identity: {
-							schemas: [{
-								id: "user"
-								url: "file:///etc/config/identity.schema.json"
-							}]
-							default_schema_id: "user"
-						}
+						development: false
 						courier: {
-							smtp: {
-								connection_uri: "smtps://test-z1VmkYfYPjgdPRgPFgmeZ31esT9rUgS%40\(input.network.domain):iW%213Kk%5EPPLFrZa%24%21bbpTPN9Wv3b8mvwS6ZJvMLtce%23A2%2A4MotD@mx1.\(input.network.domain)"
+							enabled: false
+						}
+						config: {
+							version: "v0.7.1-alpha.1"
+							dsn: "postgres://kratos:kratos@postgres.\(global.namespacePrefix)core-auth.svc:5432/kratos?sslmode=disable&max_conns=20&max_idle_conns=4"
+							serve: {
+								public: {
+									base_url: "https://accounts.\(input.network.domain)"
+									cors: {
+										enabled: true
+										debug: false
+										allow_credentials: true
+										allowed_origins: [
+											"https://\(input.network.domain)",
+											"https://*.\(input.network.domain)",
+									]
+									}
+								}
+								admin: {
+									base_url: "https://kratos-admin.\(global.namespacePrefix)core-auth.svc.cluster.local"
+								}
+							}
+							selfservice: {
+								default_browser_return_url: "https://accounts-ui.\(input.network.domain)"
+								allowed_return_urls: [
+									"https://*.\(input.network.domain)/",
+									// TODO(gio): replace with input.network.privateSubdomain
+									"https://*.\(global.privateDomain)",
+								]
+								methods: {
+									password: {
+										enabled: true
+									}
+								}
+								flows: {
+									error: {
+										ui_url: "https://accounts-ui.\(input.network.domain)/error"
+									}
+									settings: {
+										ui_url: "https://accounts-ui.\(input.network.domain)/settings"
+										privileged_session_max_age: "15m"
+									}
+									recovery: {
+										enabled: false
+									}
+									verification: {
+										enabled: false
+									}
+									logout: {
+										after: {
+											default_browser_return_url: "https://accounts-ui.\(input.network.domain)/login"
+										}
+									}
+									login: {
+										ui_url: "https://accounts-ui.\(input.network.domain)/login"
+										lifespan: "10m"
+										after: {
+											password: {
+												default_browser_return_url: "https://accounts-ui.\(input.network.domain)/"
+											}
+										}
+									}
+									registration: {
+										lifespan: "10m"
+										ui_url: "https://accounts-ui.\(input.network.domain)/register"
+										after: {
+											password: {
+												hooks: [{
+													hook: "session"
+												}]
+												default_browser_return_url: "https://accounts-ui.\(input.network.domain)/"
+											}
+										}
+									}
+								}
+							}
+							log: {
+								level: "debug"
+								format: "text"
+								leak_sensitive_values: true
+							}
+							cookies: {
+								path: "/"
+								same_site: "None"
+								domain: input.network.domain
+							}
+							secrets: {
+								cookie: ["PLEASE-CHANGE-ME-I-AM-VERY-INSECURE"]
+							}
+							hashers: {
+								argon2: {
+									parallelism: 1
+									memory: "128MB"
+									iterations: 2
+									salt_length: 16
+									key_length: 16
+									}
+							}
+							identity: {
+								schemas: [{
+									id: "user"
+									url: "file:///etc/config/identity.schema.json"
+								}]
+								default_schema_id: "user"
+							}
+							courier: {
+								smtp: {
+									connection_uri: "smtps://test-z1VmkYfYPjgdPRgPFgmeZ31esT9rUgS%40\(input.network.domain):iW%213Kk%5EPPLFrZa%24%21bbpTPN9Wv3b8mvwS6ZJvMLtce%23A2%2A4MotD@mx1.\(input.network.domain)"
+								}
 							}
 						}
-					}
-					identitySchemas: {
-                        "identity.schema.json": _userSchema
-					}
-				}
-			}
-			hydra: {
-				fullnameOverride: "hydra"
-				image: {
-					repository: images.hydra.fullName
-					tag: images.hydra.tag
-					pullPolicy: images.hydra.pullPolicy
-				}
-				service: {
-					admin: {
-						enabled: true
-						type: "ClusterIP"
-						port: 80
-						name: "http"
-					}
-					public: {
-						enabled: true
-						type: "ClusterIP"
-						port: 80
-						name: "http"
-					}
-				}
-				ingress: {
-					admin: enabled: false
-					public: {
-						enabled: true
-						className: input.network.ingressClass
-						annotations: {
-							"acme.cert-manager.io/http01-edit-in-place": "true"
-							"cert-manager.io/cluster-issuer": input.network.certificateIssuer
+						identitySchemas: {
+							"identity.schema.json": _userSchema
 						}
-						hosts: [{
-							host: "hydra.\(input.network.domain)"
-							paths: [{
-								path: "/"
-								pathType: "Prefix"
-							}]
-						}]
-						tls: [{
-							hosts: ["hydra.\(input.network.domain)"]
-							secretName: "cert-hydra.\(input.network.domain)"
-						}]
 					}
 				}
-				secret: {
-					enabled: true
-				}
-				maester: {
-					enabled: false
-				}
 				hydra: {
-					automigration: {
+					fullnameOverride: "hydra"
+					image: {
+						repository: images.hydra.fullName
+						tag: images.hydra.tag
+						pullPolicy: images.hydra.pullPolicy
+					}
+					service: {
+						admin: {
+							enabled: true
+							type: "ClusterIP"
+							port: 80
+							name: "http"
+						}
+						public: {
+							enabled: true
+							type: "ClusterIP"
+							port: 80
+							name: "http"
+						}
+					}
+					ingress: {
+						admin: enabled: false
+						public: {
+							enabled: true
+							className: input.network.ingressClass
+							annotations: {
+								"acme.cert-manager.io/http01-edit-in-place": "true"
+								"cert-manager.io/cluster-issuer": input.network.certificateIssuer
+							}
+							hosts: [{
+								host: "hydra.\(input.network.domain)"
+								paths: [{
+									path: "/"
+									pathType: "Prefix"
+								}]
+							}]
+							tls: [{
+								hosts: ["hydra.\(input.network.domain)"]
+								secretName: "cert-hydra.\(input.network.domain)"
+							}]
+						}
+					}
+					secret: {
 						enabled: true
 					}
-					config: {
-						version: "v1.10.6"
-						dsn: "postgres://hydra:hydra@postgres.\(global.namespacePrefix)core-auth.svc:5432/hydra?sslmode=disable&max_conns=20&max_idle_conns=4"
-						serve: {
-							cookies: {
-								same_site_mode: "None"
-							}
-							public: {
-								cors: {
-									enabled: true
-									debug: false
-									allow_credentials: true
-									allowed_origins: [
-										"https://\(input.network.domain)",
-										"https://*.\(input.network.domain)"
-								]
+					maester: {
+						enabled: false
+					}
+					hydra: {
+						automigration: {
+							enabled: true
+						}
+						config: {
+							version: "v1.10.6"
+							dsn: "postgres://hydra:hydra@postgres.\(global.namespacePrefix)core-auth.svc:5432/hydra?sslmode=disable&max_conns=20&max_idle_conns=4"
+							serve: {
+								cookies: {
+									same_site_mode: "None"
 								}
-							}
-							admin: {
-								cors: {
-									allowed_origins: [
-										"https://hydra-admin.\(global.namespacePrefix)core-auth.svc.cluster.local"
-								]
+								public: {
+									cors: {
+										enabled: true
+										debug: false
+										allow_credentials: true
+										allowed_origins: [
+											"https://\(input.network.domain)",
+											"https://*.\(input.network.domain)"
+									]
+									}
+								}
+								admin: {
+									cors: {
+										allowed_origins: [
+											"https://hydra-admin.\(global.namespacePrefix)core-auth.svc.cluster.local"
+									]
+									}
+									tls: {
+										allow_termination_from: [
+											"0.0.0.0/0",
+											"10.42.0.0/16",
+											"10.43.0.0/16",
+									]
+									}
 								}
 								tls: {
 									allow_termination_from: [
@@ -383,54 +392,47 @@
 								]
 								}
 							}
-							tls: {
-								allow_termination_from: [
-									"0.0.0.0/0",
-									"10.42.0.0/16",
-									"10.43.0.0/16",
-							]
+							urls: {
+								self: {
+									public: "https://hydra.\(input.network.domain)"
+									issuer: "https://hydra.\(input.network.domain)"
+								}
+								consent: "https://accounts-ui.\(input.network.domain)/consent"
+								login: "https://accounts-ui.\(input.network.domain)/login"
+								logout: "https://accounts-ui.\(input.network.domain)/logout"
 							}
-						}
-						urls: {
-							self: {
-								public: "https://hydra.\(input.network.domain)"
-								issuer: "https://hydra.\(input.network.domain)"
+							secrets: {
+								system: ["youReallyNeedToChangeThis"]
 							}
-							consent: "https://accounts-ui.\(input.network.domain)/consent"
-							login: "https://accounts-ui.\(input.network.domain)/login"
-							logout: "https://accounts-ui.\(input.network.domain)/logout"
-						}
-						secrets: {
-							system: ["youReallyNeedToChangeThis"]
-						}
-						oidc: {
-							subject_identifiers: {
-								supported_types: [
-									"pairwise",
-									"public",
-							]
-								pairwise: {
-									salt: "youReallyNeedToChangeThis"
+							oidc: {
+								subject_identifiers: {
+									supported_types: [
+										"pairwise",
+										"public",
+								]
+									pairwise: {
+										salt: "youReallyNeedToChangeThis"
+									}
 								}
 							}
-						}
-						log: {
-							level: "trace"
-							leak_sensitive_values: false
+							log: {
+								level: "trace"
+								leak_sensitive_values: false
+							}
 						}
 					}
 				}
-			}
-			ui: {
-				certificateIssuer: input.network.certificateIssuer
-				ingressClassName: input.network.ingressClass
-				domain: input.network.domain
-				hydra: "hydra-admin.\(global.namespacePrefix)core-auth.svc.cluster.local"
-				enableRegistration: false
-				image: {
-					repository: images.ui.fullName
-					tag: images.ui.tag
-					pullPolicy: images.ui.pullPolicy
+				ui: {
+					certificateIssuer: input.network.certificateIssuer
+					ingressClassName: input.network.ingressClass
+					domain: input.network.domain
+					hydra: "hydra-admin.\(global.namespacePrefix)core-auth.svc.cluster.local"
+					enableRegistration: false
+					image: {
+						repository: images.ui.fullName
+						tag: images.ui.tag
+						pullPolicy: images.ui.pullPolicy
+					}
 				}
 			}
 		}
diff --git a/core/installer/values-tmpl/csi-driver-smb.cue b/core/installer/values-tmpl/csi-driver-smb.cue
index d765f7d..4627b3b 100644
--- a/core/installer/values-tmpl/csi-driver-smb.cue
+++ b/core/installer/values-tmpl/csi-driver-smb.cue
@@ -9,58 +9,60 @@
 	pullPolicy: "IfNotPresent"
 }
 
-images: {
-	smb: _baseImage & {
-		name: "smbplugin"
-		tag: "v1.11.0"
+out: {
+	images: {
+		smb: _baseImage & {
+			name: "smbplugin"
+			tag: "v1.11.0"
+		}
+		csiProvisioner: _baseImage & {
+			name: "csi-provisioner"
+			tag: "v3.5.0"
+		}
+		livenessProbe: _baseImage & {
+			name: "livenessprobe"
+			tag: "v2.10.0"
+		}
+		nodeDriverRegistrar: _baseImage & {
+			name: "csi-node-driver-registrar"
+			tag: "v2.8.0"
+		}
 	}
-	csiProvisioner: _baseImage & {
-		name: "csi-provisioner"
-		tag: "v3.5.0"
-	}
-	livenessProbe: _baseImage & {
-		name: "livenessprobe"
-		tag: "v2.10.0"
-	}
-	nodeDriverRegistrar: _baseImage & {
-		name: "csi-node-driver-registrar"
-		tag: "v2.8.0"
-	}
-}
 
-charts: {
-	csiDriverSMB: {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/csi-driver-smb"
+	charts: {
+		csiDriverSMB: {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/csi-driver-smb"
+		}
 	}
-}
 
-helm: {
-	"csi-driver-smb": {
-		chart: charts.csiDriverSMB
-		values: {
-			image: {
-				smb: {
-					repository: images.smb.fullName
-					tag: images.smb.tag
-					pullPolicy: images.smb.pullPolicy
-				}
-				csiProvisioner: {
-					repository: images.csiProvisioner.fullName
-					tag: images.csiProvisioner.tag
-					pullPolicy: images.csiProvisioner.pullPolicy
-				}
-				livenessProbe: {
-					repository: images.livenessProbe.fullName
-					tag: images.livenessProbe.tag
-					pullPolicy: images.livenessProbe.pullPolicy
-				}
-				nodeDriverRegistrar: {
-					repository: images.nodeDriverRegistrar.fullName
-					tag: images.nodeDriverRegistrar.tag
-					pullPolicy: images.nodeDriverRegistrar.pullPolicy
+	helm: {
+		"csi-driver-smb": {
+			chart: charts.csiDriverSMB
+			values: {
+				image: {
+					smb: {
+						repository: images.smb.fullName
+						tag: images.smb.tag
+						pullPolicy: images.smb.pullPolicy
+					}
+					csiProvisioner: {
+						repository: images.csiProvisioner.fullName
+						tag: images.csiProvisioner.tag
+						pullPolicy: images.csiProvisioner.pullPolicy
+					}
+					livenessProbe: {
+						repository: images.livenessProbe.fullName
+						tag: images.livenessProbe.tag
+						pullPolicy: images.livenessProbe.pullPolicy
+					}
+					nodeDriverRegistrar: {
+						repository: images.nodeDriverRegistrar.fullName
+						tag: images.nodeDriverRegistrar.tag
+						pullPolicy: images.nodeDriverRegistrar.pullPolicy
+					}
 				}
 			}
 		}
diff --git a/core/installer/values-tmpl/dns-gateway.cue b/core/installer/values-tmpl/dns-gateway.cue
index 59d2c37..bca02df 100644
--- a/core/installer/values-tmpl/dns-gateway.cue
+++ b/core/installer/values-tmpl/dns-gateway.cue
@@ -10,109 +10,111 @@
 name: "dns-gateway"
 namespace: "dns-gateway"
 
-images: {
-	coredns: {
-		repository: "coredns"
-		name: "coredns"
-		tag: "1.11.1"
-		pullPolicy: "IfNotPresent"
+out: {
+	images: {
+		coredns: {
+			repository: "coredns"
+			name: "coredns"
+			tag: "1.11.1"
+			pullPolicy: "IfNotPresent"
+		}
 	}
-}
 
-charts: {
-	coredns: {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/coredns"
+	charts: {
+		coredns: {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/coredns"
+		}
 	}
-}
 
-helm: {
-	coredns: {
-		chart: charts.coredns
-		values: {
-			image: {
-				repository: images.coredns.fullName
-				tag: images.coredns.tag
-				pullPolicy: images.coredns.pullPolicy
-			}
-			replicaCount: 1
-			resources: {
-				limits: {
-					cpu: "100m"
-					memory: "128Mi"
+	helm: {
+		coredns: {
+			chart: charts.coredns
+			values: {
+				image: {
+					repository: images.coredns.fullName
+					tag: images.coredns.tag
+					pullPolicy: images.coredns.pullPolicy
 				}
-				requests: {
-					cpu: "100m"
-					memory: "128Mi"
+				replicaCount: 1
+				resources: {
+					limits: {
+						cpu: "100m"
+						memory: "128Mi"
+					}
+					requests: {
+						cpu: "100m"
+						memory: "128Mi"
+					}
 				}
-			}
-			rollingUpdate: {
-				maxUnavailable: 1
-				maxSurge: "25%"
-			}
-			terminationGracePeriodSeconds: 30
-			serviceType: "ClusterIP"
-			service: name: "coredns"
-			serviceAccount: create: false
-			rbac: {
-				create: false
-				pspEnable: false
-			}
-			isClusterService: false
-			if len(input.servers) > 0 {
-				servers: [
-					for s in input.servers {
+				rollingUpdate: {
+					maxUnavailable: 1
+					maxSurge: "25%"
+				}
+				terminationGracePeriodSeconds: 30
+				serviceType: "ClusterIP"
+				service: name: "coredns"
+				serviceAccount: create: false
+				rbac: {
+					create: false
+					pspEnable: false
+				}
+				isClusterService: false
+				if len(input.servers) > 0 {
+					servers: [
+						for s in input.servers {
+							zones: [{
+								zone: s.zone
+							}]
+							port: 53
+							plugins: [{
+								name: "log"
+							}, {
+								name: "forward"
+								parameters: ". \(s.address)"
+							}, {
+								name: "health"
+								configBlock: "lameduck 5s"
+							}, {
+								name: "ready"
+							}]
+						}
+					]
+				}
+				if len(input.servers) == 0 {
+					servers: [{
 						zones: [{
-							zone: s.zone
+							zone: "."
 						}]
 						port: 53
 						plugins: [{
-							name: "log"
-						}, {
-							name: "forward"
-							parameters: ". \(s.address)"
-						}, {
-							name: "health"
-							configBlock: "lameduck 5s"
-						}, {
 							name: "ready"
 						}]
-					}
-			    ]
-			}
-			if len(input.servers) == 0 {
-				servers: [{
-					zones: [{
-						zone: "."
 					}]
-					port: 53
-					plugins: [{
-						name: "ready"
-					}]
-				}]
+				}
+				livenessProbe: {
+					enabled: true
+					initialDelaySeconds: 60
+					periodSeconds: 10
+					timeoutSeconds: 5
+					failureThreshold: 5
+					successThreshold: 1
+				}
+				readinessProbe: {
+					enabled: true
+					initialDelaySeconds: 30
+					periodSeconds: 10
+					timeoutSeconds: 5
+					failureThreshold: 5
+					successThreshold: 1
+				}
+				zoneFiles: []
+				hpa: enabled: false
+				autoscaler: enabled: false
+				deployment: enabled: true
 			}
-			livenessProbe: {
-				enabled: true
-				initialDelaySeconds: 60
-				periodSeconds: 10
-				timeoutSeconds: 5
-				failureThreshold: 5
-				successThreshold: 1
-			}
-			readinessProbe: {
-				enabled: true
-				initialDelaySeconds: 30
-				periodSeconds: 10
-				timeoutSeconds: 5
-				failureThreshold: 5
-				successThreshold: 1
-			}
-			zoneFiles: []
-			hpa: enabled: false
-			autoscaler: enabled: false
-			deployment: enabled: true
 		}
 	}
 }
diff --git a/core/installer/values-tmpl/dodo-app-instance-status.cue b/core/installer/values-tmpl/dodo-app-instance-status.cue
index ad66153..b72a272 100644
--- a/core/installer/values-tmpl/dodo-app-instance-status.cue
+++ b/core/installer/values-tmpl/dodo-app-instance-status.cue
@@ -8,15 +8,17 @@
 
 _subdomain: "status.\(input.appSubdomain)"
 
-ingress: {
-	"status-\(input.appName)": {
-		auth: enabled: false
-		network: input.network
-		subdomain: _subdomain
-		appRoot: "/\(input.appName)"
-		service: {
-			name: "web"
-			port: name: "http"
+out: {
+	ingress: {
+		"status-\(input.appName)": {
+			auth: enabled: false
+			network: input.network
+			subdomain: _subdomain
+			appRoot: "/\(input.appName)"
+			service: {
+				name: "web"
+				port: name: "http"
+			}
 		}
 	}
 }
diff --git a/core/installer/values-tmpl/dodo-app-instance.cue b/core/installer/values-tmpl/dodo-app-instance.cue
index e0d6906..ad20ac7 100644
--- a/core/installer/values-tmpl/dodo-app-instance.cue
+++ b/core/installer/values-tmpl/dodo-app-instance.cue
@@ -5,6 +5,7 @@
 input: {
 	repoAddr: string
 	repoHost: string
+	branch: string
 	gitRepoPublicKey: string
 	// TODO(gio): auto generate
 	fluxKeys: #SSHKey
@@ -58,7 +59,7 @@
 		}
 		spec: {
 			interval: "1m0s"
-			ref: branch: "dodo"
+			ref: branch: input.branch
 			secretRef: name: "app"
 			timeout: "60s"
 			url: input.repoAddr
diff --git a/core/installer/values-tmpl/dodo-app.cue b/core/installer/values-tmpl/dodo-app.cue
index 07c2f1a..8bb57c0 100644
--- a/core/installer/values-tmpl/dodo-app.cue
+++ b/core/installer/values-tmpl/dodo-app.cue
@@ -52,57 +52,6 @@
 _domain: "\(input.subdomain).\(input.network.domain)"
 url: "https://\(_domain)"
 
-images: {
-	softserve: {
-		repository: "charmcli"
-		name: "soft-serve"
-		tag: "v0.7.1"
-		pullPolicy: "IfNotPresent"
-	}
-	dodoApp: {
-		repository: "giolekva"
-		name: "pcloud-installer"
-		tag: "latest"
-		pullPolicy: "Always"
-	}
-}
-
-charts: {
-	softserve: {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/soft-serve"
-	}
-	dodoApp: {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/dodo-app"
-	}
-}
-
-volumes: db: size: "10Gi"
-
-ingress: {
-	"dodo-app": {
-		auth: {
-			if input.external {
-				enabled: false
-			}
-			if !input.external {
-				enabled: true
-			}
-		}
-		network: input.network
-		subdomain: input.subdomain
-		service: {
-			name: "web"
-			port: name: "http"
-		}
-	}
-}
-
 portForward: [#PortForward & {
 	allocator: input.network.allocatePortAddr
 	reservator: input.network.reservePortAddr
@@ -112,51 +61,106 @@
 	targetPort: 22
 }]
 
-helm: {
-	softserve: {
-		chart: charts.softserve
-		info: "Installing Git server"
-		values: {
-			serviceType: "ClusterIP"
-			addressPool: ""
-			reservedIP: ""
-			adminKey: strings.Join([input.fluxKeys.public, input.dAppKeys.public], "\n")
-			privateKey: input.ssKeys.private
-			publicKey: input.ssKeys.public
-			ingress: {
-				enabled: false
+out: {
+	images: {
+		softserve: {
+			repository: "charmcli"
+			name: "soft-serve"
+			tag: "v0.7.1"
+			pullPolicy: "IfNotPresent"
+		}
+		dodoApp: {
+			repository: "giolekva"
+			name: "pcloud-installer"
+			tag: "latest"
+			pullPolicy: "Always"
+		}
+	}
+
+	charts: {
+		softserve: {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/soft-serve"
+		}
+		dodoApp: {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/dodo-app"
+		}
+	}
+
+	volumes: {
+		"config-repo": size: "10Gi"
+		db: size: "10Gi"
+	}
+
+	ingress: {
+		"dodo-app": {
+			auth: {
+				if input.external {
+					enabled: false
+				}
+				if !input.external {
+					enabled: true
+				}
 			}
-			image: {
-				repository: images.softserve.fullName
-				tag: images.softserve.tag
-				pullPolicy: images.softserve.pullPolicy
+			network: input.network
+			subdomain: input.subdomain
+			service: {
+				name: "web"
+				port: name: "http"
 			}
 		}
 	}
-	"dodo-app": {
-		chart: charts.dodoApp
-		info: "Installing supervisor"
-		values: {
-			image: {
-				repository: images.dodoApp.fullName
-				tag: images.dodoApp.tag
-				pullPolicy: images.dodoApp.pullPolicy
+
+	helm: {
+		softserve: {
+			chart: charts.softserve
+			info: "Installing Git server"
+			values: {
+				serviceType: "ClusterIP"
+				addressPool: ""
+				reservedIP: ""
+				adminKey: strings.Join([input.fluxKeys.public, input.dAppKeys.public], "\n")
+				privateKey: input.ssKeys.private
+				publicKey: input.ssKeys.public
+				image: {
+					repository: images.softserve.fullName
+					tag: images.softserve.tag
+					pullPolicy: images.softserve.pullPolicy
+				}
+				persistentVolumeClaimName: volumes["config-repo"].name
 			}
-			clusterRoleName: "\(release.namespace)-dodo-app"
-			port: 8080
-			apiPort: 8081
-			repoAddr: "soft-serve.\(release.namespace).svc.cluster.local:22"
-			sshPrivateKey: base64.Encode(null, input.dAppKeys.private)
-			self: "api.\(release.namespace).svc.cluster.local"
-			repoPublicAddr: "ssh://\(_domain):\(input.sshPort)"
-			namespace: release.namespace
-			envAppManagerAddr: "http://appmanager.\(global.namespacePrefix)appmanager.svc.cluster.local"
-			envConfig: base64.Encode(null, json.Marshal(global))
-			gitRepoPublicKey: input.ssKeys.public
-			persistentVolumeClaimName: volumes.db.name
-			allowedNetworks: strings.Join([for n in input.allowedNetworks { n.name }], ",")
-			external: input.external
-			fetchUsersAddr: "http://memberships-api.\(global.namespacePrefix)core-auth-memberships.svc.cluster.local/api/users"
+		}
+		"dodo-app": {
+			chart: charts.dodoApp
+			info: "Installing supervisor"
+			values: {
+				image: {
+					repository: images.dodoApp.fullName
+					tag: images.dodoApp.tag
+					pullPolicy: images.dodoApp.pullPolicy
+				}
+				clusterRoleName: "\(release.namespace)-dodo-app"
+				port: 8080
+				apiPort: 8081
+				repoAddr: "soft-serve.\(release.namespace).svc.cluster.local:22"
+				sshPrivateKey: base64.Encode(null, input.dAppKeys.private)
+				self: "api.\(release.namespace).svc.cluster.local"
+				repoPublicAddr: "ssh://\(_domain):\(input.sshPort)"
+				namespace: release.namespace
+				envAppManagerAddr: "http://appmanager.\(global.namespacePrefix)appmanager.svc.cluster.local"
+				envConfig: base64.Encode(null, json.Marshal(global))
+				gitRepoPublicKey: input.ssKeys.public
+				persistentVolumeClaimName: volumes.db.name
+				allowedNetworks: strings.Join([for n in input.allowedNetworks { n.name }], ",")
+				external: input.external
+				fetchUsersAddr: "http://memberships-api.\(global.namespacePrefix)core-auth-memberships.svc.cluster.local/api/users"
+				headscaleAPIAddr: "http://headscale-api.\(global.namespacePrefix)app-headscale.svc"
+			}
 		}
 	}
 }
diff --git a/core/installer/values-tmpl/env-dns.cue b/core/installer/values-tmpl/env-dns.cue
index adc8b3b..2b73ada 100644
--- a/core/installer/values-tmpl/env-dns.cue
+++ b/core/installer/values-tmpl/env-dns.cue
@@ -10,201 +10,203 @@
 description: "Environment local DNS manager"
 icon: ""
 
-images: {
-	coredns: {
-		repository: "coredns"
-		name: "coredns"
-		tag: "1.11.1"
-		pullPolicy: "IfNotPresent"
+out: {
+	images: {
+		coredns: {
+			repository: "coredns"
+			name: "coredns"
+			tag: "1.11.1"
+			pullPolicy: "IfNotPresent"
+		}
+		api: {
+			repository: "giolekva"
+			name: "dns-api"
+			tag: "latest"
+			pullPolicy: "Always"
+		}
 	}
-	api: {
-		repository: "giolekva"
-		name: "dns-api"
-		tag: "latest"
-		pullPolicy: "Always"
-	}
-}
 
-charts: {
-	coredns: {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/coredns"
+	charts: {
+		coredns: {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/coredns"
+		}
+		api: {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/dns-api"
+		}
+		service: {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/service"
+		}
+		ipAddressPool: {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/metallb-ipaddresspool"
+		}
 	}
-	api: {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/dns-api"
-	}
-	service: {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/service"
-	}
-	ipAddressPool: {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/metallb-ipaddresspool"
-	}
-}
 
-volumes: data: {
-	accessMode: "ReadWriteMany"
-	size: "5Gi"
-}
+	volumes: data: {
+		accessMode: "ReadWriteMany"
+		size: "5Gi"
+	}
 
-helm: {
-	coredns: {
-		chart: charts.coredns
-		values: {
-			image: {
-				repository: images.coredns.fullName
-				tag: images.coredns.tag
-				pullPolicy: images.coredns.pullPolicy
-			}
-			replicaCount: 1
-			resources: {
-				limits: {
-					cpu: "100m"
-					memory: "128Mi"
+	helm: {
+		coredns: {
+			chart: charts.coredns
+			values: {
+				image: {
+					repository: images.coredns.fullName
+					tag: images.coredns.tag
+					pullPolicy: images.coredns.pullPolicy
 				}
-				requests: {
-					cpu: "100m"
-					memory: "128Mi"
-				}
-			}
-			rollingUpdate: {
-				maxUnavailable: 1
-				maxSurge: "25%"
-			}
-			terminationGracePeriodSeconds: 30
-			serviceType: "LoadBalancer"
-			service: {
-				name: "coredns"
-				annotations: {
-					"metallb.universe.tf/loadBalancerIPs": global.network.dns
-				}
-			}
-			serviceAccount: create: false
-			rbac: {
-				create: false
-				pspEnable: false
-			}
-			isClusterService: false
-			servers: [{
-				zones: [{
-					zone: "."
-				}]
-				port: 53
-				plugins: [
-					{
-						name: "log"
-					},
-					{
-						name: "health"
-						configBlock: "lameduck 5s"
-					},
-					{
-						name: "ready"
+				replicaCount: 1
+				resources: {
+					limits: {
+						cpu: "100m"
+						memory: "128Mi"
 					}
-			    ]
-			}]
-			extraConfig: import: parameters: "\(_mountPath)/coredns.conf"
-			extraVolumes: [{
-				name: volumes.data.name
-				persistentVolumeClaim: claimName: volumes.data.name
-			}]
-			extraVolumeMounts: [{
-				name: volumes.data.name
-				mountPath: _mountPath
-			}]
-			livenessProbe: {
-				enabled: true
-				initialDelaySeconds: 60
-				periodSeconds: 10
-				timeoutSeconds: 5
-				failureThreshold: 5
-				successThreshold: 1
-			}
-			readinessProbe: {
-				enabled: true
-				initialDelaySeconds: 30
-				periodSeconds: 10
-				timeoutSeconds: 5
-				failureThreshold: 5
-				successThreshold: 1
-			}
-			zoneFiles: []
-			hpa: enabled: false
-			autoscaler: enabled: false
-			deployment: enabled: true
-		}
-	}
-	api: {
-		chart: charts.api
-		values: {
-			image: {
-				repository: images.api.fullName
-				tag: images.api.tag
-				pullPolicy: images.api.pullPolicy
-			}
-			config: "coredns.conf"
-			db: "records.db"
-			zone: networks.public.domain
-			publicIP: strings.Join(global.publicIP, ",")
-			privateIP: global.network.ingress
-			nameserverIP: strings.Join(global.nameserverIP, ",")
-			service: type: "ClusterIP"
-			volume: {
-				claimName: volumes.data.name
-				mountPath: _mountPath
+					requests: {
+						cpu: "100m"
+						memory: "128Mi"
+					}
+				}
+				rollingUpdate: {
+					maxUnavailable: 1
+					maxSurge: "25%"
+				}
+				terminationGracePeriodSeconds: 30
+				serviceType: "LoadBalancer"
+				service: {
+					name: "coredns"
+					annotations: {
+						"metallb.universe.tf/loadBalancerIPs": global.network.dns
+					}
+				}
+				serviceAccount: create: false
+				rbac: {
+					create: false
+					pspEnable: false
+				}
+				isClusterService: false
+				servers: [{
+					zones: [{
+						zone: "."
+					}]
+					port: 53
+					plugins: [
+						{
+							name: "log"
+						},
+						{
+							name: "health"
+							configBlock: "lameduck 5s"
+						},
+						{
+							name: "ready"
+						}
+					]
+				}]
+				extraConfig: import: parameters: "\(_mountPath)/coredns.conf"
+				extraVolumes: [{
+					name: volumes.data.name
+					persistentVolumeClaim: claimName: volumes.data.name
+				}]
+				extraVolumeMounts: [{
+					name: volumes.data.name
+					mountPath: _mountPath
+				}]
+				livenessProbe: {
+					enabled: true
+					initialDelaySeconds: 60
+					periodSeconds: 10
+					timeoutSeconds: 5
+					failureThreshold: 5
+					successThreshold: 1
+				}
+				readinessProbe: {
+					enabled: true
+					initialDelaySeconds: 30
+					periodSeconds: 10
+					timeoutSeconds: 5
+					failureThreshold: 5
+					successThreshold: 1
+				}
+				zoneFiles: []
+				hpa: enabled: false
+				autoscaler: enabled: false
+				deployment: enabled: true
 			}
 		}
-	}
-	"coredns-svc-cluster": {
-		chart: charts.service
-		values: {
-			name: "dns"
-			type: "LoadBalancer"
-			protocol: "TCP"
-			ports: [{
-				name: "udp-53"
-				port: 53
-				protocol: "UDP"
-				targetPort: 53
-			}]
-			targetPort: "http"
-			selector:{
-				"app.kubernetes.io/instance": "coredns"
-				"app.kubernetes.io/name": "coredns"
-			}
-			annotations: {
-				"metallb.universe.tf/loadBalancerIPs": global.network.dnsInClusterIP
+		api: {
+			chart: charts.api
+			values: {
+				image: {
+					repository: images.api.fullName
+					tag: images.api.tag
+					pullPolicy: images.api.pullPolicy
+				}
+				config: "coredns.conf"
+				db: "records.db"
+				zone: networks.public.domain
+				publicIP: strings.Join(global.publicIP, ",")
+				privateIP: global.network.ingress
+				nameserverIP: strings.Join(global.nameserverIP, ",")
+				service: type: "ClusterIP"
+				volume: {
+					claimName: volumes.data.name
+					mountPath: _mountPath
+				}
 			}
 		}
-	}
-	"ipaddresspool-dns": {
-		chart: charts.ipAddressPool
-		values: {
-			name: "\(global.id)-dns"
-			autoAssign: false
-			from: global.network.dns
-			to: global.network.dns
-			namespace: "metallb-system"
+		"coredns-svc-cluster": {
+			chart: charts.service
+			values: {
+				name: "dns"
+				type: "LoadBalancer"
+				protocol: "TCP"
+				ports: [{
+					name: "udp-53"
+					port: 53
+					protocol: "UDP"
+					targetPort: 53
+				}]
+				targetPort: "http"
+				selector:{
+					"app.kubernetes.io/instance": "coredns"
+					"app.kubernetes.io/name": "coredns"
+				}
+				annotations: {
+					"metallb.universe.tf/loadBalancerIPs": global.network.dnsInClusterIP
+				}
+			}
 		}
-	}
-	"ipaddresspool-dns-in-cluster": {
-		chart: charts.ipAddressPool
-		values: {
-			name: "\(global.id)-dns-in-cluster"
-			autoAssign: false
-			from: global.network.dnsInClusterIP
-			to: global.network.dnsInClusterIP
-			namespace: "metallb-system"
+		"ipaddresspool-dns": {
+			chart: charts.ipAddressPool
+			values: {
+				name: "\(global.id)-dns"
+				autoAssign: false
+				from: global.network.dns
+				to: global.network.dns
+				namespace: "metallb-system"
+			}
+		}
+		"ipaddresspool-dns-in-cluster": {
+			chart: charts.ipAddressPool
+			values: {
+				name: "\(global.id)-dns-in-cluster"
+				autoAssign: false
+				from: global.network.dnsInClusterIP
+				to: global.network.dnsInClusterIP
+				namespace: "metallb-system"
+			}
 		}
 	}
 }
diff --git a/core/installer/values-tmpl/env-manager.cue b/core/installer/values-tmpl/env-manager.cue
index cf38521..dbde7de 100644
--- a/core/installer/values-tmpl/env-manager.cue
+++ b/core/installer/values-tmpl/env-manager.cue
@@ -12,37 +12,39 @@
 name: "env-manager"
 namespace: "env-manager"
 
-images: {
-	envManager: {
-		repository: "giolekva"
-		name: "pcloud-installer"
-		tag: "latest"
-		pullPolicy: "Always"
+out: {
+	images: {
+		envManager: {
+			repository: "giolekva"
+			name: "pcloud-installer"
+			tag: "latest"
+			pullPolicy: "Always"
+		}
 	}
-}
 
-charts: {
-	envManager: {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/env-manager"
+	charts: {
+		envManager: {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/env-manager"
+		}
 	}
-}
 
-helm: {
-	"env-manager": {
-		chart: charts.envManager
-		values: {
-			repoIP: input.repoIP
-			repoPort: input.repoPort
-			repoName: input.repoName
-			sshPrivateKey: base64.Encode(null, input.sshPrivateKey)
-			clusterRoleName: "\(global.pcloudEnvName)-env-manager"
-			image: {
-				repository: images.envManager.fullName
-				tag: images.envManager.tag
-				pullPolicy: images.envManager.pullPolicy
+	helm: {
+		"env-manager": {
+			chart: charts.envManager
+			values: {
+				repoIP: input.repoIP
+				repoPort: input.repoPort
+				repoName: input.repoName
+				sshPrivateKey: base64.Encode(null, input.sshPrivateKey)
+				clusterRoleName: "\(global.pcloudEnvName)-env-manager"
+				image: {
+					repository: images.envManager.fullName
+					tag: images.envManager.tag
+					pullPolicy: images.envManager.pullPolicy
+				}
 			}
 		}
 	}
diff --git a/core/installer/values-tmpl/fluxcd-reconciler.cue b/core/installer/values-tmpl/fluxcd-reconciler.cue
index 3e742ff..fde9396 100644
--- a/core/installer/values-tmpl/fluxcd-reconciler.cue
+++ b/core/installer/values-tmpl/fluxcd-reconciler.cue
@@ -3,32 +3,34 @@
 name: "fluxcd-reconciler"
 namespace: "fluxcd-reconciler"
 
-images: {
-	fluxcdReconciler: {
-		repository: "giolekva"
-		name: "fluxcd-reconciler"
-		tag: "latest"
-		pullPolicy: "Always"
+out: {
+	images: {
+		fluxcdReconciler: {
+			repository: "giolekva"
+			name: "fluxcd-reconciler"
+			tag: "latest"
+			pullPolicy: "Always"
+		}
 	}
-}
 
-charts: {
-	fluxcdReconciler: {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/fluxcd-reconciler"
+	charts: {
+		fluxcdReconciler: {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/fluxcd-reconciler"
+		}
 	}
-}
 
-helm: {
-	"fluxcd-reconciler": {
-		chart: charts.fluxcdReconciler
-		values: {
-			image: {
-				repository: images.fluxcdReconciler.fullName
-				tag: images.fluxcdReconciler.tag
-				pullPolicy: images.fluxcdReconciler.pullPolicy
+	helm: {
+		"fluxcd-reconciler": {
+			chart: charts.fluxcdReconciler
+			values: {
+				image: {
+					repository: images.fluxcdReconciler.fullName
+					tag: images.fluxcdReconciler.tag
+					pullPolicy: images.fluxcdReconciler.pullPolicy
+				}
 			}
 		}
 	}
diff --git a/core/installer/values-tmpl/gerrit.cue b/core/installer/values-tmpl/gerrit.cue
index 91597da..4fc9eaf 100644
--- a/core/installer/values-tmpl/gerrit.cue
+++ b/core/installer/values-tmpl/gerrit.cue
@@ -32,76 +32,272 @@
   <path class='cls-1' d='m20.91007091,3.11035315l-.40677547-.44522187c.00619982-.006201.47746668-.43902117.68457526-.67217354.1996669-.24555409.56179703-.8011513.56799921-.8073523l.50351019.32244483c-.02604351.02604351-.38817364.59404272-.62008623.86564032s-.71061876.71061876-.73046245.73666257h.00123949Zm2.60932297,17.51743602c-.01984369-.00619982-.40057565-.25175391-.60768422-.36213013-.22991143-.11154711-.46273235-.21699848-.69821676-.31624294l.35468845-1.01446206-1.48572655-.73046127-.47126449,1.43984054c-.29019943.00619982-1.18188444.08433271-2.50018743.63992992-1.58866109.66473157-2.79038804,1.69903731-2.80279005,1.70523714l-.23935309.20710857,1.0653084.03844552.03224451-.02604351c.006201-.01240201,1.18808545-.88548401,1.84785668-1.16948362.14882055-.0582892.34228763-.12277823.5493962-.16742357-.34848863.16742357-.73046127.37453214-.99461837.52335388-.32988562.1996669-.94253135.63248824-.96857486.65233193l-.31004312.21331076,1.12979743.02604351.03224451-.01240201c.0198425-.01240201,1.92474772-1.03306389,2.95781042-1.26001615l.32244512-.07813052c.23935427-.0582892.40677547-.10293454.69821676-.10293454.2579561,0,.60768422.03224333,1.13723792.11657604.65853175.09673235,1.09135073.2579561,1.09755291.26539778l.39437583.15502156-.5295537-.72302077-.01984369-.01240201.00868117-.00744404Zm-14.84982503-12.065638h-.05208702l-1.66059121,1.51797106v.04464652c-.02604351.43902117.12897805.85943932.42661916,1.18808545.29764111.32244512.69077626.50971119,1.12979683.52335269h.07069003c.87804233,0,1.5948621-.67837425,1.64074811-1.55021558.0374887-.90290667-.65442416-1.66979928-1.55641658-1.72507964l.00124067.00123949Zm-.07813112,3.02850045h-.06448843c-.19170127-.00438435-.37976864-.05320469-.5493962-.14261955.46794696.07532156.90835369-.24296393.98367584-.7109109.01272844-.07907552.01432452-.1595431.00474153-.23906095-.06419689-.46466491-.49097867-.79070078-.95617285-.73046127-.43424238.06072443-.75232622.4398538-.73666227.87804233-.0493023-.1478661-.0732039-.30301539-.07069003-.45886367l1.50556906-1.38279201c.74277694.07474203,1.29972245.71365481,1.27241697,1.45968304-.0345792.7442305-.65017228,1.32863287-1.39519402,1.32450399l.00620041.00247898Zm15.42526651-6.16117612l-.48490836-.32244512-.67837543.43902117-.65233193-.47126568-.497308.29764111.67217325.48490718-.69077508.44522217.49110818.29764111.66473157-.42041815.63992992.46506467.50971001-.28399961-.67217325-.48490718.69821912-.44646166Zm15.66337715,25.53267101c-.35468845-.34228645-.69077508-.68457526-1.04050557-1.03306389-.79630214-.80614711-1.57814907-1.62644429-2.34516705-2.46050124-.90996396-.98277224-1.78242858-1.99961393-2.61552279-3.04834414-.37553745-.46918054-.73095919-.95411256-1.06530722-1.45348322-.41339634-.64390149-.78257785-1.31514039-1.10499459-2.00908043-.34239052-.73667646-.66127566-1.48404945-.95617285-2.24099065.40057565.34228645.76890797.73046245,1.09755291,1.14344011.03224333-.35468845.07068885-.71061876.09673235-1.0727489l.03844552-.5295537c0-.05828802.01984369-.11037504-.01240201-.16122256-.02454382-.04479436-.05499414-.08608905-.09053253-.12277705-.19346707-.24555409-.43282134-.46506467-.66473157-.68457526-.31804304-.29794743-.64094706-.59066724-.96857486-.87804233l-.29764111-.2579561c-.04464534-.04464652-.09673235-.08433153-.14261955-.12277705-.05208702-.05208702-.07068885-.16122256-.09053253-.22571159l-.2579561-.79495029c1.00825987.47126568,1.83421518,1.22777045,2.60932297,2.00907925.00619982-.36213013.00619982-.71681977,0-1.0789499,0-.18726607,0-.37453214-.01240201-.56799921,0-.05208702.01240201-.16742357-.02604351-.21330958-.01984369-.03224451-.05208702-.05828802-.07068885-.09053253-.18106507-.19346707-.38817364-.35468964-.5878429-.51715169-.28399961-.23935309-.58164071-.45886367-.87184014-.67837425-.2579561-.19346707-.52335388-.38073314-.7875098-.56799921-.03224333-.02604351-.12897805-.06448902-.11037622-.09673354l.06448902-.13517905c.03844552-.05828802.02604351-.07069003.09053253-.04464652l.28399961.09673354c.66473157.2579561,1.2848178.60768422,1.8863022,1.00825987-.20820614-.74461962-.49853567-1.46378708-.86564032-2.1442583-.65563881-1.25890203-1.46959424-2.42878067-2.42205572-3.4811643-.62615595-.7038808-1.29947171-1.36435044-2.01528025-1.97683473-.36833232-.31004312-.7552641-.60768422-1.15583975-.87804233-.18726489-.12277705-.36833232-.24555409-.56799921-.36213013-.08433271-.04464593-.17486524-.09053253-.25175391-.15502156-.29764111-.23315267-.60024254-.46506467-.90408584-.70441776.39437583.16122256.77510779.34228763,1.13723792.55559721-.20710857-.32244512-.56179703-.5493962-.89788365-.71681977-.51418543-.25650845-1.05045934-.46611966-1.60230259-.62628724.18726489-.19966778.38817364-.38073285.57544089-.57544001.18726489-.19966778.36833232-.40677665.5431952-.62008623.21331076-.24555409.42041934-.49110818.62008623-.74906398l-2.70605533-1.69903628c-.1996669.4005758-.45886485.78130865-.7552641,1.12359627-.29764111.33608662-.64612974.60768452-.99461837.89168413-.31004312.2579558-.62628724.51715199-.93012935.77510779-.08433153.07068973-.15502156.14261984-.24555409.19966778-.03844552.03844522-.15502156.006201-.20710857.006201h-.39437464c-.49110818.01240171-.98221636.05208731-1.47332454.11657634-.09673354.006201-.18726607.0198428-.29020061.01240171l-.29020061-.0198428c-.22571159-.01240171-.45266266-.02604351-.67837425-.02604351-.47746668-.006201-.95617285,0-1.43984054.03844522-.40456023.03341748-.80618022.09600232-1.20172695.18726607-.39394768.09978762-.76465136.27545061-1.09135191.51715199-.32244512.23315267-.63992873.5295537-.83339581.87804233-.19346707.34228763-.28399961.74906428-.35468964,1.13723792-.21951058.0198425-.43902117.0198425-.65853175.02604351-.67978583.03606293-1.3523068.15773294-2.00163816.36213013-.81508789.25388636-1.56763764.67642986-2.20874732,1.24017246-.32830018.30005267-.62690964.63105596-.89168383.98841737-.03224451.03844552-.06448902.08433153-.10293425.11037563-.0198428.01240201-.04464623.02604351-.05828802.04464652-.02450449.04328876-.05272095.08436938-.08433182.12277705l-.21951058.35468964c-.2777986.47126568-.45886367.98221636-.63248794,1.49812856l-.07813082.19966808.05828802-.03224451c-.01893831.1114525-.03383025.22355549-.04464623.33608662l-.01240171.16742357v.09053253l-.11037533.0198425c-.2219529.04571925-.44169382.10158624-.6585316.16742357-.19552693.05895389-.38235909.14361185-.55559735.25175509-.17486436.10293454-.32244483.25175509-.47126553.39437464-.53470711.51039244-.92674,1.15166711-1.13723814,1.86025869C-.00047122,14.62163461-.05875932,15.26032385.07021861,15.84816557c.03224448.14882055.07813087.31004312.17486431.43282016.12277708.14882055.32988588.20710857.51715187.15502156.21951051-.05828802.41297744-.19966808.61388537-.30384211l.52335269-.26539659c.74906398-.36833114,1.53781386-.73666227,2.37741068-.86564032.05828802-.006201.16122256.11037504.21330958.14882055.08433182.06448902.16742327.12277705.24555409.17486406.18106507.11657604.36833114.21330958.55559721.29764111.43282016.18726607.89168383.29020061,1.35054809.38073314.83339581.17486406,1.67919363.28399961,2.53243194.29764111.34228763.006201.68457526,0,1.03306389-.02604351.36833114-.03224451.74286328-.08433153,1.11739542-.08433153.41297766-.006201.81975431.03844552,1.22777045.09053253.42041815.05208702.83959681.11037504,1.26001497.17486406.85943932.12897805,1.70523714.2777986,2.55103495.45886367-.18726607.29764111-.37453214.60024373-.55559721.90408584-.01240201.0198425-.12277705,0-.14882055,0-.06889702-.00619746-.13821155-.00619746-.20710857,0-.12277705,0-.25175509.01240201-.37453214.03224451-.34628049.04689132-.68643449.13130683-1.01446088.25175509-.81355331.30384211-1.55641658.8011513-2.19634532,1.38279201-.36833114.32244512-.71061876.67217325-1.00825987,1.0591074-.07769174.10364181-.15294943.20908372-.22571159.31624294.16742357-.03844552.34848863-.07068885.52335269-.11657604.10293454-.02604351.19346707-.04464534.29020061-.06448902.03224451-.01240201.04464652-.02604351.08433153-.04464534.36033003-.33479036.74230148-.64550526,1.14343892-.93012935.18726607-.12897805.37453214-.25175391.58164071-.35468845.2715976-.13517787.58164071-.21331076.87804233-.28399961-.5431952.29764111-1.12359642.57544089-1.6147046.96237268-.28399961.23315208-.5431952.48490836-.81355331.73046245l1.0851509-.17486524c.01240201,0,.0198425-.00619982.03844552-.01984369l.2777986-.15502156c.18726607-.10293454.38073314-.20710857.57543971-.30384329.39437464-.20710857.79495029-.40057565,1.20792795-.56179703.39437464-.15502156.79495029-.29764111,1.21412895-.37453214.36213013-.07813052.70441776-.08433271,1.0727489,0,.56179821.12277823,1.10499341.38073196,1.60230259.68457526.03224451.02604351.05828802.0582892.09053253.02604351.02604351-.02604351.16122256-.12277823.14882055-.15502156l-.29764111-.54939738c-.02604351-.05208702-.03844552-.08433271-.08433153-.11037622l-.21951058-.12897805c-.28953356-.16791321-.56980641-.3513106-.83959681-.5493962-.06448902-.03844552-.12897805-.06448902-.13517905-.14882055-.01240201-.07069003.0198425-.14882055.04464652-.21951058.05208702-.14882055.12897805-.28399961.21330958-.41297766.05828802-.09673354.12277705-.18106507.18106507-.2715976.02604351-.03224451.0198425-.03844552.05208702-.02604351l.19966808.05828802c.38817364.12897805.77510779.26539659,1.17568344.36213013.44522217.11657604.89788483.20710857,1.35674969.29020061l.07813052.0198425c-.09053253-.05208702-.14882174-.14882055-.21951058-.22571159-.03844552-.05208702-.0582892-.08433153-.12277823-.09673354l-.17486524-.03844552c-.12277823-.02604351-.23935427-.04464652-.36833232-.07813052-.43511464-.0892824-.86422461-.20567275-1.28481898-.34848863-.62132927-.20887792-1.25299907-.38562961-1.89250321-.5295537-.8031773-.17243002-1.610817-.32337238-2.4220569-.45266266-.41297766-.07069003-.82719481-.12277705-1.24017246-.18106507-.40961518-.06287106-.82115347-.11250393-1.23397146-.14882055-.89168383-.05208702-1.77592716.14882055-2.673812.13517905-.60024373-.006201-1.21412895-.09053253-1.80817168-.17486406l-.11657604-.01240201c.42041815-.15502156.82719481-.31004312,1.24017246-.47126568.39437464-.15502156.78130879-.31624412,1.16948243-.47746668.20710857-.08433153.41297766-.17486406.61388523-.2579561.18726607-.08433153.37453214-.16742357.5431952-.28399961.67837425-.45886367,1.11739542-1.20172695,1.6147046-1.83421518.45266266-.59404272.96857486-1.15584093,1.63454711-1.49812856.21330958-.11037504.43282016-.19346707.66473275-.2579561-.47126568-.72302077-.91028684-1.53781357-1.03306389-2.40345389l.15502156.05828802c.05828802.0198425.11037504.02604351.12277705.07813112l.04464652.21950999c.04464652.14882055.09053253.29020061.14261955.43282016.12277705.31624412.26539659.62008623.43282016.91028684.36978352.65215334.79332405,1.27232236,1.26621597,1.85405769.89168383,1.13723792,1.89250321,2.1578998,2.86851856,3.21080619.23935309.2579561.45886367.5357547.67837425.81355331.25175509.31004312.50351019.62008623.7552641.92392834.1996669.23315208.38817364.47126568.5878429.70441776l.15502156.18726607c.02604351.03224451.06448902.04464652.10293454.05828802,1.00081819.49730919,2.00908043.99461837,3.00989862,1.47952673.72302077.34848863,1.43983936.69821676,2.17030181,1.03306389.38817364.18106507.77510779.36213013,1.17568344.5295537.04464534.01984369.10293454.04464534.16122138.06448902.02604351.01240201.04464534.02604351.07813052.03844552l.02604351.07813052c.04464534.12277823.08433271.23935427.12277823.36213013.08433271.23315208.16122138.45886485.24555409.68457526.54939738,1.51177006,1.14963993,3.00369643,1.89250202,4.42493633.578322,1.08265063,1.1791086,2.15315236,1.80196949,3.21080737.66473157,1.12359642,1.343107,2.23479083,2.02768226,3.34598525.54939738.88548401,1.09755291,1.77592598,1.66679162,2.65521017.23935427.37453214.47746668.76270578.72302077,1.13723792l.10293454.15502156,1.60230259-2.35136687c.01240201-.01240201.13517787-.16742357.12277823-.18106507l-.2579561-.40057565c-.47746668-.74286209-.96237268-1.48572655-1.43983936-2.22859101l-1.54401576-2.39601221,1.0851509,1.31830299,1.84785668,2.23479083c.1996669.23935427.38817364.47746668.58164071.72302077.36213013-.66473157.73046245-1.32450517,1.09755291-1.98303692.14261955-.2715976.29019943-.54939738.4390188-.81355331l-.00495796-.01239964ZM20.05063278,1.84413718c.50971001-.40677665.93012935-.93012935,1.25257447-1.49812827l1.95079123,1.23397175.29764111.18106507c-.40677547.49730919-.81975313,1.00081908-1.2848178,1.44728133-.06097634.05293118-.11933415.10880527-.17486524.16742327-.03224333.04464623-.07813052.08433182-.11657604.12277705l-.05208702.06448902c-.03844552-.01240171-.07813052-.02604351-.11657604-.03224451-.23935427-.06448902-.47746668-.12897805-.71681859-.18106507-.48385337-.10967516-.97316382-.19371042-1.46588405-.25175509-.31624412-.03844522-.63992873-.06448902-.95617285-.09673354.45266266-.38817394.91772734-.77510779,1.38279319-1.15584064l-.00000237-.00124038Zm-2.90076426,2.26703535c.38817364-.16122256.8011513-.24555409,1.20792795-.31624412.81333332-.13418557,1.6412555-.15588524,2.46050242-.06448902.5878429.06448902,1.16328143.17486406,1.72508082.34848863l-.23315208.18726607-.37453214-.10293454c-.23315208-.04464593-.46506467-.09673354-.69821676-.13517905-.41077543-.06070432-.8250115-.09508601-1.24017246-.10293454-.76375012-.01441855-1.52604905.07231982-2.26703535.2579561-.50273314.13067111-.99001049.31485561-1.45348204.5493962-.47126568.2579561-.91772734.57543971-1.28481898.96237386-.22622016.22823196-.4255346.4816405-.59404272.75526528-.09673354.14882055-.17486406.29764111-.25175509.45266266-.03753719.07754153-.06985385.15750409-.09673354.23935309l-.05208702.12277705c-.00516494.02191581-.01179409.04346025-.0198425.06448902l-.11037504-.0198425-.13517905-.01240201c.38817364-1.19552594,1.26001497-2.13185629,2.34516587-2.73210002.34228763-.18726607.70441776-.35468964,1.0727489-.45886367l-.00000118.00496151Zm-6.49726393.61388523c.43902117-.63248824,1.13723792-1.0727489,1.8863022-1.23397146.8271948-.16122256,1.67919363-.19346678,2.51879044-.17486436-.86564032.21951058-1.73748165.54319549-2.46050242,1.0789502-.56594483.12955226-1.09433828.38801929-1.54401457.75526528-.14516831.12120698-.28113388.2530277-.40677665.39437464-.0588983.06001006-.11281735.12471257-.16122256.19346707-.0198425.0198425-.04464652.04464593-.05828802.07813112h-.14261955c.03844552-.21951058.09053253-.44522217.16122256-.65853175.05208702-.14882055.11037504-.29764111.19966808-.43282016l.0074405-.00000059Zm1.45348204.09673354c-.23729515.23928035-.45347638.49861373-.64612974.77510779-.07813052.11037563-.16122256.25175509-.29764111.31004312-.14261955.06448902-.32244512-.006201-.46506467-.04464593.37108569-.46297185.85614544-.82153135,1.40759603-1.04050497h.00123949ZM3.81181355,9.56917155c.12897805-.26539659.2976414-.52335269.45266296-.76890678.02604351-.04464652.09053253-.07813052.12277705-.10293454.08433182-.05828802.16122227-.11657604.23935338-.18106507.5097106-.36833114,1.02686288-.73666227,1.55021558-1.0789499.2777986-.18106507.5493962-.35468964.83339581-.50971119.29764111-.16742357.60768481-.29764111.93012935-.40677665.57867031-.17905976,1.17035173-.31298572,1.76972616-.40057565.28399902-.03844552.59404213-.09673354.87804174-.02604351-.5493962.31004312-1.09135191.62008623-1.64074811.92392834-.56179821.31624412-1.13723792.60768422-1.71143814.91028684-.5493962.29764111-1.09135191.62008623-1.62090561.95617285-.55559721.34228763-1.1049937.69077626-1.65314982,1.04050438-.13517876.08433153-.26539689.17486406-.40057565.2579561.07813082-.20710857.14882055-.42041815.25175509-.61388523h-.00123979Zm1.66679162,5.05122238c-.04464593.09053253-.21951058.07069003-.31004312.07069003-.15502156,0-.30384211,0-.45886367.006201-.42560113.02528184-.8463806.10360514-1.25257417.23315208-.7875095.23935309-1.52417192.62008623-2.26083434.99461837-.16122241.09053253-.33608677.22571159-.52335277.2715976-.10319415.02663487-.21197917-.01459359-.27159775-.10293454-.05594793-.10200492-.09094479-.2141635-.10293432-.32988562-.04154617-.19982775-.06109201-.40360223-.05828809-.60768422,0-.5493962.12897794-1.09135191.35468934-1.58866109.16122241-.34848863.36833121-.66473275.61388537-.94997185.25175502-.29020061.54319557-.58164071.89168405-.74286328.58784172-.2715976,1.28481869-.35468964,1.92474772-.38817364.12277705-.01240201.23935338-.01240201.36213043-.01240201.16122256,0,.35468934-.02604351.5097109.03224451.12277734.04464652.19966778.17486406.2517548.28399961.07069003.17486406.12277705.37453214.16122256.55559721.10293454.43282016.20710857.86564032.23935309,1.31086249.0198425.19346707.03224451.39437464.006201.58784172-.01240201.12277705-.0198425.2579561-.07813112.37453214l.00124008.00123949Zm4.67669024-3.26785472c-.32191467.20096789-.6640036.36764871-1.02066188.49730919-.35418402.1315481-.71942294.2311592-1.09135191.29764111-.16122256.0198425-.32244512.04464652-.48490718.03224451-.16742357,0-.31624412-.05828802-.48490718-.11037504-.32637412-.09433498-.64220606-.22191387-.94253135-.38073314-.11292439-.06073625-.21015763-.14693057-.28399961-.25175509-.04557969-.08727414-.05918097-.18774744-.03844552-.28399961.0198425-.38073314.15502156-.75526528.33608662-1.09135191.31004312-.56799921.79495029-1.01446088,1.38899302-1.28481898,1.45348204-.65233074,3.08058865-.04464652,4.31456011.81355331l.13517905.09673354c-.2579561.2777986-.51715169.5357547-.78130879.79495029-.32988562.31004312-.67217325.62628724-1.05290639.87184133l.006201-.00123949Zm3.57789784-3.18476268c-.78077184-.34143075-1.53056113-.74972779-2.24099184-1.22032996.74286328.31004312,1.54401457.49730919,2.33772537.61388523.42661916.05828802.86564032.11657604,1.29225948.12897805.46506467.0198425.93633035-.03224451,1.38899302-.12277705.90408584-.16742357,1.76972616-.50351019,2.59071996-.91028684.82099498-.40677665,1.59486092-.88548283,2.33772537-1.42123753.35468845-.25175509.71061876-.51715169,1.04670539-.8011513.03224333-.02604351.28399961-.2715976.30384329-.2579561l.06448902.05208702.89168383.69077626c.5431952.42041815,1.0851509.83959681,1.63454829,1.26001497-1.50363058.54005862-3.02220601,1.03756828-4.55391438,1.49192756-.8594405.2579561-1.71143814.49730919-2.58327947.69821735-.68457526.16122256-1.38279201.31004252-2.07976928.34228704-.83959681.03844552-1.66059061-.21951058-2.42825791-.54319579l-.00248017-.0012389Zm14.63031445,6.51710643c.12897805.03224451.24555409.07813052.35468845.11037504l.16122138.05828802c.02604351.006201.04464534.02604351.07068885.03224451l.03224333.09673354c.07813052.24555409.14882174.47746668.23315208.71681977-.24555409-.21330958-.497308-.42041815-.74286209-.62628724l-.14882174-.12277705c-.03844552-.02604351-.07813052-.03844552-.05208702-.07813052l.09673235-.18726607h-.0049556Zm-1.10499459,2.38361139l.0582892-.10293454.04464534-.07069003c.01984369-.03224451.01240201-.03844552.05208702-.0198425.21331076.08433153.42661916.18106507.63248824.2777986.40057565.18106507.7875098.38073314,1.16328143.60024373.18106507.11037504.36213013.22571159.53575352.34228763l.24555409.17486406.12277823.09053253c.05208702.04464652.07068885.10293454.09673235.16742238.16742357.46506467.36213013.93632917.55559721,1.39519402.12897805.31624294.2715976.62628605.41297766.93632917-.49014545-.60819752-1.01871039-1.18440245-1.58245891-1.72508082-.56908259-.56757817-1.16417557-1.10845996-1.78336766-1.62090561l-.53575352-.43902117-.0186042-.00619746Zm6.21450381,10.62579745l-.1996669.14882174.01240201.02604351.10293454.15502156.45266266.69077508,1.49192637,2.31912354c.51715169.79495148,1.0268617,1.59486092,1.54401576,2.38981239l.50971001.79495148.13517787.21951058c.02113995.02331852.03869389.04964825.05208702.07813052-.43282134.63248824-.86564032,1.27241579-1.29846167,1.90490403-.04464534.0582892-.08433271.12277823-.12277823.18106507-.39437583-.61388641-.7875098-1.22777045-1.18188326-1.84785668-.65853175-1.04670539-1.31086131-2.11201261-1.95699105-3.16492018-.7160782-1.16891354-1.41396616-2.3488737-2.09341078-3.53945232-.63248824-1.11739423-1.24017246-2.25463452-1.74988247-3.43651778-.4903607-1.15152755-.93632207-2.32145824-1.33690482-3.50720899.8011513.32244512,1.62090442.60768422,2.44810159.86564032.23935427.07068885.47746668.14882174.71681859.20710857l.10293454.03224333c.01240201,0,.02604351-.06448902.03224333-.08433271.03224333-.10293454.05208702-.21331076.07813052-.32244512.04464534-.20710857.08433271-.42041934.11657604-.62628605.34228645.70441894.72302077,1.39519402,1.16328143,2.04132376.35468845.52335388.73666227,1.0268617,1.13723792,1.52417207.8640815,1.08055958,1.76924361,2.12762215,2.71349701,3.13887667.76890797.81355331,1.54401576,1.6283461,2.33152319,2.42205572l.63992992.63992992c.01240201.01240201.06448902.05208702.06448902.07068885l-.05208702.08433271-.24555409.45886485-.97477468,1.76352634c-.29764111-.36213013-.59404272-.71681859-.89168383-1.0851509l-1.86025869-2.25463452c-.52335388-.63992992-1.05290757-1.27861798-1.57625909-1.9185479l-.31004312-.36833232.00496033-.00123713Z'/>
 </svg>"""
 
-ingress: {
-	gerrit: {
-		auth: enabled: false
-		network: input.network
-		subdomain: input.subdomain
-		service: {
-			name: "gerrit-gerrit-service"
-			port: number: _httpPort // TODO(gio): make optional
+out: {
+	ingress: {
+		gerrit: {
+			auth: enabled: false
+			network: input.network
+			subdomain: input.subdomain
+			service: {
+				name: "gerrit-gerrit-service"
+				port: number: _httpPort // TODO(gio): make optional
+			}
 		}
 	}
-}
 
-// TODO(gio): configure busybox
-_images: {
-	gerrit: #Image & {
-		repository: "k8sgerrit"
-		name: "gerrit"
-		tag: _version
-		pullPolicy: "Always"
+	// TODO(gio): configure busybox
+	images: {
+		gerrit: {
+			repository: "k8sgerrit"
+			name: "gerrit"
+			tag: _version
+			pullPolicy: "Always"
+		}
+		gerritInit: {
+			repository: "k8sgerrit"
+			name: "gerrit-init"
+			tag: _version
+			pullPolicy: "Always"
+		}
+		gitGC: {
+			repository: "k8sgerrit"
+			name: "git-gc"
+			tag: _version
+			pullPolicy: "Always"
+		}
 	}
-	gerritInit: #Image & {
-		repository: "k8sgerrit"
-		name: "gerrit-init"
-		tag: _version
-		pullPolicy: "Always"
-	}
-	gitGC: #Image & {
-		repository: "k8sgerrit"
-		name: "git-gc"
-		tag: _version
-		pullPolicy: "Always"
-	}
-}
-images: _images
+	_images: images
 
-charts: {
-	ingress: {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/ingress"
+	charts: {
+		ingress: {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/ingress"
+		}
+		gerrit: {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/gerrit"
+		}
+		oauth2Client: {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/oauth2-client"
+		}
+		resourceRenderer: {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/resource-renderer"
+		}
 	}
-	gerrit: {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/gerrit"
-	}
-	oauth2Client: {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/oauth2-client"
-	}
-	resourceRenderer: {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/resource-renderer"
-	}
-}
 
-volumes: {
-	git: {
-		accessMode: "ReadWriteMany"
-		size: "50Gi"
+	volumes: {
+		git: {
+			accessMode: "ReadWriteMany"
+			size: "50Gi"
+		}
+		logs: {
+			accessMode: "ReadWriteMany"
+			size: "5Gi"
+		}
 	}
-	logs: {
-		accessMode: "ReadWriteMany"
-		size: "5Gi"
+
+	helm: {
+		"oauth2-client": {
+			chart: charts.oauth2Client
+			info: "Creating OAuth2 client"
+			values: {
+				name: "\(release.namespace)-gerrit"
+				secretName: _oauth2ClientCredentials
+				grantTypes: ["authorization_code"]
+				scope: "openid profile email"
+				hydraAdmin: "http://hydra-admin.\(global.id)-core-auth.svc.cluster.local"
+				redirectUris: ["https://\(_domain)/oauth"]
+			}
+		}
+		"config-renderer": {
+			chart: charts.resourceRenderer
+			info: "Generating Gerrit configuration"
+			values: {
+				name: "config-renderer"
+				secretName: _oauth2ClientCredentials
+				resourceTemplate: """
+				apiVersion: v1
+				kind: ConfigMap
+				metadata:
+				  name: \(_gerritConfigMapName)
+				  namespace: \(release.namespace)
+				data:
+				  replication.config: |
+					[gerrit]
+					  autoReload = false
+					  replicateOnStartup = true
+					  defaultForceUpdate = true
+				  gerrit.config: |
+					[gerrit]
+					  basePath = git # FIXED
+					  serverId = gerrit-1
+					  # The canonical web URL has to be set to the Ingress host, if an Ingress
+					  # is used. If a LoadBalancer-service is used, this should be set to the
+					  # LoadBalancer's external IP. This can only be done manually after installing
+					  # the chart, when you know the external IP the LoadBalancer got from the
+					  # cluster.
+					  canonicalWebUrl = https://\(_domain)
+					  disableReverseDnsLookup = true
+					[index]
+					  type = LUCENE
+					[auth]
+					  type = OAUTH
+					  gitBasicAuthPolicy = HTTP
+					  userNameToLowerCase = true
+					  userNameCaseInsensitive = true
+					[plugin "gerrit-oauth-provider-pcloud-oauth"]
+					  root-url = https://hydra.\(networks.public.domain)
+					  client-id = "{{ .client_id }}"
+					  client-secret = "{{ .client_secret }}"
+					  link-to-existing-openid-accounts = true
+					[download]
+					  command = branch
+					  command = checkout
+					  command = cherry_pick
+					  command = pull
+					  command = format_patch
+					  command = reset
+					  scheme = http
+					  scheme = anon_http
+					[httpd]
+					  # If using an ingress use proxy-http or proxy-https
+					  listenUrl = proxy-http://*:8080/
+					  requestLog = true
+					  gracefulStopTimeout = 1m
+					[sshd]
+					  listenAddress = 0.0.0.0:29418
+					  advertisedAddress = \(_domain):\(input.sshPort)
+					[transfer]
+					  timeout = 120 s
+					[user]
+					  name = Gerrit Code Review
+					  email = gerrit@\(networks.public.domain)
+					  anonymousCoward = Unnamed User
+					[cache]
+					  directory = cache
+					[container]
+					  user = gerrit # FIXED
+					  javaHome = /usr/lib/jvm/java-11-openjdk # FIXED
+					  javaOptions = -Djavax.net.ssl.trustStore=/var/gerrit/etc/keystore # FIXED
+					  javaOptions = -Xms200m
+					  # Has to be lower than 'gerrit.resources.limits.memory'. Also
+					  # consider memories used by other applications in the container.
+					  javaOptions = -Xmx4g
+				"""
+			}
+		}
+		gerrit: {
+			chart: charts.gerrit
+			info: "Installing Gerrit server"
+			values: {
+				images: {
+					busybox: {
+						registry: _dockerIO
+						tag: "latest"
+					}
+					registry: {
+						name: _dockerIO
+						ImagePullSecret: create: false
+						imagePullPolicy: "Always"
+					}
+					version: _version
+				}
+				storageClasses: {
+					default: {
+						name: _longhorn
+						create: false
+					}
+					shared: {
+						name: _longhorn
+						create: false
+					}
+				}
+				persistence: {
+					enabled: true
+					size: "10Gi"
+				}
+				nfsWorkaround: {
+					enabled: false
+					chownOnStartup: false
+					idDomain: _domain
+				}
+				networkPolicies: enabled: false
+				gitRepositoryStorage: {
+					externalPVC: {
+						use: true
+						name: volumes.git.name
+					}
+				}
+				logStorage: {
+					enabled: true
+					externalPVC: {
+						use: true
+						name: volumes.logs.name
+					}
+				}
+				ingress: enabled: false
+				gitGC: {
+					image: _images.gitGC.imageName
+					logging: persistence: enabled: false
+				}
+				gerrit: {
+					images: {
+						gerritInit: _images.gerritInit.imageName
+						gerrit: _images.gerrit.imageName
+					}
+					service: {
+						type: "LoadBalancer"
+						externalTrafficPolicy: ""
+						additionalAnnotations: {
+							"metallb.universe.tf/address-pool": global.id
+						}
+						http: port: _httpPort
+						ssh: {
+							enabled: true
+							port: _sshPort
+						}
+					}
+					pluginManagement: {
+						plugins: [{
+							name: "gitiles"
+						}, {
+							name: "download-commands"
+						}, {
+							name: "singleusergroup"
+						}, {
+							name: "codemirror-editor"
+						}, {
+							name: "reviewnotes"
+						}, {
+							name: "oauth"
+							url: "https://drive.google.com/uc?export=download&id=1rSUpZCAVvHZTmRgUl4enrsAM73gndjeP"
+							sha1: "cbdc5228a18b051a6e048a8e783e556394cc5db1"
+						}, {
+							name: "webhooks"
+						}]
+						libs: []
+						cache: enabled: false
+					}
+					etc: {
+						secret: {
+							ssh_host_ecdsa_key: input.key.private
+							"ssh_host_ecdsa_key.pub": input.key.public
+						}
+						existingConfigMapName: _gerritConfigMapName
+					}
+				}
+			}
+		}
 	}
 }
 
@@ -124,197 +320,3 @@
 
 _oauth2ClientCredentials: "gerrit-oauth2-credentials"
 _gerritConfigMapName: "gerrit-config"
-
-helm: {
-	"oauth2-client": {
-		chart: charts.oauth2Client
-		info: "Creating OAuth2 client"
-		values: {
-			name: "\(release.namespace)-gerrit"
-			secretName: _oauth2ClientCredentials
-			grantTypes: ["authorization_code"]
-			scope: "openid profile email"
-			hydraAdmin: "http://hydra-admin.\(global.id)-core-auth.svc.cluster.local"
-			redirectUris: ["https://\(_domain)/oauth"]
-		}
-	}
-	"config-renderer": {
-		chart: charts.resourceRenderer
-		info: "Generating Gerrit configuration"
-		values: {
-			name: "config-renderer"
-			secretName: _oauth2ClientCredentials
-			resourceTemplate: """
-apiVersion: v1
-kind: ConfigMap
-metadata:
-  name: \(_gerritConfigMapName)
-  namespace: \(release.namespace)
-data:
-  replication.config: |
-    [gerrit]
-      autoReload = false
-      replicateOnStartup = true
-      defaultForceUpdate = true
-  gerrit.config: |
-    [gerrit]
-      basePath = git # FIXED
-      serverId = gerrit-1
-      # The canonical web URL has to be set to the Ingress host, if an Ingress
-      # is used. If a LoadBalancer-service is used, this should be set to the
-      # LoadBalancer's external IP. This can only be done manually after installing
-      # the chart, when you know the external IP the LoadBalancer got from the
-      # cluster.
-      canonicalWebUrl = https://\(_domain)
-      disableReverseDnsLookup = true
-    [index]
-      type = LUCENE
-    [auth]
-      type = OAUTH
-      gitBasicAuthPolicy = HTTP
-      userNameToLowerCase = true
-      userNameCaseInsensitive = true
-    [plugin "gerrit-oauth-provider-pcloud-oauth"]
-      root-url = https://hydra.\(networks.public.domain)
-      client-id = "{{ .client_id }}"
-      client-secret = "{{ .client_secret }}"
-      link-to-existing-openid-accounts = true
-    [download]
-      command = branch
-      command = checkout
-      command = cherry_pick
-      command = pull
-      command = format_patch
-      command = reset
-      scheme = http
-      scheme = anon_http
-    [httpd]
-      # If using an ingress use proxy-http or proxy-https
-      listenUrl = proxy-http://*:8080/
-      requestLog = true
-      gracefulStopTimeout = 1m
-    [sshd]
-      listenAddress = 0.0.0.0:29418
-      advertisedAddress = \(_domain):\(input.sshPort)
-    [transfer]
-      timeout = 120 s
-    [user]
-      name = Gerrit Code Review
-      email = gerrit@\(networks.public.domain)
-      anonymousCoward = Unnamed User
-    [cache]
-      directory = cache
-    [container]
-      user = gerrit # FIXED
-      javaHome = /usr/lib/jvm/java-11-openjdk # FIXED
-      javaOptions = -Djavax.net.ssl.trustStore=/var/gerrit/etc/keystore # FIXED
-      javaOptions = -Xms200m
-      # Has to be lower than 'gerrit.resources.limits.memory'. Also
-      # consider memories used by other applications in the container.
-      javaOptions = -Xmx4g
-"""
-		}
-	}
-	gerrit: {
-		chart: charts.gerrit
-		info: "Installing Gerrit server"
-		values: {
-			images: {
-				busybox: {
-					registry: _dockerIO
-					tag: "latest"
-				}
-				registry: {
-					name: _dockerIO
-					ImagePullSecret: create: false
-					imagePullPolicy: "Always"
-				}
-				version: _version
-			}
-			storageClasses: {
-				default: {
-					name: _longhorn
-					create: false
-				}
-				shared: {
-					name: _longhorn
-					create: false
-				}
-			}
-			persistence: {
-				enabled: true
-				size: "10Gi"
-			}
-			nfsWorkaround: {
-				enabled: false
-				chownOnStartup: false
-				idDomain: _domain
-			}
-			networkPolicies: enabled: false
-			gitRepositoryStorage: {
-				externalPVC: {
-					use: true
-					name: volumes.git.name
-				}
-			}
-			logStorage: {
-				enabled: true
-				externalPVC: {
-					use: true
-					name: volumes.logs.name
-				}
-			}
-			ingress: enabled: false
-			gitGC: {
-				image: _images.gitGC.imageName
-				logging: persistence: enabled: false
-			}
-			gerrit: {
-				images: {
-					gerritInit: _images.gerritInit.imageName
-					gerrit: _images.gerrit.imageName
-				}
-				service: {
-					type: "LoadBalancer"
-					externalTrafficPolicy: ""
-					additionalAnnotations: {
-						"metallb.universe.tf/address-pool": global.id
-					}
-					http: port: _httpPort
-					ssh: {
-						enabled: true
-						port: _sshPort
-					}
-				}
-				pluginManagement: {
-					plugins: [{
-						name: "gitiles"
-					}, {
-						name: "download-commands"
-					}, {
-						name: "singleusergroup"
-					}, {
-						name: "codemirror-editor"
-					}, {
-						name: "reviewnotes"
-					}, {
-						name: "oauth"
-						url: "https://drive.google.com/uc?export=download&id=1rSUpZCAVvHZTmRgUl4enrsAM73gndjeP"
-						sha1: "cbdc5228a18b051a6e048a8e783e556394cc5db1"
-					}, {
-						name: "webhooks"
-					}]
-					libs: []
-					cache: enabled: false
-				}
-				etc: {
-					secret: {
-						ssh_host_ecdsa_key: input.key.private
-						"ssh_host_ecdsa_key.pub": input.key.public
-					}
-					existingConfigMapName: _gerritConfigMapName
-				}
-			}
-		}
-	}
-}
diff --git a/core/installer/values-tmpl/headscale-controller.cue b/core/installer/values-tmpl/headscale-controller.cue
index a2e3f22..7d61ac2 100644
--- a/core/installer/values-tmpl/headscale-controller.cue
+++ b/core/installer/values-tmpl/headscale-controller.cue
@@ -3,46 +3,48 @@
 name: "headscale-controller"
 namespace: "core-headscale"
 
-images: {
-	headscaleController: {
-		repository: "giolekva"
-		name: "headscale-controller"
-		tag: "latest"
-		pullPolicy: "Always"
+out: {
+	images: {
+		headscaleController: {
+			repository: "giolekva"
+			name: "headscale-controller"
+			tag: "latest"
+			pullPolicy: "Always"
+		}
+		kubeRBACProxy: {
+			registry: "gcr.io"
+			repository: "kubebuilder"
+			name: "kube-rbac-proxy"
+			tag: "v0.13.0"
+			pullPolicy: "IfNotPresent"
+		}
 	}
-	kubeRBACProxy: {
-		registry: "gcr.io"
-		repository: "kubebuilder"
-		name: "kube-rbac-proxy"
-		tag: "v0.13.0"
-		pullPolicy: "IfNotPresent"
-	}
-}
 
-charts: {
-	headscaleController: {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/headscale-controller"
+	charts: {
+		headscaleController: {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/headscale-controller"
+		}
 	}
-}
 
-helm: {
-	"headscale-controller": {
-		chart: charts.headscaleController
-		values: {
-			installCRDs: true
-			image: {
-				repository: images.headscaleController.fullName
-				tag: images.headscaleController.tag
-				pullPolicy: images.headscaleController.pullPolicy
-			}
-			kubeRBACProxy: {
+	helm: {
+		"headscale-controller": {
+			chart: charts.headscaleController
+			values: {
+				installCRDs: true
 				image: {
-					repository: images.kubeRBACProxy.fullName
-					tag: images.kubeRBACProxy.tag
-					pullPolicy: images.kubeRBACProxy.pullPolicy
+					repository: images.headscaleController.fullName
+					tag: images.headscaleController.tag
+					pullPolicy: images.headscaleController.pullPolicy
+				}
+				kubeRBACProxy: {
+					image: {
+						repository: images.kubeRBACProxy.fullName
+						tag: images.kubeRBACProxy.tag
+						pullPolicy: images.kubeRBACProxy.pullPolicy
+					}
 				}
 			}
 		}
diff --git a/core/installer/values-tmpl/headscale-user.cue b/core/installer/values-tmpl/headscale-user.cue
new file mode 100644
index 0000000..036d0a3
--- /dev/null
+++ b/core/installer/values-tmpl/headscale-user.cue
@@ -0,0 +1,34 @@
+input: {
+	username: string
+	preAuthKey: {
+		enabled: bool | *false
+	}
+}
+
+name: "headscale-user"
+namespace: "app-headscale"
+
+out: {
+	charts: {
+		headscaleUser: {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/headscale-user"
+		}
+	}
+
+	helm: {
+		"headscale-user-\(input.username)": {
+			chart: charts.headscaleUser
+			values: {
+				username: input.username
+				headscaleApiAddress: "http://headscale-api.\(global.namespacePrefix)app-headscale.svc.cluster.local"
+				preAuthKey: {
+					enabled: input.preAuthKey.enabled
+					secretName: "\(input.username)-headscale-preauthkey"
+				}
+			}
+		}
+	}
+}
diff --git a/core/installer/values-tmpl/headscale.cue b/core/installer/values-tmpl/headscale.cue
index e13c1f0..fdbcb5a 100644
--- a/core/installer/values-tmpl/headscale.cue
+++ b/core/installer/values-tmpl/headscale.cue
@@ -8,89 +8,92 @@
 namespace: "app-headscale"
 icon: "<svg xmlns='http://www.w3.org/2000/svg' width='50' height='50' viewBox='0 0 48 48'><circle cx='24' cy='24' r='4.5' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round'/><circle cx='38' cy='24' r='4.5' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round'/><circle cx='38' cy='10' r='4.5' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round'/><circle cx='24' cy='10' r='4.5' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round'/><circle cx='10' cy='10' r='4.5' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round'/><circle cx='10' cy='24' r='4.5' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round'/><circle cx='10' cy='38' r='4.5' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round'/><circle cx='24' cy='38' r='4.5' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round'/><circle cx='38' cy='38' r='4.5' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round'/><circle cx='24' cy='38' r='2' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round'/><circle cx='24' cy='24' r='2' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round'/><circle cx='10' cy='24' r='2' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round'/><circle cx='38' cy='24' r='2' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round'/></svg>"
 
-images: {
-	headscale: {
-		repository: "headscale"
-		name: "headscale"
-		tag: "0.22.3"
-		pullPolicy: "IfNotPresent"
-	}
-	api: {
-		repository: "giolekva"
-		name: "headscale-api"
-		tag: "latest"
-		pullPolicy: "Always"
-	}
-}
-
-charts: {
-	oauth2Client: {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/oauth2-client"
-	}
-	headscale: {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/headscale"
-	}
-}
-
 _domain: "\(input.subdomain).\(input.network.domain)"
 _oauth2ClientSecretName: "oauth2-client"
 
-helm: {
-	"oauth2-client": {
-		chart: charts.oauth2Client
-		// TODO(gio): remove once hydra maester is installed as part of dodo itself
-		dependsOn: [{
-			name: "auth"
-			namespace: "\(global.namespacePrefix)core-auth"
-		}]
-		values: {
-			name: "\(release.namespace)-headscale"
-			secretName: _oauth2ClientSecretName
-			grantTypes: ["authorization_code"]
-			responseTypes: ["code"]
-			scope: "openid profile email"
-			redirectUris: ["https://\(_domain)/oidc/callback"]
-			hydraAdmin: "http://hydra-admin.\(global.namespacePrefix)core-auth.svc.cluster.local"
+out: {
+	images: {
+		headscale: {
+			repository: "headscale"
+			name: "headscale"
+			tag: "0.22.3"
+			pullPolicy: "IfNotPresent"
+		}
+		api: {
+			repository: "giolekva"
+			name: "headscale-api"
+			tag: "latest"
+			pullPolicy: "Always"
 		}
 	}
-	headscale: {
-		chart: charts.headscale
-		dependsOn: [{
-			name: "auth"
-			namespace: "\(global.namespacePrefix)core-auth"
-		}]
-		values: {
-			image: {
-				repository: images.headscale.fullName
-				tag: images.headscale.tag
-				pullPolicy: images.headscale.pullPolicy
-			}
-			storage: size: "5Gi"
-			ingressClassName: input.network.ingressClass
-			certificateIssuer: input.network.certificateIssuer
-			domain: _domain
-			publicBaseDomain: input.network.domain
-			ipAddressPool: "\(global.id)-headscale"
-			oauth2: {
+
+	charts: {
+		oauth2Client: {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/oauth2-client"
+		}
+		headscale: {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/headscale"
+		}
+	}
+
+	helm: {
+		"oauth2-client": {
+			chart: charts.oauth2Client
+			// TODO(gio): remove once hydra maester is installed as part of dodo itself
+			dependsOn: [{
+				name: "auth"
+				namespace: "\(global.namespacePrefix)core-auth"
+			}]
+			values: {
+				name: "\(release.namespace)-headscale"
 				secretName: _oauth2ClientSecretName
-				issuer: "https://hydra.\(input.network.domain)"
+				grantTypes: ["authorization_code"]
+				responseTypes: ["code"]
+				scope: "openid profile email"
+				redirectUris: ["https://\(_domain)/oidc/callback"]
+				hydraAdmin: "http://hydra-admin.\(global.namespacePrefix)core-auth.svc.cluster.local"
 			}
-			api: {
-				port: 8585
-				ipSubnet: input.ipSubnet
+		}
+		headscale: {
+			chart: charts.headscale
+			dependsOn: [{
+				name: "auth"
+				namespace: "\(global.namespacePrefix)core-auth"
+			}]
+			values: {
 				image: {
-					repository: images.api.fullName
-					tag: images.api.tag
-					pullPolicy: images.api.pullPolicy
+					repository: images.headscale.fullName
+					tag: images.headscale.tag
+					pullPolicy: images.headscale.pullPolicy
 				}
+				storage: size: "5Gi"
+				ingressClassName: input.network.ingressClass
+				certificateIssuer: input.network.certificateIssuer
+				domain: _domain
+				publicBaseDomain: input.network.domain
+				ipAddressPool: "\(global.id)-headscale"
+				oauth2: {
+					secretName: _oauth2ClientSecretName
+					issuer: "https://hydra.\(input.network.domain)"
+				}
+				api: {
+					port: 8585
+					ipSubnet: input.ipSubnet
+					self: "http://headscale-api.\(release.namespace).svc.cluster/sync-users"
+					image: {
+						repository: images.api.fullName
+						tag: images.api.tag
+						pullPolicy: images.api.pullPolicy
+					}
+				}
+				ui: enabled: false
 			}
-			ui: enabled: false
 		}
 	}
 }
diff --git a/core/installer/values-tmpl/hydra-maester.cue b/core/installer/values-tmpl/hydra-maester.cue
index 406dab3..22ba9b5 100644
--- a/core/installer/values-tmpl/hydra-maester.cue
+++ b/core/installer/values-tmpl/hydra-maester.cue
@@ -3,37 +3,39 @@
 name: "hydra-maester"
 namespace: "auth"
 
-images: {
-	hydraMaester: {
-		repository: "giolekva"
-		name: "ory-hydra-maester"
-		tag: "latest"
-		pullPolicy: "Always"
+out: {
+	images: {
+		hydraMaester: {
+			repository: "giolekva"
+			name: "ory-hydra-maester"
+			tag: "latest"
+			pullPolicy: "Always"
+		}
 	}
-}
 
-charts: {
-	hydraMaester: {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/hydra-maester"
+	charts: {
+		hydraMaester: {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/hydra-maester"
+		}
 	}
-}
 
-helm: {
-	"hydra-maester": {
-		chart: charts.hydraMaester
-		values: {
-			adminService: {
-				name: "foo.bar.svc.cluster.local"
-				port: 80
-				scheme: "http"
-			}
-			image: {
-				repository: images.hydraMaester.fullName
-				tag: images.hydraMaester.tag
-				pullPolicy: images.hydraMaester.pullPolicy
+	helm: {
+		"hydra-maester": {
+			chart: charts.hydraMaester
+			values: {
+				adminService: {
+					name: "foo.bar.svc.cluster.local"
+					port: 80
+					scheme: "http"
+				}
+				image: {
+					repository: images.hydraMaester.fullName
+					tag: images.hydraMaester.tag
+					pullPolicy: images.hydraMaester.pullPolicy
+				}
 			}
 		}
 	}
diff --git a/core/installer/values-tmpl/ingress-public.cue b/core/installer/values-tmpl/ingress-public.cue
index abb2439..fe6098e 100644
--- a/core/installer/values-tmpl/ingress-public.cue
+++ b/core/installer/values-tmpl/ingress-public.cue
@@ -9,116 +9,118 @@
 name: "ingress-public"
 namespace: "ingress-public"
 
-images: {
-	ingressNginx: {
-		registry: "registry.k8s.io"
-		repository: "ingress-nginx"
-		name: "controller"
-		tag: "v1.8.0"
-		pullPolicy: "IfNotPresent"
-	}
-	portAllocator: {
-		repository: "giolekva"
-		name: "port-allocator"
-		tag: "latest"
-		pullPolicy: "Always"
-	}
-}
-
-charts: {
-	ingressNginx: {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/ingress-nginx"
-	}
-	portAllocator: {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/port-allocator"
-	}
-}
-
-helm: {
-	"ingress-public": {
-		chart: charts.ingressNginx
-		values: {
-			fullnameOverride: "\(global.pcloudEnvName)-ingress-public"
-			controller: {
-				kind: "Deployment"
-				replicaCount: 1 // TODO(gio): configurable
-				topologySpreadConstraints: [{
-					labelSelector: {
-						matchLabels: {
-							"app.kubernetes.io/instance": "ingress-public"
-						}
-					}
-					maxSkew: 1
-					topologyKey: "kubernetes.io/hostname"
-					whenUnsatisfiable: "DoNotSchedule"
-				}]
-				hostNetwork: false
-				hostPort: enabled: false
-				updateStrategy: {
-					type: "RollingUpdate"
-					rollingUpdate: {
-						maxSurge: "100%"
-						maxUnavailable: "30%"
-					}
-				}
-				service: {
-					enabled: true
-					type: "NodePort"
-					nodePorts: {
-						http: 80
-						https: 443
-						tcp: {
-							"53": 53
-						}
-						udp: {
-							"53": 53
-						}
-					}
-				}
-				ingressClassByName: true
-				ingressClassResource: {
-					name: networks.public.ingressClass
-					enabled: true
-					default: false
-					controllerValue: "k8s.io/\(networks.public.ingressClass)"
-				}
-				config: {
-					"proxy-body-size": "200M" // TODO(giolekva): configurable
-					"server-snippet": """
-					more_clear_headers "X-Frame-Options";
-					"""
-				}
-				image: {
-					registry: images.ingressNginx.registry
-					image: images.ingressNginx.imageName
-					tag: images.ingressNginx.tag
-					pullPolicy: images.ingressNginx.pullPolicy
-				}
-			}
-			tcp: {
-				"53": "\(global.pcloudEnvName)-dns-gateway/coredns:53"
-			}
-			udp: {
-				"53": "\(global.pcloudEnvName)-dns-gateway/coredns:53"
-			}
+out: {
+	images: {
+		ingressNginx: {
+			registry: "registry.k8s.io"
+			repository: "ingress-nginx"
+			name: "controller"
+			tag: "v1.8.0"
+			pullPolicy: "IfNotPresent"
+		}
+		portAllocator: {
+			repository: "giolekva"
+			name: "port-allocator"
+			tag: "latest"
+			pullPolicy: "Always"
 		}
 	}
-	"port-allocator": {
-		chart: charts.portAllocator
-		values: {
-			repoAddr: release.repoAddr
-			sshPrivateKey: base64.Encode(null, input.sshPrivateKey)
-			ingressNginxPath: "\(release.appDir)/ingress-public.yaml"
-			image: {
-				repository: images.portAllocator.fullName
-				tag: images.portAllocator.tag
-				pullPolicy: images.portAllocator.pullPolicy
+
+	charts: {
+		ingressNginx: {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/ingress-nginx"
+		}
+		portAllocator: {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/port-allocator"
+		}
+	}
+
+	helm: {
+		"ingress-public": {
+			chart: charts.ingressNginx
+			values: {
+				fullnameOverride: "\(global.pcloudEnvName)-ingress-public"
+				controller: {
+					kind: "Deployment"
+					replicaCount: 1 // TODO(gio): configurable
+					topologySpreadConstraints: [{
+						labelSelector: {
+							matchLabels: {
+								"app.kubernetes.io/instance": "ingress-public"
+							}
+						}
+						maxSkew: 1
+						topologyKey: "kubernetes.io/hostname"
+						whenUnsatisfiable: "DoNotSchedule"
+					}]
+					hostNetwork: false
+					hostPort: enabled: false
+					updateStrategy: {
+						type: "RollingUpdate"
+						rollingUpdate: {
+							maxSurge: "100%"
+							maxUnavailable: "30%"
+						}
+					}
+					service: {
+						enabled: true
+						type: "NodePort"
+						nodePorts: {
+							http: 80
+							https: 443
+							tcp: {
+								"53": 53
+							}
+							udp: {
+								"53": 53
+							}
+						}
+					}
+					ingressClassByName: true
+					ingressClassResource: {
+						name: networks.public.ingressClass
+						enabled: true
+						default: false
+						controllerValue: "k8s.io/\(networks.public.ingressClass)"
+					}
+					config: {
+						"proxy-body-size": "200M" // TODO(giolekva): configurable
+						"server-snippet": """
+						more_clear_headers "X-Frame-Options";
+						"""
+					}
+					image: {
+						registry: images.ingressNginx.registry
+						image: images.ingressNginx.imageName
+						tag: images.ingressNginx.tag
+						pullPolicy: images.ingressNginx.pullPolicy
+					}
+				}
+				tcp: {
+					"53": "\(global.pcloudEnvName)-dns-gateway/coredns:53"
+				}
+				udp: {
+					"53": "\(global.pcloudEnvName)-dns-gateway/coredns:53"
+				}
+			}
+		}
+		"port-allocator": {
+			chart: charts.portAllocator
+			values: {
+				repoAddr: release.repoAddr
+				sshPrivateKey: base64.Encode(null, input.sshPrivateKey)
+				ingressNginxPath: "\(release.appDir)/ingress-public.yaml"
+				image: {
+					repository: images.portAllocator.fullName
+					tag: images.portAllocator.tag
+					pullPolicy: images.portAllocator.pullPolicy
+				}
 			}
 		}
 	}
diff --git a/core/installer/values-tmpl/jellyfin.cue b/core/installer/values-tmpl/jellyfin.cue
index 4df8248..3fecee0 100644
--- a/core/installer/values-tmpl/jellyfin.cue
+++ b/core/installer/values-tmpl/jellyfin.cue
@@ -13,37 +13,39 @@
 
 readme: "jellyfin application will be installed on \(input.network.name) network and be accessible to any user on https://\(_domain)"
 
-images: {
-	jellyfin: {
-		repository: "jellyfin"
-		name: "jellyfin"
-		tag: "10.8.10"
-		pullPolicy: "IfNotPresent"
+out: {
+	images: {
+		jellyfin: {
+			repository: "jellyfin"
+			name: "jellyfin"
+			tag: "10.8.10"
+			pullPolicy: "IfNotPresent"
+		}
 	}
-}
 
-charts: {
-	jellyfin: {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/jellyfin"
+	charts: {
+		jellyfin: {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/jellyfin"
+		}
 	}
-}
 
-helm: {
-	jellyfin: {
-		chart: charts.jellyfin
-		values: {
-			pcloudInstanceId: global.id
-			ingress: {
-				className: input.network.ingressClass
-				domain: _domain
-			}
-			image: {
-				repository: images.jellyfin.fullName
-				tag: images.jellyfin.tag
-				pullPolicy: images.jellyfin.pullPolicy
+	helm: {
+		jellyfin: {
+			chart: charts.jellyfin
+			values: {
+				pcloudInstanceId: global.id
+				ingress: {
+					className: input.network.ingressClass
+					domain: _domain
+				}
+				image: {
+					repository: images.jellyfin.fullName
+					tag: images.jellyfin.tag
+					pullPolicy: images.jellyfin.pullPolicy
+				}
 			}
 		}
 	}
diff --git a/core/installer/values-tmpl/jenkins.cue b/core/installer/values-tmpl/jenkins.cue
index d2f3602..7da855d 100644
--- a/core/installer/values-tmpl/jenkins.cue
+++ b/core/installer/values-tmpl/jenkins.cue
@@ -32,114 +32,116 @@
 
 _jenkinsServiceHTTPPortNumber: 80
 
-ingress: {
-	jenkins: {
-		auth: enabled: false
-		network: input.network
-		subdomain: input.subdomain
-		service: {
+out: {
+	ingress: {
+		jenkins: {
+			auth: enabled: false
+			network: input.network
+			subdomain: input.subdomain
+			service: {
+				name: "jenkins"
+				port: number: _jenkinsServiceHTTPPortNumber
+			}
+		}
+	}
+
+	images: {
+		jenkins: {
+			repository: "jenkins"
 			name: "jenkins"
-			port: number: _jenkinsServiceHTTPPortNumber
+			tag: "2.452-jdk17"
+			pullPolicy: "IfNotPresent"
+		}
+	}
+
+	charts: {
+		jenkins: {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/jenkins"
+		}
+		oauth2Client: {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/oauth2-client"
+		}
+	}
+
+	volumes: jenkins: size: "10Gi"
+
+	helm: {
+		"oauth2-client": {
+			chart: charts.oauth2Client
+			info: "Creating OAuth2 client"
+			values: {
+				name: "\(release.namespace)-jenkins"
+				secretName: _oauth2ClientCredentials
+				grantTypes: ["authorization_code"]
+				scope: "openid profile email offline offline_access"
+				hydraAdmin: "http://hydra-admin.\(global.id)-core-auth.svc.cluster.local"
+				redirectUris: ["https://\(_domain)/securityRealm/finishLogin"]
+				tokenEndpointAuthMethod: "client_secret_post"
+			}
+		}
+		jenkins: {
+			chart: charts.jenkins
+			info: "Installing Jenkins server"
+			values: {
+				fullnameOverride: "jenkins"
+				controller: {
+					image: {
+						repository: images.jenkins.imageName
+						tag: images.jenkins.tag
+						pullPolicy: images.jenkins.pullPolicy
+					}
+					jenkinsUrlProtocol: "https://"
+					jenkinsUrl: _domain
+					sidecars: configAutoReload: enabled: false
+					ingress: enabled: false
+					servicePort: _jenkinsServiceHTTPPortNumber
+					installPlugins: [
+						"kubernetes:4203.v1dd44f5b_1cf9",
+						"workflow-aggregator:596.v8c21c963d92d",
+						"git:5.2.1",
+						"configuration-as-code:1775.v810dc950b_514",
+						"gerrit-code-review:0.4.9",
+						"oic-auth:4.239.v325750a_96f3b_",
+					]
+					additionalExistingSecrets: [{
+						name: _oauth2ClientCredentials
+						keyName: _oauth2ClientId
+					}, {
+						name: _oauth2ClientCredentials
+						keyName: _oauth2ClientSecret
+					}]
+					JCasC: {
+						defaultConfig: true
+						overwriteConfiguration: false
+						securityRealm: """
+	oic:
+	  clientId: "${\(_oauth2ClientCredentials)-\(_oauth2ClientId)}"
+	  clientSecret: "${\(_oauth2ClientCredentials)-\(_oauth2ClientSecret)}"
+	  wellKnownOpenIDConfigurationUrl: "https://hydra.\(networks.public.domain)/.well-known/openid-configuration"
+	  userNameField: "email"
+	"""
+					}
+				}
+				agent: {
+					runAsUser: 1000
+					runAsGroup: 1000
+					jenkinsUrl: "http://jenkins.\(release.namespace).svc.cluster.local"
+				}
+				persistence: {
+					enabled: true
+					existingClaim: volumes.jenkins.name
+				}
+			}
 		}
 	}
 }
 
-images: {
-    jenkins: {
-        repository: "jenkins"
-        name: "jenkins"
-        tag: "2.452-jdk17"
-        pullPolicy: "IfNotPresent"
-    }
-}
-
-charts: {
-    jenkins: {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/jenkins"
-    }
-	oauth2Client: {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/oauth2-client"
-	}
-}
-
-volumes: jenkins: size: "10Gi"
-
 _oauth2ClientCredentials:  "oauth2-credentials"
 _oauth2ClientId: "client_id"
 _oauth2ClientSecret: "client_secret"
-
-helm: {
-	"oauth2-client": {
-		chart: charts.oauth2Client
-		info: "Creating OAuth2 client"
-		values: {
-			name: "\(release.namespace)-jenkins"
-			secretName: _oauth2ClientCredentials
-			grantTypes: ["authorization_code"]
-			scope: "openid profile email offline offline_access"
-			hydraAdmin: "http://hydra-admin.\(global.id)-core-auth.svc.cluster.local"
-			redirectUris: ["https://\(_domain)/securityRealm/finishLogin"]
-			tokenEndpointAuthMethod: "client_secret_post"
-		}
-	}
-    jenkins: {
-        chart: charts.jenkins
-		info: "Installing Jenkins server"
-        values: {
-			fullnameOverride: "jenkins"
-			controller: {
-				image: {
-					repository: images.jenkins.imageName
-					tag: images.jenkins.tag
-					pullPolicy: images.jenkins.pullPolicy
-				}
-				jenkinsUrlProtocol: "https://"
-				jenkinsUrl: _domain
-				sidecars: configAutoReload: enabled: false
-				ingress: enabled: false
-				servicePort: _jenkinsServiceHTTPPortNumber
-				installPlugins: [
-					"kubernetes:4203.v1dd44f5b_1cf9",
-					"workflow-aggregator:596.v8c21c963d92d",
-					"git:5.2.1",
-					"configuration-as-code:1775.v810dc950b_514",
-					"gerrit-code-review:0.4.9",
-					"oic-auth:4.239.v325750a_96f3b_",
-				]
-				additionalExistingSecrets: [{
-					name: _oauth2ClientCredentials
-					keyName: _oauth2ClientId
-				}, {
-					name: _oauth2ClientCredentials
-					keyName: _oauth2ClientSecret
-				}]
-				JCasC: {
-					defaultConfig: true
-					overwriteConfiguration: false
-					securityRealm: """
-oic:
-  clientId: "${\(_oauth2ClientCredentials)-\(_oauth2ClientId)}"
-  clientSecret: "${\(_oauth2ClientCredentials)-\(_oauth2ClientSecret)}"
-  wellKnownOpenIDConfigurationUrl: "https://hydra.\(networks.public.domain)/.well-known/openid-configuration"
-  userNameField: "email"
-"""
-				}
-			}
-			agent: {
-				runAsUser: 1000
-				runAsGroup: 1000
-				jenkinsUrl: "http://jenkins.\(release.namespace).svc.cluster.local"
-			}
-			persistence: {
-				enabled: true
-				existingClaim: volumes.jenkins.name
-			}
-        }
-    }
-}
diff --git a/core/installer/values-tmpl/launcher.cue b/core/installer/values-tmpl/launcher.cue
index 4574b72..09c0ec3 100644
--- a/core/installer/values-tmpl/launcher.cue
+++ b/core/installer/values-tmpl/launcher.cue
@@ -19,51 +19,53 @@
 
 _httpPortName: "http"
 
-ingress: {
-	launcher: {
-		auth: enabled: true
-		network: input.network
-		subdomain: _subdomain
-		service: {
-			name: "launcher"
-			port: name: _httpPortName
+out: {
+	ingress: {
+		launcher: {
+			auth: enabled: true
+			network: input.network
+			subdomain: _subdomain
+			service: {
+				name: "launcher"
+				port: name: _httpPortName
+			}
 		}
 	}
-}
 
-images: {
-    launcher: {
-        repository: "giolekva"
-        name: "pcloud-installer"
-        tag: "latest"
-        pullPolicy: "Always"
-    }
-}
+	images: {
+		launcher: {
+			repository: "giolekva"
+			name: "pcloud-installer"
+			tag: "latest"
+			pullPolicy: "Always"
+		}
+	}
 
-charts: {
-    launcher: {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/launcher"
-    }
-}
+	charts: {
+		launcher: {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/launcher"
+		}
+	}
 
-helm: {
-    launcher: {
-        chart: charts.launcher
-        values: {
-            image: {
-                repository: images.launcher.fullName
-                tag: images.launcher.tag
-                pullPolicy: images.launcher.pullPolicy
-            }
-            portName: _httpPortName
-            repoAddr: input.repoAddr
-            sshPrivateKey: base64.Encode(null, input.sshPrivateKey)
-            logoutUrl: "https://accounts-ui.\(networks.public.domain)/logout"
-			repoAddr: input.repoAddr
-			sshPrivateKey: base64.Encode(null, input.sshPrivateKey)
-        }
-    }
+	helm: {
+		launcher: {
+			chart: charts.launcher
+			values: {
+				image: {
+					repository: images.launcher.fullName
+					tag: images.launcher.tag
+					pullPolicy: images.launcher.pullPolicy
+				}
+				portName: _httpPortName
+				repoAddr: input.repoAddr
+				sshPrivateKey: base64.Encode(null, input.sshPrivateKey)
+				logoutUrl: "https://accounts-ui.\(networks.public.domain)/logout"
+				repoAddr: input.repoAddr
+				sshPrivateKey: base64.Encode(null, input.sshPrivateKey)
+			}
+		}
+	}
 }
diff --git a/core/installer/values-tmpl/matrix.cue b/core/installer/values-tmpl/matrix.cue
index 4cb0f0e..8bf8426 100644
--- a/core/installer/values-tmpl/matrix.cue
+++ b/core/installer/values-tmpl/matrix.cue
@@ -29,131 +29,133 @@
   <path class='cls-1' d='m1.04503942.90944884v37.86613982h2.72503927v.90945071H0V0h3.77007869v.90944884H1.04503942Zm11.64590578,12.00472508v1.91314893h.05456692c.47654392-.69956134,1.10875881-1.27913948,1.84700726-1.69322862.71598361-.40511792,1.54771632-.60354293,2.48031496-.60354293.89291332,0,1.70811022.17692893,2.44889755.51921281.74078733.34393731,1.29803124.96236184,1.68661493,1.83212566.41999952-.61842453.99212662-1.16740212,1.70976444-1.64031434.71763782-.47456723,1.57086583-.71102334,2.55637717-.71102334.74905523,0,1.44188933.09259881,2.08346495.27614143.64157561.18188998,1.18393635.47291301,1.64196855.8763783.45637641.40511792.80858321.92433073,1.06818882,1.57252004.25133929.6481893.3803142,1.42700774.3803142,2.34307056v9.47149555h-3.88417161v-8.02133831c0-.4729138-.01653581-.92433073-.0529127-1.34267762-.02666609-.3797812-.12779852-.75060537-.2976383-1.09133833-.16496703-.31157689-.41647821-.56882971-.72425151-.74078733-.32078781-.1818892-.75566893-.27448879-1.29803124-.27448879-.54897601,0-.99212662.10582699-1.32779444.3125199-.33038665.20312114-.60355081.48709839-.79370003.82511744-.19910782.35594888-.32873086.74650374-.38196842,1.15086631-.06370056.42978918-.09685576.86355382-.09921329,1.29803124v7.88409548h-3.8858274v-7.93700819c0-.41999952-.00661369-.83173271-.0297632-1.24346433-.01353647-.38990201-.09350161-.7746348-.23645611-1.13763734-.13486952-.34292964-.3751576-.63417029-.68622041-.83173271-.32078781-.20669291-.78708634-.31417253-1.41212614-.31417253-.18354341,0-.42826743.03968532-.72590573.1223628-.2976383.08433012-.59527502.23645611-.87637751.46629853-.31383822.26829772-.56214032.60483444-.72590573.98385871-.19842501.42826743-.29763751.99212662-.29763751,1.68661335v8.21149541h-3.88417713v-14.16259852l3.66259868.00000079Zm25.94905485,25.86141789V.90944884h-2.72504056v-.90944884h3.77007988v39.68503937h-3.77007988v-.90944756h2.72504056Z'/>
 </svg>"""
 
-images: {
-	matrix: {
-		repository: "matrixdotorg"
-		name: "synapse"
-		tag: "v1.104.0"
-		pullPolicy: "IfNotPresent"
-	}
-	postgres: {
-		repository: "library"
-		name: "postgres"
-		tag: "15.3"
-		pullPolicy: "IfNotPresent"
-	}
-}
-
-charts: {
-	oauth2Client: {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/oauth2-client"
-	}
-	matrix: {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/matrix"
-	}
-	postgres: {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/postgresql"
-	}
-}
-
-_oauth2ClientSecretName: "oauth2-client"
-
-helm: {
-	"oauth2-client": {
-		chart: charts.oauth2Client
-		info: "Creating OAuth2 client"
-		values: {
-			name: "\(release.namespace)-matrix"
-			secretName: _oauth2ClientSecretName
-			grantTypes: ["authorization_code"]
-			responseTypes: ["code"]
-			scope: "openid profile"
-			redirectUris: ["https://\(_domain)/_synapse/client/oidc/callback"]
-			hydraAdmin: "http://hydra-admin.\(global.namespacePrefix)core-auth.svc.cluster.local"
+out: {
+	images: {
+		matrix: {
+			repository: "matrixdotorg"
+			name: "synapse"
+			tag: "v1.104.0"
+			pullPolicy: "IfNotPresent"
 		}
-	}
-	matrix: {
-		dependsOn: [{
+		postgres: {
+			repository: "library"
 			name: "postgres"
-			namespace: release.namespace
-		}]
-		chart: charts.matrix
-		info: "Installing Synapse server"
-		values: {
-			domain: input.network.domain
-			subdomain: input.subdomain
-			oauth2: {
-				secretName: "oauth2-client"
-				issuer: "https://hydra.\(input.network.domain)"
-			}
-			postgresql: {
-				host: "postgres"
-				port: 5432
-				database: "matrix"
-				user: "matrix"
-				password: "matrix"
-			}
-			certificateIssuer: input.network.certificateIssuer
-			ingressClassName: input.network.ingressClass
-			configMerge: {
-				configName: "config-to-merge"
-				fileName: "to-merge.yaml"
-			}
-			image: {
-				repository: images.matrix.fullName
-				tag: images.matrix.tag
-				pullPolicy: images.matrix.pullPolicy
-			}
+			tag: "15.3"
+			pullPolicy: "IfNotPresent"
 		}
 	}
-	postgres: {
-		chart: charts.postgres
-		info: "Installing PostgreSQL"
-		values: {
-			fullnameOverride: "postgres"
-			image: {
-				registry: images.postgres.registry
-				repository: images.postgres.imageName
-				tag: images.postgres.tag
-				pullPolicy: images.postgres.pullPolicy
+
+	charts: {
+		oauth2Client: {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/oauth2-client"
+		}
+		matrix: {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/matrix"
+		}
+		postgres: {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/postgresql"
+		}
+	}
+
+	_oauth2ClientSecretName: "oauth2-client"
+
+	helm: {
+		"oauth2-client": {
+			chart: charts.oauth2Client
+			info: "Creating OAuth2 client"
+			values: {
+				name: "\(release.namespace)-matrix"
+				secretName: _oauth2ClientSecretName
+				grantTypes: ["authorization_code"]
+				responseTypes: ["code"]
+				scope: "openid profile"
+				redirectUris: ["https://\(_domain)/_synapse/client/oidc/callback"]
+				hydraAdmin: "http://hydra-admin.\(global.namespacePrefix)core-auth.svc.cluster.local"
 			}
-			service: {
-				type: "ClusterIP"
-				port: 5432
+		}
+		matrix: {
+			dependsOn: [{
+				name: "postgres"
+				namespace: release.namespace
+			}]
+			chart: charts.matrix
+			info: "Installing Synapse server"
+			values: {
+				domain: input.network.domain
+				subdomain: input.subdomain
+				oauth2: {
+					secretName: "oauth2-client"
+					issuer: "https://hydra.\(input.network.domain)"
+				}
+				postgresql: {
+					host: "postgres"
+					port: 5432
+					database: "matrix"
+					user: "matrix"
+					password: "matrix"
+				}
+				certificateIssuer: input.network.certificateIssuer
+				ingressClassName: input.network.ingressClass
+				configMerge: {
+					configName: "config-to-merge"
+					fileName: "to-merge.yaml"
+				}
+				image: {
+					repository: images.matrix.fullName
+					tag: images.matrix.tag
+					pullPolicy: images.matrix.pullPolicy
+				}
 			}
-			primary: {
-				initdb: {
-					scripts: {
-						"init.sql": """
-						CREATE USER matrix WITH PASSWORD 'matrix';
-						CREATE DATABASE matrix WITH OWNER = matrix ENCODING = UTF8 LOCALE = 'C' TEMPLATE = template0;
-						"""
+		}
+		postgres: {
+			chart: charts.postgres
+			info: "Installing PostgreSQL"
+			values: {
+				fullnameOverride: "postgres"
+				image: {
+					registry: images.postgres.registry
+					repository: images.postgres.imageName
+					tag: images.postgres.tag
+					pullPolicy: images.postgres.pullPolicy
+				}
+				service: {
+					type: "ClusterIP"
+					port: 5432
+				}
+				primary: {
+					initdb: {
+						scripts: {
+							"init.sql": """
+							CREATE USER matrix WITH PASSWORD 'matrix';
+							CREATE DATABASE matrix WITH OWNER = matrix ENCODING = UTF8 LOCALE = 'C' TEMPLATE = template0;
+							"""
+						}
+					}
+					persistence: {
+						size: "10Gi"
+					}
+					securityContext: {
+						enabled: true
+						fsGroup: 0
+					}
+					containerSecurityContext: {
+						enabled: true
+						runAsUser: 0
 					}
 				}
-				persistence: {
-					size: "10Gi"
-				}
-				securityContext: {
-					enabled: true
-					fsGroup: 0
-				}
-				containerSecurityContext: {
-					enabled: true
-					runAsUser: 0
-				}
-			}
-			volumePermissions: {
-				securityContext: {
-					runAsUser: 0
+				volumePermissions: {
+					securityContext: {
+						runAsUser: 0
+					}
 				}
 			}
 		}
diff --git a/core/installer/values-tmpl/memberships.cue b/core/installer/values-tmpl/memberships.cue
index bf1424e..5fc55d1 100644
--- a/core/installer/values-tmpl/memberships.cue
+++ b/core/installer/values-tmpl/memberships.cue
@@ -15,52 +15,54 @@
 
 _httpPortName: "http"
 
-ingress: {
-	memberships: {
-		auth: {
-			enabled: true
-			groups: input.authGroups
-		}
-		network: input.network
-		subdomain: _subdomain
-		service: {
-			name: "memberships"
-			port: name: _httpPortName
+out: {
+	ingress: {
+		memberships: {
+			auth: {
+				enabled: true
+				groups: input.authGroups
+			}
+			network: input.network
+			subdomain: _subdomain
+			service: {
+				name: "memberships"
+				port: name: _httpPortName
+			}
 		}
 	}
-}
 
-images: {
-    memberships: {
-        repository: "giolekva"
-        name: "memberships"
-        tag: "latest"
-        pullPolicy: "Always"
-    }
-}
+	images: {
+		memberships: {
+			repository: "giolekva"
+			name: "memberships"
+			tag: "latest"
+			pullPolicy: "Always"
+		}
+	}
 
-charts: {
-    memberships: {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/memberships"
-    }
-}
+	charts: {
+		memberships: {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/memberships"
+		}
+	}
 
-helm: {
-    memberships: {
-        chart: charts.memberships
-        values: {
-            storage: {
-                size: "1Gi"
-            }
-            image: {
-                repository: images.memberships.fullName
-                tag: images.memberships.tag
-                pullPolicy: images.memberships.pullPolicy
-            }
-            portName: _httpPortName
-        }
-    }
+	helm: {
+		memberships: {
+			chart: charts.memberships
+			values: {
+				storage: {
+					size: "1Gi"
+				}
+				image: {
+					repository: images.memberships.fullName
+					tag: images.memberships.tag
+					pullPolicy: images.memberships.pullPolicy
+				}
+				portName: _httpPortName
+			}
+		}
+	}
 }
diff --git a/core/installer/values-tmpl/metallb-ipaddresspool.cue b/core/installer/values-tmpl/metallb-ipaddresspool.cue
index 47236ce..a0bb4e5 100644
--- a/core/installer/values-tmpl/metallb-ipaddresspool.cue
+++ b/core/installer/values-tmpl/metallb-ipaddresspool.cue
@@ -9,26 +9,26 @@
 name: "metallb-ipaddresspool"
 namespace: "metallb-ipaddresspool"
 
-images: {}
-
-charts: {
-	metallbIPAddressPool: {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/metallb-ipaddresspool"
+out: {
+	charts: {
+		metallbIPAddressPool: {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/metallb-ipaddresspool"
+		}
 	}
-}
 
-helm: {
-	"metallb-ipaddresspool-\(input.name)": {
-		chart: charts.metallbIPAddressPool
-		values: {
-			name: input.name
-			from: input.from
-			to: input.to
-			autoAssign: input.autoAssign
-			namespace: input.namespace
+	helm: {
+		"metallb-ipaddresspool-\(input.name)": {
+			chart: charts.metallbIPAddressPool
+			values: {
+				name: input.name
+				from: input.from
+				to: input.to
+				autoAssign: input.autoAssign
+				namespace: input.namespace
+			}
 		}
 	}
 }
diff --git a/core/installer/values-tmpl/open-project.cue b/core/installer/values-tmpl/open-project.cue
index 927db43..6598094 100644
--- a/core/installer/values-tmpl/open-project.cue
+++ b/core/installer/values-tmpl/open-project.cue
@@ -13,160 +13,163 @@
 icon: "<svg xmlns='http://www.w3.org/2000/svg' width='50' height='50' viewBox='0 0 24 24'><path fill='currentColor' d='M19.35.37h-1.86a4.63 4.63 0 0 0-4.652 4.624v5.609H4.652A4.63 4.63 0 0 0 0 15.23v3.721c0 2.569 2.083 4.679 4.652 4.679h1.86c2.57 0 4.652-2.11 4.652-4.679v-3.72c0-.063 0-.158-.005-.158H8.373v3.88c0 1.026-.835 1.886-1.861 1.886h-1.86c-1.027 0-1.861-.864-1.861-1.886V15.23a1.84 1.84 0 0 1 1.86-1.833h14.697c2.57 0 4.652-2.11 4.652-4.679V4.997A4.63 4.63 0 0 0 19.35.37m1.861 8.345c0 1.026-.835 1.886-1.861 1.886h-3.721V4.997a1.84 1.84 0 0 1 1.86-1.833h1.86a1.84 1.84 0 0 1 1.862 1.833zm-8.373 9.706v.03c0 .746.629 1.344 1.396 1.344s1.395-.594 1.395-1.34v-3.384h-2.791z'/></svg>"
 
 _httpPort: 8080
-ingress: {
-	gerrit: {
-		auth: enabled: false
-		network: input.network
-		subdomain: input.subdomain
-		service: {
-			name: "open-project"
-			port: number: _httpPort
+
+out: {
+	ingress: {
+		gerrit: {
+			auth: enabled: false
+			network: input.network
+			subdomain: input.subdomain
+			service: {
+				name: "open-project"
+				port: number: _httpPort
+			}
 		}
 	}
-}
 
-images: {
-	openProject: {
-		repository: "openproject"
-		name: "openproject"
-		tag: "13.4.1"
-		pullPolicy: "Always"
+	images: {
+		openProject: {
+			repository: "openproject"
+			name: "openproject"
+			tag: "13.4.1"
+			pullPolicy: "Always"
+		}
+		postgres: {
+			repository: "library"
+			name: "postgres"
+			tag: "15.3"
+			pullPolicy: "IfNotPresent"
+		}
 	}
-	postgres: {
-		repository: "library"
-		name: "postgres"
-		tag: "15.3"
-		pullPolicy: "IfNotPresent"
-	}
-}
 
-charts: {
-	openProject: {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/openproject"
+	charts: {
+		openProject: {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/openproject"
+		}
+		volume: {
+			path: "charts/volumes"
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+		}
+		postgres: {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/postgresql"
+		}
 	}
-	volume: {
-		path: "charts/volumes"
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-	}
-	postgres: {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/postgresql"
-	}
-}
 
-volumes: {
-	openProject: {
-		name: "open-project"
-		accessMode: "ReadWriteMany"
-		size: "50Gi"
+	volumes: {
+		openProject: {
+			name: "open-project"
+			accessMode: "ReadWriteMany"
+			size: "50Gi"
+		}
 	}
-}
 
-helm: {
-	"open-project": {
-		chart: charts.openProject
-		values: {
-			image: {
-				registry: images.openProject.registry
-				repository: images.openProject.imageName
-				tag: images.openProject.tag
-				imagePullPolicy: images.openProject.pullPolicy
-			}
-			nameOverride: "open-project"
-			ingress: enabled: false
-			memcached: bundled: true
-			s3: enabled: false
-			openproject: {
-				host: _domain
-				https: false
-				hsts: false
-				oidc: enabled: false // TODO(gio): enable
-				admin_user: {
-					password: "admin"
-					password_reset: false
-					name: "admin"
-					mail: "op-admin@\(networks.public.domain)"
+	helm: {
+		"open-project": {
+			chart: charts.openProject
+			values: {
+				image: {
+					registry: images.openProject.registry
+					repository: images.openProject.imageName
+					tag: images.openProject.tag
+					imagePullPolicy: images.openProject.pullPolicy
+				}
+				nameOverride: "open-project"
+				ingress: enabled: false
+				memcached: bundled: true
+				s3: enabled: false
+				openproject: {
+					host: _domain
+					https: false
+					hsts: false
+					oidc: enabled: false // TODO(gio): enable
+					admin_user: {
+						password: "admin"
+						password_reset: false
+						name: "admin"
+						mail: "op-admin@\(networks.public.domain)"
+					}
+				}
+				persistence: {
+					enabled: true
+					existingClaim: volumes.openProject.name
+				}
+				postgresql: {
+					bundled: false
+					connection: {
+						host: "postgres.\(release.namespace).svc.cluster.local"
+						port: 5432
+					}
+					auth: {
+						username: "openproject"
+						password: "openproject"
+						database: "openproject"
+					}
+				}
+				service: {
+					enabled: true
+					type: "ClusterIP"
+				}
+				initDb: {
+					image: {
+						registry: images.postgres.registry
+						repository: images.postgres.imageName
+						tag: images.postgres.tag
+						imagePullPolicy: images.postgres.pullPolicy
+					}
 				}
 			}
-			persistence: {
-				enabled: true
-				existingClaim: volumes.openProject.name
-			}
-			postgresql: {
-				bundled: false
-				connection: {
-					host: "postgres.\(release.namespace).svc.cluster.local"
-					port: 5432
-				}
-				auth: {
-					username: "openproject"
-					password: "openproject"
-					database: "openproject"
-				}
-			}
-			service: {
-				enabled: true
-				type: "ClusterIP"
-			}
-			initDb: {
+		}
+		"open-project-volume": {
+			chart: charts.volume
+			values: volumes.openProject
+		}
+		postgres: {
+			chart: charts.postgres
+			values: {
+				fullnameOverride: "postgres"
 				image: {
 					registry: images.postgres.registry
 					repository: images.postgres.imageName
 					tag: images.postgres.tag
-					imagePullPolicy: images.postgres.pullPolicy
+					pullPolicy: images.postgres.pullPolicy
 				}
-			}
-		}
-	}
-	"open-project-volume": {
-		chart: charts.volume
-		values: volumes.openProject
-	}
-	postgres: {
-		chart: charts.postgres
-		values: {
-			fullnameOverride: "postgres"
-			image: {
-				registry: images.postgres.registry
-				repository: images.postgres.imageName
-				tag: images.postgres.tag
-				pullPolicy: images.postgres.pullPolicy
-			}
-			service: {
-				type: "ClusterIP"
-				port: 5432
-			}
-			primary: {
-				initdb: {
-					scripts: {
-						"init.sql": """
-						CREATE USER openproject WITH PASSWORD 'openproject';
-						CREATE DATABASE openproject WITH OWNER = openproject ENCODING = UTF8 LOCALE = 'C' TEMPLATE = template0;
-						"""
+				service: {
+					type: "ClusterIP"
+					port: 5432
+				}
+				primary: {
+					initdb: {
+						scripts: {
+							"init.sql": """
+							CREATE USER openproject WITH PASSWORD 'openproject';
+							CREATE DATABASE openproject WITH OWNER = openproject ENCODING = UTF8 LOCALE = 'C' TEMPLATE = template0;
+							"""
+						}
+					}
+					persistence: {
+						size: "50Gi"
+					}
+					securityContext: {
+						enabled: true
+						fsGroup: 0
+					}
+					containerSecurityContext: {
+						enabled: true
+						runAsUser: 0
 					}
 				}
-				persistence: {
-					size: "50Gi"
-				}
-				securityContext: {
-					enabled: true
-					fsGroup: 0
-				}
-				containerSecurityContext: {
-					enabled: true
-					runAsUser: 0
-				}
-			}
-			volumePermissions: {
-				securityContext: {
-					runAsUser: 0
+				volumePermissions: {
+					securityContext: {
+						runAsUser: 0
+					}
 				}
 			}
 		}
diff --git a/core/installer/values-tmpl/penpot.cue b/core/installer/values-tmpl/penpot.cue
index 0e25a43..21004f4 100644
--- a/core/installer/values-tmpl/penpot.cue
+++ b/core/installer/values-tmpl/penpot.cue
@@ -12,165 +12,167 @@
 description: "Penpot is the first Open Source design and prototyping platform meant for cross-domain teams. Non dependent on operating systems, Penpot is web based and works with open standards (SVG). Penpot invites designers all over the world to fall in love with open source while getting developers excited about the design process in return."
 icon: "<svg xmlns='http://www.w3.org/2000/svg' width='50' height='50' viewBox='0 0 24 24'><path fill='currentColor' d='M7.654 0L5.13 3.554v2.01L2.934 6.608l-.02-.009v13.109l8.563 4.045L12 24l.523-.247l8.563-4.045V6.6l-.017.008l-2.196-1.045V3.555l-.077-.108L16.349.001l-2.524 3.554v.004L11.989.973l-1.823 2.566l-.065-.091zm.447 2.065l.976 1.374H6.232l.964-1.358zm8.694 0l.976 1.374h-2.845l.965-1.358zm-4.36.971l.976 1.375h-2.845l.965-1.359zM5.962 4.132h1.35v4.544l-1.35-.638Zm2.042 0h1.343v5.506l-1.343-.635zm6.652 0h1.35V9l-1.35.637zm2.042 0h1.343v3.905l-1.343.634zm-6.402.972h1.35v5.62l-1.35-.638zm2.042 0h1.343v4.993l-1.343.634zm6.534 1.493l1.188.486l-1.188.561zM5.13 6.6v1.047l-1.187-.561ZM3.96 8.251l7.517 3.55v10.795l-7.516-3.55zm16.08 0v10.794l-7.517 3.55V11.802z'/></svg>"
 
-images: {
-	postgres: {
-		repository: "library"
-		name: "postgres"
-		tag: "15.3"
-		pullPolicy: "IfNotPresent"
-	}
-	backend: {
-		repository: "penpotapp"
-		name: "backend"
-		tag: "1.16.0-beta"
-		pullPolicy: "IfNotPresent"
-	}
-	frontend: {
-		repository: "penpotapp"
-		name: "frontend"
-		tag: "1.16.0-beta"
-		pullPolicy: "IfNotPresent"
-	}
-	exporter: {
-		repository: "penpotapp"
-		name: "exporter"
-		tag: "1.16.0-beta"
-		pullPolicy: "IfNotPresent"
-	}
-}
-
-charts: {
-	postgres: {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/postgresql"
-	}
-	oauth2Client: {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/oauth2-client"
-	}
-	penpot: {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/penpot"
-	}
-}
-
-_oauth2SecretName: "oauth2-credentials"
-
-helm: {
-	"oauth2-client": {
-		chart: charts.oauth2Client
-		values: {
-			name: "\(release.namespace)-penpot"
-			secretName: _oauth2SecretName
-			grantTypes: ["authorization_code"]
-			responseTypes: ["code"]
-			scope: "openid profile email"
-			redirectUris: ["https://\(_domain)/api/auth/oauth/oidc/callback"]
-			hydraAdmin: "http://hydra-admin.\(global.namespacePrefix)core-auth.svc.cluster.local"
-			tokenEndpointAuthMethod: "client_secret_post"
+out: {
+	images: {
+		postgres: {
+			repository: "library"
+			name: "postgres"
+			tag: "15.3"
+			pullPolicy: "IfNotPresent"
+		}
+		backend: {
+			repository: "penpotapp"
+			name: "backend"
+			tag: "1.16.0-beta"
+			pullPolicy: "IfNotPresent"
+		}
+		frontend: {
+			repository: "penpotapp"
+			name: "frontend"
+			tag: "1.16.0-beta"
+			pullPolicy: "IfNotPresent"
+		}
+		exporter: {
+			repository: "penpotapp"
+			name: "exporter"
+			tag: "1.16.0-beta"
+			pullPolicy: "IfNotPresent"
 		}
 	}
-	postgres: {
-		chart: charts.postgres
-		values: {
-			fullnameOverride: "postgres"
-			image: {
-				registry: images.postgres.registry
-				repository: images.postgres.imageName
-				tag: images.postgres.tag
-				pullPolicy: images.postgres.pullPolicy
-			}
-			auth: {
-				username: "penpot"
-				password: "penpot"
-				database: "penpot"
-			}
+
+	charts: {
+		postgres: {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/postgresql"
+		}
+		oauth2Client: {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/oauth2-client"
+		}
+		penpot: {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/penpot"
 		}
 	}
-	penpot: {
-		chart: charts.penpot
-		values: {
-			"global": {
-				postgresqlEnabled: false
-				redisEnabled: true // TODO(gio): provide redis from outside
+
+	_oauth2SecretName: "oauth2-credentials"
+
+	helm: {
+		"oauth2-client": {
+			chart: charts.oauth2Client
+			values: {
+				name: "\(release.namespace)-penpot"
+				secretName: _oauth2SecretName
+				grantTypes: ["authorization_code"]
+				responseTypes: ["code"]
+				scope: "openid profile email"
+				redirectUris: ["https://\(_domain)/api/auth/oauth/oidc/callback"]
+				hydraAdmin: "http://hydra-admin.\(global.namespacePrefix)core-auth.svc.cluster.local"
+				tokenEndpointAuthMethod: "client_secret_post"
 			}
-			fullnameOverride: "penpot"
-			backend: {
+		}
+		postgres: {
+			chart: charts.postgres
+			values: {
+				fullnameOverride: "postgres"
 				image: {
-					repository: images.backend.fullName
-					tag: images.backend.tag
-					imagePullPolicy: images.backend.pullPolicy
+					registry: images.postgres.registry
+					repository: images.postgres.imageName
+					tag: images.postgres.tag
+					pullPolicy: images.postgres.pullPolicy
 				}
-			}
-			frontend: {
-				image: {
-					repository: images.frontend.fullName
-					tag: images.frontend.tag
-					imagePullPolicy: images.frontend.pullPolicy
-				}
-				ingress: {
-					enabled: true
-					className: input.network.ingressClass
-					if input.network.certificateIssuer != "" {
-						annotations: {
-							"acme.cert-manager.io/http01-edit-in-place": "true"
-							"cert-manager.io/cluster-issuer": input.network.certificateIssuer
-						}
-					}
-					hosts: [_domain]
-					tls: [{
-						hosts: [_domain]
-						secretName: "cert-\(_domain)"
-					}]
-				}
-			}
-			persistence: enabled: true
-			config: {
-				publicURI: _domain
-				flags: "enable-login-with-oidc enable-registration enable-insecure-register disable-demo-users disable-demo-warning" // TODO(gio): remove enable-insecure-register?
-				postgresql: {
-					host: "postgres.\(release.namespace).svc.cluster.local"
-					database: "penpot"
+				auth: {
 					username: "penpot"
 					password: "penpot"
+					database: "penpot"
 				}
-				redis: host: "penpot-redis-headless.\(release.namespace).svc.cluster.local"
-				providers: {
-					oidc: {
+			}
+		}
+		penpot: {
+			chart: charts.penpot
+			values: {
+				"global": {
+					postgresqlEnabled: false
+					redisEnabled: true // TODO(gio): provide redis from outside
+				}
+				fullnameOverride: "penpot"
+				backend: {
+					image: {
+						repository: images.backend.fullName
+						tag: images.backend.tag
+						imagePullPolicy: images.backend.pullPolicy
+					}
+				}
+				frontend: {
+					image: {
+						repository: images.frontend.fullName
+						tag: images.frontend.tag
+						imagePullPolicy: images.frontend.pullPolicy
+					}
+					ingress: {
 						enabled: true
-						baseURI: "https://hydra.\(networks.public.domain)"
-						clientID: ""
-						clientSecret: ""
-						authURI: ""
-						tokenURI: ""
-						userURI: ""
-						roles: ""
-						rolesAttribute: ""
-						scopes: ""
-						nameAttribute: "name"
-						emailAttribute: "email"
-					}
-					existingSecret: _oauth2SecretName
-					secretKeys: {
-						oidcClientIDKey: "client_id"
-						oidcClientSecretKey: "client_secret"
+						className: input.network.ingressClass
+						if input.network.certificateIssuer != "" {
+							annotations: {
+								"acme.cert-manager.io/http01-edit-in-place": "true"
+								"cert-manager.io/cluster-issuer": input.network.certificateIssuer
+							}
+						}
+						hosts: [_domain]
+						tls: [{
+							hosts: [_domain]
+							secretName: "cert-\(_domain)"
+						}]
 					}
 				}
-			}
-			exporter: {
-				image: {
-					repository: images.exporter.fullName
-					tag: images.exporter.tag
-					imagePullPolicy: images.exporter.pullPolicy
+				persistence: enabled: true
+				config: {
+					publicURI: _domain
+					flags: "enable-login-with-oidc enable-registration enable-insecure-register disable-demo-users disable-demo-warning" // TODO(gio): remove enable-insecure-register?
+					postgresql: {
+						host: "postgres.\(release.namespace).svc.cluster.local"
+						database: "penpot"
+						username: "penpot"
+						password: "penpot"
+					}
+					redis: host: "penpot-redis-headless.\(release.namespace).svc.cluster.local"
+					providers: {
+						oidc: {
+							enabled: true
+							baseURI: "https://hydra.\(networks.public.domain)"
+							clientID: ""
+							clientSecret: ""
+							authURI: ""
+							tokenURI: ""
+							userURI: ""
+							roles: ""
+							rolesAttribute: ""
+							scopes: ""
+							nameAttribute: "name"
+							emailAttribute: "email"
+						}
+						existingSecret: _oauth2SecretName
+						secretKeys: {
+							oidcClientIDKey: "client_id"
+							oidcClientSecretKey: "client_secret"
+						}
+					}
 				}
+				exporter: {
+					image: {
+						repository: images.exporter.fullName
+						tag: images.exporter.tag
+						imagePullPolicy: images.exporter.pullPolicy
+					}
+				}
+				redis: image: tag: "7.0.8-debian-11-r16"
 			}
-			redis: image: tag: "7.0.8-debian-11-r16"
 		}
 	}
 }
diff --git a/core/installer/values-tmpl/pihole.cue b/core/installer/values-tmpl/pihole.cue
index 59cab5d..01a3ca1 100644
--- a/core/installer/values-tmpl/pihole.cue
+++ b/core/installer/values-tmpl/pihole.cue
@@ -2,6 +2,7 @@
 	network: #Network @name(Network)
 	subdomain: string @name(Subdomain)
 	auth: #Auth @name(Authentication)
+	storageSize: string
 }
 
 _domain: "\(input.subdomain).\(input.network.domain)"
@@ -33,83 +34,87 @@
 
 _serviceWebPort: 80
 
-ingress: {
-	pihole: {
-		auth: input.auth
-		network: input.network
-		subdomain: input.subdomain
-		service: {
-			name: "pihole-web"
-			port: number: _serviceWebPort
+out: {
+	ingress: {
+		pihole: {
+			auth: input.auth
+			network: input.network
+			subdomain: input.subdomain
+			service: {
+				name: "pihole-web"
+				port: number: _serviceWebPort
+			}
 		}
 	}
-}
 
-images: {
-	pihole: {
-		repository: "pihole"
-		name: "pihole"
-		tag: "v5.8.1"
-		pullPolicy: "IfNotPresent"
+	images: {
+		pihole: {
+			repository: "pihole"
+			name: "pihole"
+			tag: "v5.8.1"
+			pullPolicy: "IfNotPresent"
+		}
 	}
-}
 
-charts: {
-	pihole: {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/pihole"
+	charts: {
+		pihole: {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/pihole"
+		}
 	}
-}
 
-helm: {
-	pihole: {
-		chart: charts.pihole
-		info: "Installing Pi-hole server"
-		values: {
-			fullnameOverride: "pihole"
-			persistentVolumeClaim: { // TODO(gio): create volume separately as a dependency
-				enabled: true
-				size: "5Gi"
-			}
-			admin: {
-				enabled: false
-			}
-			ingress: {
-				enabled: false
-			}
-			serviceDhcp: {
-				enabled: false
-			}
-			serviceDns: {
-				type: "ClusterIP"
-			}
-			serviceWeb: {
-				type: "ClusterIP"
-				http: {
+	volumes: data: size: input.storageSize
+
+	helm: {
+		pihole: {
+			chart: charts.pihole
+			info: "Installing Pi-hole server"
+			values: {
+				fullnameOverride: "pihole"
+				persistentVolumeClaim: {
 					enabled: true
-					port: _serviceWebPort
+					existingClaim: volumes.data.name
 				}
-				https: {
+				admin: {
 					enabled: false
 				}
-			}
-			virtualHost: _domain
-			resources: {
-				requests: {
-					cpu: "250m"
-					memory: "100M"
+				ingress: {
+					enabled: false
 				}
-				limits: {
-					cpu: "500m"
-					memory: "250M"
+				serviceDhcp: {
+					enabled: false
 				}
-			}
-			image: {
-				repository: images.pihole.fullName
-				tag: images.pihole.tag
-				pullPolicy: images.pihole.pullPolicy
+				serviceDns: {
+					type: "ClusterIP"
+				}
+				serviceWeb: {
+					type: "ClusterIP"
+					http: {
+						enabled: true
+						port: _serviceWebPort
+					}
+					https: {
+						enabled: false
+					}
+				}
+				virtualHost: _domain
+				resources: {
+					requests: {
+						cpu: "250m"
+						memory: "100M"
+					}
+					limits: {
+						cpu: "500m"
+						memory: "250M"
+					}
+				}
+				image: {
+					repository: images.pihole.fullName
+					tag: images.pihole.tag
+					pullPolicy: images.pihole.pullPolicy
+				}
 			}
 		}
 	}
diff --git a/core/installer/values-tmpl/private-network.cue b/core/installer/values-tmpl/private-network.cue
index 255b375..653da67 100644
--- a/core/installer/values-tmpl/private-network.cue
+++ b/core/installer/values-tmpl/private-network.cue
@@ -14,119 +14,121 @@
 name: "private-network"
 namespace: "ingress-private"
 
-images: {
-	"ingress-nginx": {
-		registry: "registry.k8s.io"
-		repository: "ingress-nginx"
-		name: "controller"
-		tag: "v1.8.0"
-		pullPolicy: "IfNotPresent"
+out: {
+	images: {
+		"ingress-nginx": {
+			registry: "registry.k8s.io"
+			repository: "ingress-nginx"
+			name: "controller"
+			tag: "v1.8.0"
+			pullPolicy: "IfNotPresent"
+		}
+		"tailscale-proxy": {
+			repository: "tailscale"
+			name: "tailscale"
+			tag: "v1.42.0"
+			pullPolicy: "IfNotPresent"
+		}
+		portAllocator: {
+			repository: "giolekva"
+			name: "port-allocator"
+			tag: "latest"
+			pullPolicy: "Always"
+		}
 	}
-	"tailscale-proxy": {
-		repository: "tailscale"
-		name: "tailscale"
-		tag: "v1.42.0"
-		pullPolicy: "IfNotPresent"
-	}
-	portAllocator: {
-		repository: "giolekva"
-		name: "port-allocator"
-		tag: "latest"
-		pullPolicy: "Always"
-	}
-}
 
-charts: {
-	"ingress-nginx": {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/ingress-nginx"
+	charts: {
+		"ingress-nginx": {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/ingress-nginx"
+		}
+		"tailscale-proxy": {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/tailscale-proxy"
+		}
+		portAllocator: {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/port-allocator"
+		}
 	}
-	"tailscale-proxy": {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/tailscale-proxy"
-	}
-	portAllocator: {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/port-allocator"
-	}
-}
 
-_ingressPrivate: "\(global.id)-ingress-private"
+	_ingressPrivate: "\(global.id)-ingress-private"
 
-helm: {
-	"ingress-nginx": {
-		chart: charts["ingress-nginx"]
-		values: {
-			fullnameOverride: "\(global.id)-nginx-private"
-			controller: {
-				service: {
-					enabled: true
-					type: "LoadBalancer"
-					annotations: {
-						"metallb.universe.tf/address-pool": _ingressPrivate
+	helm: {
+		"ingress-nginx": {
+			chart: charts["ingress-nginx"]
+			values: {
+				fullnameOverride: "\(global.id)-nginx-private"
+				controller: {
+					service: {
+						enabled: true
+						type: "LoadBalancer"
+						annotations: {
+							"metallb.universe.tf/address-pool": _ingressPrivate
+						}
+					}
+					ingressClassByName: true
+					ingressClassResource: {
+						name: _ingressPrivate
+						enabled: true
+						default: false
+						controllerValue: "k8s.io/\(_ingressPrivate)"
+					}
+					config: {
+						"proxy-body-size": "200M" // TODO(giolekva): configurable
+						"force-ssl-redirect": "true"
+						"server-snippet": """
+						more_clear_headers "X-Frame-Options";
+						"""
+					}
+					extraArgs: {
+						"default-ssl-certificate": "\(_ingressPrivate)/cert-wildcard.\(global.privateDomain)"
+					}
+					admissionWebhooks: {
+						enabled: false
+					}
+					image: {
+						registry: images["ingress-nginx"].registry
+						image: images["ingress-nginx"].imageName
+						tag: images["ingress-nginx"].tag
+						pullPolicy: images["ingress-nginx"].pullPolicy
 					}
 				}
-				ingressClassByName: true
-				ingressClassResource: {
-					name: _ingressPrivate
-					enabled: true
-					default: false
-					controllerValue: "k8s.io/\(_ingressPrivate)"
-				}
-				config: {
-					"proxy-body-size": "200M" // TODO(giolekva): configurable
-					"force-ssl-redirect": "true"
-					"server-snippet": """
-					more_clear_headers "X-Frame-Options";
-					"""
-				}
-				extraArgs: {
-					"default-ssl-certificate": "\(_ingressPrivate)/cert-wildcard.\(global.privateDomain)"
-				}
-				admissionWebhooks: {
-					enabled: false
-				}
+			}
+		}
+		"tailscale-proxy": {
+			chart: charts["tailscale-proxy"]
+			values: {
+				hostname: input.privateNetwork.hostname
+				apiServer: "http://headscale-api.\(global.namespacePrefix)app-headscale.svc.cluster.local"
+				loginServer: "https://headscale.\(networks.public.domain)" // TODO(gio): take headscale subdomain from configuration
+				ipSubnet: input.privateNetwork.ipSubnet
+				username: input.privateNetwork.username // TODO(gio): maybe install headscale-user chart separately?
+				preAuthKeySecret: "headscale-preauth-key"
 				image: {
-					registry: images["ingress-nginx"].registry
-					image: images["ingress-nginx"].imageName
-					tag: images["ingress-nginx"].tag
-					pullPolicy: images["ingress-nginx"].pullPolicy
+					repository: images["tailscale-proxy"].fullName
+					tag: images["tailscale-proxy"].tag
+					pullPolicy: images["tailscale-proxy"].pullPolicy
 				}
 			}
 		}
-	}
-	"tailscale-proxy": {
-		chart: charts["tailscale-proxy"]
-		values: {
-			hostname: input.privateNetwork.hostname
-			apiServer: "http://headscale-api.\(global.namespacePrefix)app-headscale.svc.cluster.local"
-			loginServer: "https://headscale.\(networks.public.domain)" // TODO(gio): take headscale subdomain from configuration
-			ipSubnet: input.privateNetwork.ipSubnet
-			username: input.privateNetwork.username // TODO(gio): maybe install headscale-user chart separately?
-			preAuthKeySecret: "headscale-preauth-key"
-			image: {
-				repository: images["tailscale-proxy"].fullName
-				tag: images["tailscale-proxy"].tag
-				pullPolicy: images["tailscale-proxy"].pullPolicy
-			}
-		}
-	}
-	"port-allocator": {
-		chart: charts.portAllocator
-		values: {
-			repoAddr: release.repoAddr
-			sshPrivateKey: base64.Encode(null, input.sshPrivateKey)
-			ingressNginxPath: "\(release.appDir)/resources/ingress-nginx.yaml"
-			image: {
-				repository: images.portAllocator.fullName
-				tag: images.portAllocator.tag
-				pullPolicy: images.portAllocator.pullPolicy
+		"port-allocator": {
+			chart: charts.portAllocator
+			values: {
+				repoAddr: release.repoAddr
+				sshPrivateKey: base64.Encode(null, input.sshPrivateKey)
+				ingressNginxPath: "\(release.appDir)/resources/ingress-nginx.yaml"
+				image: {
+					repository: images.portAllocator.fullName
+					tag: images.portAllocator.tag
+					pullPolicy: images.portAllocator.pullPolicy
+				}
 			}
 		}
 	}
diff --git a/core/installer/values-tmpl/qbittorrent.cue b/core/installer/values-tmpl/qbittorrent.cue
index d569311..bec6a3c 100644
--- a/core/installer/values-tmpl/qbittorrent.cue
+++ b/core/installer/values-tmpl/qbittorrent.cue
@@ -12,41 +12,43 @@
 description: "qBittorrent is a cross-platform free and open-source BitTorrent client written in native C++. It relies on Boost, Qt 6 toolkit and the libtorrent-rasterbar library, with an optional search engine written in Python."
 icon: "<svg xmlns='http://www.w3.org/2000/svg' width='50' height='50' viewBox='0 0 48 48'><circle cx='24' cy='24' r='21.5' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round'/><path fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' d='M26.651 22.364a5.034 5.034 0 0 1 5.035-5.035h0a5.034 5.034 0 0 1 5.034 5.035v3.272a5.034 5.034 0 0 1-5.034 5.035h0a5.034 5.034 0 0 1-5.035-5.035m0 5.035V10.533m-5.302 15.103a5.034 5.034 0 0 1-5.035 5.035h0a5.034 5.034 0 0 1-5.034-5.035v-3.272a5.034 5.034 0 0 1 5.034-5.035h0a5.034 5.034 0 0 1 5.035 5.035m0-5.035v20.138'/></svg>"
 
-images: {
-	qbittorrent: {
-		registry: "lscr.io"
-		repository: "linuxserver"
-		name: "qbittorrent"
-		tag: "4.5.3"
-		pullPolicy: "IfNotPresent"
+out: {
+	images: {
+		qbittorrent: {
+			registry: "lscr.io"
+			repository: "linuxserver"
+			name: "qbittorrent"
+			tag: "4.5.3"
+			pullPolicy: "IfNotPresent"
+		}
 	}
-}
 
-charts: {
-	qbittorrent: {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/qbittorrent"
+	charts: {
+		qbittorrent: {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/qbittorrent"
+		}
 	}
-}
 
-helm: {
-	qbittorrent: {
-		chart: charts.qbittorrent
-		values: {
-			pcloudInstanceId: global.id
-			ingress: {
-				className: input.network.ingressClass
-				domain: _domain
-			}
-			webui: port: 8080
-			bittorrent: port: 6881
-			storage: size: "100Gi"
-			image: {
-				repository: images.qbittorrent.fullName
-				tag: images.qbittorrent.tag
-				pullPolicy: images.qbittorrent.pullPolicy
+	helm: {
+		qbittorrent: {
+			chart: charts.qbittorrent
+			values: {
+				pcloudInstanceId: global.id
+				ingress: {
+					className: input.network.ingressClass
+					domain: _domain
+				}
+				webui: port: 8080
+				bittorrent: port: 6881
+				storage: size: "100Gi"
+				image: {
+					repository: images.qbittorrent.fullName
+					tag: images.qbittorrent.tag
+					pullPolicy: images.qbittorrent.pullPolicy
+				}
 			}
 		}
 	}
diff --git a/core/installer/values-tmpl/resource-renderer-controller.cue b/core/installer/values-tmpl/resource-renderer-controller.cue
index 23d1a54..1169be7 100644
--- a/core/installer/values-tmpl/resource-renderer-controller.cue
+++ b/core/installer/values-tmpl/resource-renderer-controller.cue
@@ -3,46 +3,48 @@
 name: "resource-renderer-controller"
 namespace: "rr-controller"
 
-images: {
-	resourceRenderer: {
-		repository: "giolekva"
-		name: "resource-renderer-controller"
-		tag: "latest"
-		pullPolicy: "Always"
+out: {
+	images: {
+		resourceRenderer: {
+			repository: "giolekva"
+			name: "resource-renderer-controller"
+			tag: "latest"
+			pullPolicy: "Always"
+		}
+		kubeRBACProxy: {
+			registry: "gcr.io"
+			repository: "kubebuilder"
+			name: "kube-rbac-proxy"
+			tag: "v0.13.0"
+			pullPolicy: "IfNotPresent"
+		}
 	}
-	kubeRBACProxy: {
-		registry: "gcr.io"
-		repository: "kubebuilder"
-		name: "kube-rbac-proxy"
-		tag: "v0.13.0"
-		pullPolicy: "IfNotPresent"
-	}
-}
 
-charts: {
-	resourceRenderer: {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/resource-renderer-controller"
+	charts: {
+		resourceRenderer: {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/resource-renderer-controller"
+		}
 	}
-}
 
-helm: {
-	"resource-renderer": {
-		chart: charts.resourceRenderer
-		values: {
-			installCRDs: true
-			image: {
-				repository: images.resourceRenderer.fullName
-				tag: images.resourceRenderer.tag
-				pullPolicy: images.resourceRenderer.pullPolicy
-			}
-			kubeRBACProxy: {
+	helm: {
+		"resource-renderer": {
+			chart: charts.resourceRenderer
+			values: {
+				installCRDs: true
 				image: {
-					repository: images.kubeRBACProxy.fullName
-					tag: images.kubeRBACProxy.tag
-					pullPolicy: images.kubeRBACProxy.pullPolicy
+					repository: images.resourceRenderer.fullName
+					tag: images.resourceRenderer.tag
+					pullPolicy: images.resourceRenderer.pullPolicy
+				}
+				kubeRBACProxy: {
+					image: {
+						repository: images.kubeRBACProxy.fullName
+						tag: images.kubeRBACProxy.tag
+						pullPolicy: images.kubeRBACProxy.pullPolicy
+					}
 				}
 			}
 		}
diff --git a/core/installer/values-tmpl/rpuppy.cue b/core/installer/values-tmpl/rpuppy.cue
index 65bfbdb..ab77052 100644
--- a/core/installer/values-tmpl/rpuppy.cue
+++ b/core/installer/values-tmpl/rpuppy.cue
@@ -32,47 +32,49 @@
 
 _httpPortName: "http"
 
-ingress: {
-	rpuppy: {
-		auth: input.auth
-		network: input.network
-		subdomain: input.subdomain
-		service: {
-			name: "rpuppy"
-			port: name: _httpPortName
+out: {
+	ingress: {
+		rpuppy: {
+			auth: input.auth
+			network: input.network
+			subdomain: input.subdomain
+			service: {
+				name: "rpuppy"
+				port: name: _httpPortName
+			}
 		}
 	}
-}
 
-images: {
-	rpuppy: {
-		repository: "giolekva"
-		name: "rpuppy"
-		tag: "latest"
-		pullPolicy: "Always"
+	images: {
+		rpuppy: {
+			repository: "giolekva"
+			name: "rpuppy"
+			tag: "latest"
+			pullPolicy: "Always"
+		}
 	}
-}
 
-charts: {
-	rpuppy: {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/rpuppy"
+	charts: {
+		rpuppy: {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/rpuppy"
+		}
 	}
-}
 
-helm: {
-	rpuppy: {
-		chart: charts.rpuppy
-		info: "Installing rPuppy server"
-		values: {
-			image: {
-				repository: images.rpuppy.fullName
-				tag: images.rpuppy.tag
-				pullPolicy: images.rpuppy.pullPolicy
+	helm: {
+		rpuppy: {
+			chart: charts.rpuppy
+			info: "Installing rPuppy server"
+			values: {
+				image: {
+					repository: images.rpuppy.fullName
+					tag: images.rpuppy.tag
+					pullPolicy: images.rpuppy.pullPolicy
+				}
+				portName: _httpPortName
 			}
-			portName: _httpPortName
 		}
 	}
 }
diff --git a/core/installer/values-tmpl/soft-serve.cue b/core/installer/values-tmpl/soft-serve.cue
index a52ddd7..a6f85c0 100644
--- a/core/installer/values-tmpl/soft-serve.cue
+++ b/core/installer/values-tmpl/soft-serve.cue
@@ -36,36 +36,6 @@
   </g>
 </svg>"""
 
-images: {
-	softserve: {
-		repository: "charmcli"
-		name: "soft-serve"
-		tag: "v0.7.1"
-		pullPolicy: "IfNotPresent"
-	}
-}
-
-charts: {
-	softserve: {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/soft-serve"
-	}
-}
-
-ingress: {
-	gerrit: { // TODO(gio): rename to soft-serve
-		auth: enabled: false
-		network: input.network
-		subdomain: input.subdomain
-		service: {
-			name: "soft-serve"
-			port: number: 80
-		}
-	}
-}
-
 portForward: [#PortForward & {
 	allocator: input.network.allocatePortAddr
 	reservator: input.network.reservePortAddr
@@ -75,22 +45,55 @@
 	targetPort: 22
 }]
 
-helm: {
-	softserve: {
-		chart: charts.softserve
-		info: "Installing SoftServe server"
-		values: {
-			serviceType: "ClusterIP"
-			adminKey: input.adminKey
-			sshPublicPort: input.sshPort
-			ingress: {
-				enabled: false
-				domain: _domain
+
+out: {
+	images: {
+		softserve: {
+			repository: "charmcli"
+			name: "soft-serve"
+			tag: "v0.7.1"
+			pullPolicy: "IfNotPresent"
+		}
+	}
+
+	charts: {
+		softserve: {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/soft-serve"
+		}
+	}
+
+	ingress: {
+		softserve: {
+			auth: enabled: false
+			network: input.network
+			subdomain: input.subdomain
+			service: {
+				name: "soft-serve"
+				port: number: 80
 			}
-			image: {
-				repository: images.softserve.fullName
-				tag: images.softserve.tag
-				pullPolicy: images.softserve.pullPolicy
+		}
+	}
+
+	volumes: data: size: "1Gi"
+
+	helm: {
+		softserve: {
+			chart: charts.softserve
+			info: "Installing SoftServe server"
+			values: {
+				serviceType: "ClusterIP"
+				adminKey: input.adminKey
+				host: _domain
+				sshPublicPort: input.sshPort
+				persistentVolumeClaimName: volumes.data.name
+				image: {
+					repository: images.softserve.fullName
+					tag: images.softserve.tag
+					pullPolicy: images.softserve.pullPolicy
+				}
 			}
 		}
 	}
diff --git a/core/installer/values-tmpl/url-shortener.cue b/core/installer/values-tmpl/url-shortener.cue
index 26f3287..1fa70c4 100644
--- a/core/installer/values-tmpl/url-shortener.cue
+++ b/core/installer/values-tmpl/url-shortener.cue
@@ -2,6 +2,7 @@
     network: #Network @name(Network)
     subdomain: string @name(Subdomain)
 	auth: #Auth @name(Authentication)
+	storageSize: string @name(Storage Size)
 }
 
 _domain: "\(input.subdomain).\(input.network.domain)"
@@ -37,51 +38,53 @@
 
 _httpPortName: "http"
 
-ingress: {
-	"url-shorteners": {
-		auth: input.auth
-		network: input.network
-		subdomain: input.subdomain
-		service: {
-			name: "url-shortener"
-			port: name: _httpPortName
+out: {
+	ingress: {
+		"url-shorteners": {
+			auth: input.auth
+			network: input.network
+			subdomain: input.subdomain
+			service: {
+				name: "url-shortener"
+				port: name: _httpPortName
+			}
 		}
 	}
-}
 
-images: {
-	urlShortener: {
-		repository: "giolekva"
-		name: "url-shortener"
-		tag: "latest"
-		pullPolicy: "Always"
+	images: {
+		urlShortener: {
+			repository: "giolekva"
+			name: "url-shortener"
+			tag: "latest"
+			pullPolicy: "Always"
+		}
 	}
-}
 
-charts: {
-    urlShortener: {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/url-shortener"
-    }
-}
+	charts: {
+		urlShortener: {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/url-shortener"
+		}
+	}
 
-helm: {
-    "url-shortener": {
-        chart: charts.urlShortener
-		info: "Installing server"
-        values: {
-            storage: {
-                size: "1Gi"
-            }
-            image: {
-				repository: images.urlShortener.fullName
-				tag: images.urlShortener.tag
-				pullPolicy: images.urlShortener.pullPolicy
+		volumes: data: size: input.storageSize
+
+	helm: {
+		"url-shortener": {
+			chart: charts.urlShortener
+			info: "Installing server"
+			values: {
+				image: {
+					repository: images.urlShortener.fullName
+					tag: images.urlShortener.tag
+					pullPolicy: images.urlShortener.pullPolicy
+				}
+				portName: _httpPortName
+				persistentVolumeClaimNama: volumes.data.name
+				requireAuth: input.auth.enabled
 			}
-            portName: _httpPortName
-			requireAuth: input.auth.enabled
-        }
-    }
+		}
+	}
 }
diff --git a/core/installer/values-tmpl/vaultwarden.cue b/core/installer/values-tmpl/vaultwarden.cue
index 4b675c5..69ac75f 100644
--- a/core/installer/values-tmpl/vaultwarden.cue
+++ b/core/installer/values-tmpl/vaultwarden.cue
@@ -1,6 +1,7 @@
 input: {
     network: #Network @name(Network)
     subdomain: string @name(Subdomain)
+	storageSize: string
 }
 
 _domain: "\(input.subdomain).\(input.network.domain)"
@@ -30,36 +31,52 @@
   <path class='cls-1' d='m16.59579535,39.68503937c-.31541688,0-.63121702-.07051848-.92555501-.21155543l-1.05816041-.49976138c-.48500615-.2368501-1.24959508-.66149397-2.27996967-1.26396705-1.22238414-.71514934-2.19948662-1.35211514-3.07502717-2.00364455-1.11583992-.82092705-2.19661223-1.72003763-3.20954883-2.67050406-1.0945694-.97882712-2.11363804-2.07876206-3.01753928-3.26071305-.8868465-1.18501701-1.60889438-2.47811126-2.15023867-3.84785602-.57832816-1.42493314-.87515729-2.93341534-.87975632-4.47715678V2.24126116C.00747343,1.01102034,1.01121196.00766505,2.23762026,0h28.73053054c1.23024082.00766505,2.23397936,1.01102034,2.24145278,2.23742863v19.16109658c.00210789,1.56060455-.29472124,3.08671637-.88205584,4.53387816-.53732013,1.38124234-1.26281729,2.6911997-2.15292143,3.88541478-.90620075,1.18501701-1.92526939,2.28571846-3.03382752,3.27757616-1.01025383.92747127-2.09447541,1.80971874-3.21625575,2.6168487-1.1200557.77263722-2.08834337,1.40347099-3.0577808,1.99214697-.71150844.43230892-1.2898366.73661148-1.71198933.95889798-.20983079.11037675-.38651024.20312387-.53042159.28590643l-1.10759999.52582256c-.29203847.13950394-.6063056.21002242-.92095598.21002242ZM30.96431827,1.28006366H2.24145278c-.52505605.00306602-.95813148.43614145-.96138913.96503003v19.20248786c.00421578,1.37740981.26942657,2.72569243.78815895,4.00345657.50167764,1.27009909,1.16796227,2.46278115,1.98256566,3.55198502.85101238,1.11219902,1.8152759,2.15311306,2.86155548,3.08901589.98706705.92593826,2.02836434,1.79208912,3.10607063,2.58465548.83989805.62546823,1.77944178,1.23713937,2.96024302,1.92776054,1.24921182.73124595,1.87947071,1.0646757,2.18798905,1.21567722l1.05336975.49746186c.23934124.11420927.51068408.11420927.7469593.00153301l1.06390919-.5028274c.10941861-.06591945.30047003-.16633162.52754719-.28590643.43039266-.22688553.96579653-.50819294,1.64377037-.92057273.94778366-.57564539,1.89633382-1.19344857,2.98515444-1.94385715,1.07042449-.77033771,2.1147878-1.62039196,3.09399817-2.51873603,1.05471113-.94433439,2.01878303-1.98524843,2.87171167-3.10051347.81632802-1.09610241,1.4858703-2.30488109,1.98486517-3.58724426.5283137-1.3015258.79333286-2.66437202.79160823-4.06017796V2.24279417c-.0044074-.52812207-.43690795-.95966449-.96522165-.96273051Zm-14.35951648,33.14751666c-.11535903,0-.23033481-.03142671-.33208837-.09274713-.19124304-.11650879-.30794346-.32346519-.30794346-.5472847V5.42455718c0-.35335889.28648131-.64003183.64003183-.64003183h11.18024461c.35355052,0,.64003183.28667294.64003183.64003183v15.77237716c.01935426.06132041.02951045.12647336.02951045.1923928,0,3.12887416-2.06649797,6.31983524-6.14219766,9.48473514-1.68688628,1.31915542-3.50848585,2.49114185-5.4122931,3.48146654-.09274713.04828983-.19411744.07205149-.29529612.07205149Zm.64003183-28.3629913v26.64985222c1.49621812-.83932318,2.93245721-1.79592164,4.2805482-2.85063278,3.66581104-2.84603375,5.5638695-5.63534611,5.64626881-8.29358609-.01724637-.05518837-.02663606-.11267626-.02663606-.17169716V6.06458901h-9.90018095Z'/>
 </svg>"""
 
-images: {
-	vaultwarden: {
-		repository: "vaultwarden"
-		name: "server"
-		tag: "1.28.1"
-		pullPolicy: "IfNotPresent"
+out: {
+	ingress: {
+		vaultwarden: {
+			auth: enabled: false
+			network: input.network
+			subdomain: input.subdomain
+			service: {
+				name: "server"
+				port: name: _httpPortName
+			}
+		}
 	}
-}
 
-charts: {
-	vaultwarden: {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/vaultwarden"
+	images: {
+		vaultwarden: {
+			repository: "vaultwarden"
+			name: "server"
+			tag: "1.28.1"
+			pullPolicy: "IfNotPresent"
+		}
 	}
-}
 
-helm: {
-	vaultwarden: {
-		chart: charts.vaultwarden
-		info: "Installing Vaultwarden server"
-		values: {
-			ingressClassName: input.network.ingressClass
-			certificateIssuer: input.network.certificateIssuer
-			domain: _domain
-			image: {
-				repository: images.vaultwarden.fullName
-				tag: images.vaultwarden.tag
-				pullPolicy: images.vaultwarden.pullPolicy
+	charts: {
+		vaultwarden: {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/vaultwarden"
+		}
+	}
+
+	volumes: data: size: input.storageSize
+
+	helm: {
+		vaultwarden: {
+			chart: charts.vaultwarden
+			info: "Installing Vaultwarden server"
+			values: {
+				image: {
+					repository: images.vaultwarden.fullName
+					tag: images.vaultwarden.tag
+					pullPolicy: images.vaultwarden.pullPolicy
+				}
+				domain: _domain
+				persistentVolumeClaimName: volumes.data.name
+				httpPortName: _httpPortName
 			}
 		}
 	}
@@ -69,3 +86,5 @@
 	title: "Access"
 	contents: "Open [\(url)](\(url)) in a new tab."
 }]
+
+_httpPortName: "http"
diff --git a/core/installer/values-tmpl/virtual-machine.cue b/core/installer/values-tmpl/virtual-machine.cue
index 292c082..5b08788 100644
--- a/core/installer/values-tmpl/virtual-machine.cue
+++ b/core/installer/values-tmpl/virtual-machine.cue
@@ -11,62 +11,20 @@
 readme: "Virtual Machine"
 description: "Virtual Machine"
 icon: """
-<svg xmlns="http://www.w3.org/2000/svg" width="50" height="50" viewBox="0 0 2048 2048"><path fill="currentColor" d="M1280 384H640V256h640zm0 1024H640v-128h640zm0 256H640v-128h640zM1408 0q27 0 50 10t40 27t28 41t10 50v1792H384V128q0-27 10-50t27-40t41-28t50-10zm0 128H512v1664h896z"/></svg>"""
+	   <svg xmlns="http://www.w3.org/2000/svg" width="50" height="50" viewBox="0 0 2048 2048"><path fill="currentColor" d="M1280 384H640V256h640zm0 1024H640v-128h640zm0 256H640v-128h640zM1408 0q27 0 50 10t40 27t28 41t10 50v1792H384V128q0-27 10-50t27-40t41-28t50-10zm0 128H512v1664h896z"/></svg>"""
 
-charts: {
-	virtualMachine: {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/virtual-machine"
-	}
-}
-
-helm: {
-	"virtual-machine": {
-		chart: charts.virtualMachine
-		values: {
-			name: input.name
+out: {
+	vm: {
+		"\(input.name)": {
+			username: input.username
+			domain: global.domain
 			cpuCores: input.cpuCores
 			memory: input.memory
-			disk: {
-				source: "https://cloud.debian.org/images/cloud/bookworm-backports/latest/debian-12-backports-generic-amd64.qcow2"
-				size: "64Gi"
+			vpn: {
+				enabled: true
+				loginServer: "https://headscale.\(global.domain)"
+				authKey: input.authKey
 			}
-			ports: [22, 8080]
-			cloudInit: userData: _cloudInitUserData
 		}
 	}
 }
-
-_cloudInitUserData: {
-	system_info: {
-		default_user: {
-			name: input.username
-			home: "/home/\(input.username)"
-		}
-	}
-	password: "dodo" // TODO(gio): remove if possible
-	chpasswd: {
-		expire: false
-	}
-	hostname: input.name
-	ssh_pwauth: true
-	disable_root: false
-	ssh_authorized_keys: [
-		"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOa7FUrmXzdY3no8qNGUk7OPaRcIUi8G7MVbLlff9eB/ lekva@gl-mbp-m1-max.local"
-    ]
-	runcmd: [
-		["sh", "-c", "curl -fsSL https://tailscale.com/install.sh | sh"],
-		// TODO(gio): take auth key from input
-		// TODO(gio): enable tailscale ssh
-		["sh", "-c", "tailscale up --login-server=https://headscale.\(global.domain) --auth-key=\(input.authKey) --accept-routes"],
-		["sh", "-c", "curl -fsSL https://code-server.dev/install.sh | HOME=/home/\(input.username) sh"],
-		["sh", "-c", "systemctl enable --now code-server@\(input.username)"],
-		["sh", "-c", "sleep 10"],
-		// TODO(gio): listen only on tailscale interface
-		["sh", "-c", "sed -i -e 's/127.0.0.1/0.0.0.0/g' /home/\(input.username)/.config/code-server/config.yaml"],
-		["sh", "-c", "sed -i -e 's/auth: password/auth: none/g' /home/\(input.username)/.config/code-server/config.yaml"],
-		["sh", "-c", "systemctl restart --now code-server@\(input.username)"],
-    ]
-}
diff --git a/core/installer/values-tmpl/welcome.cue b/core/installer/values-tmpl/welcome.cue
index 2d68207..6022fb7 100644
--- a/core/installer/values-tmpl/welcome.cue
+++ b/core/installer/values-tmpl/welcome.cue
@@ -11,43 +11,45 @@
 name: "welcome"
 namespace: "app-welcome"
 
-images: {
-	welcome: {
-		repository: "giolekva"
-		name: "pcloud-installer"
-		tag: "latest"
-		pullPolicy: "Always"
+out: {
+	images: {
+		welcome: {
+			repository: "giolekva"
+			name: "pcloud-installer"
+			tag: "latest"
+			pullPolicy: "Always"
+		}
 	}
-}
 
-charts: {
-	welcome: {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/welcome"
+	charts: {
+		welcome: {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/welcome"
+		}
 	}
-}
 
-helm: {
-	welcome: {
-		chart: charts.welcome
-		values: {
-			repoAddr: input.repoAddr
-			sshPrivateKey: base64.Encode(null, input.sshPrivateKey)
-			createAccountAddr: "http://api.\(global.namespacePrefix)core-auth.svc.cluster.local/identities"
-			loginAddr: "https://launcher.\(networks.public.domain)"
-			membershipsAddr: "http://memberships-api.\(global.namespacePrefix)core-auth-memberships.svc.cluster.local"
-			ingress: {
-				className: input.network.ingressClass
-				domain: "welcome.\(input.network.domain)"
-				certificateIssuer: input.network.certificateIssuer
-			}
-			clusterRoleName: "\(global.id)-welcome"
-			image: {
-				repository: images.welcome.fullName
-				tag: images.welcome.tag
-				pullPolicy: images.welcome.pullPolicy
+	helm: {
+		welcome: {
+			chart: charts.welcome
+			values: {
+				repoAddr: input.repoAddr
+				sshPrivateKey: base64.Encode(null, input.sshPrivateKey)
+				createAccountAddr: "http://api.\(global.namespacePrefix)core-auth.svc.cluster.local/identities"
+				loginAddr: "https://launcher.\(networks.public.domain)"
+				membershipsAddr: "http://memberships-api.\(global.namespacePrefix)core-auth-memberships.svc.cluster.local"
+				ingress: {
+					className: input.network.ingressClass
+					domain: "welcome.\(input.network.domain)"
+					certificateIssuer: input.network.certificateIssuer
+				}
+				clusterRoleName: "\(global.id)-welcome"
+				image: {
+					repository: images.welcome.fullName
+					tag: images.welcome.tag
+					pullPolicy: images.welcome.pullPolicy
+				}
 			}
 		}
 	}
diff --git a/core/installer/values-tmpl/zot.cue b/core/installer/values-tmpl/zot.cue
index 35fdbc7..c5cf631 100644
--- a/core/installer/values-tmpl/zot.cue
+++ b/core/installer/values-tmpl/zot.cue
@@ -39,153 +39,155 @@
   </g>
 </svg>"""
 
-ingress: {
-	zot: {
-		auth: enabled: false
-		network: input.network
-		subdomain: input.subdomain
-		service: {
-			name: "zot"
-			port: number: _httpPort // TODO(gio): make optional
+out: {
+	ingress: {
+		zot: {
+			auth: enabled: false
+			network: input.network
+			subdomain: input.subdomain
+			service: {
+				name: "zot"
+				port: number: _httpPort // TODO(gio): make optional
+			}
 		}
 	}
-}
 
-// TODO(gio): configure busybox
-images: {
-	zot: {
-		registry: "ghcr.io"
-		repository: "project-zot"
-		name: "zot-linux-amd64"
-		tag: "v2.0.3"
-		pullPolicy: "IfNotPresent"
-	}
-}
-
-charts: {
-	zot: {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/zot"
-	}
-	oauth2Client: {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/oauth2-client"
-	}
-	resourceRenderer: {
-		kind: "GitRepository"
-		address: "https://code.v1.dodo.cloud/helm-charts"
-		branch: "main"
-		path: "charts/resource-renderer"
-	}
-}
-
-volumes: zot: size: "100Gi"
-
-_httpPort: 80
-_oauth2ClientSecretName: "oauth2-client"
-
-helm: {
-	"oauth2-client": {
-		chart: charts.oauth2Client
-		info: "Creating OAuth2 client"
-		// TODO(gio): remove once hydra maester is installed as part of dodo itself
-		dependsOn: [{
-			name: "auth"
-			namespace: "\(global.namespacePrefix)core-auth"
-		}]
-		values: {
-			name: "\(release.namespace)-zot"
-			secretName: _oauth2ClientSecretName
-			grantTypes: ["authorization_code"]
-			responseTypes: ["code"]
-			scope: "openid profile email groups"
-			redirectUris: ["https://\(_domain)/zot/auth/callback/oidc"]
-			hydraAdmin: "http://hydra-admin.\(global.namespacePrefix)core-auth.svc.cluster.local"
+	// TODO(gio): configure busybox
+	images: {
+		zot: {
+			registry: "ghcr.io"
+			repository: "project-zot"
+			name: "zot-linux-amd64"
+			tag: "v2.0.3"
+			pullPolicy: "IfNotPresent"
 		}
 	}
-	"config-renderer": {
-		chart: charts.resourceRenderer
-		info: "Generating Zot configuration"
-		values: {
-			name: "config-renderer"
-			secretName: _oauth2ClientSecretName
-			resourceTemplate: yaml.Marshal({
-				apiVersion: "v1"
-				kind: "ConfigMap"
-				metadata: {
-					name: _zotConfigMapName
-					namespace: "\(release.namespace)"
-				}
-				data: {
-					"config.json": json.Marshal({
-						storage: rootDirectory: "/var/lib/registry"
-						http: {
-							address: "0.0.0.0"
-							port: "5000"
-							externalUrl: url
-							auth: openid: providers: oidc: {
-								name: "dodo:"
-								issuer: "https://hydra.\(networks.public.domain)"
-								clientid: "{{ .client_id }}"
-								clientsecret: "{{ .client_secret }}"
-								keypath: ""
-								scopes: ["openid", "profile", "email", "groups"]
-							}
-							accessControl: {
-								repositories: {
-									"**": {
-										defaultPolicy: ["read", "create", "update", "delete"]
-										anonymousPolicy: ["read"]
+
+	charts: {
+		zot: {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/zot"
+		}
+		oauth2Client: {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/oauth2-client"
+		}
+		resourceRenderer: {
+			kind: "GitRepository"
+			address: "https://code.v1.dodo.cloud/helm-charts"
+			branch: "main"
+			path: "charts/resource-renderer"
+		}
+	}
+
+	volumes: zot: size: "100Gi"
+
+	_httpPort: 80
+	_oauth2ClientSecretName: "oauth2-client"
+
+	helm: {
+		"oauth2-client": {
+			chart: charts.oauth2Client
+			info: "Creating OAuth2 client"
+			// TODO(gio): remove once hydra maester is installed as part of dodo itself
+			dependsOn: [{
+				name: "auth"
+				namespace: "\(global.namespacePrefix)core-auth"
+			}]
+			values: {
+				name: "\(release.namespace)-zot"
+				secretName: _oauth2ClientSecretName
+				grantTypes: ["authorization_code"]
+				responseTypes: ["code"]
+				scope: "openid profile email groups"
+				redirectUris: ["https://\(_domain)/zot/auth/callback/oidc"]
+				hydraAdmin: "http://hydra-admin.\(global.namespacePrefix)core-auth.svc.cluster.local"
+			}
+		}
+		"config-renderer": {
+			chart: charts.resourceRenderer
+			info: "Generating Zot configuration"
+			values: {
+				name: "config-renderer"
+				secretName: _oauth2ClientSecretName
+				resourceTemplate: yaml.Marshal({
+					apiVersion: "v1"
+					kind: "ConfigMap"
+					metadata: {
+						name: _zotConfigMapName
+						namespace: "\(release.namespace)"
+					}
+					data: {
+						"config.json": json.Marshal({
+							storage: rootDirectory: "/var/lib/registry"
+							http: {
+								address: "0.0.0.0"
+								port: "5000"
+								externalUrl: url
+								auth: openid: providers: oidc: {
+									name: "dodo:"
+									issuer: "https://hydra.\(networks.public.domain)"
+									clientid: "{{ .client_id }}"
+									clientsecret: "{{ .client_secret }}"
+									keypath: ""
+									scopes: ["openid", "profile", "email", "groups"]
+								}
+								accessControl: {
+									repositories: {
+										"**": {
+											defaultPolicy: ["read", "create", "update", "delete"]
+											anonymousPolicy: ["read"]
+										}
 									}
 								}
 							}
-						}
-						log: level: "debug"
-						extensions: {
-							ui: enable: true
-							search: enable: true
-						}
-					})
-				}
-			})
+							log: level: "debug"
+							extensions: {
+								ui: enable: true
+								search: enable: true
+							}
+						})
+					}
+				})
+			}
 		}
-	}
-	zot: {
-		chart: charts.zot
-		info: "Installing Zot server"
-		values: {
-			image: {
-				repository: images.zot.fullName
-				tag: images.zot.tag
-				pullPolicy: images.zot.pullPolicy
-			}
-			service: {
-				type: "ClusterIP"
-				additionalAnnotations: {
-					"metallb.universe.tf/address-pool": global.id
+		zot: {
+			chart: charts.zot
+			info: "Installing Zot server"
+			values: {
+				image: {
+					repository: images.zot.fullName
+					tag: images.zot.tag
+					pullPolicy: images.zot.pullPolicy
 				}
-				port: _httpPort
+				service: {
+					type: "ClusterIP"
+					additionalAnnotations: {
+						"metallb.universe.tf/address-pool": global.id
+					}
+					port: _httpPort
+				}
+				ingress: enabled: false
+				mountConfig: false
+				persistence: true
+				pvc: {
+					create: false
+					name: volumes.zot.name
+				}
+				extraVolumes: [{
+					name: "config"
+					configMap: name: _zotConfigMapName
+				}]
+				extraVolumeMounts: [{
+					name: "config"
+					mountPath: "/etc/zot"
+				}]
+				startupProbe: {}
 			}
-			ingress: enabled: false
-			mountConfig: false
-			persistence: true
-			pvc: {
-				create: false
-				name: volumes.zot.name
-			}
-			extraVolumes: [{
-				name: "config"
-				configMap: name: _zotConfigMapName
-			}]
-			extraVolumeMounts: [{
-				name: "config"
-				mountPath: "/etc/zot"
-			}]
-			startupProbe: {}
 		}
 	}
 }