Move 21 blumeops-tagged zettelkasten cards from ~/code/personal/zk/ to docs/ in this repository. These files are symlinked back into the zk at ~/code/personal/zk/blumeops for seamless obsidian.nvim integration. This enables: - Git-managed documentation in the blumeops repo - Preserved wiki links between blumeops docs - obsidian-sync isolation (docs don't sync to other devices) - Direct editing via obsidian.nvim with the blumeops workspace Also updates zk-docs mise task to read from local docs/ directory. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
5.2 KiB
| id | aliases | tags | |||||||
|---|---|---|---|---|---|---|---|---|---|
| 1768246525-RVRY |
|
|
Mon Jan 12 11:35
❯ brew install forgejo
❯ brew --prefix forgejo
/opt/homebrew/opt/forgejo
❯ brew services start forgejo
==> Successfully started `forgejo` (label: homebrew.mxcl.forgejo)
From the service definition I can see that this runs as:
/opt/homebrew/opt/forgejo/bin/forgejo web --work-path /opt/homebrew/var/forgejo > /opt/homebrew/var/log/forgejo.log 2> /opt/homebrew/var/log/forgejo.log
It sounds from the docs like this means the config file should live at:
/opt/homebrew/var/forgejo/custom/conf/app.ini
Ah, based on the logs, it looks like forgejo has picked port 3000 which is used by grafana:
❯ lsof -nP -iTCP:3000 -sTCP:LISTEN
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
grafana 1530 erichblume 15u IPv6 0x4acfad8b21dcb063 0t0 TCP *:3000 (LISTEN)
Ok I've set a basic config for port 3001, and then gone through the basic app setup. Looks like it's working! Not sure how SSH works yet though. Let's get this service registered.
Ok so the next issue is that I want to use ssh as my primary git interface, and I want that to look to users like I'm using port 22 but I want to host it on indri which has its own separate ssh setup. Hmm. Let's tell forgejo to use port 2200. Ah perfect, we can set SSH_PORT to 22 and SSH_LISTEN_PORT to 2200.
Hmm, let's stop running this as me and run as a new user, 'forgejo'.
sudo sysadminctl -addUser forgejo -system -shell /usr/bin/false
sudo chown -R forgejo:staff /opt/homebrew/var/forgejo
Ok, I think I need to switch all my services on this host over to a services file.
Wow, missing from the above is like 4 hours of deep diving in to the particulars of tailscale service definition hosting. In the end, I never got a services file to work - and yes, I did remember to advertise! Adding to the complexity is that I didn't discover until the end that you can't do "hairpinning", ie you CANNOT use the tailnet service name from the host doing that hosting. I probably had it fixed at some point hours ago and ruled it out because I didn't know about the hairpinning issue. So anyway... what ended up working was to just use the cli:
tailscale serve --service="svc:forge" --tcp=22 tcp://localhost:2200
tailscale serve --service="svc:forge" --https=443 http://localhost:3001
That's it. Nothing else needed, worked right away. Sheesh. (Ok there was also a
solid hour spent on permission issues... I honestly don't know how it's working
now, as there is now a forgejo user and the config says to use it but the
files are all owned by erichblume:staff but with group permissions set... in
any case, it friggin' works. So I'm happy.
Configuration (Ansible-Managed)
As of 2026-01-23, the app.ini is managed by ansible:
- Template:
ansible/roles/forgejo/templates/app.ini.j2 - Secrets fetched from 1Password in playbook pre_tasks
- Secrets item: "Forgejo Secrets" in blumeops vault (fields:
lfs-jwt-secret,internal-token,oauth2-jwt-secret,runner_reg)
Deploy config changes:
mise run provision-indri -- --tags forgejo
Forgejo Actions (CI/CD)
Runner (k8s)
The Forgejo runner runs in Kubernetes with Docker-in-Docker (DinD) for container builds.
Architecture:
- Runner daemon + DinD sidecar in a single pod
- Jobs execute in containers using the
k8slabel - DinD exposes Docker API on
tcp://127.0.0.1:2375 - Pods reach
*.ops.eblu.meservices via Caddy reverse proxy
Components:
- ArgoCD app:
argocd/apps/forgejo-runner.yaml - Manifests:
argocd/manifests/forgejo-runner/ - Job image:
registry.ops.eblu.me/blumeops/forgejo-runner(Node.js + Docker CLI) - Job image source:
containers/forgejo-runner/
Deployment:
# Apply secret (contains runner token from 1Password)
op inject -i argocd/manifests/forgejo-runner/secret.yaml.tpl | kubectl --context=minikube-indri apply -f -
# Sync via ArgoCD
argocd app sync forgejo-runner
View logs:
kubectl --context=minikube-indri logs -n forgejo-runner -l app=forgejo-runner -c runner
Container Build Workflow
Container images are built via .forgejo/workflows/build-container.yaml, triggered by tags matching <container>-v<version>.
Release a container:
mise run container-list # See available containers
mise run container-tag-and-release nettest v1.0.0 # Tag and trigger build
Test container (containers/nettest/): Network connectivity test for debugging CI/CD.
Workflows
Workflows live in .forgejo/workflows/ (not .github/workflows/).
Important: Use github.* context variables, not gitea.*. Forgejo supports both at runtime, but:
- The Forgejo web UI schema validator only recognizes
github.* actionlintpre-commit hook validates workflows locally (catches errors before push)- Pass untrusted inputs (like
github.head_ref) through env vars for security
Runner Token
Stored in 1Password "Forgejo Secrets" item, field runner_reg.
To create a new token:
- Go to https://forge.ops.eblu.me/admin/actions/runners
- Click "Create new Runner"
- Copy the token and update 1Password