summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-06-19 21:49:02 +0300
committerPaul Buetow <paul@buetow.org>2026-06-19 21:49:02 +0300
commit9e4c0f14ceab7840ed35b49fd63397783b1c311f (patch)
treed43a17e6b24f0df09c08591dc0a544108ae11002
parent61315b40a35c1ebe54619194507ab00657b91a57 (diff)
protonbridge: add k8s helm chart and ArgoCD app manifest
Deploys Proton Bridge (shenxn/protonmail-bridge) as a headless pod in the services namespace. Config persisted on NFS-backed PVC; nfs-sentinel initContainer guards against local-XFS shadow on NFS mount failure. Exposes IMAP (STARTTLS) on NodePort 30143 and SMTP (STARTTLS) on NodePort 30025 for LAN access. Initial ProtonMail authentication is done once via: kubectl exec -it <pod> -n services -- bridge --cli Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
-rw-r--r--f3s/argocd-apps/services/protonbridge.yaml28
-rw-r--r--f3s/protonbridge/helm-chart/Chart.yaml5
-rw-r--r--f3s/protonbridge/helm-chart/templates/deployment.yaml70
-rw-r--r--f3s/protonbridge/helm-chart/templates/persistent-volumes.yaml27
-rw-r--r--f3s/protonbridge/helm-chart/templates/service.yaml24
5 files changed, 154 insertions, 0 deletions
diff --git a/f3s/argocd-apps/services/protonbridge.yaml b/f3s/argocd-apps/services/protonbridge.yaml
new file mode 100644
index 0000000..3be5959
--- /dev/null
+++ b/f3s/argocd-apps/services/protonbridge.yaml
@@ -0,0 +1,28 @@
+apiVersion: argoproj.io/v1alpha1
+kind: Application
+metadata:
+ name: protonbridge
+ namespace: cicd
+ finalizers:
+ - resources-finalizer.argocd.argoproj.io
+spec:
+ project: default
+ source:
+ repoURL: http://git-server.cicd.svc.cluster.local/conf.git
+ targetRevision: master
+ path: f3s/protonbridge/helm-chart
+ destination:
+ server: https://kubernetes.default.svc
+ namespace: services
+ syncPolicy:
+ automated:
+ prune: true
+ selfHeal: true
+ syncOptions:
+ - CreateNamespace=false
+ retry:
+ limit: 3
+ backoff:
+ duration: 5s
+ factor: 2
+ maxDuration: 1m
diff --git a/f3s/protonbridge/helm-chart/Chart.yaml b/f3s/protonbridge/helm-chart/Chart.yaml
new file mode 100644
index 0000000..7f63a13
--- /dev/null
+++ b/f3s/protonbridge/helm-chart/Chart.yaml
@@ -0,0 +1,5 @@
+apiVersion: v2
+name: protonbridge
+description: A Helm chart for deploying Proton Bridge in headless mode.
+version: 0.1.0
+appVersion: "latest"
diff --git a/f3s/protonbridge/helm-chart/templates/deployment.yaml b/f3s/protonbridge/helm-chart/templates/deployment.yaml
new file mode 100644
index 0000000..e32a234
--- /dev/null
+++ b/f3s/protonbridge/helm-chart/templates/deployment.yaml
@@ -0,0 +1,70 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: protonbridge
+ namespace: services
+spec:
+ replicas: 1
+ # Recreate so the old pod fully terminates before the new one starts —
+ # prevents two bridge instances racing for the same config/keychain on NFS.
+ strategy:
+ type: Recreate
+ selector:
+ matchLabels:
+ app: protonbridge
+ template:
+ metadata:
+ labels:
+ app: protonbridge
+ spec:
+ initContainers:
+ - name: nfs-check-data
+ image: busybox:stable
+ command:
+ - sh
+ - -c
+ - |
+ test -f /mnt/.nfs-sentinel || (
+ echo "ERROR: NFS sentinel missing at /mnt/.nfs-sentinel"
+ echo "refusing to start; node likely has NFS unmounted"
+ echo "pod would otherwise bind-mount the local-XFS shadow"
+ exit 1
+ )
+ volumeMounts:
+ - name: protonbridge-data
+ mountPath: /mnt
+ readOnly: true
+ containers:
+ - name: protonbridge
+ # shenxn/protonmail-bridge runs the bridge in headless/noninteractive mode.
+ # On first start, authenticate interactively:
+ # kubectl exec -it <pod> -n services -- bridge --cli
+ # > login
+ # Credentials and session tokens are persisted to the data PVC so
+ # subsequent restarts reconnect automatically without re-login.
+ image: shenxn/protonmail-bridge:latest
+ ports:
+ - name: imap
+ containerPort: 1143
+ protocol: TCP
+ - name: smtp
+ containerPort: 1025
+ protocol: TCP
+ volumeMounts:
+ - name: protonbridge-data
+ # Bridge stores its config (tokens, keychain) under ~/.config/protonmail
+ mountPath: /home/protonmail/.config
+ readinessProbe:
+ tcpSocket:
+ port: 1143
+ initialDelaySeconds: 30
+ periodSeconds: 15
+ livenessProbe:
+ tcpSocket:
+ port: 1143
+ initialDelaySeconds: 60
+ periodSeconds: 30
+ volumes:
+ - name: protonbridge-data
+ persistentVolumeClaim:
+ claimName: protonbridge-data-pvc
diff --git a/f3s/protonbridge/helm-chart/templates/persistent-volumes.yaml b/f3s/protonbridge/helm-chart/templates/persistent-volumes.yaml
new file mode 100644
index 0000000..aa5cffe
--- /dev/null
+++ b/f3s/protonbridge/helm-chart/templates/persistent-volumes.yaml
@@ -0,0 +1,27 @@
+apiVersion: v1
+kind: PersistentVolume
+metadata:
+ name: protonbridge-data-pv
+spec:
+ capacity:
+ storage: 1Gi
+ volumeMode: Filesystem
+ accessModes:
+ - ReadWriteOnce
+ persistentVolumeReclaimPolicy: Retain
+ hostPath:
+ path: /data/nfs/k3svolumes/protonbridge/data
+ type: Directory
+---
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+ name: protonbridge-data-pvc
+ namespace: services
+spec:
+ storageClassName: ""
+ accessModes:
+ - ReadWriteOnce
+ resources:
+ requests:
+ storage: 1Gi
diff --git a/f3s/protonbridge/helm-chart/templates/service.yaml b/f3s/protonbridge/helm-chart/templates/service.yaml
new file mode 100644
index 0000000..3a389bb
--- /dev/null
+++ b/f3s/protonbridge/helm-chart/templates/service.yaml
@@ -0,0 +1,24 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: protonbridge
+ namespace: services
+spec:
+ selector:
+ app: protonbridge
+ type: NodePort
+ ports:
+ - name: imap
+ protocol: TCP
+ port: 1143
+ targetPort: 1143
+ # NodePort 30143 — configure email clients as:
+ # IMAP server: <any-r-vm-lan-ip>:30143, STARTTLS, accept self-signed cert
+ nodePort: 30143
+ - name: smtp
+ protocol: TCP
+ port: 1025
+ targetPort: 1025
+ # NodePort 30025 — configure email clients as:
+ # SMTP server: <any-r-vm-lan-ip>:30025, STARTTLS, accept self-signed cert
+ nodePort: 30025