Files
felhom.eu/manifests/contact-mailer.yaml
T
adminandClaude Opus 5.5 c28ce7ce2f
gates / gates (push) Successful in 3m25s
R-1228: retire DooPlex's copy of the website (operator yes); the installer pin moves to INSTALLER-TAG
- INSTALLER-TAG (one line) is the only installer pin; publish-site-cloudflare.sh reads it.
- hostinstall gate 6c: pin file holds one tag, no manifest pins one, publish script takes
  the site from origin/main and scripts/ from the tag. Red seen on five mutants.
- manifests: webpage.yaml keeps only FileBrowser; contact-mailer.yaml loses the old
  felhom.eu/api Ingress (an orphan: glued to the next doc by a `80---` typo).
- R-110 fence text, manifests/website rules, build skill, runbooks, poster facts updated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-11-07 23:10:21 +01:00

148 lines
4.9 KiB
YAML

# Contact Mailer - Lightweight email sender for felhom.eu contact form
# Uses Resend.com API for transactional email delivery.
#
# PREREQUISITES:
# 1. Build and push the container image:
# docker build -t contact-mailer:latest .
# # Option A: Push to Gitea registry (if configured):
# # docker tag contact-mailer:latest gitea.felhom.eu/felhom/contact-mailer:latest
# # docker push gitea.felhom.eu/felhom/contact-mailer:latest
# # Option B: Import directly into k3s (single node):
# # docker save contact-mailer:latest | sudo k3s ctr images import -
#
# 2. The Resend API key comes from the out-of-band Secret/resend-api (NOT committed).
# Create it per documentation/runbooks/secrets.md — the key comes from the CC secret store through `sec run`,
# and the pipe into `kubectl apply` stays INSIDE `sec run` (it masks its own output):
# sec run --file RESEND_API -- sh -c 'kubectl create secret generic resend-api -n felhom-system \
# --from-file=RESEND_API_KEY="$RESEND_API_FILE" --dry-run=client -o yaml | sudo kubectl apply -f -'
#
# 3. Apply this manifest:
# kubectl apply -f contact-mailer.yaml
#
# 4. Test:
# # Health check:
# curl https://felhom.eu/api/healthz
# # Send test email (only works if DEBUG=true):
# curl -X POST https://felhom.eu/api/debug/test
#
# 5. Update contact form endpoint in kapcsolat.html:
# CONFIG.formEndpoint = '/api/contact';
#
# DEBUGGING:
# kubectl logs -n felhom-system deploy/contact-mailer -f
# kubectl exec -it -n felhom-system deploy/contact-mailer -- wget -qO- http://localhost:8080/healthz
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: contact-mailer
namespace: felhom-system
labels:
app: contact-mailer
spec:
replicas: 1
selector:
matchLabels:
app: contact-mailer
template:
metadata:
labels:
app: contact-mailer
spec:
containers:
- name: contact-mailer
image: contact-mailer:latest
# Use 'Never' for locally imported images, 'Always' for registry
imagePullPolicy: Never
ports:
- containerPort: 8080
env:
# Resend API key — injected from the shared out-of-band Secret/resend-api (NOT committed).
# See documentation/runbooks/secrets.md.
- name: RESEND_API_KEY
valueFrom:
secretKeyRef:
name: resend-api
key: RESEND_API_KEY
- name: FROM_EMAIL
value: "Felhom.eu <noreply@felhom.eu>"
- name: TO_EMAIL
value: "info@felhom.eu"
- name: ALLOWED_ORIGIN
value: "https://felhom.eu"
- name: TZ
value: "Europe/Budapest"
# Set to "true" to enable /debug/test endpoint
- name: DEBUG
value: "false"
resources:
requests:
memory: "16Mi"
cpu: "5m"
limits:
memory: "64Mi"
cpu: "100m"
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 5
periodSeconds: 30
readinessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 3
periodSeconds: 10
securityContext:
runAsNonRoot: true
runAsUser: 1000
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
---
apiVersion: v1
kind: Service
metadata:
name: contact-mailer
namespace: felhom-system
spec:
selector:
app: contact-mailer
ports:
- port: 80
targetPort: 8080
---
# D35 / R-1228 (operator yes 2026-10-30): the website moves to Cloudflare Pages, which cannot run this mailer. The form
# posts here instead (website `formEndpoint` = https://api.felhom.eu/api/contact); the mailer's CORS already answers
# for https://felhom.eu and https://www.felhom.eu. DNS: api.felhom.eu CNAME → the home line, NOT proxied (HTTP-01).
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: contact-mailer-api
namespace: felhom-system
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/proxy-body-size: "25m"
nginx.ingress.kubernetes.io/proxy-read-timeout: "60"
nginx.ingress.kubernetes.io/proxy-send-timeout: "60"
# Only the form's one route is published here, and a client gets at most 20 requests a minute (the form sends a
# CORS preflight plus one POST per message).
nginx.ingress.kubernetes.io/limit-rpm: "20"
spec:
ingressClassName: nginx-internal
tls:
- hosts:
- api.felhom.eu
secretName: felhom-api-tls
rules:
- host: api.felhom.eu
http:
paths:
- path: /api/contact
pathType: Exact
backend:
service:
name: contact-mailer
port:
number: 80