Files
ouranos/docs/gitea.md
Robert Helewka b4d60f2f38 docs: rewrite README with structured overview and quick start guide
Replaces the minimal project description with a comprehensive README
including a component overview table, quick start instructions, common
Ansible operations, and links to detailed documentation. Aligns with
Red Panda Approval™ standards.
2026-03-03 12:49:06 +00:00

387 lines
13 KiB
Markdown

# Gitea - Git with a Cup of Tea
## Overview
Gitea is a lightweight, self-hosted Git service providing a GitHub-like web interface with repository management, issue tracking, pull requests, and code review capabilities. Deployed on **Rosalind** with PostgreSQL backend on Portia and Memcached caching.
**Host:** rosalind.incus
**Role:** Collaboration (PHP, Go, Node.js runtimes)
**Container Port:** 22083 (HTTP), 22022 (SSH), 22093 (Metrics)
**External Access:** https://gitea.ouranos.helu.ca/ (via HAProxy on Titania)
**SSH Access:** `ssh -p 22022 git@gitea.ouranos.helu.ca` (TCP passthrough via HAProxy)
## Architecture
```
┌──────────┐ ┌────────────┐ ┌──────────┐ ┌───────────┐
│ Client │─────▶│ HAProxy │─────▶│ Gitea │─────▶│PostgreSQL │
│ │ │ (Titania) │ │(Rosalind)│ │ (Portia) │
└──────────┘ └────────────┘ └──────────┘ └───────────┘
┌───────────┐
│ Memcached │
│ (Local) │
└───────────┘
```
## Deployment
### Playbook
```bash
cd ansible
ansible-playbook gitea/deploy.yml
```
### Files
| File | Purpose |
|------|---------|
| `gitea/deploy.yml` | Main deployment playbook |
| `gitea/app.ini.j2` | Gitea configuration template |
### Deployment Steps
1. **Install Dependencies**: git, git-lfs, curl, memcached
2. **Create System User**: `git:git` with home directory
3. **Create Directories**: Work dir, data, LFS storage, repository root, logs
4. **Download Gitea Binary**: Latest release from GitHub (architecture-specific)
5. **Template Configuration**: Apply `app.ini.j2` with variables
6. **Create Systemd Service**: Custom service unit for Gitea
7. **Start Service**: Enable and start gitea.service
8. **Configure OAuth2**: Register Casdoor as OpenID Connect provider
## Configuration
### Key Features
- **Git LFS Support**: Large file storage enabled
- **SSH Server**: Built-in SSH server on port 22022
- **Prometheus Metrics**: Metrics endpoint on port 22094
- **Memcached Caching**: Session and cache storage with `gt_` prefix
- **Repository Settings**: Push-to-create, all units enabled
- **Security**: Argon2 password hashing, reverse proxy trusted
### Storage Locations
| Path | Purpose | Owner |
|------|---------|-------|
| `/var/lib/gitea` | Working directory | git:git |
| `/var/lib/gitea/data` | Application data | git:git |
| `/var/lib/gitea/data/lfs` | Git LFS objects | git:git |
| `/mnt/dv` | Git repositories | git:git |
| `/var/log/gitea` | Application logs | git:git |
| `/etc/gitea` | Configuration files | root:git |
### Logging
- **Console Output**: Info level to systemd journal
- **File Logs**: `/var/log/gitea/gitea.log`
- **Rotation**: Daily rotation, 7-day retention
- **SSH Logs**: Enabled for debugging
## Access After Deployment
1. **Web Interface**: https://gitea.ouranos.helu.ca/
2. **First-Time Setup**: Create admin account on first visit
3. **Git Clone**:
```bash
git clone https://gitea.ouranos.helu.ca/username/repo.git
```
4. **SSH Clone**:
```bash
git clone git@gitea.ouranos.helu.ca:username/repo.git
```
Note: SSH requires port 22022 configured in `~/.ssh/config`
## Monitoring
### Alloy Configuration
**File:** `ansible/alloy/rosalind/config.alloy.j2`
- **Log Collection**: `/var/log/gitea/gitea.log` → Loki
- **Metrics**: Port 22094 → Prometheus (token-protected)
- **System Metrics**: Process exporter tracks Gitea process
### Metrics Endpoint
- **URL**: `http://rosalind.incus:22083/metrics`
- **Authentication**: Bearer token required (`vault_gitea_metrics_token`)
- **Note**: Metrics are exposed on the main web port, not a separate metrics port
## Required Vault Secrets
Add to `ansible/inventory/group_vars/all/vault.yml`:
### 1. Database Password
```yaml
vault_gitea_db_password: "YourSecurePassword123!"
```
**Requirements:**
- Minimum 12 characters recommended
- Used by PostgreSQL authentication
### 2. Secret Key (Session Encryption)
```yaml
vault_gitea_secret_key: "RandomString64CharactersLongForSessionCookieEncryptionSecurity123"
```
**Requirements:**
- **Length**: Recommended 64+ characters
- **Format**: Base64 or hex string
- **Generation**:
```bash
openssl rand -base64 48
```
### 3. LFS JWT Secret
```yaml
vault_gitea_lfs_jwt_secret: "AnotherRandomString64CharsForLFSJWTTokenSigning1234567890ABC"
```
**Requirements:**
- **Length**: Recommended 64+ characters
- **Purpose**: Signs JWT tokens for Git LFS authentication
- **Generation**:
```bash
openssl rand -base64 48
```
### 4. Metrics Token
```yaml
vault_gitea_metrics_token: "RandomTokenForPrometheusMetricsAccess123"
```
**Requirements:**
- **Length**: 32+ characters recommended
- **Purpose**: Bearer token for Prometheus scraping
- **Generation**:
```bash
openssl rand -hex 32
```
### 5. OAuth Client ID
```yaml
vault_gitea_oauth_client_id: "gitea-oauth-client"
```
**Requirements:**
- **Purpose**: Client ID for Casdoor OAuth2 application
- **Source**: Must match `clientId` in Casdoor application configuration
### 6. OAuth Client Secret
```yaml
vault_gitea_oauth_client_secret: "YourRandomOAuthSecret123!"
```
**Requirements:**
- **Length**: 32+ characters recommended
- **Purpose**: Client secret for Casdoor OAuth2 authentication
- **Generation**:
```bash
openssl rand -base64 32
```
- **Source**: Must match `clientSecret` in Casdoor application configuration
## Host Variables
**File:** `ansible/inventory/host_vars/rosalind.incus.yml`
```yaml
# Gitea User and Directories
gitea_user: git
gitea_group: git
gitea_work_dir: /var/lib/gitea
gitea_data_dir: /var/lib/gitea/data
gitea_lfs_dir: /var/lib/gitea/data/lfs
gitea_repo_root: /mnt/dv
gitea_config_file: /etc/gitea/app.ini
# Ports
gitea_web_port: 22083
gitea_ssh_port: 22022
gitea_metrics_port: 22094
# Network
gitea_domain: ouranos.helu.ca
gitea_root_url: https://gitea.ouranos.helu.ca/
# Database Configuration
gitea_db_type: postgres
gitea_db_host: portia.incus
gitea_db_port: 5432
gitea_db_name: gitea
gitea_db_user: gitea
gitea_db_password: "{{vault_gitea_db_password}}"
gitea_db_ssl_mode: disable
# Features
gitea_lfs_enabled: true
gitea_metrics_enabled: true
# Service Settings
gitea_disable_registration: true # Use Casdoor SSO
gitea_require_signin_view: false
# Security (vault secrets)
gitea_secret_key: "{{vault_gitea_secret_key}}"
gitea_lfs_jwt_secret: "{{vault_gitea_lfs_jwt_secret}}"
gitea_metrics_token: "{{vault_gitea_metrics_token}}"
# OAuth2 (Casdoor SSO)
gitea_oauth_enabled: true
gitea_oauth_name: "casdoor"
gitea_oauth_display_name: "Sign in with Casdoor"
gitea_oauth_client_id: "{{vault_gitea_oauth_client_id}}"
gitea_oauth_client_secret: "{{vault_gitea_oauth_client_secret}}"
gitea_oauth_auth_url: "https://id.ouranos.helu.ca/login/oauth/authorize"
gitea_oauth_token_url: "http://titania.incus:22081/api/login/oauth/access_token"
gitea_oauth_userinfo_url: "http://titania.incus:22081/api/userinfo"
gitea_oauth_scopes: "openid profile email"
```
## OAuth2 / Casdoor SSO
Gitea integrates with Casdoor for Single Sign-On using OpenID Connect.
### Architecture
```
┌──────────┐ ┌────────────┐ ┌──────────┐ ┌──────────┐
│ Browser │─────▶│ HAProxy │─────▶│ Gitea │─────▶│ Casdoor │
│ │ │ (Titania) │ │(Rosalind)│ │(Titania) │
└──────────┘ └────────────┘ └──────────┘ └──────────┘
│ │ │
│ 1. Click "Sign in with Casdoor" │ │
│◀─────────────────────────────────────│ │
│ 2. Redirect to Casdoor login │ │
│─────────────────────────────────────────────────────▶│
│ 3. User authenticates │ │
│◀─────────────────────────────────────────────────────│
│ 4. Redirect back with auth code │ │
│─────────────────────────────────────▶│ │
│ │ 5. Exchange code for token
│ │────────────────▶│
│ │◀────────────────│
│ 6. User logged into Gitea │ │
│◀─────────────────────────────────────│ │
```
### Casdoor Application Configuration
A Gitea application is defined in `ansible/casdoor/init_data.json.j2`:
| Setting | Value |
|---------|-------|
| **Name** | `app-gitea` |
| **Client ID** | `vault_gitea_oauth_client_id` |
| **Redirect URI** | `https://gitea.ouranos.helu.ca/user/oauth2/casdoor/callback` |
| **Grant Types** | `authorization_code`, `refresh_token` |
### URL Strategy
| URL Type | Address | Used By |
|----------|---------|---------|
| **Auth URL** | `https://id.ouranos.helu.ca/...` | User's browser (external) |
| **Token URL** | `http://titania.incus:22081/...` | Gitea server (internal) |
| **Userinfo URL** | `http://titania.incus:22081/...` | Gitea server (internal) |
| **Discovery URL** | `http://titania.incus:22081/.well-known/openid-configuration` | Gitea server (internal) |
The auth URL uses the external HAProxy address because it runs in the user's browser. Token/userinfo URLs use internal addresses for server-to-server communication.
### User Auto-Registration
With `ENABLE_AUTO_REGISTRATION = true` in `[oauth2_client]`, users who authenticate via Casdoor are automatically created in Gitea. Account linking uses `auto` mode to match by email address.
### Deployment Order
1. **Deploy Casdoor first** (if not already running):
```bash
ansible-playbook casdoor/deploy.yml
```
2. **Deploy Gitea** (registers OAuth provider):
```bash
ansible-playbook gitea/deploy.yml
```
### Verify OAuth Configuration
```bash
# List authentication sources
ssh rosalind.incus "sudo -u git /usr/local/bin/gitea admin auth list --config /etc/gitea/app.ini"
# Should show: casdoor (OpenID Connect)
```
## Database Setup
Gitea requires a PostgreSQL database on Portia. This is automatically created by the `postgresql/deploy.yml` playbook.
**Database Details:**
- **Name**: gitea
- **User**: gitea
- **Owner**: gitea
- **Extensions**: None required
## Integration with Other Services
### HAProxy Routing
**Backend Configuration** (`titania.incus.yml`):
```yaml
- subdomain: "gitea"
backend_host: "rosalind.incus"
backend_port: 22083
health_path: "/api/healthz"
timeout_server: 120s
```
### Memcached Integration
- **Host**: localhost:11211
- **Session Prefix**: N/A (Memcache adapter doesn't require prefix)
- **Cache Prefix**: N/A
### Prometheus Monitoring
- **Scrape Target**: `rosalind.incus:22094`
- **Job Name**: gitea
- **Authentication**: Bearer token
## Troubleshooting
### Service Status
```bash
ssh rosalind.incus
sudo systemctl status gitea
```
### View Logs
```bash
# Application logs
sudo tail -f /var/log/gitea/gitea.log
# Systemd journal
sudo journalctl -u gitea -f
```
### Test Database Connection
```bash
psql -h portia.incus -U gitea -d gitea
```
### Check Memcached
```bash
echo "stats" | nc localhost 11211
```
### Verify Metrics Endpoint
```bash
curl -H "Authorization: Bearer YOUR_TOKEN" http://localhost:22094/metrics
```
## Version Information
- **Installation Method**: Binary download from GitHub releases
- **Version Selection**: Latest stable release (dynamic)
- **Update Process**: Re-run deployment playbook to fetch latest binary
- **Architecture**: linux-amd64
## References
- **Official Documentation**: https://docs.gitea.com/
- **GitHub Repository**: https://github.com/go-gitea/gitea
- **Configuration Reference**: https://docs.gitea.com/administration/config-cheat-sheet