forgejo-autohebergement/docs/CONFIGURATION.md
Horacio Duran 822e42dbb8 Add Template to deploy forgejo.
This template allows deploying a forgejo en either Scaleway or Hetzner
(untested) without much knowledge about them.
It DOES require knowledge about Terragrunt and ansible. A wizard of
sorts is provided but it will not guarantee success without some
knowledge about the underlying technology.
2026-01-09 16:07:44 +01:00

14 KiB

Configuration Reference

This document explains all configuration options for the Forgejo self-hosting setup.

Table of Contents


Domain Configuration

The domain is configured in one primary location:

File: ansible/inventory/production/hosts.yml

forgejo_domain: git.yourdomain.com

This domain is used for:

  • HTTPS certificate (automatically obtained via Caddy/Let's Encrypt)
  • Forgejo web interface URL
  • Git clone URLs: https://git.yourdomain.com/user/repo.git
  • SSH clone URLs: git@git.yourdomain.com:user/repo.git
  • Email "From" addresses

Before deployment, ensure your DNS is configured:

git.yourdomain.com.  IN  A     <server-ipv4>
git.yourdomain.com.  IN  AAAA  <server-ipv6>

Secrets (Vault Variables)

All secrets are stored in ansible/playbooks/vars/secrets.yml encrypted with Ansible Vault.

How to Set Up Secrets

# 1. Copy the example file
cp ansible/playbooks/vars/secrets.yml.example ansible/playbooks/vars/secrets.yml

# 2. Edit with your values
nano ansible/playbooks/vars/secrets.yml

# 3. Encrypt it
ansible-vault encrypt ansible/playbooks/vars/secrets.yml

# 4. To edit later
ansible-vault edit ansible/playbooks/vars/secrets.yml

Secret Variables Explained

Variable Purpose How to Generate
vault_forgejo_db_password PostgreSQL database password for Forgejo openssl rand -base64 32
vault_forgejo_admin_password Initial admin account password Choose a strong password
vault_forgejo_secret_key Used for CSRF tokens, session cookies, and encryption. Must be 64+ characters. openssl rand -base64 48
vault_forgejo_internal_token Used for internal API calls between Forgejo components openssl rand -base64 48
vault_forgejo_jwt_secret Signs JWT tokens for OAuth2 and API authentication openssl rand -base64 32
vault_forgejo_metrics_token Required to access /metrics endpoint (if Prometheus enabled) openssl rand -base64 32
vault_email_password SMTP password (if email enabled) Your email provider password
vault_s3_access_key S3-compatible storage access key (if S3 enabled) From your cloud provider
vault_s3_secret_key S3-compatible storage secret key (if S3 enabled) From your cloud provider

Example secrets.yml

---
vault_forgejo_db_password: "xK9mN2pL8qR5tW7vY3zB1cD4fG6hJ0kM"
vault_forgejo_admin_password: "MySecureAdminPassword123!"
vault_forgejo_secret_key: "aB3cD5eF7gH9iJ1kL3mN5oP7qR9sT1uV3wX5yZ7aB9cD1eF3gH5iJ7kL9mN1oP"
vault_forgejo_internal_token: "qW2eR4tY6uI8oP0aS2dF4gH6jK8lZ0xC2vB4nM6qW8eR0tY2uI4oP6aS8dF0g"
vault_forgejo_jwt_secret: "mN3bV5cX7zL9kJ1hG3fD5sA7pO9iU1yT"
vault_forgejo_metrics_token: "pR0mE7hEuS_t0K3n_H3r3"
vault_email_password: ""
vault_s3_access_key: ""
vault_s3_secret_key: ""

Feature Flags

Configure features in ansible/inventory/production/hosts.yml:

Core Features

Flag Default Description
forgejo_enable_letsencrypt true Automatic HTTPS via Let's Encrypt (handled by Caddy)
forgejo_enable_lfs true Git Large File Storage support
forgejo_enable_2fa true Allow users to enable Two-Factor Authentication
forgejo_use_redis true Use Redis for caching (recommended for performance)
forgejo_enable_backups true Enable automated daily backups
forgejo_enable_prometheus false Enable internal Prometheus metrics collection

Access Control

Flag Default Description
forgejo_disable_registration false Disable public user registration (invite-only)
forgejo_require_signin_view false Require login to view public repositories

Optional Services

Flag Default Description
forgejo_enable_email false Enable email notifications (requires SMTP config)
forgejo_enable_s3 false Use S3-compatible storage for LFS and attachments

Example Configuration

# In ansible/inventory/production/hosts.yml
forgejo_prod:
  # ... other settings ...

  # Enable all recommended features
  forgejo_enable_letsencrypt: true
  forgejo_enable_lfs: true
  forgejo_enable_2fa: true
  forgejo_use_redis: true
  forgejo_enable_backups: true

  # Enable monitoring
  forgejo_enable_prometheus: true

  # Private instance (no public registration)
  forgejo_disable_registration: true
  forgejo_require_signin_view: false

Security (Tailscale + UFW)

This setup uses Tailscale VPN and UFW firewall to secure your Forgejo instance:

  • SSH access: Only via Tailscale (not exposed to the public internet)
  • Git SSH (port 2222): Only via Tailscale
  • Web interface: Public via HTTPS (ports 80/443)
  • Internal services: Only via Tailscale (Prometheus, database, etc.)

Enable Security Features

# In ansible/inventory/production/hosts.yml
forgejo_enable_tailscale: true
forgejo_enable_ufw: true

How It Works

  1. Tailscale creates a secure mesh VPN network
  2. UFW is configured to:
    • Allow all traffic on the tailscale0 interface
    • Allow only HTTP/HTTPS (80/443) from the public internet
    • Block SSH from the public internet

Post-Deployment: Authenticate Tailscale

After deployment, SSH into the server (while SSH is still open) and authenticate Tailscale:

# SSH into server (before UFW locks down SSH)
ssh root@<server-public-ip>

# Authenticate Tailscale
sudo tailscale up --ssh

# This will print a URL - open it in your browser to authenticate

For headless/automated setup, use an auth key:

sudo tailscale up --authkey=tskey-auth-XXXXX

Generate auth keys at: https://login.tailscale.com/admin/settings/keys

Accessing Your Server After Setup

Once UFW is configured, SSH is only accessible via Tailscale:

# Via Tailscale IP
ssh root@100.x.x.x

# Via Tailscale hostname (from admin console)
ssh root@your-server.tailnet-name.ts.net

# Via Tailscale SSH (if enabled with --ssh)
tailscale ssh root@your-server

Git Clone URLs

Method URL Access
HTTPS https://git.yourdomain.com/user/repo.git Public
SSH git@<tailscale-hostname>:user/repo.git Tailscale only

Firewall Rules Summary

Port Protocol Access Purpose
80 TCP Public HTTP (redirects to HTTPS)
443 TCP Public HTTPS (Forgejo web)
22 TCP Tailscale only System SSH
2222 TCP Tailscale only Git SSH
3000 TCP Tailscale only Forgejo internal
9090 TCP Tailscale only Prometheus

Disabling Security Features

If you need public SSH access (not recommended):

forgejo_enable_tailscale: false
forgejo_enable_ufw: false

Or configure UFW manually after deployment.


S3/Object Storage

S3-compatible object storage can be used for:

  1. Git LFS - Large file storage
  2. Backups - Off-site backup storage
  3. Attachments - Issue/PR attachments (future)

What is S3?

S3 (Simple Storage Service) is an object storage protocol. Both Scaleway and Hetzner offer S3-compatible storage:

  • Scaleway: Object Storage (S3-compatible)
  • Hetzner: Object Storage (S3-compatible, in beta)

Setting Up S3 Storage

For Scaleway

  1. Create storage via Terraform (already included):

    make terraform-apply PROVIDER=scaleway
    
  2. Get credentials from Terraform output:

    cd terraform/scaleway/storage
    terragrunt output access_key
    terragrunt output secret_key
    
  3. Configure in inventory:

    forgejo_enable_s3: true
    forgejo_s3_endpoint: https://s3.fr-par.scw.cloud
    forgejo_s3_bucket: your-project-production-lfs
    forgejo_s3_region: fr-par
    
  4. Add credentials to secrets.yml:

    vault_s3_access_key: "SCWXXXXXXXXXXXXXXXXX"
    vault_s3_secret_key: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
    

For Hetzner

Hetzner Object Storage is S3-compatible:

  1. Create a storage box in Hetzner Cloud Console

  2. Configure in inventory:

    forgejo_enable_s3: true
    forgejo_s3_endpoint: https://fsn1.your-objectstorage.com
    forgejo_s3_bucket: forgejo-lfs
    forgejo_s3_region: fsn1
    
  3. Add credentials to secrets.yml

S3 for Backups

To upload backups to S3:

# In inventory
forgejo_backup_to_s3: true
forgejo_backup_s3_bucket: your-project-production-backups

Then run:

make backup-to-s3

Database Configuration

PostgreSQL is the recommended database.

Settings

Variable Default Description
forgejo_db_type postgres Database type (postgres recommended)
forgejo_db_host localhost Database host
forgejo_db_port 5432 Database port
forgejo_db_name forgejo Database name
forgejo_db_user forgejo Database user

The password is in vault_forgejo_db_password.

PostgreSQL Tuning

Default tuning in ansible/roles/forgejo/defaults/main.yml:

postgres_version: "16"
postgres_max_connections: 100
postgres_shared_buffers: "256MB"
postgres_effective_cache_size: "1GB"

For larger instances, adjust these based on available RAM.


Email Configuration

Enable email for notifications, password resets, and registration confirmation.

Settings

# In inventory
forgejo_enable_email: true
forgejo_email_host: smtp.example.com
forgejo_email_port: 587
forgejo_email_user: noreply@yourdomain.com

# In secrets.yml
vault_email_password: "your-smtp-password"

Common SMTP Providers

Gmail (with App Password):

forgejo_email_host: smtp.gmail.com
forgejo_email_port: 587
forgejo_email_user: your-email@gmail.com

Mailgun:

forgejo_email_host: smtp.mailgun.org
forgejo_email_port: 587
forgejo_email_user: postmaster@your-domain.mailgun.org

SendGrid:

forgejo_email_host: smtp.sendgrid.net
forgejo_email_port: 587
forgejo_email_user: apikey
# vault_email_password should be your SendGrid API key

Monitoring (Prometheus)

Internal Prometheus monitoring for your Forgejo instance.

Enable Monitoring

# In inventory
forgejo_enable_prometheus: true

What Gets Monitored

  • Forgejo metrics: HTTP requests, Git operations, users, repos, issues
  • Prometheus self-monitoring: Scrape health

Accessing Metrics

Prometheus is internal only (bound to localhost:9090). To access:

  1. SSH tunnel:

    ssh -L 9090:localhost:9090 root@your-server
    

    Then open http://localhost:9090

  2. Forgejo metrics endpoint:

    https://git.yourdomain.com/metrics?token=YOUR_METRICS_TOKEN
    

    The token is vault_forgejo_metrics_token.

Adding Grafana (Optional)

To add Grafana dashboards, extend the monitoring setup:

# Create docker-compose.grafana.yml manually
services:
  grafana:
    image: grafana/grafana:latest
    container_name: grafana
    ports:
      - "127.0.0.1:3001:3000"
    volumes:
      - grafana-data:/var/lib/grafana
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=your-grafana-password
    networks:
      - forgejo-network

Backup Configuration

Settings

Variable Default Description
forgejo_enable_backups true Enable automated backups
forgejo_backup_schedule 0 2 * * * Cron schedule (default: 2 AM daily)
forgejo_backup_retention_days 30 Days to keep local backups
forgejo_backup_to_s3 false Upload backups to S3
forgejo_backup_s3_bucket "" S3 bucket for backups

What Gets Backed Up

  1. PostgreSQL database - Full SQL dump
  2. Git repositories - All repository data
  3. Configuration - app.ini, docker-compose.yml
  4. User data - Attachments, LFS files, avatars

Backup Commands

# Manual backup
make backup

# Backup and upload to S3
make backup-to-s3

# Restore from backup
make restore
# You'll be prompted for the backup timestamp

Backup Location

Local backups are stored in: /opt/forgejo/backups/

Files:

  • database-TIMESTAMP.sql.gz
  • repositories-TIMESTAMP.tar.gz
  • config-TIMESTAMP.tar.gz
  • data-TIMESTAMP.tar.gz

Quick Reference: Enable Everything

For a fully-featured setup with all options enabled:

# ansible/inventory/production/hosts.yml
forgejo-prod:
  ansible_host: YOUR_SERVER_IP
  ansible_user: root

  # Domain
  forgejo_domain: git.yourdomain.com

  # Core
  forgejo_version: "9.0.2"
  forgejo_enable_letsencrypt: true
  forgejo_enable_lfs: true
  forgejo_enable_2fa: true
  forgejo_use_redis: true

  # Database
  forgejo_db_type: postgres

  # Backups
  forgejo_enable_backups: true
  forgejo_backup_retention_days: 30
  forgejo_backup_to_s3: true
  forgejo_backup_s3_bucket: your-backup-bucket

  # S3 Storage
  forgejo_enable_s3: true
  forgejo_s3_endpoint: https://s3.fr-par.scw.cloud
  forgejo_s3_bucket: your-lfs-bucket
  forgejo_s3_region: fr-par

  # Email
  forgejo_enable_email: true
  forgejo_email_host: smtp.mailgun.org
  forgejo_email_port: 587
  forgejo_email_user: noreply@yourdomain.com

  # Monitoring
  forgejo_enable_prometheus: true

  # Access
  forgejo_disable_registration: false  # Set to true for invite-only
  forgejo_require_signin_view: false

Then in ansible/playbooks/vars/secrets.yml:

vault_forgejo_db_password: "GENERATED_PASSWORD"
vault_forgejo_admin_password: "YOUR_ADMIN_PASSWORD"
vault_forgejo_secret_key: "64_CHAR_GENERATED_KEY"
vault_forgejo_internal_token: "GENERATED_TOKEN"
vault_forgejo_jwt_secret: "GENERATED_SECRET"
vault_forgejo_metrics_token: "GENERATED_TOKEN"
vault_email_password: "YOUR_SMTP_PASSWORD"
vault_s3_access_key: "YOUR_S3_ACCESS_KEY"
vault_s3_secret_key: "YOUR_S3_SECRET_KEY"