--- # gitea-proxy — nginx CF Access header-injecting proxy # # act_runner cannot add custom HTTP headers, so it can't send the # CF-Access-Client-Id / CF-Access-Client-Secret headers that Cloudflare # Access requires for service-to-service access to git.neuralplatform.ai. # # This proxy sits in the ci namespace. Runners use: # GITEA_INSTANCE_URL: http://gitea-proxy.ci.svc.cluster.local:3000 # # nginx:alpine processes *.conf.template files in /etc/nginx/templates/ via # envsubst at startup — so CF Access credentials come from the Secret as env # vars and get interpolated into the nginx config before nginx starts. apiVersion: v1 kind: ConfigMap metadata: name: gitea-proxy-config namespace: ci data: # Placed at /etc/nginx/templates/default.conf.template — nginx:alpine # runs envsubst on this and writes the result to /etc/nginx/conf.d/default.conf default.conf.template: | server { listen 3000; location / { proxy_pass https://git.neuralplatform.ai; # Inject CF Access service-token headers so Cloudflare lets # the request through without interactive auth. proxy_set_header CF-Access-Client-Id "${CF_ACCESS_CLIENT_ID}"; proxy_set_header CF-Access-Client-Secret "${CF_ACCESS_CLIENT_SECRET}"; # Send SNI so Cloudflare routes the TLS connection correctly. proxy_ssl_server_name on; # Preserve Host so Gitea/CF edge routes correctly. proxy_set_header Host git.neuralplatform.ai; # Forward all original request headers (auth tokens, etc). proxy_pass_request_headers on; # Rewrite Location headers in redirects back to the proxy URL. proxy_redirect https://git.neuralplatform.ai/ http://gitea-proxy.ci.svc.cluster.local:3000/; # Standard proxy headers. proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto http; # Allow large request bodies (git push payloads). client_max_body_size 512m; } } --- # ExternalSecret — CF Access service token for the proxy apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: name: gitea-proxy-secret namespace: ci annotations: force-sync: "2026-05-05-sni-fix" spec: refreshInterval: 1h secretStoreRef: name: vault kind: ClusterSecretStore target: name: gitea-proxy-secret creationPolicy: Owner data: - secretKey: CF_ACCESS_CLIENT_ID remoteRef: key: secret/data/gitea-runner-cf-access property: client_id - secretKey: CF_ACCESS_CLIENT_SECRET remoteRef: key: secret/data/gitea-runner-cf-access property: client_secret --- # Deployment apiVersion: apps/v1 kind: Deployment metadata: name: gitea-proxy namespace: ci labels: app: gitea-proxy spec: replicas: 1 selector: matchLabels: app: gitea-proxy template: metadata: labels: app: gitea-proxy annotations: config-version: "2026-05-05-sni-fix" spec: containers: - name: nginx image: nginx:alpine ports: - containerPort: 3000 volumeMounts: - name: config-template mountPath: /etc/nginx/templates envFrom: - secretRef: name: gitea-proxy-secret resources: requests: cpu: 50m memory: 32Mi limits: cpu: 200m memory: 64Mi volumes: - name: config-template configMap: name: gitea-proxy-config --- # Service — ClusterIP reachable by all runner pods as gitea-proxy.ci:3000 apiVersion: v1 kind: Service metadata: name: gitea-proxy namespace: ci spec: selector: app: gitea-proxy ports: - port: 3000 targetPort: 3000