headscale ingress-private
diff --git a/charts/headscale/templates/config.yaml b/charts/headscale/templates/config.yaml
index 79724fb..5abe533 100644
--- a/charts/headscale/templates/config.yaml
+++ b/charts/headscale/templates/config.yaml
@@ -17,7 +17,7 @@
     #
     # https://myheadscale.example.com:443
     #
-    server_url: https://headscale.{{ .Values.domain }}
+    server_url: https://{{ .Values.domain }}
 
     # Address to listen to / bind to on the server
     #
@@ -252,7 +252,7 @@
       # `base_domain` must be a FQDNs, without the trailing dot.
       # The FQDN of the hosts will be
       # `hostname.namespace.base_domain` (e.g., _myhost.mynamespace.example.com_).
-      base_domain: example.com
+      base_domain: {{ .Values.internalBaseDomain }}
 
     # Unix socket used for the CLI to connect without authentication
     # Note: for production you will want to set this to something like:
diff --git a/charts/headscale/values.yaml b/charts/headscale/values.yaml
index d0766a2..25709ed 100644
--- a/charts/headscale/values.yaml
+++ b/charts/headscale/values.yaml
@@ -7,6 +7,7 @@
 ingressClassName: pcloud-ingress-public
 certificateIssuer: lekva-public
 domain: headscale.example.com
+internalBaseDomain: p.example.com
 oauth2:
   hydraAdmin: http://hydra-admin
   hydraPublic: https://hydra.example.com
diff --git a/core/auth/ui/Makefile b/core/auth/ui/Makefile
index a401141..0bafc13 100644
--- a/core/auth/ui/Makefile
+++ b/core/auth/ui/Makefile
@@ -15,5 +15,6 @@
 build_amd64:
 	go build -o server_amd64 *.go
 
