## Summary Expose Forgejo publicly at `forge.eblu.me` via the Fly.io reverse proxy — the first dynamic, authenticated public-facing service. - **Forgejo hardening:** Domain changed to forge.eblu.me, SSH stays on forge.ops.eblu.me, reverse proxy trust headers configured, local registration locked to external-only (Authentik SSO) - **Tailscale Ingress:** ExternalName Service + Ingress in tailscale-operator creates forge.tail8d86e.ts.net endpoint - **Fly.io proxy:** nginx server block with rate-limited auth endpoints (3r/s), fail2ban with custom nginx-deny action, security headers, /swagger blocked, WebSocket support, 512m body limit - **Authentik:** OAuth callback updated to forge.eblu.me - **DNS/TLS:** CNAME record in Pulumi, cert in fly-setup - **Rename:** ~29 files updated from forge.ops.eblu.me to forge.eblu.me (HTTPS refs only; SSH, container builds, and Caddy table kept as-is) ## Deployment Order 1. `mise run provision-indri -- --tags forgejo` (config changes) 2. Verify forge.ops.eblu.me still works 3. `argocd app set tailscale-operator --revision feature/forge-public && argocd app sync tailscale-operator` 4. Verify `curl https://forge.tail8d86e.ts.net` 5. `cd fly && fly deploy` 6. Verify pre-DNS: `curl -H "Host: forge.eblu.me" https://blumeops-proxy.fly.dev/` 7. `fly certs add forge.eblu.me -a blumeops-proxy` 8. `argocd app set authentik --revision feature/forge-public && argocd app sync authentik` 9. `mise run dns-preview && mise run dns-up` 10. Full verification (see below) 11. Rehearse `mise run fly-shutoff` 12. After merge: reset ArgoCD revisions to main, re-sync ## Verification Checklist - [ ] forge.eblu.me loads, shows public repos - [ ] forge.ops.eblu.me still works from tailnet - [ ] SSH clone via forge.ops.eblu.me:2222 works - [ ] HTTPS clone via forge.eblu.me works - [ ] UI shows forge.eblu.me for HTTPS clone, forge.ops.eblu.me for SSH - [ ] /swagger returns 403 - [ ] Rapid login attempts trigger 429 rate limit - [ ] fail2ban bans after 5 failed logins in 10 minutes - [ ] ArgoCD can still sync (SSH unaffected) - [ ] `mise run fly-shutoff` stops all public traffic - [ ] `mise run services-check` passes Reviewed-on: #278
4.1 KiB
| title | modified | tags | ||
|---|---|---|---|---|
| Contributing | 2026-02-07 |
|
Your First Contribution
Audiences: Contributor
This tutorial walks through making your first contribution to BluemeOps - from understanding the codebase to submitting a pull request.
Prerequisites
Before contributing, you'll need:
- Access to the tailscale network (request from Erich)
- SSH key added to forgejo (https://forge.eblu.me)
- Development tools installed (see below)
Tooling Setup
The repo includes a Brewfile and mise.toml for easy setup, but these are optional - install the tools however you prefer.
Required Tools
tea- Gitea/Forgejo CLI for creating PRsargocd- ArgoCD CLI for deploymentsprek- Git hooks for validation
Using Brewfile (Optional)
brew bundle # installs tea, argocd, mise, etc.
Using Mise (Optional)
Mise manages language toolchains and runs tasks:
mise install # installs Python, Node.js, etc. from mise.toml
Git Hooks (prek)
Git hooks validate changes on git commit:
prek install
prek run --all-files # verify setup
All hooks should pass on a fresh clone.
Understanding the Codebase
BlumeOps manages infrastructure through three main systems:
| System | Directory | What It Manages |
|---|---|---|
| Ansible | ansible/ |
Services running directly on indri |
| ArgoCD | argocd/ |
Kubernetes services in the cluster |
| Pulumi | pulumi/ |
[[tailscale |
Most contributions involve either Ansible roles or ArgoCD manifests.
The Contribution Workflow
1. Clone and Branch
git clone ssh://git@forge.ops.eblu.me:2222/eblume/blumeops.git
cd blumeops
git checkout -b feature/your-change-name
2. Make Your Changes
Depending on what you're changing:
For Kubernetes services:
- Edit manifests in
argocd/manifests/<service>/ - Or create new Application in
argocd/apps/ - For new apps, set
targetRevisionto your feature branch for testing - For existing apps, you'll need to temporarily change the revision via
argocd app set
For Indri services:
- Edit or create roles in
ansible/roles/ - Update
ansible/playbooks/indri.ymlif adding a role
For documentation:
- Edit files in
docs/ - Add changelog fragment (see below)
3. Add a Changelog Fragment
For user-visible changes:
echo "Description of your change" > docs/changelog.d/your-branch.feature.md
Fragment types (file suffix):
.feature.md- New functionality.bugfix.md- Bug fixes.infra.md- Infrastructure changes.doc.md- Documentation.misc.md- Other
4. Test Your Changes
Before pushing, always test:
For Kubernetes changes:
# Preview what will change
argocd app diff <service>
For DNS changes:
mise run dns-preview
5. Commit and Push
git add <files>
git commit -m "Brief description of change"
git push -u origin feature/your-change-name
6. Create a Pull Request
tea pr create --title "Your PR Title" --description "$(cat <<'EOF'
## Summary
- What you changed
- Why you changed it
## Deployment and Testing
- [ ] Tested locally / dry run
- [ ] Ready for ArgoCD sync / Ansible apply
EOF
)"
7. Wait for Review
Erich will review your PR and may leave comments. Check for feedback:
mise run pr-comments <pr_number>
Address each comment, then Erich will:
- Approve the changes
- Deploy them (you don't need to do this)
- Merge the PR
Example: Adding a Homepage Link
A simple first contribution - adding a service to the Homepage dashboard (go.ops.eblu.me):
- Find the service's Ingress in
argocd/manifests/<service>/ - Add homepage annotations:
annotations:
gethomepage.dev/enabled: "true"
gethomepage.dev/name: "Service Name"
gethomepage.dev/group: "Apps"
gethomepage.dev/icon: "service.png"
- Create PR and wait for sync
Related
- adding-a-service - Full tutorial on deploying a new service
- replicating-blumeops - If you want to build your own instead