stack.basicstack.de/apps/vikunja
CTO b2b0d27803 fix(vikunja): set pod FQDN so SMTP EHLO passes Stalwart validation (DEV-563)
Stalwart's port-25 relay rejects bare EHLO labels — needs at least one
dot. Vikunja doesn't call go-mail's WithHELO, so it sends
os.Hostname() as EHLO. Setting hostname/subdomain plus
setHostnameAsFQDN=true makes the pod's kernel hostname a valid FQDN
(vikunja.basicstack.vikunja.svc.cluster.local), which Stalwart
accepts.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-05 10:05:26 +00:00
..
README.md feat(vikunja): enable mailer via port-25 in-cluster relay (DEV-563) 2026-09-05 10:03:07 +00:00
vikunja-app-secrets-sealed.yaml feat(vikunja): deploy Vikunja 2.6.0 with Pocket ID OIDC (DEV-560) 2026-09-05 09:38:25 +00:00
vikunja-db-credentials-sealed.yaml feat(vikunja): deploy Vikunja 2.6.0 with Pocket ID OIDC (DEV-560) 2026-09-05 09:38:25 +00:00
vikunja-db-pvc.yaml feat(vikunja): deploy Vikunja 2.6.0 with Pocket ID OIDC (DEV-560) 2026-09-05 09:38:25 +00:00
vikunja-deployment.yaml fix(vikunja): set pod FQDN so SMTP EHLO passes Stalwart validation (DEV-563) 2026-09-05 10:05:26 +00:00
vikunja-files-pvc.yaml feat(vikunja): deploy Vikunja 2.6.0 with Pocket ID OIDC (DEV-560) 2026-09-05 09:38:25 +00:00
vikunja-ingress.yaml feat(vikunja): deploy Vikunja 2.6.0 with Pocket ID OIDC (DEV-560) 2026-09-05 09:38:25 +00:00
vikunja-oidc-secret-sealed.yaml feat(vikunja): deploy Vikunja 2.6.0 with Pocket ID OIDC (DEV-560) 2026-09-05 09:38:25 +00:00
vikunja-postgres-deployment.yaml feat(vikunja): deploy Vikunja 2.6.0 with Pocket ID OIDC (DEV-560) 2026-09-05 09:38:25 +00:00
vikunja-postgres-service.yaml feat(vikunja): deploy Vikunja 2.6.0 with Pocket ID OIDC (DEV-560) 2026-09-05 09:38:25 +00:00
vikunja-service.yaml feat(vikunja): deploy Vikunja 2.6.0 with Pocket ID OIDC (DEV-560) 2026-09-05 09:38:25 +00:00

Vikunja (vikunja.basicstack.de)

Self-hosted task manager. Unified vikunja/vikunja container (API + frontend on port 3456). Backed by a namespace-local PostgreSQL. OIDC via Pocket ID (auth.basicstack.de); local login disabled.

Layout

File Purpose
vikunja-db-pvc.yaml 10 Gi encrypted PVC for Postgres data
vikunja-files-pvc.yaml 10 Gi encrypted PVC for user-uploaded attachments (/app/vikunja/files)
vikunja-postgres-deployment.yaml Postgres 16, pinned to csi.hetzner.cloud/location=fsn1
vikunja-postgres-service.yaml ClusterIP vikunja-postgres:5432
vikunja-deployment.yaml Vikunja app, pinned to fsn1, waits on Postgres
vikunja-service.yaml ClusterIP vikunja:80 → pod 3456
vikunja-ingress.yaml Traefik + letsencrypt-prod cert
vikunja-db-credentials-sealed.yaml Postgres user password
vikunja-oidc-secret-sealed.yaml Pocket ID client id + secret
vikunja-app-secrets-sealed.yaml Vikunja JWT secret

Node placement

Both the app and Postgres pin to Hetzner location fsn1 because their PVCs live on hcloud-volumes-encrypted (datacenter-local).

OIDC

  • Pocket ID client Vikunja (id cdfff4ee-28ba-4aab-9f47-7e41b4b6b847), callback https://vikunja.basicstack.de/auth/openid/basicstack.
  • Pocket ID groups vikunja_admins and vikunja_members.
  • Vikunja does not map OIDC groups to the admin flag. Promote the first user post-login: kubectl -n vikunja exec deploy/vikunja -- /app/vikunja/vikunja user set-admin --admin <username>.
  • PKCE must be OFF on the Pocket ID client. Vikunja 2.x's OAuth redirect (frontend/src/helpers/redirectToProvider.ts) does not send code_challenge, and the Go backend does not implement PKCE either. With pkceEnabled: true on Pocket ID the flow fails at /authorize with invalid_request … 'code_challenge' parameter is missing. Client is confidential (isPublic: false), so client_secret still authenticates the token exchange.

SMTP

Reminder emails go through Stalwart on stalwart-smtp.stalwart.svc.cluster.local:25 using unauthenticated in-cluster relay. Stalwart's port-25 listener trusts the pod-network CIDR (10.244.0.0/16), so no SMTP AUTH is required and no sealed secret is needed. Envelope-from is vikunja@basicstack.de (the mailbox already exists in Stalwart as principal g).

If a future policy tightens the port-25 CIDR trust, switch to submission on stalwart-smtp:587 with STARTTLS and a vikunja-mailer sealed secret (VIKUNJA_MAILER_USERNAME/VIKUNJA_MAILER_PASSWORD from a secretKeyRef, VIKUNJA_MAILER_AUTHTYPE=plain); creating that secret requires a working Stalwart admin session to (re)set the vikunja principal's password.

Change control

Manifest changes flow through Argo CD (Application: apps/app-vikunja.yaml, auto-sync + prune + selfHeal). Sealed secrets are encrypted against the cluster-active sealed-secrets key.