-push: clean build_arm64 build_amd64
-	docker buildx build --tag=giolekva/auth-ui:latest . --platform=linux/arm64,linux/amd64 --push
+push: clean build_arm64 # build_amd64
+	podman build --tag=giolekva/auth-ui:debug .
+	podman push giolekva/auth-ui:debug
diff --git a/core/auth/ui/hydra.go b/core/auth/ui/hydra.go
index 8a0dea0..8775d9e 100644
--- a/core/auth/ui/hydra.go
+++ b/core/auth/ui/hydra.go
@@ -41,9 +41,9 @@
 	req := &http.Request{
 		Method: http.MethodPut,
 		URL: &url.URL{
-			Scheme:   "https",
+			Scheme:   "http",
 			Host:     c.host,
-			Path:     "/oauth2/auth/requests/login/accept",
+			Path:     "/admin/oauth2/auth/requests/login/accept",
 			RawQuery: fmt.Sprintf("login_challenge=%s", challenge),
 		},
 		Header: map[string][]string{
@@ -75,9 +75,9 @@
 	req := &http.Request{
 		Method: http.MethodPut,
 		URL: &url.URL{
-			Scheme:   "https",
+			Scheme:   "http",
 			Host:     c.host,
-			Path:     "/oauth2/auth/requests/login/reject",
+			Path:     "/admin/oauth2/auth/requests/login/reject",
 			RawQuery: fmt.Sprintf("login_challenge=%s", challenge),
 		},
 		Header: map[string][]string{
@@ -110,7 +110,7 @@
 
 func (c *HydraClient) GetConsentChallenge(challenge string) (RequestedConsent, error) {
 	var consent RequestedConsent
-	resp, err := c.httpClient.Get(fmt.Sprintf("https://%s/oauth2/auth/requests/consent?consent_challenge=%s", c.host, challenge))
+	resp, err := c.httpClient.Get(fmt.Sprintf("http://%s/admin/oauth2/auth/requests/consent?consent_challenge=%s", c.host, challenge))
 	if err != nil {
 		return consent, err
 	}
@@ -140,9 +140,9 @@
 	req := &http.Request{
 		Method: http.MethodPut,
 		URL: &url.URL{
-			Scheme:   "https",
+			Scheme:   "http",
 			Host:     c.host,
-			Path:     "/oauth2/auth/requests/consent/accept",
+			Path:     "/admin/oauth2/auth/requests/consent/accept",
 			RawQuery: fmt.Sprintf("challenge=%s", challenge),
 		},
 		Header: map[string][]string{
diff --git a/core/installer/app.go b/core/installer/app.go
index 2b4f08e..e1af152 100644
--- a/core/installer/app.go
+++ b/core/installer/app.go
@@ -80,6 +80,7 @@
 	}
 }
 
+// TODO(gio): service account needs permission to create/update secret
 func CreateAppIngressPrivate(fs embed.FS, tmpls *template.Template) App {
 	schema, err := fs.ReadFile("values-tmpl/ingress-private.jsonschema")
 	if err != nil {
@@ -93,7 +94,7 @@
 			tmpls.Lookup("certificate-issuer.yaml"),
 		},
 		string(schema),
-		nil,
+		tmpls.Lookup("ingress-private.md"),
 	}
 }
 
@@ -124,7 +125,7 @@
 			tmpls.Lookup("vaultwarden.yaml"),
 		},
 		string(schema),
-		nil,
+		tmpls.Lookup("vaultwarden.md"),
 	}
 }
 
diff --git a/core/installer/config.go b/core/installer/config.go
index fa171e8..f234d04 100644
--- a/core/installer/config.go
+++ b/core/installer/config.go
@@ -16,6 +16,7 @@
 	Id                       string `json:"id,omitempty"`
 	ContactEmail             string `json:"contactEmail,omitempty"`
 	Domain                   string `json:"domain,omitempty"`
+	PrivateDomain            string `json:"privateDomain,omitempty"`
 	PublicIP                 string `json:"publicIP,omitempty"`
 	GandiAPIToken            string `json:"gandiAPIToken,omitempty"`
 	NamespacePrefix          string `json:"namespacePrefix,omitempty"`
diff --git a/core/installer/values-tmpl/certificate-issuer.yaml b/core/installer/values-tmpl/certificate-issuer.yaml
index 7cabe94..db2ed7b 100644
--- a/core/installer/values-tmpl/certificate-issuer.yaml
+++ b/core/installer/values-tmpl/certificate-issuer.yaml
@@ -2,7 +2,7 @@
 kind: HelmRelease
 metadata:
   name: certificate-issuer
-  namespace: {{ .Values.NamespacePrefix }}ingress-private
+  namespace: {{ .Global.NamespacePrefix }}ingress-private
 spec:
   chart:
     spec:
@@ -10,28 +10,28 @@
       sourceRef:
         kind: GitRepository
         name: pcloud
-        namespace: {{ .Values.Id }}
+        namespace: {{ .Global.Id }}
   dependsOn:
   - name: ingress-private
-    namespace: {{ .Values.NamespacePrefix }}ingress-private
+    namespace: {{ .Global.NamespacePrefix }}ingress-private
   interval: 1m0s
   values:
-    pcloudInstanceId: {{ .Values.Id }}
+    pcloudInstanceId: {{ .Global.Id }}
     certManager:
-      namespace: {{ .Values.PCloudEnvName }}-cert-manager
-      gandiWebhookSecretReader: {{ .Values.PCloudEnvName }}-cert-manager-webhook-gandi
+      namespace: {{ .Global.PCloudEnvName }}-cert-manager
+      gandiWebhookSecretReader: {{ .Global.PCloudEnvName }}-cert-manager-webhook-gandi
     public:
-      name: {{ .Values.Id }}-public
-      # server: https://acme-v02.api.letsencrypt.org/directory
-      server: https://acme-staging-v02.api.letsencrypt.org/directory
-      domain: {{ .Values.Domain }}
-      contactEmail: {{ .Values.ContactEmail }}
-      ingressClass: {{ .Values.PCloudEnvName }}-ingress-public
+      name: {{ .Global.Id }}-public
+      server: https://acme-v02.api.letsencrypt.org/directory
+      # server: https://acme-staging-v02.api.letsencrypt.org/directory
+      domain: {{ .Global.Domain }}
+      contactEmail: {{ .Global.ContactEmail }}
+      ingressClass: {{ .Global.PCloudEnvName }}-ingress-public
     private:
-      name: {{ .Values.Id }}-private
-      # server: https://acme-v02.api.letsencrypt.org/directory
-      server: https://acme-staging-v02.api.letsencrypt.org/directory
-      domain: p.{{ .Values.Domain }}
-      contactEmail: {{ .Values.ContactEmail }}
-      ingressClassName: {{ .Values.Id }}-ingress-private
+      name: {{ .Global.Id }}-private
+      server: https://acme-v02.api.letsencrypt.org/directory
+      # server: https://acme-staging-v02.api.letsencrypt.org/directory
+      domain: {{ .Global.PrivateDomain }}
+      contactEmail: {{ .Global.ContactEmail }}
+      ingressClassName: {{ .Global.Id }}-ingress-private
       gandiAPIToken: {{ .Values.GandiAPIToken }}
diff --git a/core/installer/values-tmpl/core-auth.yaml b/core/installer/values-tmpl/core-auth.yaml
index a454c3b..1dcdef7 100644
--- a/core/installer/values-tmpl/core-auth.yaml
+++ b/core/installer/values-tmpl/core-auth.yaml
@@ -230,17 +230,15 @@
       secret:
         enabled: true
       maester:
-        enabled: false
-        hydraFullnameOverride: hydra
+        enabled: true
       hydra-maester:
-        fullnameOverride: {{ .Global.Id }}-hydra-maester
+        adminService:
+          name: hydra-admin
+          port: 80
         image:
           repository: giolekva/ory-hydra-maester
           tag: latest
           pullPolicy: IfNotPresent
-        adminService:
-          name: hydra
-          port: 80
       hydra:
         automigration:
           enabled: true
diff --git a/core/installer/values-tmpl/headscale.yaml b/core/installer/values-tmpl/headscale.yaml
index 317eb68..b908419 100644
--- a/core/installer/values-tmpl/headscale.yaml
+++ b/core/installer/values-tmpl/headscale.yaml
@@ -3,6 +3,8 @@
 metadata:
   name: headscale
   namespace: {{ .Global.NamespacePrefix }}app-headscale
+  annotations:
+    version: 2-with-oidc-hydra-admin
 spec:
   chart:
     spec:
@@ -22,3 +24,10 @@
     ingressClassName: pcloud-ingress-public
     certificateIssuer: {{ .Global.Id }}-public
     domain: {{ .Values.Subdomain }}.{{ .Global.Domain }}
+    internalBaseDomain: {{ .Global.PrivateDomain }}
+    oauth2:
+      hydraAdmin: http://hydra-admin.{{ .Global.NamespacePrefix }}core-auth.svc.cluster.local
+      hydraPublic: https://hydra.{{ .Global.Domain }}
+      clientId: headscale
+      secretName: oauth2-client-headscale
+
diff --git a/core/installer/values-tmpl/ingress-private.jsonschema b/core/installer/values-tmpl/ingress-private.jsonschema
index ec6a2c5..c89f310 100644
--- a/core/installer/values-tmpl/ingress-private.jsonschema
+++ b/core/installer/values-tmpl/ingress-private.jsonschema
@@ -1,15 +1,8 @@
 {
   "type": "object",
   "properties": {
-    "Values": {
-      "type": "object",
-      "properties": {
-        "NamespacePrefix": { "type": "string" },
-        "Id": { "type": "string" },
-        "Domain": { "type": "string" }
-      },
-      "additionalProperties": false
-    }
+    "GandiAPIToken": { "type": "string" },
+    "TailscaleAuthKey": { "type": "string" }
   },
   "additionalProperties": false
 }
diff --git a/core/installer/values-tmpl/ingress-private.md b/core/installer/values-tmpl/ingress-private.md
new file mode 100644
index 0000000..35a878f
--- /dev/null
+++ b/core/installer/values-tmpl/ingress-private.md
@@ -0,0 +1 @@
+{{ .Global.PrivateDomain }}
diff --git a/core/installer/values-tmpl/ingress-private.yaml b/core/installer/values-tmpl/ingress-private.yaml
index 760ff96..a0e4246 100644
--- a/core/installer/values-tmpl/ingress-private.yaml
+++ b/core/installer/values-tmpl/ingress-private.yaml
@@ -2,7 +2,7 @@
 kind: HelmRelease
 metadata:
   name: ingress-private
-  namespace: {{ .Values.NamespacePrefix }}ingress-private
+  namespace: {{ .Global.NamespacePrefix }}ingress-private
 spec:
   chart:
     spec:
@@ -10,58 +10,31 @@
       sourceRef:
         kind: GitRepository
         name: pcloud
-        namespace: {{ .Values.Id }}
+        namespace: {{ .Global.Id }}
   interval: 1m0s
   values:
-    fullnameOverride: {{ .Values.Id }}-nginx-private
+    fullnameOverride: {{ .Global.Id }}-nginx-private
     controller:
       service:
         enabled: true
         type: ClusterIP
       ingressClassByName: true
       ingressClassResource:
-        name: {{ .Values.Id }}-ingress-private
+        name: {{ .Global.Id }}-ingress-private
         enabled: true
         default: false
-        controllerValue: k8s.io/{{ .Values.Id }}-ingress-private
+        controllerValue: k8s.io/{{ .Global.Id }}-ingress-private
       extraArgs:
-        default-ssl-certificate: "{{ .Values.Id }}-ingress-private/cert-wildcard.p.{{ .Values.Domain }}"
-      # extraVolumes:
-      # - name: lighthouse-cert
-      #   secret:
-      #     secretName: node-lighthouse-cert
-      # - name: config
-      #   configMap:
-      #     name: lighthouse-config
-      # extraContainers:
-      # - name: lighthouse
-      #   image: giolekva/nebula:latest
-      #   imagePullPolicy: IfNotPresent
-      #   securityContext:
-      #     privileged: true
-      #     capabilities:
-      #       add:
-      #       - NET_ADMIN
-      #   ports:
-      #   - name: nebula
-      #     containerPort: {{ .Values.LighthouseMainPort }}
-      #     protocol: UDP
-      #   command:
-      #   - nebula
-      #   - --config=/etc/nebula/config/lighthouse.yaml
-      #   volumeMounts:
-      #   - name: lighthouse-cert
-      #     mountPath: /etc/nebula/lighthouse
-      #   - name: config
-      #     mountPath: /etc/nebula/config
-      # config:
-      #   bind-address: {{ .Values.LighthouseMainIP }}
-      #   proxy-body-size: 0
-    # udp:
-    #   "53": "{{ .Values.NamespacePrefix }}app-pihole/pihole-dns-udp:53"
-    # tcp:
-    #   "53": "{{ .Values.NamespacePrefix }}app-pihole/pihole-dns-tcp:53"
-    #   "143": "{{ .Values.NamespacePrefix }}app-maddy/maddy:143"
-    #   "465": "{{ .Values.NamespacePrefix }}app-maddy/maddy:465"
-    #   "587": "{{ .Values.NamespacePrefix }}app-maddy/maddy:587"
-    #   "993": "{{ .Values.NamespacePrefix }}app-maddy/maddy:993"
+        default-ssl-certificate: "{{ .Global.Id }}-ingress-private/cert-wildcard.p.{{ .Global.Domain }}"
+      extraContainers:
+      - name: tailscale
+        image: tailscale/tailscale:v1.42.0
+        imagePullPolicy: IfNotPresent
+        securityContext:
+          privileged: true
+          capabilities:
+            add:
+            - NET_ADMIN
+        env:
+        - name: TS_EXTRA_ARGS
+          value: --hostname={{ .Global.PCloudEnvName }}-ingress --login-server=headscale.{{ .Global.Domain }} # TODO(gio): take headscale subdomain from configuration
diff --git a/core/installer/values-tmpl/vaultwarden.jsonschema b/core/installer/values-tmpl/vaultwarden.jsonschema
index ec6a2c5..88c96cb 100644
--- a/core/installer/values-tmpl/vaultwarden.jsonschema
+++ b/core/installer/values-tmpl/vaultwarden.jsonschema
@@ -1,15 +1,7 @@
 {
   "type": "object",
   "properties": {
-    "Values": {
-      "type": "object",
-      "properties": {
-        "NamespacePrefix": { "type": "string" },
-        "Id": { "type": "string" },
-        "Domain": { "type": "string" }
-      },
-      "additionalProperties": false
-    }
+    "Subdomain": { "type": "string", "default": "vaultwarden" }
   },
   "additionalProperties": false
 }
diff --git a/core/installer/values-tmpl/vaultwarden.md b/core/installer/values-tmpl/vaultwarden.md
new file mode 100644
index 0000000..ab9d05d
--- /dev/null
+++ b/core/installer/values-tmpl/vaultwarden.md
@@ -0,0 +1 @@
+Installs vaultwarden on private network accessible at https://{{ .Values.Subdomain }}.{{ .Global.PrivateDomain }}
diff --git a/core/installer/values-tmpl/vaultwarden.yaml b/core/installer/values-tmpl/vaultwarden.yaml
index 32d66e7..c35a45b 100644
--- a/core/installer/values-tmpl/vaultwarden.yaml
+++ b/core/installer/values-tmpl/vaultwarden.yaml
@@ -2,7 +2,7 @@
 kind: HelmRelease
 metadata:
   name: vaultwarden
-  namespace: {{ .Values.NamespacePrefix }}app-vaultwarden
+  namespace: {{ .Global.NamespacePrefix }}app-vaultwarden
 spec:
   chart:
     spec:
@@ -10,10 +10,10 @@
       sourceRef:
         kind: GitRepository
         name: pcloud
-        namespace: {{ .Values.Id }}
+        namespace: {{ .Global.Id }}
   dependsOn:
     - name: namespaces
-      namespace: {{ .Values.Id }}
+      namespace: {{ .Global.Id }}
   interval: 1m0s
   values:
     image:
@@ -22,6 +22,6 @@
       pullPolicy: IfNotPresent
     storage:
       size: 1Gi
-    domain: bitwarden.p.{{ .Values.Domain }}
-    certificateIssuer: {{ .Values.Id }}-private
-    ingressClassName: {{ .Values.Id }}-ingress-private
+    domain: {{ .Values.Subdomain }}.{{ .Global.PrivateDomain }}
+    certificateIssuer: {{ .Global.Id }}-private
+    ingressClassName: {{ .Global.Id }}-ingress-private