Files
rick-infra/roles/gitea
Joakim 467e79c84b Configure Gitea as private OAuth-enabled Git server with email support
Major Changes:
- Configure private Git server with OAuth-preferred authentication
- Integrate Titan Email for notifications and OAuth workflows
- Enable CI/CD Actions and repository mirroring
- Implement enhanced security hardening

Authentication & Access Control:
- Require sign-in for all access (unauthorized users blocked)
- OAuth via Authentik as primary login method (password form hidden)
- Password authentication still functional as backup via direct URL
- Registration disabled (admin-only user creation)
- Auto-registration for OAuth users with account linking support

Email Configuration (Titan Email):
- SMTP: smtp.titan.email:587 (STARTTLS)
- From address: hello@jnss.me
- Used for: OAuth account linking, notifications, confirmations
- Subject prefix: [Gitea]

Repository Privacy & Features:
- Private repositories by default (public repos allowed)
- Unauthorized users cannot view any content (must sign in)
- External integrations disabled (ext_issues, ext_wiki)
- Manual repository creation required (no push-to-create)
- LFS enabled for large file storage

Features Enabled:
- CI/CD Actions with GitHub actions support
- Repository mirroring (pull/push mirrors enabled)
- User organization creation
- Webhook security (restricted to private/loopback)

Security Enhancements:
- HTTPS-only session cookies with strict SameSite policy
- CSRF cookie HTTP-only protection
- Password breach checking (HaveIBeenPwned)
- 1-hour session timeout (reduced from 24h)
- Reverse proxy trust limited to Caddy only
- API Swagger docs disabled in production

Configuration Sections Added:
- [oauth2_client] - OAuth integration settings
- [mailer] - Email/SMTP configuration
- [session] - Enhanced session security
- [actions] - CI/CD workflow configuration
- [mirror] - Repository mirroring settings
- [api] - API access configuration
- [webhook] - Webhook security restrictions
- [service.explore] - Public content settings

Files Changed:
- roles/gitea/defaults/main.yml: +97 lines (OAuth, email, security vars)
- roles/gitea/templates/app.ini.j2: +94 lines (config sections)
- host_vars/arch-vps/vault.yml: +1 line (SMTP password - not committed)

Deployment Status:
- Successfully deployed to arch-vps
- Service running and healthy
- Ready for OAuth provider configuration in Authentik
- Tested: HTTP access, configuration generation, service health
2025-12-18 21:09:31 +01:00
..

Gitea Git Service Role

Self-contained Gitea Git service for rick-infra following the established architectural patterns.

Features

  • Self-contained: Manages its own database and configuration
  • Native Arch installation: Uses pacman packages
  • PostgreSQL integration: Uses shared PostgreSQL infrastructure
  • Caddy integration: Deploys reverse proxy configuration
  • Dual SSH modes: Passthrough (default) or dedicated SSH server
  • Flexible domains: Separate HTTP and SSH domains
  • Security hardened: SystemD restrictions and secure defaults
  • Firewall management: Automatic nftables configuration per mode
  • fail2ban protection: Brute force protection for SSH authentication
  • Production ready: HTTPS, SSH access, LFS support

Architecture

  • Dependencies: PostgreSQL infrastructure role
  • Database: Self-managed gitea database and user
  • Network: HTTP on :3000 (localhost), SSH via system SSH (port 22) or dedicated (port 2222)
  • Web access: https://git.jnss.me (via Caddy reverse proxy)
  • SSH access: git@jnss.me:user/repo.git (passthrough mode, default)
  • Firewall: Managed per SSH mode (no extra ports in passthrough)
  • Security: fail2ban protects SSH authentication (system or dedicated jail)

Configuration

Key variables (defaults in defaults/main.yml):

# Service
gitea_service_enabled: true
gitea_http_port: 3000

# Domain Configuration
gitea_http_domain: "git.jnss.me"  # Web interface
gitea_ssh_domain: "jnss.me"       # SSH/Git operations

# SSH Mode
gitea_ssh_mode: "passthrough"  # or "dedicated"

# Database (self-managed)
gitea_db_name: "gitea"
gitea_db_user: "gitea" 
gitea_db_password: "{{ vault_gitea_db_password }}"

# Application
gitea_app_name: "Gitea: Git with a cup of tea"
gitea_disable_registration: false
gitea_enable_lfs: true

Domain Configuration

Gitea uses separate domains for HTTP and SSH access, providing flexibility and cleaner URLs:

HTTP Domain (gitea_http_domain)

  • Purpose: Web interface access
  • Default: git.jnss.me
  • Example: https://git.jnss.me
  • Used for: Browsing repos, managing settings, viewing commits

SSH Domain (gitea_ssh_domain)

  • Purpose: Git clone/push/pull operations
  • Default: jnss.me (root domain)
  • Example: git@jnss.me:user/repo.git
  • Used for: Git operations over SSH

