layered-soul/skills/forgejo-operations/references/self-hosted-setup.md
Sam & Claude 4d8ce07fa7 docs: apply Prettier to current markdown (Sam & Codex)
Normalize markdown formatting after the latest main updates.\n\nChecks: python3 scripts/layered_soul.py validate .; npx --yes prettier@3 --check '**/*.md'; git diff --check.
2026-06-14 01:48:32 +02:00

121 lines
4.8 KiB
Markdown

# Self-Hosted Setup & Codeberg Migration
Workflow for setting up a self-hosted Forgejo instance and migrating repos from Codeberg.
## SSH Setup
Forgejo often runs SSH on a non-standard port (e.g. 2222). Always probe:
```bash
ssh -T git@<host> # port 22 — may return password prompt
ssh -T -p 2222 git@<host> # try 2222
```
Once confirmed, add to `~/.ssh/config`:
```
Host code.<domain>
HostName code.<domain>
User git
Port 2222
IdentityFile ~/.ssh/<key>
IdentitiesOnly yes
```
## Org vs User Namespace
If the admin account name matches the desired org name (e.g. user `clawdie` cannot have org `clawdie`), repos go under the user: `code.<domain>/clawdie/repo`. Same URL structure, same SSH path. Multi-agent audit trail comes from machine users, not org membership.
## Push-to-Create
Usually disabled by default. Check:
```bash
# If push fails with "Push to create is not enabled"
curl -s "https://code.<domain>/api/v1/settings/ui" | jq .
```
Create repos via API or web UI instead.
## Shallow Clone → Push (Codeberg Migration)
Forgejo rejects shallow pushes unless `ALLOW_SHALLOW_UPDATES` is enabled (off by default). For repos cloned shallow from Codeberg:
### Small repos (few commits, full objects present)
```bash
# Check if all objects are present
git fsck --connectivity-only
# Remove shallow marker and rewrite root commit to be parentless
echo "<root-commit> " > .git/info/grafts
git filter-branch -f -- --all
rm .git/info/grafts .git/shallow
```
### Large repos (many objects missing)
```bash
# Fetch full history via HTTPS (more reliable than SSH for large fetches)
git remote set-url origin https://codeberg.org/<owner>/<repo>.git
git fetch --unshallow origin
git remote set-url origin git@codeberg.org:<owner>/<repo>.git # restore
```
## Machine-User Permissions
Pattern for multi-agent git access:
| User | Host | Permissions |
| ---------------- | -------- | ---------------------------------- |
| `<agent>-<host>` | hostname | `write:repository` token + SSH key |
- **Never copy private SSH keys** between hosts.
- Each machine user gets their own SSH key registered on Forgejo.
- Passwords: only needed if agent uses browser to access web UI (e.g. PR review). Others: random, no force-change.
- Encode the permissions table in the repo's AGENTS.md for agent self-discovery.
## Browser-Based Agent Access
Some agents (e.g. Hermes on debby) need web UI access for PR review, issue triage, repo settings, and CI status checks. For these, set a real password (untick "require password change") and store it in Vaultwarden. Other agents (Claude, Codex) only need SSH keys — random passwords are fine.
### Password Rotation via Browser
When admin-created user has "require password change" ticked, the agent can handle first-login rotation:
```bash
# Generate strong password
openssl rand -base64 24
```
Then use browser tools to:
1. Navigate to `https://code.<domain>/user/login`
2. Type username + temp password
3. Forgejo redirects to "Update password" page
4. Type new password in both fields, submit
5. Verify landing on dashboard
Special characters (šđžčć, etc.) work fine in Forgejo passwords.
## Git Hooks Bypass When Node Not on PATH
When `node` isn't on PATH (e.g. in a tool-call shell that doesn't source `.bashrc`), git hooks like `pre-commit` and `prepare-commit-msg` hang with `node: not found`. Workaround:
```bash
GIT_AUTHOR_NAME="Name" GIT_AUTHOR_EMAIL="email" \
GIT_COMMITTER_NAME="Name" GIT_COMMITTER_EMAIL="email" \
git -c core.hooksPath=/dev/null commit -m "message"
```
Use `--no-verify` only for `pre-commit` and `commit-msg`; `core.hooksPath=/dev/null` kills all hooks including `prepare-commit-msg` which otherwise still fires and hangs.
## Pitfalls
- **Forgejo SSH on non-standard port**: always probe port 2222 first. The default port 22 often hits system SSH, not Forgejo's, producing confusing password prompts.
- **Token is immutable**: no edit after creation. Get scopes right on first generate. Wrong scope = new token.
- **Org name collision with username**: Forgejo won't let you create an org named the same as an existing user. Use the user namespace instead.
- **Shallow clones from Codeberg**: unshallow before pushing, or rewrite root commits. Forgejo blocks shallow updates by default.
- **`git fetch --unshallow` timeouts**: Codeberg can be slow. Use HTTPS URL (not SSH) for large unshallow operations — often faster and more reliable.
- **`git filter-branch` grafts are deprecated**: the `echo "<hash> " > .git/info/grafts` + `git filter-branch -f -- --all` pattern works but is deprecated. Prefer `git replace --convert-graft-file` by default.
- **Git hooks hang when `node` not on PATH**: use `-c core.hooksPath=/dev/null` (not just `--no-verify` — that skips pre-commit but not prepare-commit-msg).