All checks were successful
Reindex Knowledge Base / reindex (push) Successful in 3s
Adds title, description, type, domain, and tags frontmatter to every doc for improved KB semantic search. The description field is prepended to every search chunk, and domain/type/tags enable filtered queries. Type values: context, guide, runbook, reference, troubleshooting Domain values match directory structure (networking, docker, etc.) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
500 lines
14 KiB
Markdown
500 lines
14 KiB
Markdown
---
|
|
title: "Gitea Server Setup and Config"
|
|
description: "Complete setup and configuration reference for the self-hosted Gitea instance on LXC 225 (10.10.0.225). Covers service management, Gitea Actions CI/CD runner setup, shared composite actions, branch protection, backup/restore, and troubleshooting."
|
|
type: reference
|
|
domain: server-configs
|
|
tags: [gitea, git, ci-cd, gitea-actions, lxc, postgresql, docker-runner, branch-protection]
|
|
---
|
|
|
|
# Gitea - Self-Hosted Git Server
|
|
|
|
**LXC 225** | **10.10.0.225** | **git.manticorum.com**
|
|
|
|
Self-hosted Git server with web UI, Git LFS support, and Gitea Actions for CI/CD pipelines.
|
|
|
|
## Quick Info
|
|
|
|
| Property | Value |
|
|
|----------|-------|
|
|
| **Type** | LXC Container (Proxmox) |
|
|
| **OS** | Ubuntu 20.04 LTS |
|
|
| **IP** | 10.10.0.225 |
|
|
| **Public URL** | https://git.manticorum.com |
|
|
| **Gitea Version** | 1.22.6 |
|
|
| **Database** | PostgreSQL 12 |
|
|
| **Reverse Proxy** | Nginx Proxy Manager (10.10.0.16) |
|
|
|
|
## Container Specs
|
|
|
|
- **VMID**: 225
|
|
- **CPU**: 2 cores
|
|
- **RAM**: 2GB
|
|
- **Disk**: 20GB
|
|
- **Features**: Nesting enabled (for future Docker runner support)
|
|
|
|
## Services
|
|
|
|
### Gitea Web
|
|
- **Port**: 3000 (internal)
|
|
- **Service**: `gitea.service`
|
|
- **User**: `git`
|
|
- **Work Dir**: `/var/lib/gitea`
|
|
- **Config**: `/etc/gitea/app.ini`
|
|
- **Data**: `/var/lib/gitea/data`
|
|
- **Logs**: `/var/lib/gitea/log`
|
|
|
|
### PostgreSQL
|
|
- **Version**: 12
|
|
- **Port**: 5432 (localhost only)
|
|
- **Database**: `gitea`
|
|
- **User**: `gitea`
|
|
- **Service**: `postgresql`
|
|
|
|
## Management
|
|
|
|
### Access Container
|
|
```bash
|
|
ssh root@10.10.0.225
|
|
# or via Proxmox
|
|
pct enter 225
|
|
```
|
|
|
|
### Service Management
|
|
```bash
|
|
# Status
|
|
systemctl status gitea
|
|
systemctl status postgresql
|
|
|
|
# Restart
|
|
systemctl restart gitea
|
|
|
|
# Logs
|
|
journalctl -u gitea -f
|
|
```
|
|
|
|
### Database Access
|
|
```bash
|
|
# As postgres user
|
|
sudo -u postgres psql -d gitea
|
|
|
|
# As gitea user (from container)
|
|
PGPASSWORD=gitea123 psql -U gitea -d gitea -h 127.0.0.1
|
|
```
|
|
|
|
## Configuration
|
|
|
|
### Main Config File
|
|
`/etc/gitea/app.ini` contains all Gitea settings:
|
|
- Database connection
|
|
- Server domain and URLs
|
|
- SSH settings
|
|
- LFS configuration
|
|
- OAuth2/JWT secrets
|
|
- Actions enabled
|
|
|
|
**Permissions**:
|
|
- Owner: `root:git`
|
|
- Mode: `640`
|
|
- Directory: `750` on `/etc/gitea`
|
|
|
|
### Admin Account
|
|
- **Username**: `cal`
|
|
- **Password**: Set during initial setup (change immediately!)
|
|
- **Email**: `cal@manticorum.com`
|
|
|
|
### Features Enabled
|
|
- ✅ **Gitea Actions** - Built-in CI/CD (GitHub Actions compatible)
|
|
- ✅ **Git LFS** - Large file storage support
|
|
- ✅ **SSH Access** - Git over SSH on port 22
|
|
- ✅ **Web UI** - Repository browser and management
|
|
- ✅ **Organizations** - Multi-user repository groups
|
|
- ✅ **Webhooks** - Integration with external services
|
|
|
|
### Key app.ini Settings (Actions)
|
|
```ini
|
|
[actions]
|
|
DEFAULT_ACTIONS_URL = self # Short-form actions resolve against local Gitea instance
|
|
|
|
[service]
|
|
REQUIRE_SIGNIN_VIEW = false # Public repos (like gitea-actions) cloneable without auth
|
|
```
|
|
|
|
- `DEFAULT_ACTIONS_URL=self` means `uses: cal/gitea-actions/calver@main` resolves locally
|
|
- `REQUIRE_SIGNIN_VIEW=false` only exposes PUBLIC repos — all private repos remain locked down
|
|
- The only public repo is `cal/gitea-actions` (reusable CI composite actions, no sensitive code)
|
|
|
|
## Backup
|
|
|
|
### What to Backup
|
|
1. **PostgreSQL database**: `gitea` database
|
|
2. **Repository data**: `/var/lib/gitea/data/gitea-repositories`
|
|
3. **Configuration**: `/etc/gitea/app.ini`
|
|
4. **Custom files**: `/var/lib/gitea/custom` (if any)
|
|
|
|
### Backup Commands
|
|
```bash
|
|
# Database dump
|
|
sudo -u postgres pg_dump gitea > gitea-backup-$(date +%Y%m%d).sql
|
|
|
|
# Full data directory
|
|
tar -czf gitea-data-$(date +%Y%m%d).tar.gz /var/lib/gitea
|
|
|
|
# Config only
|
|
cp /etc/gitea/app.ini gitea-app-$(date +%Y%m%d).ini
|
|
```
|
|
|
|
### Restore
|
|
```bash
|
|
# Restore database
|
|
sudo -u postgres psql -d gitea < gitea-backup.sql
|
|
|
|
# Restore data
|
|
tar -xzf gitea-data.tar.gz -C /
|
|
chown -R git:git /var/lib/gitea
|
|
```
|
|
|
|
## Upgrades
|
|
|
|
### Upgrade Gitea
|
|
```bash
|
|
# Stop service
|
|
systemctl stop gitea
|
|
|
|
# Backup current binary
|
|
cp /usr/local/bin/gitea /usr/local/bin/gitea.backup
|
|
|
|
# Download new version
|
|
wget -O /usr/local/bin/gitea https://dl.gitea.com/gitea/VERSION/gitea-VERSION-linux-amd64
|
|
|
|
# Set permissions
|
|
chmod +x /usr/local/bin/gitea
|
|
|
|
# Start service (will auto-migrate database)
|
|
systemctl start gitea
|
|
|
|
# Check logs
|
|
journalctl -u gitea -f
|
|
```
|
|
|
|
### Check Version
|
|
```bash
|
|
/usr/local/bin/gitea --version
|
|
```
|
|
|
|
## Setting Up CI/CD with Gitea Actions
|
|
|
|
Gitea Actions are enabled and the runner is deployed on the same LXC.
|
|
|
|
### Runner Container
|
|
|
|
```bash
|
|
# Current production runner setup
|
|
docker run -d \
|
|
--name gitea-runner \
|
|
--restart unless-stopped \
|
|
-e GITEA_RUNNER_REGISTRATION_TOKEN=<token-from-gitea-admin> \
|
|
-e GITEA_INSTANCE_URL=http://10.10.0.225:3000 \
|
|
-v /var/run/docker.sock:/var/run/docker.sock \
|
|
-v gitea-runner-data:/data \
|
|
-v /etc/gitea/runner-config.yaml:/config.yaml:ro \
|
|
gitea/act_runner:latest
|
|
```
|
|
|
|
**CRITICAL**: `GITEA_INSTANCE_URL` must be the **internal** URL (`http://10.10.0.225:3000`), not the public domain. The runner uses this for API communication and auth token matching.
|
|
|
|
### Runner Config (`/etc/gitea/runner-config.yaml`)
|
|
|
|
Key settings:
|
|
- `container.options: --add-host=git.manticorum.com:host-gateway` — lets job containers resolve the public domain
|
|
- `container.force_pull: true` — always pulls latest runner images
|
|
- Labels: `ubuntu-latest`, `ubuntu-22.04`, `ubuntu-20.04`
|
|
|
|
### Shared Composite Actions (`cal/gitea-actions`)
|
|
|
|
Reusable CI/CD actions shared across all projects. This repo is **public** (required for runner auth).
|
|
|
|
| Action | Purpose |
|
|
|--------|---------|
|
|
| `cal/gitea-actions/calver@main` | Generate CalVer version (YYYY.MM.BUILD) from git tags |
|
|
| `cal/gitea-actions/gitea-tag@main` | Create git tag via Gitea API |
|
|
| `cal/gitea-actions/discord-notify@main` | Send Discord embed notification via webhook |
|
|
|
|
### Action Reference Rules
|
|
|
|
Because `DEFAULT_ACTIONS_URL=self` is set:
|
|
|
|
```yaml
|
|
# Local actions (cal/gitea-actions) — use SHORT FORM
|
|
uses: cal/gitea-actions/calver@main
|
|
|
|
# GitHub actions — use FULL URL (otherwise they'd resolve against local Gitea)
|
|
uses: https://github.com/actions/checkout@v4
|
|
uses: https://github.com/docker/setup-buildx-action@v3
|
|
uses: https://github.com/docker/login-action@v3
|
|
uses: https://github.com/docker/build-push-action@v5
|
|
```
|
|
|
|
### Creating a New Workflow
|
|
|
|
1. Copy an existing workflow as a template (e.g., from major-domo-database)
|
|
2. Use short form for `cal/gitea-actions/*` references
|
|
3. Use `https://github.com/` prefix for all GitHub action references
|
|
4. Required secrets: `DOCKERHUB_USERNAME`, `DOCKERHUB_TOKEN`, `DISCORD_WEBHOOK`
|
|
|
|
## Adding Repositories
|
|
|
|
### Via Web UI
|
|
1. Go to https://git.manticorum.com
|
|
2. Click "+" → "New Repository"
|
|
3. Fill in details and create
|
|
|
|
### Via Command Line
|
|
```bash
|
|
# Add remote
|
|
git remote add homelab git@git.manticorum.com:cal/repo-name.git
|
|
|
|
# Or HTTPS
|
|
git remote add homelab https://git.manticorum.com/cal/repo-name.git
|
|
|
|
# Push
|
|
git push homelab main
|
|
```
|
|
|
|
### Migrate from GitHub
|
|
Gitea has built-in migration:
|
|
1. New Repository → "Migrate from GitHub"
|
|
2. Enter GitHub URL and token
|
|
3. Gitea will clone all commits, branches, tags
|
|
|
|
## Integration with NPM
|
|
|
|
Reverse proxy is configured on NPM (10.10.0.16):
|
|
- **Domain**: git.manticorum.com
|
|
- **Forward to**: 10.10.0.225:3000
|
|
- **SSL**: Let's Encrypt
|
|
- **Websockets**: Enabled
|
|
|
|
## Troubleshooting
|
|
|
|
### Gitea won't start
|
|
```bash
|
|
# Check logs
|
|
journalctl -u gitea -n 50
|
|
|
|
# Common issues:
|
|
# - Permission on /etc/gitea/app.ini (should be 640, root:git)
|
|
# - PostgreSQL not running
|
|
# - Port 3000 already in use
|
|
```
|
|
|
|
### Can't connect to database
|
|
```bash
|
|
# Check PostgreSQL is running
|
|
systemctl status postgresql
|
|
|
|
# Test connection
|
|
PGPASSWORD=gitea123 psql -U gitea -d gitea -h 127.0.0.1 -c "SELECT 1;"
|
|
|
|
# Check pg_hba.conf allows md5 auth
|
|
cat /etc/postgresql/12/main/pg_hba.conf | grep md5
|
|
```
|
|
|
|
### 502 Bad Gateway on web
|
|
```bash
|
|
# Check Gitea is listening
|
|
ss -tlnp | grep 3000
|
|
|
|
# Check NPM can reach container
|
|
curl http://10.10.0.225:3000
|
|
|
|
# Verify firewall rules (should allow from 10.10.0.0/24)
|
|
```
|
|
|
|
### Actions runner not working
|
|
- Ensure runner is registered in Gitea Admin → Actions → Runners
|
|
- Check runner logs: `docker logs gitea-runner`
|
|
- Verify `GITEA_INSTANCE_URL` uses internal URL (`http://10.10.0.225:3000`), NOT the public domain
|
|
- Ensure runner has network access to Gitea
|
|
|
|
### Actions can't clone composite actions ("authentication required")
|
|
- Verify `REQUIRE_SIGNIN_VIEW = false` in app.ini (allows public repo clone without auth)
|
|
- Verify `DEFAULT_ACTIONS_URL = self` in app.ini
|
|
- Use short-form references for local actions (`cal/gitea-actions/calver@main`)
|
|
- Use full GitHub URLs for GitHub actions (`https://github.com/actions/checkout@v4`)
|
|
- The `cal/gitea-actions` repo must be set to **public** visibility
|
|
|
|
## Security Notes
|
|
|
|
- Database password is stored in `/etc/gitea/app.ini` (secured with 640 permissions)
|
|
- SSH keys for Git access are stored per-user in Gitea database
|
|
- JWT secrets are auto-generated and stored in config
|
|
- LXC is unprivileged for better isolation
|
|
- PostgreSQL only listens on localhost
|
|
- `REQUIRE_SIGNIN_VIEW=false` — only public repos are accessible without login; all private repos remain fully protected
|
|
- The only public repo is `cal/gitea-actions` (audited — contains no secrets or sensitive code)
|
|
|
|
## Related Documentation
|
|
|
|
- [Official Gitea Docs](https://docs.gitea.io/)
|
|
- [Gitea Actions](https://docs.gitea.io/en-us/usage/actions/overview/)
|
|
- [Proxmox LXC Config](../proxmox/lxc/225.conf)
|
|
- [Networking Setup](../../networking/CONTEXT.md)
|
|
|
|
## Deployment Date
|
|
|
|
**Created**: 2026-02-03
|
|
**By**: Claude Code (Proxmox Skill)
|
|
**Initial Version**: Gitea 1.22.6 on Ubuntu 20.04
|
|
|
|
|
|
## Git Remotes
|
|
|
|
This repository is mirrored on both GitHub and Gitea for redundancy:
|
|
- **GitHub**: https://github.com/calcorum/claude-home
|
|
- **Gitea**: https://git.manticorum.com/cal/claude-home
|
|
|
|
---
|
|
|
|
## Branch Protection Manager
|
|
|
|
Automated script to apply consistent branch protection rules across all your Gitea repositories.
|
|
|
|
### Features
|
|
|
|
- Applies branch protection rules to all repositories for a user/organization
|
|
- Supports dry-run mode to preview changes
|
|
- Configurable protection rules via environment variables
|
|
- Handles updating existing protection rules
|
|
- Clear success/error reporting
|
|
|
|
### Requirements
|
|
|
|
```bash
|
|
pip install requests
|
|
```
|
|
|
|
### Configuration
|
|
|
|
The script (`apply_branch_protection.py`) uses these settings:
|
|
- ✅ Disable direct pushes (force PR workflow)
|
|
- ✅ Require 1 approval before merge
|
|
- ✅ Restrict approvals to whitelisted users
|
|
- ✅ Dismiss stale approvals when new commits are pushed
|
|
- ✅ Enable status checks (for CI/CD)
|
|
- ✅ Restrict merging to whitelisted users
|
|
- ✅ Block merge on rejected reviews
|
|
- ✅ Block merge if pull request is outdated (critical for DB migrations)
|
|
|
|
### Usage
|
|
|
|
#### 1. Create a Gitea API Token
|
|
|
|
1. Go to https://git.manticorum.com/user/settings/applications
|
|
2. Click "Generate New Token"
|
|
3. Give it a name (e.g., "Branch Protection Script")
|
|
4. Select permissions: `repo` (full control)
|
|
5. Click "Generate Token"
|
|
6. Copy the token (you won't see it again!)
|
|
|
|
#### 2. Set Environment Variables
|
|
|
|
```bash
|
|
export GITEA_TOKEN='your-api-token-here'
|
|
export GITEA_URL='https://git.manticorum.com' # Optional, defaults to this
|
|
export GITEA_OWNER='cal' # Optional, defaults to cal
|
|
```
|
|
|
|
#### 3. Run the Script
|
|
|
|
**Dry run (preview changes without applying):**
|
|
```bash
|
|
cd /mnt/NV2/Development/claude-home/server-configs/gitea
|
|
python apply_branch_protection.py --dry-run
|
|
```
|
|
|
|
**Apply to all repositories:**
|
|
```bash
|
|
python apply_branch_protection.py
|
|
```
|
|
|
|
### Customizing Protection Rules
|
|
|
|
Edit the `BranchProtectionConfig` section in `main()` to customize the rules:
|
|
|
|
```python
|
|
config = BranchProtectionConfig(
|
|
branch_name="main", # Branch to protect
|
|
enable_push=False, # Disable direct pushes
|
|
required_approvals=1, # Number of required approvals
|
|
enable_approvals_whitelist=True, # Restrict who can approve
|
|
approvals_whitelist_usernames=[GITEA_OWNER],
|
|
dismiss_stale_approvals=True, # Dismiss approvals on new commits
|
|
enable_status_check=True, # Require status checks to pass
|
|
enable_merge_whitelist=True, # Restrict who can merge
|
|
merge_whitelist_usernames=[GITEA_OWNER],
|
|
block_on_rejected_reviews=True, # Block merge if reviews are rejected
|
|
block_on_outdated_branch=True, # Block merge if branch is outdated
|
|
require_signed_commits=False, # Require GPG signatures
|
|
)
|
|
```
|
|
|
|
### Example Output
|
|
|
|
```
|
|
============================================================
|
|
Gitea Branch Protection Configuration
|
|
============================================================
|
|
Gitea URL: https://git.manticorum.com
|
|
Owner: cal
|
|
Branch: main
|
|
============================================================
|
|
Protection Rules:
|
|
• Direct pushes: Disabled
|
|
• Required approvals: 1
|
|
• Approvals whitelist: cal
|
|
• Dismiss stale approvals: True
|
|
• Status checks enabled: True
|
|
• Merge whitelist: cal
|
|
• Block on rejected reviews: True
|
|
• Block on outdated branch: True
|
|
• Require signed commits: False
|
|
============================================================
|
|
|
|
Applying branch protection to 5 repositories...
|
|
|
|
📦 major-domo-database
|
|
🔄 Updating existing protection...
|
|
✅ Successfully applied branch protection
|
|
📦 major-domo-bot
|
|
✅ Successfully applied branch protection
|
|
...
|
|
```
|
|
|
|
### Troubleshooting Branch Protection Script
|
|
|
|
**"GITEA_TOKEN environment variable is required"**
|
|
- You need to set your API token. See usage step 2 above.
|
|
|
|
**"Error fetching repositories"**
|
|
- Check that your `GITEA_URL` is correct
|
|
- Verify your API token has `repo` permissions
|
|
- Ensure the `GITEA_OWNER` username is correct
|
|
|
|
**"Could not delete existing protection"**
|
|
- The script will still try to create the new protection
|
|
- If this fails, manually delete the old protection rule from Gitea web UI
|
|
|
|
**"Error: 422 Unprocessable Entity"**
|
|
This usually means:
|
|
- The branch doesn't exist in the repository
|
|
- Invalid username in whitelist
|
|
- Conflicting protection rule settings
|
|
|
|
### API References
|
|
|
|
This script uses the Gitea API branch protection endpoints:
|
|
- [Gitea API Documentation](https://docs.gitea.com/api/)
|
|
- [Protected Branches](https://docs.gitea.com/usage/access-control/protected-branches)
|
|
- [Create Branch Protection Endpoint](https://share.apidog.com/apidoc/docs-site/346218/api-3521477)
|
|
|