Why Separate Domains?

  • Cleaner SSH URLs (no redundant "git" subdomain)
  • Flexibility to use completely different domains
  • Matches industry standards (GitHub, GitLab use root domain for SSH)
  • Professional appearance

Configuration Examples:

# Standard setup (recommended)
gitea_http_domain: "git.jnss.me"
gitea_ssh_domain: "jnss.me"
# Result: git@jnss.me:user/repo.git

# Same domain for both
gitea_http_domain: "git.jnss.me"
gitea_ssh_domain: "git.jnss.me"
# Result: git@git.jnss.me:user/repo.git

# Completely custom
gitea_http_domain: "code.jnss.me"
gitea_ssh_domain: "git.example.com"
# Result: git@git.example.com:user/repo.git

SSH Modes

System SSH handles Git operations via AuthorizedKeysCommand:

# Clone repository (standard Git URL, no port number)
git clone git@jnss.me:username/repository.git

# Add as remote
git remote add origin git@jnss.me:username/repository.git

# Test SSH connection
ssh -T git@jnss.me

Features:

  • Standard Git URLs (no :2222 port)
  • Single SSH daemon (smaller attack surface)
  • System fail2ban protects everything
  • Port 22 only (no extra firewall rules)
  • Matches GitHub/GitLab pattern

Dedicated Mode (Fallback)

Gitea runs its own SSH server on port 2222:

# Clone repository (with port number)
git clone ssh://git@jnss.me:2222/username/repository.git

# Add as remote
git remote add origin ssh://git@jnss.me:2222/username/repository.git

# Test SSH connection
ssh -T -p 2222 git@jnss.me

Features:

  • Complete isolation from system SSH
  • Independent configuration
  • ⚠️ Requires port 2222 open in firewall
  • ⚠️ Non-standard URLs (requires :2222)

To switch modes:

# host_vars/arch-vps/main.yml
gitea_ssh_mode: "dedicated"  # or "passthrough"

Then re-run the playbook.

Usage

  1. Add vault password: Set vault_gitea_db_password in host_vars vault
  2. Configure domains (optional): Override gitea_http_domain and gitea_ssh_domain in host_vars
  3. Deploy: ansible-playbook site.yml --tags gitea
  4. Access: Visit https://git.jnss.me to set up admin account

SSH Key Setup

  1. Generate SSH key (if you don't have one):

    ssh-keygen -t ed25519 -C "your_email@example.com"
    
  2. Copy your public key:

    cat ~/.ssh/id_ed25519.pub
    
  3. Add to Gitea:

    • Log into Gitea web interface
    • Go to Settings → SSH/GPG Keys
    • Click "Add Key"
    • Paste your public key
  4. Test SSH connection:

    # Passthrough mode
    ssh -T git@jnss.me
    
    # Dedicated mode
    ssh -T -p 2222 git@jnss.me
    

Firewall and Security

Automatic Firewall Management

Firewall configuration is mode-aware:

Passthrough Mode:

  • No extra firewall rules needed (uses port 22)
  • System SSH already configured in security playbook

Dedicated Mode:

  • Port 2222 automatically opened via nftables
  • Firewall rules stored in /etc/nftables.d/50-gitea.nft
  • Rules integrated with main security playbook
  • Automatically removed when switching to passthrough

fail2ban Protection

Protection is mode-aware:

Passthrough Mode:

  • System sshd jail protects all SSH traffic (port 22)
  • Covers admin SSH + Git operations automatically
  • No separate Gitea jail needed

Dedicated Mode:

  • gitea-ssh jail monitors Gitea logs (port 2222)
  • Max retries: 5 failed attempts
  • Find time: 10 minutes (600 seconds)
  • Ban time: 1 hour (3600 seconds)
  • Action: IP banned via nftables

Check fail2ban status:

# Passthrough mode
fail2ban-client status sshd

# Dedicated mode
fail2ban-client status gitea-ssh

Firewall Verification

# List active nftables rules
nft list ruleset

# Check for Gitea SSH port (should be empty in passthrough)
nft list ruleset | grep 2222

# Verify SSH connectivity
nc -zv jnss.me 22          # Passthrough
nc -zv jnss.me 2222        # Dedicated

Dependencies

  • PostgreSQL infrastructure role (auto-included)
  • Caddy web server (for HTTPS access)
  • Vault password: vault_gitea_db_password

Self-Contained Design

This role follows rick-infra's self-contained service pattern:

  • Creates its own database and user via PostgreSQL infrastructure
  • Manages its own configuration and data
  • Deploys its own Caddy reverse proxy config
  • Manages its own firewall rules and security (nftables, fail2ban)
  • Flexible domain configuration (not tied to infrastructure variables)
  • Independent lifecycle from other services

Migration Guide

See docs/gitea-ssh-migration-guide.md for:

  • Switching between SSH modes
  • Updating Git remote URLs
  • Bulk migration scripts
  • Troubleshooting

Rick-Infra Gitea Service
Git repository management with flexible SSH modes and domain configuration.