blumeops/docs/reference/services/forgejo.md
Erich Blume e6cf7e47e0
All checks were successful
Deploy Fly.io Proxy / deploy (push) Successful in 1m8s
Restrict flyio-proxy ACLs to dedicated tag:flyio-target endpoints (#126)
## Summary
- Introduce `tag:flyio-target` so services must explicitly opt in to be reachable by the fly.io proxy
- Replace broad `tag:k8s` and `tag:homelab` grants with the new tag in the ACL rule and test
- Add `tailscale.com/tags: "tag:k8s,tag:flyio-target"` annotation to docs, loki, and prometheus Ingresses
- Switch Alloy push endpoints from `*.ops.eblu.me` (Caddy) to `*.tail8d86e.ts.net` (Tailscale Ingress)
- Update docs: flyio-proxy, caddy, tailscale, forgejo (future public access + security checklist), expose-service-publicly

## Manual step (not in PR)
Update the k8s operator OAuth client in the Tailscale admin console to include `tag:flyio-target` in its scope. Without this, the operator cannot assign the new tag to Ingress proxy nodes.

## Deployment order
1. **Pulumi ACLs** — `mise run tailnet-preview && mise run tailnet-up`
2. **OAuth client** — Manual update in Tailscale admin console
3. **K8s Ingresses** — `argocd app sync apps && argocd app sync docs loki prometheus`
4. **Fly.io proxy** — `mise run fly-deploy`
5. **Verify** — `mise run services-check`, check Grafana dashboards

## Test plan
- [ ] `mise run tailnet-preview` shows clean diff
- [ ] `argocd app diff docs`, `argocd app diff loki`, `argocd app diff prometheus` show only annotation additions
- [ ] After deploy: Grafana dashboards show continued log/metric flow
- [ ] `curl -sf https://docs.eblu.me` returns 200
- [ ] `mise run services-check` passes

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Reviewed-on: https://forge.ops.eblu.me/eblume/blumeops/pulls/126
2026-02-08 21:54:18 -08:00

3.2 KiB

title tags
Forgejo
service
git
ci-cd

Forgejo

Git forge and CI/CD platform. Primary source of truth for blumeops (mirrored to GitHub).

Quick Reference

Property Value
URL https://forge.ops.eblu.me
SSH ssh://forgejo@forge.ops.eblu.me:2222
Local Ports 3001 (HTTP), 2200 (SSH)
Config ansible/roles/forgejo/templates/app.ini.j2

Repositories

Repo Description
eblume/blumeops Infrastructure as code (primary)
eblume/alloy Grafana Alloy fork (CGO build)
eblume/tesla_auth Tesla OAuth helper
Helm chart mirrors cloudnative-pg-charts, grafana-helm-charts

CI/CD (Forgejo Actions)

Runner: Kubernetes pod with Docker-in-Docker sidecar

  • Namespace: forgejo-runner
  • Labels: k8s
  • ArgoCD app: forgejo-runner

Workflows: .forgejo/workflows/

  • build-container.yaml - Container image builds on tag
  • build-blumeops.yaml - Documentation builds and releases

Secrets (Forgejo Config)

Server configuration secrets managed via 1Password → Ansible:

  • lfs-jwt-secret, internal-token, oauth2-jwt-secret - Forgejo server tokens
  • runner_reg - Runner registration token (also in k8s via external-secrets)

Forgejo Actions Secrets

Repository-level secrets for CI/CD workflows, synced from 1Password via Ansible.

Secret 1Password Field Used By Purpose
ARGOCD_AUTH_TOKEN argocd_token build-blumeops.yaml Sync docs app after release

These secrets are injected as ${{ secrets.SECRET_NAME }} in workflow files.

IaC: The forgejo_actions_secrets Ansible role syncs these secrets from 1Password to Forgejo via the Forgejo API. Run with:

mise run provision-indri -- --tags forgejo_actions_secrets

API Token Setup (Manual, One-Time)

The Ansible role authenticates to the Forgejo API using a Personal Access Token (PAT). This PAT must be created manually:

  1. Go to https://forge.ops.eblu.me/user/settings/applications
  2. Create a new token with write:repository scope
  3. Store it in 1Password → "Forgejo Secrets" item → api-token field

This is a bootstrapping requirement - the PAT enables IaC for all other secrets.

Future: Public Access

Forgejo can be exposed publicly at forge.eblu.me via flyio-proxy. Since Forgejo runs natively on indri (not in k8s), the pattern is:

  1. Create a k8s ExternalName Service pointing to indri's Tailscale IP
  2. Create a Tailscale Ingress with tailscale.com/tags: "tag:k8s,tag:flyio-target"
  3. Add the nginx server block and DNS CNAME

Exposing a dynamic, authenticated service like Forgejo requires a full security review before going live:

  • Disable open user registration (require invites or admin approval)
  • Configure fail2ban on indri with a filter for Forgejo's log format
  • Ensure Forgejo logs the forwarded client IP (X-Real-IP) rather than the proxy's Tailscale IP
  • Audit repository visibility defaults and permissions
  • Rehearse the break-glass shutoff (mise run fly-shutoff)

See expose-service-publicly for the full howto and dynamic service checklist.

  • argocd - Uses Forgejo as git source
  • zot - Container registry for built images