--- id: FORGE-WP-0005 type: workplan title: "Remove public Gitea NodePort side door" domain: railiance repo: railiance-forge status: finished owner: codex topic_slug: railiance planning_priority: high created: "2026-06-14" updated: "2026-06-14" state_hub_workstream_id: "d6af707c-d9b1-463b-b24e-b384c5fb390d" --- # Remove public Gitea NodePort side door ## Context After `FORGE-WP-0004`, `https://gitea.coulomb.social/` is the canonical public Gitea endpoint. The legacy `default/gitea` Service still exposed HTTP through NodePort `32166`, which made `http://92.205.130.254:32166/` look like a second Gitea entry point. It reached the same pod and database, but it bypassed the canonical HTTPS host and created operator confusion. ## T01 - Make the HTTP Service internal-only ```task id: FORGE-WP-0005-T01 status: done priority: high state_hub_task_id: "1ab4f7d0-0eef-4618-84d9-a84d72db9629" ``` Set the non-secret Gitea Helm overlay to `service.http.type: ClusterIP` so the chart-supported `gitea-http` Service stays internal-only and the web/API surface is only public through the forge-owned HTTPS ingress. Keep Git SSH exposure separate and unchanged. ## T02 - Reconcile live Gitea and verify the side door is gone ```task id: FORGE-WP-0005-T02 status: done priority: high state_hub_task_id: "34a9759e-10f1-4202-b8e9-443265495022" ``` Apply a pinned chart `--reuse-values` Helm reconciliation that keeps the chart-supported HTTP service internal-only while preserving the existing Gitea app version and HTTPS `ROOT_URL`. Move the ingress backend to `gitea-http`, then delete the legacy `default/gitea` NodePort Service because it is no longer part of the current chart's supported public endpoint model. Verify: - `default/gitea` is absent and `default/gitea-http` is internal-only; - `http://92.205.130.254:32166/` is no longer reachable; - `https://gitea.coulomb.social/` still returns `200`; - `/api/v1/version` still returns the live Gitea version; - `/v2/` still returns the OCI authentication challenge; - the package-specific PyPI simple index for `issue-core` still returns `200`. Completed on 2026-06-14. A pinned Helm `--reuse-values` reconciliation kept chart `gitea-12.5.0`, app `1.25.4`, and `gitea.config.server.ROOT_URL=https://gitea.coulomb.social/` while setting `service.http.type=ClusterIP`. The forge ingress backend was moved from the legacy `gitea` Service to the chart-supported internal `gitea-http` Service, then the legacy `default/gitea` NodePort Service was deleted. Verification evidence: - `kubectl get svc -n default -l app.kubernetes.io/instance=gitea` lists `gitea-http` as `ClusterIP`, `gitea-ssh` as `ClusterIP`, and `gitea-ssh-nodeport` for Git SSH only; the legacy `gitea` Service is absent; - `http://92.205.130.254:32166/` timed out; - `https://gitea.coulomb.social/` returned `200`; - `https://gitea.coulomb.social/api/v1/version` returned `200`; - `https://gitea.coulomb.social/v2/` returned `401`, preserving the OCI auth challenge; - `https://gitea.coulomb.social/api/packages/coulomb/pypi/simple/issue-core/` returned `200`. ## T03 - Sync State Hub and record closure evidence ```task id: FORGE-WP-0005-T03 status: done priority: medium state_hub_task_id: "0f9f6b29-aeef-4558-a5f8-d1039a136224" ``` Run State Hub consistency sync for `railiance-forge`, record a progress note, and keep the repo docs clear that raw HTTP NodePort access is not a supported Gitea entry point. Completed on 2026-06-14 after live verification.