Deploying Forgejo
Introduction
Forgejo is a self-hosted, community-driven Git forge focused on software freedom, collaboration, and transparency. As a soft fork of Gitea, Forgejo maintains compatibility while emphasizing community governance, open development, and long-term sustainability. Written in Go with a Vue.js frontend, Forgejo provides a lightweight yet feature-rich platform for hosting Git repositories, managing code, and coordinating development workflows.
Forgejo is known for:
- Community Governance: Fully community-driven project with transparent decision-making and democratic processes
- Software Freedom: Committed to free and open-source software principles with MIT license
- Git Hosting: Complete repository management with branching, tagging, and advanced Git operations
- Code Collaboration: Pull requests, code reviews, inline comments, and approval workflows
- Issue Management: Built-in issue tracker with labels, milestones, assignees, and project boards
- CI/CD Integration: Native Forgejo Actions (GitHub Actions compatible) and webhook support
- Package Registry: Built-in support for Docker, npm, Maven, NuGet, PyPI, and more
- Wiki & Documentation: Integrated wiki system for project documentation and knowledge base
- Organizations & Teams: Multi-tiered permission system with fine-grained access control
- Migration Tools: Import repositories from GitHub, GitLab, Bitbucket, and other Git forges
- API & Webhooks: Comprehensive REST API and webhook system for automation
- Multilingual: Available in 30+ languages with active translation community
- Lightweight: Minimal resource requirements with excellent performance on modest hardware
Common use cases include private code hosting, team collaboration, open-source project management, DevOps pipelines, self-hosted CI/CD, package hosting, and decentralized software development.
This comprehensive guide walks you through deploying Forgejo on Klutch.sh using Docker, including database configuration, SSH access, persistent storage, environment variables, and production-ready best practices.
Why Deploy Forgejo on Klutch.sh?
- Complete Control: Own your Git infrastructure without vendor lock-in
- Simplified Infrastructure: No need to manage servers or complex configurations manually
- Persistent Storage: Reliable volume storage for Git repositories, uploads, and data
- Database Integration: Easy PostgreSQL or MySQL setup with persistent data storage
- Automatic HTTPS: Secure connections out of the box for safe code operations
- SSH Support: Enable Git over SSH for secure repository operations
- Environment Variables: Secure configuration management without hardcoding credentials
- Easy Scaling: Scale resources as your development team grows
- Cost-Effective: Pay only for what you use with transparent pricing
- Zero Downtime: Rolling deployments without disrupting development workflows
Prerequisites
Before you begin, ensure you have the following:
- A Klutch.sh account
- A GitHub account with a repository for your Forgejo project
- Docker installed locally for testing (optional but recommended)
- Basic understanding of Docker, Git, and database systems
- (Optional) A PostgreSQL or MySQL database - see our PostgreSQL guide or MySQL guide
Installation and Setup
Step 1: Create Your Project Directory
First, create a new directory for your Forgejo deployment project:
mkdir forgejo-klutchcd forgejo-klutchgit initStep 2: Create the Dockerfile
Create a Dockerfile in your project root directory. This will define your Forgejo container configuration:
FROM codeberg.org/forgejo/forgejo:11
# Forgejo runs on port 3000 by default for HTTPEXPOSE 3000
# Expose SSH port for Git operations over SSHEXPOSE 22
# The official image includes:# - Forgejo application (Go binary)# - Git command-line tools# - SSH server for Git operations# - SQLite, PostgreSQL, and MySQL drivers# - All required dependencies
# Data directory that should be mounted as a persistent volumeVOLUME /data
# The image uses the official Forgejo entrypoint# Configuration can be provided via environment variables or app.iniNote: The official Forgejo Docker image is production-ready and includes all necessary components. Version 11 refers to Forgejo v11 (the latest major version as of writing).
Step 3: Create Environment Variables Template
Create a .env.example file to document required environment variables:
# .env.example - Forgejo Configuration Template
# Application SettingsFORGEJO__server__DOMAIN=example-app.klutch.shFORGEJO__server__ROOT_URL=https://example-app.klutch.sh/FORGEJO__server__HTTP_PORT=3000FORGEJO__server__DISABLE_SSH=falseFORGEJO__server__SSH_PORT=22FORGEJO__server__START_SSH_SERVER=true
# Database Configuration (SQLite - default)FORGEJO__database__DB_TYPE=sqlite3FORGEJO__database__PATH=/data/forgejo.db
# Database Configuration (PostgreSQL - recommended for production)# FORGEJO__database__DB_TYPE=postgres# FORGEJO__database__HOST=postgres-app.klutch.sh:8000# FORGEJO__database__NAME=forgejo# FORGEJO__database__USER=forgejo# FORGEJO__database__PASSWD=your_secure_password
# Database Configuration (MySQL - alternative)# FORGEJO__database__DB_TYPE=mysql# FORGEJO__database__HOST=mysql-app.klutch.sh:8000# FORGEJO__database__NAME=forgejo# FORGEJO__database__USER=forgejo# FORGEJO__database__PASSWD=your_secure_password
# Security SettingsFORGEJO__security__INSTALL_LOCK=falseFORGEJO__security__SECRET_KEY=FORGEJO__security__INTERNAL_TOKEN=
# Service SettingsFORGEJO__service__DISABLE_REGISTRATION=falseFORGEJO__service__REQUIRE_SIGNIN_VIEW=falseFORGEJO__service__ENABLE_NOTIFY_MAIL=falseFORGEJO__service__DEFAULT_KEEP_EMAIL_PRIVATE=true
# Repository SettingsFORGEJO__repository__ROOT=/data/git/repositoriesFORGEJO__repository__DEFAULT_BRANCH=mainFORGEJO__repository__ENABLE_PUSH_CREATE_USER=trueFORGEJO__repository__ENABLE_PUSH_CREATE_ORG=true
# Actions (CI/CD) SettingsFORGEJO__actions__ENABLED=trueFORGEJO__actions__DEFAULT_ACTIONS_URL=https://code.forgejo.org
# Mailer Settings (optional)# FORGEJO__mailer__ENABLED=true# FORGEJO__mailer__SMTP_ADDR=smtp.gmail.com# FORGEJO__mailer__SMTP_PORT=587# FORGEJO__mailer__FROM=noreply@example.com# FORGEJO__mailer__USER=your-email@gmail.com# FORGEJO__mailer__PASSWD=your-app-password
# LoggingFORGEJO__log__MODE=consoleFORGEJO__log__LEVEL=Info
# Session SettingsFORGEJO__session__PROVIDER=memory# For production with multiple instances, use database:# FORGEJO__session__PROVIDER=dbNote: Forgejo uses double underscore (__) to separate configuration sections in environment variables. The format is FORGEJO__{section}__{key}.
Step 4: Create .gitignore
Create a .gitignore file to exclude sensitive and unnecessary files:
# Environment files.env*.env.local
# Forgejo data directory (if testing locally)data/forgejo-data/
# Docker volumesvolumes/
# Logs*.loglogs/
# OS files.DS_StoreThumbs.db
# IDE.vscode/.idea/*.swp*.swoStep 5: Test Locally (Optional)
Before deploying to Klutch.sh, you can test your Forgejo setup locally:
# Build the Docker imagedocker build -t my-forgejo .
# Run with SQLite (simplest setup)docker run -d \ --name forgejo-test \ -p 3000:3000 \ -p 2222:22 \ -v $(pwd)/forgejo-data:/data \ -e FORGEJO__server__DOMAIN=localhost \ -e FORGEJO__server__ROOT_URL=http://localhost:3000/ \ my-forgejo
# Access at http://localhost:3000# Stop with: docker stop forgejo-test && docker rm forgejo-testFor local development with PostgreSQL, you can use Docker Compose:
version: '3.8'
services: postgres: image: postgres:16-alpine environment: POSTGRES_DB: forgejo POSTGRES_USER: forgejo POSTGRES_PASSWORD: forgejo volumes: - postgres_data:/var/lib/postgresql/data ports: - "5432:5432"
forgejo: build: . depends_on: - postgres ports: - "3000:3000" - "2222:22" volumes: - forgejo_data:/data environment: - FORGEJO__server__DOMAIN=localhost - FORGEJO__server__ROOT_URL=http://localhost:3000/ - FORGEJO__database__DB_TYPE=postgres - FORGEJO__database__HOST=postgres:5432 - FORGEJO__database__NAME=forgejo - FORGEJO__database__USER=forgejo - FORGEJO__database__PASSWD=forgejo
volumes: postgres_data: forgejo_data:Start with docker-compose up -d and access at http://localhost:3000.
Step 6: Initialize Git Repository
Commit your files to Git:
# Add filesgit add Dockerfile .env.example .gitignoregit commit -m "Initial Forgejo setup for Klutch.sh deployment"
# Create GitHub repository and pushgit remote add origin https://github.com/yourusername/forgejo-klutch.gitgit branch -M mastergit push -u origin masterDeploying to Klutch.sh
Step 1: Push to GitHub
- Create a new repository on GitHub.
- Push your local repository:
git remote add origin https://github.com/yourusername/forgejo-klutch.gitgit branch -M mastergit push -u origin masterStep 2: Create a New App on Klutch.sh
- Log in to your Klutch.sh dashboard.
- Click New App and select your GitHub repository.
- Klutch.sh will automatically detect your
Dockerfileand prepare for deployment. - Select HTTP traffic since Forgejo is a web application.
- Set the internal port to 3000 (Forgejo's default HTTP port).
Step 3: Configure Environment Variables
In the Klutch.sh dashboard, add the following environment variables. Start with SQLite for simplicity, or configure PostgreSQL/MySQL for production.
Basic Configuration (SQLite):
# Application SettingsFORGEJO__server__DOMAIN=your-app.klutch.shFORGEJO__server__ROOT_URL=https://your-app.klutch.sh/FORGEJO__server__HTTP_PORT=3000
# Database (SQLite)FORGEJO__database__DB_TYPE=sqlite3FORGEJO__database__PATH=/data/forgejo.db
# SSH SettingsFORGEJO__server__DISABLE_SSH=falseFORGEJO__server__SSH_PORT=22FORGEJO__server__START_SSH_SERVER=true
# Repository SettingsFORGEJO__repository__ROOT=/data/git/repositoriesFORGEJO__repository__DEFAULT_BRANCH=main
# Actions (CI/CD)FORGEJO__actions__ENABLED=trueProduction Configuration (PostgreSQL):
If using PostgreSQL (recommended for production), deploy PostgreSQL first (see our PostgreSQL guide), then configure:
# Application SettingsFORGEJO__server__DOMAIN=your-app.klutch.shFORGEJO__server__ROOT_URL=https://your-app.klutch.sh/FORGEJO__server__HTTP_PORT=3000
# Database (PostgreSQL)FORGEJO__database__DB_TYPE=postgresFORGEJO__database__HOST=postgres-app.klutch.sh:8000FORGEJO__database__NAME=forgejoFORGEJO__database__USER=forgejo_userFORGEJO__database__PASSWD=your_secure_password
# SSH SettingsFORGEJO__server__DISABLE_SSH=falseFORGEJO__server__SSH_PORT=22FORGEJO__server__START_SSH_SERVER=true
# Security (will be auto-generated on first run if empty)FORGEJO__security__SECRET_KEY=FORGEJO__security__INTERNAL_TOKEN=
# Repository SettingsFORGEJO__repository__ROOT=/data/git/repositoriesFORGEJO__repository__DEFAULT_BRANCH=main
# ActionsFORGEJO__actions__ENABLED=trueFORGEJO__actions__DEFAULT_ACTIONS_URL=https://code.forgejo.org
# Service SettingsFORGEJO__service__DISABLE_REGISTRATION=falseFORGEJO__service__REQUIRE_SIGNIN_VIEW=falseMark sensitive variables like FORGEJO__database__PASSWD, FORGEJO__security__SECRET_KEY, and FORGEJO__security__INTERNAL_TOKEN as secret.
Step 4: Attach Persistent Volumes
Forgejo requires persistent storage for repositories, data, and configuration:
- In the Klutch.sh dashboard, navigate to Volumes.
- Add a persistent volume:
Primary Data Volume:
- Mount Path:
/data - Size: 20-100 GB (depending on expected repository size)
- Purpose: Git repositories, database (if using SQLite), configuration, logs, and user uploads
Note: All Forgejo data is stored in /data, including:
/data/forgejo.db- SQLite database (if using SQLite)/data/git/repositories- Git repository storage/data/gitea/conf- Configuration files (app.ini)/data/gitea/log- Application logs/data/forgejo/attachments- Issue and pull request attachments/data/gitea/indexers- Search indexes/data/tmp- Temporary files
Step 5: Deploy Your Application
- Click Deploy in the Klutch.sh dashboard.
- Klutch.sh will build your Docker image and deploy the application.
- Monitor the build logs for any errors.
- Once deployed, your Forgejo instance will be accessible at
https://your-app.klutch.sh.
Step 6: Complete Initial Setup
- Access your deployed Forgejo instance at
https://your-app.klutch.sh. - On first access, you'll see the installation wizard (if
FORGEJO__security__INSTALL_LOCK=false). - Review the pre-configured settings from environment variables.
- Create the initial administrator account with a strong password.
- Complete the installation to finalize setup.
After installation, the INSTALL_LOCK setting will be automatically set to true, preventing the installation wizard from running again.
Step 7: Configure SSH Access (Optional)
For Git operations over SSH (recommended for developers):
- SSH is enabled by default on port 22 inside the container.
- Git clone commands will use SSH format:
git clone ssh://git@your-app.klutch.sh:2222/username/repo.git - Add your SSH public key in Forgejo settings under Settings → SSH / GPG Keys.
- Test SSH access:
ssh -p 2222 git@your-app.klutch.sh
Note: If Klutch.sh doesn’t support custom SSH ports externally, you can still use HTTPS for Git operations: git clone https://your-app.klutch.sh/username/repo.git
Configuration
Database Options
Forgejo supports three database backends:
SQLite (Default - Suitable for Small Teams):
FORGEJO__database__DB_TYPE=sqlite3FORGEJO__database__PATH=/data/forgejo.db- Pros: Zero configuration, no external dependencies, easy backups
- Cons: Limited concurrency, not suitable for high-traffic instances
- Best for: Personal use, small teams (< 10 users), testing
PostgreSQL (Recommended for Production):
FORGEJO__database__DB_TYPE=postgresFORGEJO__database__HOST=postgres-app.klutch.sh:8000FORGEJO__database__NAME=forgejoFORGEJO__database__USER=forgejo_userFORGEJO__database__PASSWD=secure_password- Pros: Excellent performance, scalability, full-text search
- Cons: Requires separate database instance
- Best for: Medium to large teams, production deployments
MySQL/MariaDB (Alternative):
FORGEJO__database__DB_TYPE=mysqlFORGEJO__database__HOST=mysql-app.klutch.sh:8000FORGEJO__database__NAME=forgejoFORGEJO__database__USER=forgejo_userFORGEJO__database__PASSWD=secure_password- Pros: Wide compatibility, familiar to many teams
- Cons: Less feature-rich than PostgreSQL
- Best for: Organizations with existing MySQL infrastructure
Email Configuration
Configure SMTP for notifications, password resets, and collaboration features:
# Enable emailFORGEJO__mailer__ENABLED=trueFORGEJO__mailer__PROTOCOL=smtp
# SMTP server settingsFORGEJO__mailer__SMTP_ADDR=smtp.gmail.comFORGEJO__mailer__SMTP_PORT=587FORGEJO__mailer__USE_STARTTLS=true
# AuthenticationFORGEJO__mailer__USER=notifications@yourdomain.comFORGEJO__mailer__PASSWD=your_app_password
# Email settingsFORGEJO__mailer__FROM=Forgejo <noreply@yourdomain.com>FORGEJO__mailer__SKIP_VERIFY=falseRecommended SMTP Providers:
- Gmail: Free for low volume (use app-specific password)
- SendGrid: Excellent deliverability, generous free tier
- Mailgun: Great for transactional emails
- Amazon SES: Cost-effective for high volume
Git Operations Configuration
Fine-tune Git operations and repository settings:
# Repository defaultsFORGEJO__repository__ROOT=/data/git/repositoriesFORGEJO__repository__DEFAULT_BRANCH=mainFORGEJO__repository__DEFAULT_PRIVATE=privateFORGEJO__repository__ENABLE_PUSH_CREATE_USER=trueFORGEJO__repository__ENABLE_PUSH_CREATE_ORG=true
# Git configurationFORGEJO__git__DISABLE_DIFF_HIGHLIGHT=falseFORGEJO__git__MAX_GIT_DIFF_FILES=100FORGEJO__git__MAX_GIT_DIFF_LINES=5000FORGEJO__git__TIMEOUT__DEFAULT=360FORGEJO__git__TIMEOUT__MIGRATE=600FORGEJO__git__TIMEOUT__MIRROR=300FORGEJO__git__TIMEOUT__CLONE=300FORGEJO__git__TIMEOUT__PULL=300FORGEJO__git__TIMEOUT__GC=60
# LFS (Large File Storage)FORGEJO__lfs__START_SERVER=trueFORGEJO__lfs__STORAGE_TYPE=localFORGEJO__lfs__PATH=/data/lfsForgejo Actions (CI/CD)
Configure Forgejo Actions for continuous integration and deployment:
# Enable ActionsFORGEJO__actions__ENABLED=true
# Default Actions URL (compatible with GitHub Actions)FORGEJO__actions__DEFAULT_ACTIONS_URL=https://code.forgejo.org
# Or use GitHub for broader action availability# FORGEJO__actions__DEFAULT_ACTIONS_URL=https://github.com
# Actions artifactsFORGEJO__actions__ARTIFACTS_STORAGE_TYPE=localFORGEJO__actions__ARTIFACTS_PATH=/data/actions_artifactsTo use Actions, you’ll need to deploy Forgejo Runners separately to execute workflows.
Security Settings
Enhance security with these configuration options:
# Security keys (auto-generated on first run if empty)FORGEJO__security__INSTALL_LOCK=falseFORGEJO__security__SECRET_KEY=FORGEJO__security__INTERNAL_TOKEN=
# Password requirementsFORGEJO__security__MIN_PASSWORD_LENGTH=8FORGEJO__security__PASSWORD_COMPLEXITY=lower,upper,digitFORGEJO__security__PASSWORD_HASH_ALGO=pbkdf2
# Session securityFORGEJO__security__COOKIE_NAME=i_like_forgejoFORGEJO__security__COOKIE_SECURE=trueFORGEJO__security__LOGIN_REMEMBER_DAYS=7
# CSRF protectionFORGEJO__security__CSRF_TOKEN_GENERATION_INTERVAL=600Performance Tuning
Optimize Forgejo for your workload:
# HTTP serverFORGEJO__server__HTTP_PORT=3000FORGEJO__server__PROTOCOL=httpFORGEJO__server__CERT_FILE=FORGEJO__server__KEY_FILE=
# PerformanceFORGEJO__server__ENABLE_GZIP=trueFORGEJO__server__LANDING_PAGE=exploreFORGEJO__server__LFS_START_SERVER=true
# CachingFORGEJO__cache__ENABLED=trueFORGEJO__cache__ADAPTER=memoryFORGEJO__cache__INTERVAL=60FORGEJO__cache__HOST=
# Indexer (for code search)FORGEJO__indexer__ISSUE_INDEXER_TYPE=bleveFORGEJO__indexer__ISSUE_INDEXER_PATH=/data/indexers/issues.bleveFORGEJO__indexer__REPO_INDEXER_ENABLED=trueFORGEJO__indexer__REPO_INDEXER_TYPE=bleveFORGEJO__indexer__REPO_INDEXER_PATH=/data/indexers/repos.bleveSample Code: Using Forgejo API
Forgejo provides a comprehensive REST API compatible with Gitea and GitHub APIs. Here are examples in multiple languages:
Ruby - Create a Repository
require 'net/http'require 'json'require 'uri'
# Configure API credentialsforgejo_url = 'https://your-app.klutch.sh'api_token = 'your_api_token_here'
# Create a new repositoryuri = URI("#{forgejo_url}/api/v1/user/repos")request = Net::HTTP::Post.new(uri)request['Authorization'] = "token #{api_token}"request['Content-Type'] = 'application/json'
request.body = { name: 'my-new-repo', description: 'Created via API', private: false, auto_init: true, default_branch: 'main', gitignores: 'Go', license: 'MIT', readme: 'Default'}.to_json
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http| http.request(request)end
if response.code == '201' repo = JSON.parse(response.body) puts "Repository created: #{repo['html_url']}" puts "Clone URL: #{repo['clone_url']}"else puts "Error: #{response.code} - #{response.body}"endPython - List Repositories
import requestsimport json
# Configure API credentialsforgejo_url = 'https://your-app.klutch.sh'api_token = 'your_api_token_here'
headers = { 'Authorization': f'token {api_token}', 'Content-Type': 'application/json'}
# List all user repositoriesresponse = requests.get( f'{forgejo_url}/api/v1/user/repos', headers=headers, params={'limit': 50, 'page': 1})
if response.status_code == 200: repos = response.json() print(f"Found {len(repos)} repositories:")
for repo in repos: print(f"\n{repo['full_name']}") print(f" Private: {repo['private']}") print(f" Clone: {repo['clone_url']}") print(f" Stars: {repo['stars_count']}") print(f" Forks: {repo['forks_count']}")else: print(f"Error: {response.status_code} - {response.text}")JavaScript - Create an Issue
const axios = require('axios');
// Configure API credentialsconst forgejoUrl = 'https://your-app.klutch.sh';const apiToken = 'your_api_token_here';
// Create a new issueasync function createIssue(owner, repo, issueData) { try { const response = await axios.post( `${forgejoUrl}/api/v1/repos/${owner}/${repo}/issues`, { title: issueData.title, body: issueData.body, labels: issueData.labels || [], assignees: issueData.assignees || [], milestone: issueData.milestone || null }, { headers: { 'Authorization': `token ${apiToken}`, 'Content-Type': 'application/json' } } );
const issue = response.data; console.log(`Issue created: #${issue.number}`); console.log(`Title: ${issue.title}`); console.log(`URL: ${issue.html_url}`);
return issue; } catch (error) { console.error('Error creating issue:', error.response?.data || error.message); throw error; }}
// UsagecreateIssue('username', 'my-repo', { title: 'Bug: Application crashes on startup', body: 'Detailed description of the bug...', labels: ['bug', 'high-priority'], assignees: ['developer1']}).then(issue => console.log('Success:', issue)).catch(err => console.error('Failed:', err));Go - Clone and Commit
package main
import ( "fmt" "log" "os" "time"
"github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/plumbing/object" "github.com/go-git/go-git/v5/plumbing/transport/http")
func main() { // Clone repository cloneURL := "https://your-app.klutch.sh/username/my-repo.git" username := "your-username" token := "your_api_token"
dir := "/tmp/my-repo"
fmt.Println("Cloning repository...") repo, err := git.PlainClone(dir, false, &git.CloneOptions{ URL: cloneURL, Auth: &http.BasicAuth{ Username: username, Password: token, }, Progress: os.Stdout, }) if err != nil { log.Fatal(err) }
// Create a new file filename := dir + "/README.md" content := []byte("# Updated via Go\n\nThis file was updated programmatically.")
if err := os.WriteFile(filename, content, 0644); err != nil { log.Fatal(err) }
// Stage the file w, err := repo.Worktree() if err != nil { log.Fatal(err) }
if _, err := w.Add("README.md"); err != nil { log.Fatal(err) }
// Commit commit, err := w.Commit("Update README via API", &git.CommitOptions{ Author: &object.Signature{ Name: "API User", Email: "api@example.com", When: time.Now(), }, }) if err != nil { log.Fatal(err) }
fmt.Printf("Commit created: %s\n", commit.String())
// Push fmt.Println("Pushing changes...") if err := repo.Push(&git.PushOptions{ Auth: &http.BasicAuth{ Username: username, Password: token, }, }); err != nil { log.Fatal(err) }
fmt.Println("Changes pushed successfully!")}PHP - Manage Webhooks
<?php
// Configure API credentials$forgejoUrl = 'https://your-app.klutch.sh';$apiToken = 'your_api_token_here';$owner = 'username';$repo = 'my-repo';
// Function to create a webhookfunction createWebhook($forgejoUrl, $apiToken, $owner, $repo, $webhookUrl) { $ch = curl_init();
$data = [ 'type' => 'forgejo', 'config' => [ 'url' => $webhookUrl, 'content_type' => 'json', 'secret' => bin2hex(random_bytes(16)) ], 'events' => ['push', 'pull_request', 'issues'], 'active' => true ];
curl_setopt_array($ch, [ CURLOPT_URL => "$forgejoUrl/api/v1/repos/$owner/$repo/hooks", CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_POSTFIELDS => json_encode($data), CURLOPT_HTTPHEADER => [ "Authorization: token $apiToken", "Content-Type: application/json" ] ]);
$response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch);
if ($httpCode === 201) { $webhook = json_decode($response, true); echo "Webhook created successfully!\n"; echo "ID: {$webhook['id']}\n"; echo "URL: {$webhook['config']['url']}\n"; echo "Secret: {$webhook['config']['secret']}\n"; return $webhook; } else { echo "Error: $httpCode - $response\n"; return null; }}
// Function to list webhooksfunction listWebhooks($forgejoUrl, $apiToken, $owner, $repo) { $ch = curl_init();
curl_setopt_array($ch, [ CURLOPT_URL => "$forgejoUrl/api/v1/repos/$owner/$repo/hooks", CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ "Authorization: token $apiToken", "Content-Type: application/json" ] ]);
$response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch);
if ($httpCode === 200) { $webhooks = json_decode($response, true); echo "Found " . count($webhooks) . " webhooks:\n\n";
foreach ($webhooks as $webhook) { echo "ID: {$webhook['id']}\n"; echo "URL: {$webhook['config']['url']}\n"; echo "Events: " . implode(', ', $webhook['events']) . "\n"; echo "Active: " . ($webhook['active'] ? 'Yes' : 'No') . "\n\n"; }
return $webhooks; } else { echo "Error: $httpCode - $response\n"; return null; }}
// Usageecho "Creating webhook...\n";createWebhook($forgejoUrl, $apiToken, $owner, $repo, 'https://hooks.example.com/forgejo');
echo "\n\nListing all webhooks...\n";listWebhooks($forgejoUrl, $apiToken, $owner, $repo);
?>Production Best Practices
Security Hardening
- Use Strong Database Passwords: Generate secure passwords for database credentials.
# Generate secure passwordopenssl rand -base64 32- Enable HTTPS Only: Klutch.sh provides automatic HTTPS, but ensure your ROOT_URL uses
https://. - Restrict Registration: For private instances, disable public registration:
FORGEJO__service__DISABLE_REGISTRATION=trueFORGEJO__service__REQUIRE_SIGNIN_VIEW=true- Configure Rate Limiting: Protect against abuse with rate limits:
FORGEJO__server__ENABLE_RATE_LIMIT=trueFORGEJO__server__RATE_LIMIT_BURST=10FORGEJO__server__RATE_LIMIT_INTERVAL=60s- Enable Two-Factor Authentication: Encourage or require 2FA for users.
- Regular Security Updates: Keep Forgejo updated to the latest version:
FROM codeberg.org/forgejo/forgejo:11# Check releases: https://codeberg.org/forgejo/forgejo/releases- Audit Logs: Monitor admin actions and security events through Forgejo's admin panel.
Performance Optimization
- Use PostgreSQL: For production deployments with multiple users, use PostgreSQL instead of SQLite.
- Enable Caching: Configure Redis for improved performance (optional):
FORGEJO__cache__ENABLED=trueFORGEJO__cache__ADAPTER=redisFORGEJO__cache__HOST=redis-app.klutch.sh:8000- Enable Indexing: Improve search performance with code indexing:
FORGEJO__indexer__REPO_INDEXER_ENABLED=trueFORGEJO__indexer__REPO_INDEXER_TYPE=bleve- Configure Git LFS: For large files, enable Git LFS:
FORGEJO__lfs__START_SERVER=trueFORGEJO__lfs__STORAGE_TYPE=localFORGEJO__lfs__PATH=/data/lfs- Optimize Database: Regularly maintain your database with VACUUM (PostgreSQL) or OPTIMIZE (MySQL).
Backup Strategy
- Volume Backups: Regularly backup the
/datavolume containing repositories and configuration.
# Backup script exampletar -czf forgejo-backup-$(date +%Y%m%d).tar.gz /path/to/data/volume- Database Backups: If using PostgreSQL, backup the database separately:
# PostgreSQL backuppg_dump forgejo > forgejo-db-backup-$(date +%Y%m%d).sql
# Compressed backuppg_dump forgejo | gzip > forgejo-db-backup-$(date +%Y%m%d).sql.gz- Automated Backups: Schedule automated backups daily or weekly depending on activity level.
- Test Restores: Periodically test backup restoration to ensure data integrity.
- Offsite Storage: Store backups in a separate location or cloud storage (S3, Backblaze B2).
Monitoring and Logging
- Application Logs: Monitor Forgejo logs for errors and warnings:
FORGEJO__log__MODE=console,fileFORGEJO__log__LEVEL=InfoFORGEJO__log__ROOT_PATH=/data/forgejo/log- Health Checks: Use Forgejo's built-in health endpoint for monitoring:
curl https://your-app.klutch.sh/api/healthz- Webhook Monitoring: Monitor webhook deliveries in the admin panel.
- Resource Monitoring: Track CPU, memory, and disk usage through Klutch.sh dashboard.
- Database Monitoring: Monitor database performance, especially query times and connection pool usage.
Scaling Recommendations
- Vertical Scaling: Start with 1-2 GB RAM, scale to 4-8 GB for larger teams (100+ users).
- Storage Scaling: Monitor repository growth and expand volume size as needed.
- Database Optimization: Add indexes for frequently queried fields, tune connection pools.
- Consider Caching: Deploy Redis for caching frequently accessed data.
- Load Balancing: For high availability, run multiple Forgejo instances behind a load balancer (requires shared storage and database).
Troubleshooting
Cannot Access Forgejo Web Interface
Problem: Unable to access Forgejo at the deployed URL.
Solution:
- Verify deployment status in Klutch.sh dashboard
- Check that HTTP traffic is enabled and port 3000 is configured
- Review deployment logs for startup errors
- Ensure
FORGEJO__server__ROOT_URLmatches your actual URL - Check that persistent volume is properly mounted at
/data
Database Connection Errors
Problem: Forgejo fails to connect to PostgreSQL or MySQL database.
Solution:
- Verify database is deployed and accessible
- Check database credentials in environment variables
- Test database connection:
telnet postgres-app.klutch.sh 8000 - Ensure database name exists and user has proper permissions
- Review Forgejo logs for specific database errors
Git Operations Fail
Problem: Cannot clone, push, or pull repositories.
Solution:
- For HTTPS: Verify your username and password/token
- For SSH: Check SSH key is added to your Forgejo account
- Ensure repository permissions are correctly configured
- Check Git LFS is enabled if using large files
- Verify firewall rules allow Git protocol traffic
SSH Port Issues
Problem: Cannot connect to Forgejo via SSH.
Solution:
- Verify SSH is enabled:
FORGEJO__server__DISABLE_SSH=false - Check SSH server is running:
FORGEJO__server__START_SSH_SERVER=true - Use correct SSH URL format:
ssh://git@your-app.klutch.sh:2222/user/repo.git - Test SSH connection:
ssh -p 2222 git@your-app.klutch.sh - If custom SSH ports aren’t supported, use HTTPS instead
Installation Wizard Reappears
Problem: Installation wizard shows up after initial setup.
Solution:
- Check that installation completed successfully
- Verify
INSTALL_LOCK=truein/data/forgejo/conf/app.ini - Set environment variable:
FORGEJO__security__INSTALL_LOCK=true - Ensure persistent volume is properly mounted
Performance Issues
Problem: Slow page loads, timeouts, or unresponsive interface.
Solution:
- Check resource usage (CPU, memory) in Klutch.sh dashboard
- Switch from SQLite to PostgreSQL for better performance
- Enable caching with Redis
- Optimize database indexes and queries
- Increase container resources (RAM, CPU)
- Enable repository indexing for faster code search
- Clear temporary files and caches in
/data/tmp
Email Not Sending
Problem: Email notifications not working.
Solution:
- Verify SMTP settings are correct
- Test SMTP connection manually
- Check SMTP credentials and authentication
- Enable debug logging:
FORGEJO__log__LEVEL=Debug - Verify email provider allows SMTP access
- Check spam folders for test emails
Additional Resources
- Forgejo Official Website
- Forgejo Source Code
- Forgejo Documentation
- Administrator Guide
- User Guide
- Forgejo Runner (for Actions)
- Forgejo Actions & Packages
- Forgejo Community Forum
- PostgreSQL Deployment Guide
- MySQL Deployment Guide
- Klutch.sh Persistent Volumes
- Klutch.sh Networking
You now have a fully functional Forgejo instance running on Klutch.sh! Your team can host Git repositories, collaborate on code, manage issues, run CI/CD workflows, and build software together with complete control and privacy. Remember to regularly backup your data, keep Forgejo updated, and monitor performance as your development team grows.