# 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