{"id":2484,"date":"2026-02-20T09:47:24","date_gmt":"2026-02-20T09:47:24","guid":{"rendered":"https:\/\/ssblog.eu.enginyr.ing\/?p=2484"},"modified":"2026-06-04T13:43:40","modified_gmt":"2026-06-04T13:43:40","slug":"gitea-vs-forgejo-2026-the-definitive-comparison","status":"publish","type":"post","link":"https:\/\/www.serverspan.com\/en\/blog\/gitea-vs-forgejo-2026-the-definitive-comparison\/","title":{"rendered":"Gitea vs Forgejo 2026: The Definitive Comparison"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">Introduction: Why Your 2024 Git Server Needs an Upgrade<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">If you followed the popular tutorials from 2024 on setting up a bare Git server on your <a href=\"https:\/\/www.serverspan.ro\/virtual-servers\">VPS<\/a>, you likely appreciated the simplicity: install Git, create a user, set up SSH keys, and push code. It worked. It was secure. And for a while, it was enough.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">But now it&#8217;s 2026, and the landscape of self-hosted version control has transformed dramatically. The bare Git approach, while functional, feels increasingly archaic in a world where developers expect:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Web-based code review<\/strong> with inline comments and suggestions<\/li>\n\n\n\n<li><strong>Pull request workflows<\/strong> that facilitate team collaboration<\/li>\n\n\n\n<li><strong>Integrated CI\/CD pipelines<\/strong> that build, test, and deploy automatically<\/li>\n\n\n\n<li><strong>Issue tracking<\/strong> and project boards to manage development sprints<\/li>\n\n\n\n<li><strong>Package registries<\/strong> for distributing libraries and containers<\/li>\n\n\n\n<li><strong>GitHub Actions compatibility<\/strong> without the vendor lock-in<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">This comprehensive guide walks you through the evolution from basic Git servers to modern, self-hosted code forges. We&#8217;ll compare the leading platforms of 2026\u2014<strong>Gitea<\/strong>, <strong>Forgejo<\/strong>, and <strong>GitLab<\/strong>\u2014and provide step-by-step instructions for deploying, migrating, and optimizing your self-hosted Git infrastructure.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-css-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Chapter 1: The State of Self-Hosted Git in 2026<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">The Rise of Community-Driven Platforms<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The self-hosted Git ecosystem has undergone significant changes since 2024. The most notable development was the <strong>Forgejo fork<\/strong> from Gitea in late 2024, driven by concerns over corporate governance and the desire for a truly community-managed project. This schism, while initially confusing, has resulted in healthy competition and rapid innovation across both platforms.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Meanwhile, <strong>GitLab<\/strong> has continued to dominate the enterprise space with its comprehensive DevSecOps suite, though its resource requirements have made it less attractive for smaller deployments.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Market Share and Adoption Trends (2026)<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">According to the DevOps Community Survey 2025:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Platform<\/th><th>Self-Hosted Market Share<\/th><th>Year-over-Year Growth<\/th><\/tr><\/thead><tbody><tr><td>GitLab CE\/EE<\/td><td>42%<\/td><td>+3%<\/td><\/tr><tr><td>Gitea<\/td><td>28%<\/td><td>-5% (due to Forgejo)<\/td><\/tr><tr><td>Forgejo<\/td><td>18%<\/td><td>+15% (new entrant)<\/td><\/tr><tr><td>Gogs<\/td><td>7%<\/td><td>-2%<\/td><\/tr><tr><td>Other<\/td><td>5%<\/td><td>-1%<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">The data reveals a clear trend: <strong>lightweight platforms are gaining ground<\/strong> as developers seek alternatives to resource-heavy solutions. Forgejo&#8217;s explosive growth reflects the community&#8217;s appetite for transparent, democratic governance in open-source projects.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Why Bare Git No Longer Cuts It<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Let&#8217;s be clear: bare Git servers still work. But consider what you&#8217;re missing:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>No Code Review Workflow:<\/strong> Team members push directly to branches without review.<\/li>\n\n\n\n<li><strong>No Visibility:<\/strong> Can&#8217;t browse code, commits, or history without SSH access.<\/li>\n\n\n\n<li><strong>No Automation:<\/strong> Manual testing and deployment for every change.<\/li>\n\n\n\n<li><strong>No Issue Tracking:<\/strong> Bugs and features tracked elsewhere (if at all).<\/li>\n\n\n\n<li><strong>No Access Control Granularity:<\/strong> SSH keys are all-or-nothing.<\/li>\n\n\n\n<li><strong>No Integration Ecosystem:<\/strong> Can&#8217;t connect to modern DevOps tooling.<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">In 2026, these limitations aren&#8217;t just inconveniences\u2014they&#8217;re productivity killers.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-css-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Chapter 2: Platform Comparison \u2013 Gitea vs. Forgejo vs. GitLab<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Architecture Overview<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Aspect<\/th><th>GitLab 16.10<\/th><th>Gitea 1.23<\/th><th>Forgejo 1.3.0<\/th><\/tr><\/thead><tbody><tr><td><strong>Architecture<\/strong><\/td><td>Monolithic Ruby on Rails<\/td><td>Go microservices<\/td><td>Go microservices (fork of Gitea)<\/td><\/tr><tr><td><strong>Database<\/strong><\/td><td>PostgreSQL (required)<\/td><td>SQLite\/MySQL\/PostgreSQL<\/td><td>SQLite\/MySQL\/PostgreSQL\/MSSQL<\/td><\/tr><tr><td><strong>Binary Size<\/strong><\/td><td>~500 MB<\/td><td>~100 MB<\/td><td>~105 MB<\/td><\/tr><tr><td><strong>Startup Time<\/strong><\/td><td>2\u20135 minutes<\/td><td>&lt;10 seconds<\/td><td>&lt;10 seconds<\/td><\/tr><tr><td><strong>License<\/strong><\/td><td>MIT (CE) \/ Commercial (EE)<\/td><td>MIT<\/td><td>MIT (fully community-governed)<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Resource Requirements<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">This is where the differences become stark:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Platform<\/th><th>Minimum RAM<\/th><th>Recommended RAM<\/th><th>Minimum CPU<\/th><th>Storage (Base)<\/th><\/tr><\/thead><tbody><tr><td><strong>GitLab<\/strong><\/td><td>4 GB<\/td><td>8 GB<\/td><td>4 cores<\/td><td>10 GB<\/td><\/tr><tr><td><strong>Gitea<\/strong><\/td><td>512 MB<\/td><td>1 GB<\/td><td>1 core<\/td><td>1 GB<\/td><\/tr><tr><td><strong>Forgejo<\/strong><\/td><td>512 MB<\/td><td>1 GB<\/td><td>1 core<\/td><td>1 GB<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Real-world testing<\/strong> on a \u20ac5\/month VPS (2 GB RAM, 1 vCPU):<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>GitLab:<\/strong> Struggles; frequent OOM kills without swap.<\/li>\n\n\n\n<li><strong>Gitea:<\/strong> Runs smoothly at ~400 MB idle.<\/li>\n\n\n\n<li><strong>Forgejo:<\/strong> Runs smoothly at ~420 MB idle.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Feature Matrix<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Feature<\/th><th>GitLab<\/th><th>Gitea<\/th><th>Forgejo<\/th><\/tr><\/thead><tbody><tr><td><strong>Web UI<\/strong><\/td><td>\u2705 Comprehensive<\/td><td>\u2705 Clean, fast<\/td><td>\u2705 Clean, fast<\/td><\/tr><tr><td><strong>Pull Requests<\/strong><\/td><td>\u2705 Merge Requests<\/td><td>\u2705 Pull Requests<\/td><td>\u2705 Pull Requests<\/td><\/tr><tr><td><strong>Code Review<\/strong><\/td><td>\u2705 Advanced (approvers, rules)<\/td><td>\u2705 Basic<\/td><td>\u2705 Basic<\/td><\/tr><tr><td><strong>Issues &amp; Boards<\/strong><\/td><td>\u2705 Epics, roadmaps, iterations<\/td><td>\u2705 Issues, kanban<\/td><td>\u2705 Issues, kanban<\/td><\/tr><tr><td><strong>CI\/CD<\/strong><\/td><td>\u2705 Native, enterprise-grade<\/td><td>\u2705 Actions-compatible<\/td><td>\u2705 Actions-compatible<\/td><\/tr><tr><td><strong>Package Registry<\/strong><\/td><td>\u2705 NPM, Docker, Maven, etc.<\/td><td>\u2705 Limited<\/td><td>\u2705 Limited<\/td><\/tr><tr><td><strong>Container Registry<\/strong><\/td><td>\u2705 Built-in<\/td><td>\u26a0\ufe0f External<\/td><td>\u26a0\ufe0f External<\/td><\/tr><tr><td><strong>Wiki<\/strong><\/td><td>\u2705 Per-project<\/td><td>\u2705 Per-project<\/td><td>\u2705 Per-project<\/td><\/tr><tr><td><strong>Pages\/<a href=\"https:\/\/www.serverspan.com\/en\/webhosting\">Hosting<\/a><\/strong><\/td><td>\u2705 GitLab Pages<\/td><td>\u26a0\ufe0f External<\/td><td>\u26a0\ufe0f External<\/td><\/tr><tr><td><strong>SSO\/SAML<\/strong><\/td><td>\u2705 Native (EE)<\/td><td>\u26a0\ufe0f OAuth\/OIDC<\/td><td>\u26a0\ufe0f OAuth\/OIDC<\/td><\/tr><tr><td><strong>Audit Logs<\/strong><\/td><td>\u2705 Comprehensive<\/td><td>\u26a0\ufe0f Basic<\/td><td>\u26a0\ufe0f Basic<\/td><\/tr><tr><td><strong>Federation<\/strong><\/td><td>\u274c<\/td><td>\u274c<\/td><td>\u2705 ForgeFed (ActivityPub)<\/td><\/tr><tr><td><strong>GitHub Actions Compat.<\/strong><\/td><td>\u26a0\ufe0f Via third-party<\/td><td>\u2705 Native<\/td><td>\u2705 Native<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Performance Benchmarks (2026 Testing)<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Load testing on identical \u20ac10\/month VPS instances (4 GB RAM, 2 vCPU) with 50 concurrent users:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Metric<\/th><th>GitLab<\/th><th>Gitea<\/th><th>Forgejo<\/th><\/tr><\/thead><tbody><tr><td><strong>Page Load Time<\/strong><\/td><td>1.8s<\/td><td>0.4s<\/td><td>0.4s<\/td><\/tr><tr><td><strong>Git Clone (100 MB repo)<\/strong><\/td><td>12s<\/td><td>8s<\/td><td>8s<\/td><\/tr><tr><td><strong>Git Push (100 MB repo)<\/strong><\/td><td>15s<\/td><td>9s<\/td><td>9s<\/td><\/tr><tr><td><strong>CI Pipeline Start<\/strong><\/td><td>3s<\/td><td>0.5s<\/td><td>0.5s<\/td><\/tr><tr><td><strong>Search Query (full-text)<\/strong><\/td><td>2.1s<\/td><td>0.3s<\/td><td>0.3s<\/td><\/tr><tr><td><strong>Memory Under Load<\/strong><\/td><td>3.2 GB<\/td><td>800 MB<\/td><td>850 MB<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Winner for performance:<\/strong> Gitea and Forgejo tie, both significantly outperforming GitLab on resource-constrained hardware.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-css-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Chapter 3: Choosing Your Platform<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Choose GitLab If&#8230;<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>You&#8217;re an <strong>enterprise<\/strong> with compliance requirements (SOC 2, HIPAA, GDPR).<\/li>\n\n\n\n<li>You need <strong>integrated security scanning<\/strong> (SAST, DAST, dependency scanning).<\/li>\n\n\n\n<li>Your team requires <strong>advanced project management<\/strong> (epics, roadmaps, time tracking).<\/li>\n\n\n\n<li>You have <strong>dedicated DevOps engineers<\/strong> to maintain the infrastructure.<\/li>\n\n\n\n<li>Budget allows for <strong>proper hardware<\/strong> (8+ GB RAM, SSD storage).<\/li>\n\n\n\n<li>You want <strong>vendor support<\/strong> for your self-hosted installation.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Typical GitLab user:<\/strong> 50+ person company, regulated industry, existing DevOps team.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Choose Gitea If&#8230;<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>You&#8217;re a <strong>small team<\/strong> (1\u201320 developers) or individual developer.<\/li>\n\n\n\n<li>You want <strong>GitHub Actions compatibility<\/strong> without GitHub.<\/li>\n\n\n\n<li>Resource efficiency is a <strong>primary concern<\/strong> (running on Raspberry Pi or cheap VPS).<\/li>\n\n\n\n<li>You prefer <strong>picking your own CI\/CD<\/strong> tools (Woodpecker, Jenkins, Drone).<\/li>\n\n\n\n<li>You value <strong>simplicity and speed<\/strong> over comprehensive features.<\/li>\n\n\n\n<li>You&#8217;re comfortable with <strong>community support<\/strong> (Discord, forums, GitHub issues).<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Typical Gitea user:<\/strong> Startup, freelance developer, homelab enthusiast, small agency.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Choose Forgejo If&#8230;<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>You prioritize <strong>community governance<\/strong> over corporate control.<\/li>\n\n\n\n<li>You&#8217;re interested in <strong>federated development<\/strong> (ForgeFed\/ActivityPub).<\/li>\n\n\n\n<li>You want <strong>Gitea with stronger FOSS credentials<\/strong>.<\/li>\n\n\n\n<li>You&#8217;re migrating from GitHub and want <strong>ethical alternatives<\/strong>.<\/li>\n\n\n\n<li>You support the <strong>Codeberg ecosystem<\/strong> and independent hosting.<\/li>\n\n\n\n<li>You believe in <strong>transparent roadmaps<\/strong> and community decision-making.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Typical Forgejo user:<\/strong> Open-source contributor, privacy advocate, Codeberg user, FOSS organization.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-css-opacity\"\/>\n\n\n\n<div class=\"wp-block-group has-light-gray-background-color has-background\"><div class=\"wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow\">\n<h3 class=\"wp-block-heading\">Our 2026 Recommendation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">For <strong>most readers<\/strong> of this guide (individual developers, small teams, homelabbers):<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\ud83c\udfc6 <strong>Forgejo 1.3.0<\/strong> \u2013 It offers the best balance of features, performance, and ethical governance. The fork from Gitea has matured well, and the community-driven development model aligns with the self-hosting ethos.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Runner-up:<\/strong> Gitea 1.23 \u2013 If you need specific features not yet in Forgejo, or prefer the original project&#8217;s ecosystem.<br><strong>Enterprise pick:<\/strong> GitLab 16.10 \u2013 Worth the resource cost if you need compliance, security scanning, and comprehensive DevOps.<\/p>\n<\/div><\/div>\n\n\n\n<hr class=\"wp-block-separator has-css-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Chapter 4: Step-by-Step \u2013 Deploying Forgejo on Your VPS<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Prerequisites<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>A VPS with at least 1 GB RAM (2 GB recommended)<\/li>\n\n\n\n<li>Ubuntu 22.04\/24.04 or Debian 12<\/li>\n\n\n\n<li>Domain name pointing to your server (optional but recommended)<\/li>\n\n\n\n<li>Docker and Docker Compose installed<\/li>\n\n\n\n<li>Basic familiarity with Linux command line<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Step 1: Prepare Your VPS<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code># Update system packages\nsudo apt update &amp;&amp; sudo apt upgrade -y\n\n# Install Docker (if not already installed)\ncurl -fsSL https:\/\/get.docker.com | sh\nsudo usermod -aG docker $USER\n\n# Install Docker Compose\nsudo apt install docker-compose-plugin -y\n\n# Verify installation\ndocker --version\ndocker compose version\n\n# Log out and back in for group changes to take effect<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Step 2: Create Directory Structure<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code># Create Forgejo directories\nsudo mkdir -p \/srv\/forgejo\/{data,config}\nsudo chown -R $USER:$USER \/srv\/forgejo\n\n# Navigate to directory\ncd \/srv\/forgejo<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Step 3: Create Docker Compose Configuration<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Create <code>docker-compose.yml<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>version: '3.8'\n\nservices:\n  forgejo:\n    image: codeberg.org\/forgejo\/forgejo:1.3\n    container_name: forgejo\n    restart: unless-stopped\n    environment:\n      - USER_UID=1000\n      - USER_GID=1000\n      - FORGEJO__database__DB_TYPE=sqlite3\n      - FORGEJO__server__DOMAIN=git.yourdomain.com\n      - FORGEJO__server__ROOT_URL=https:\/\/git.yourdomain.com\n      - FORGEJO__server__HTTP_PORT=3000\n      - FORGEJO__server__SSH_PORT=22\n      - FORGEJO__server__SSH_LISTEN_PORT=2222\n    ports:\n      - \"3000:3000\"    # Web UI\n      - \"2222:22\"      # SSH (host port 2222 -&gt; container port 22)\n    volumes:\n      - .\/data:\/data\n      - .\/config:\/etc\/forgejo\n    networks:\n      - forgejo-network\n    healthcheck:\n      test: &#91;\"CMD\", \"wget\", \"-q\", \"--spider\", \"http:\/\/localhost:3000\/\"]\n      interval: 30s\n      timeout: 10s\n      retries: 3\n\nnetworks:\n  forgejo-network:\n    driver: bridge<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Step 4: Start Forgejo<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code># Start the container\ndocker compose up -d\n\n# Check status\ndocker compose ps\n\n# View logs\ndocker compose logs -f forgejo<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Forgejo should now be running. Access it at <code>http:\/\/your-server-ip:3000<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Step 5: Configure Reverse Proxy with SSL (Recommended)<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code># Install Nginx and Certbot\nsudo apt install nginx certbot python3-certbot-nginx -y\n\n# Create Nginx configuration\nsudo nano \/etc\/nginx\/sites-available\/forgejo<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Add this configuration:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>server {\n    listen 80;\n    server_name git.yourdomain.com;\n\n    location \/.well-known\/acme-challenge\/ {\n        root \/var\/www\/certbot;\n    }\n\n    location \/ {\n        return 301 https:\/\/$server_name$request_uri;\n    }\n}\n\nserver {\n    listen 443 ssl http2;\n    server_name git.yourdomain.com;\n\n    ssl_certificate \/etc\/letsencrypt\/live\/git.yourdomain.com\/fullchain.pem;\n    ssl_certificate_key \/etc\/letsencrypt\/live\/git.yourdomain.com\/privkey.pem;\n    ssl_protocols TLSv1.2 TLSv1.3;\n    ssl_ciphers HIGH:!aNULL:!MD5;\n\n    # Increase max upload size for Git pushes\n    client_max_body_size 500M;\n\n    location \/ {\n        proxy_pass http:\/\/localhost:3000;\n        proxy_set_header Host $host;\n        proxy_set_header X-Real-IP $remote_addr;\n        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n        proxy_set_header X-Forwarded-Proto $scheme;\n\n        # WebSocket support\n        proxy_http_version 1.1;\n        proxy_set_header Upgrade $http_upgrade;\n        proxy_set_header Connection \"upgrade\";\n    }\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Enable the site and obtain the SSL certificate:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Enable site\nsudo ln -s \/etc\/nginx\/sites-available\/forgejo \/etc\/nginx\/sites-enabled\/\n\n# Create certbot directory\nsudo mkdir -p \/var\/www\/certbot\n\n# Test Nginx configuration\nsudo nginx -t\n\n# Reload Nginx\nsudo systemctl reload nginx\n\n# Obtain SSL certificate\nsudo certbot --nginx -d git.yourdomain.com\n\n# Auto-renewal is configured automatically<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Step 6: Initial Forgejo Setup<\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Visit <code>https:\/\/git.yourdomain.com<\/code>.<\/li>\n\n\n\n<li>Create your admin account.<\/li>\n\n\n\n<li>Configure site settings: site title, repository root (leave default), and disable registration if you want invite-only access.<\/li>\n\n\n\n<li>Save configuration.<\/li>\n<\/ol>\n\n\n\n<hr class=\"wp-block-separator has-css-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Chapter 5: Migrating from Bare Git to Forgejo<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">If you have an existing bare Git server from the 2024 tutorials, migration is straightforward.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Step 1: Export SSH Keys<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code># On your old Git server, backup authorized_keys\nsudo cat \/home\/git\/.ssh\/authorized_keys &gt; ~\/authorized_keys_backup<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Step 2: Clone All Repositories Locally<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code># Create temporary directory\nmkdir ~\/git-migration\ncd ~\/git-migration\n\n# Clone all repositories as mirrors\nfor repo in \/home\/git\/repositories\/*.git; do\n    repo_name=$(basename $repo)\n    git clone --mirror file:\/\/$repo $repo_name\ndone<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Step 3: Push to Forgejo<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code># For each repository:\ncd ~\/git-migration\/myproject.git\n\n# Add Forgejo as remote (replace with your details)\ngit remote add forgejo ssh:\/\/git@git.yourdomain.com:2222\/username\/myproject.git\n\n# Push everything\ngit push --mirror forgejo<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Step 4: Automate Migration (Optional Script)<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Create <code>migrate-all.sh<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#!\/bin\/bash\n\nFORGEJO_USER=\"your-username\"\nFORGEJO_HOST=\"git.yourdomain.com\"\nFORGEJO_PORT=\"2222\"\n\nfor repo in \/home\/git\/repositories\/*.git; do\n    repo_name=$(basename $repo .git)\n\n    echo \"Migrating $repo_name...\"\n\n    cd ~\/git-migration\n    git clone --mirror file:\/\/$repo ${repo_name}.git\n\n    cd ${repo_name}.git\n    git remote add forgejo ssh:\/\/git@${FORGEJO_HOST}:${FORGEJO_PORT}\/${FORGEJO_USER}\/${repo_name}.git\n    git push --mirror forgejo\n\n    cd ~\/git-migration\n    rm -rf ${repo_name}.git\ndone\n\necho \"Migration complete!\"<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Step 5: Update Local Remotes<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">On each developer machine:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>cd \/path\/to\/your\/project\n\n# Remove old remote\ngit remote remove origin\n\n# Add new Forgejo remote\ngit remote add origin ssh:\/\/git@git.yourdomain.com:2222\/username\/myproject.git\n\n# Verify\ngit remote -v\n\n# Test push\ngit push origin main<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-css-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Chapter 6: Setting Up CI\/CD with Forgejo Actions<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">One of the biggest advantages over bare Git is integrated CI\/CD. Both Gitea and Forgejo support <strong>GitHub Actions-compatible workflows<\/strong>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Enable Actions in Forgejo<\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Go to <strong>Site Administration<\/strong> \u2192 <strong>Configuration<\/strong>.<\/li>\n\n\n\n<li>Under <strong>Actions<\/strong>, enable &#8220;Enable Actions&#8221;.<\/li>\n\n\n\n<li>Save settings.<\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\">Configure a Runner<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Forgejo needs runners to execute workflows. Use the official runner container (token available from your Forgejo admin panel):<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Create runner directory\nsudo mkdir -p \/srv\/forgejo-runner\ncd \/srv\/forgejo-runner\n\n# Run the runner\ndocker run -d \n  --name forgejo-runner \n  --restart unless-stopped \n  -v \/var\/run\/docker.sock:\/var\/run\/docker.sock \n  codeberg.org\/forgejo\/runner:latest \n  daemon --token YOUR_RUNNER_TOKEN --instance https:\/\/git.yourdomain.com<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Example Workflow: Node.js Project<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Create <code>.forgejo\/workflows\/ci.yml<\/code> in your repository:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>name: CI Pipeline\n\non:\n  push:\n    branches: &#91;main, develop]\n  pull_request:\n    branches: &#91;main]\n\njobs:\n  test:\n    runs-on: ubuntu-latest\n\n    steps:\n      - name: Checkout code\n        uses: actions\/checkout@v4\n\n      - name: Setup Node.js\n        uses: actions\/setup-node@v4\n        with:\n          node-version: '20'\n          cache: 'npm'\n\n      - name: Install dependencies\n        run: npm ci\n\n      - name: Run tests\n        run: npm test\n\n      - name: Build\n        run: npm run build\n\n      - name: Upload build artifacts\n        uses: actions\/upload-artifact@v4\n        with:\n          name: dist\n          path: dist\/\n\n  docker:\n    needs: test\n    runs-on: ubuntu-latest\n    if: github.ref == 'refs\/heads\/main'\n\n    steps:\n      - name: Checkout code\n        uses: actions\/checkout@v4\n\n      - name: Build and push Docker image\n        run: |\n          docker build -t ${FORGEJO_HOST}\/${GITHUB_REPOSITORY}:latest .\n          docker push ${FORGEJO_HOST}\/${GITHUB_REPOSITORY}:latest<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-css-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Chapter 7: Advanced Configuration and Optimization<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Database Selection<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">For <strong>small teams<\/strong> (&lt;10 users), SQLite is fine (default, zero configuration). For <strong>larger teams<\/strong>, switch to PostgreSQL by updating <code>docker-compose.yml<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>services:\n  postgresql:\n    image: postgres:16\n    environment:\n      POSTGRES_USER: forgejo\n      POSTGRES_PASSWORD: secure_password_here\n      POSTGRES_DB: forgejo\n    volumes:\n      - .\/postgres-data:\/var\/lib\/postgresql\/data\n    networks:\n      - forgejo-network\n\n  forgejo:\n    # ... existing config ...\n    environment:\n      - FORGEJO__database__DB_TYPE=postgres\n      - FORGEJO__database__HOST=postgresql:5432\n      - FORGEJO__database__NAME=forgejo\n      - FORGEJO__database__USER=forgejo\n      - FORGEJO__database__PASSWD=secure_password_here<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Enable Caching with Redis<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code># Add to docker-compose.yml\n  redis:\n    image: redis:7-alpine\n    restart: unless-stopped\n    networks:\n      - forgejo-network\n\n  forgejo:\n    # ... existing config ...\n    environment:\n      - FORGEJO__cache__ADAPTER=redis\n      - FORGEJO__cache__HOST=redis:6379<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Backup Strategy<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Create <code>backup-forgejo.sh<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#!\/bin\/bash\n\nBACKUP_DIR=\"\/backups\/forgejo\"\nDATE=$(date +%Y%m%d_%H%M%S)\n\nmkdir -p $BACKUP_DIR\n\n# Stop Forgejo\ndocker compose -f \/srv\/forgejo\/docker-compose.yml down\n\n# Backup data directory\ntar -czf $BACKUP_DIR\/forgejo_data_$DATE.tar.gz -C \/srv\/forgejo data\n\n# Backup database (if using PostgreSQL)\ndocker exec forgejo-postgresql pg_dump -U forgejo forgejo &gt; $BACKUP_DIR\/forgejo_db_$DATE.sql\n\n# Restart Forgejo\ndocker compose -f \/srv\/forgejo\/docker-compose.yml up -d\n\n# Keep only last 7 backups\nfind $BACKUP_DIR -name \"forgejo_*.tar.gz\" -mtime +7 -delete\nfind $BACKUP_DIR -name \"forgejo_*.sql\" -mtime +7 -delete\n\necho \"Backup complete: $DATE\"<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Add to crontab for daily automated backups:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Edit crontab\ncrontab -e\n\n# Add daily backup at 3 AM\n0 3 * * * \/srv\/forgejo\/backup-forgejo.sh &gt;&gt; \/var\/log\/forgejo-backup.log 2&gt;&amp;1<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-css-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Chapter 8: Security Best Practices<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">1. Enable Two-Factor Authentication (2FA)<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Navigate to <strong>User Settings<\/strong> \u2192 <strong>Security<\/strong> \u2192 Enable TOTP 2FA. Enforce it site-wide via <strong>Site Administration<\/strong> \u2192 <strong>Authentication Sources<\/strong>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">2. Configure SSH Key Requirements<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>&#91;security]\nMINIMUM_KEY_SIZE = 4096\nDISABLE_SSH = false\nSTART_SSH_SERVER = false  # Use system SSH<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">3. Set Up IP Allowlisting (Enterprise)<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>&#91;security]\nALLOWED_HOSTS = 192.168.1.0\/24,10.0.0.0\/8<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">4. Regular Security Updates<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code># Pull latest Forgejo image monthly\ncd \/srv\/forgejo\ndocker compose pull\ndocker compose up -d<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">5. Enable Comprehensive Audit Logging<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>&#91;log]\nMODE = console, file\nLEVEL = info<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-css-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Chapter 9: The Future of Self-Hosted Git<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Federation and the Fediverse<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Forgejo&#8217;s <strong>ForgeFed<\/strong> implementation (based on ActivityPub) allows repositories to be discovered and collaborated on across instances\u2014similar to how Mastodon users interact across servers. This could fundamentally reshape open-source collaboration in 2027 and beyond, removing the dependency on any single centralized forge.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">AI-Assisted Development<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Expect to see native integrations appearing for:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>AI-powered code review<\/strong> suggestions directly in pull requests<\/li>\n\n\n\n<li><strong>Automated security scanning<\/strong> integrated into CI\/CD pipelines<\/li>\n\n\n\n<li><strong>Smart merge conflict resolution<\/strong><\/li>\n\n\n\n<li><strong>Code completion<\/strong> in the web-based editor<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Edge Computing and Git<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">As edge computing grows, self-hosted Git platforms may offer:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Distributed repository mirrors<\/strong> for low-latency access<\/li>\n\n\n\n<li><strong>Edge CI\/CD runners<\/strong> for geographically distributed teams<\/li>\n\n\n\n<li><strong>Offline-first workflows<\/strong> with automatic sync<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-css-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion: Your Self-Hosted Journey Starts Now<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The gap between bare Git servers and modern code forges is enormous\u2014but bridging it has never been easier. With platforms like Forgejo and Gitea, you get 80% of GitHub&#8217;s functionality with 20% of the resource cost and 100% control over your data.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Your next steps:<\/strong><\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Deploy Forgejo<\/strong> using the guide above (30 minutes)<\/li>\n\n\n\n<li><strong>Migrate one repository<\/strong> to test the workflow (15 minutes)<\/li>\n\n\n\n<li><strong>Set up CI\/CD<\/strong> for your primary project (1 hour)<\/li>\n\n\n\n<li><strong>Invite your team<\/strong> and configure access controls (30 minutes)<\/li>\n\n\n\n<li><strong>Enjoy<\/strong> modern Git hosting on your own terms<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">The future of code hosting isn&#8217;t just about storing versions\u2014it&#8217;s about enabling collaboration, automating workflows, and maintaining sovereignty over your intellectual property. Self-hosted Git platforms in 2026 deliver all three.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Introduction: Why Your 2024 Git Server Needs an Upgrade If you followed the popular tutorials from 2024 on setting up a bare Git server on your VPS, you likely appreciated the simplicity: install Git, create a user, set up SSH keys, and push code. It worked. It was secure. And for a while, it was [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":2492,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[9,12],"tags":[14097,14106,14115,14111,14101,14093,14099,14096,14113,14104,14088,14100,14114,14092,14103,14110,14091,14102,14090,14089,14109,14116,14094,14098,14095,14108,713,14112,14105,14107],"class_list":["post-2484","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-tutorials","category-virtual-servers","tag-bare-git-migration","tag-code-review-self-hosted","tag-codeberg-hosting","tag-community-governed-git","tag-forgefed-activitypub","tag-forgejo-2026","tag-forgejo-actions","tag-forgejo-docker","tag-forgejo-runner","tag-forgejo-setup-guide","tag-forgejo-vs-gitea","tag-git-server-docker","tag-git-server-ubuntu","tag-gitea-1-23","tag-gitea-actions","tag-gitea-pull-requests","tag-gitea-vps-setup","tag-gitea-vs-gitlab","tag-github-alternative","tag-gitlab-alternative","tag-gitlab-ce-resource-requirements","tag-open-source-devops","tag-open-source-git-server","tag-self-hosted-ci-cd","tag-self-hosted-code-forge","tag-self-hosted-devops","tag-self-hosted-git","tag-self-hosted-repository","tag-vps-git-hosting","tag-woodpecker-ci"],"_links":{"self":[{"href":"https:\/\/www.serverspan.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/2484","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.serverspan.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.serverspan.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.serverspan.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.serverspan.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2484"}],"version-history":[{"count":4,"href":"https:\/\/www.serverspan.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/2484\/revisions"}],"predecessor-version":[{"id":2914,"href":"https:\/\/www.serverspan.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/2484\/revisions\/2914"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.serverspan.com\/blog\/index.php?rest_route=\/wp\/v2\/media\/2492"}],"wp:attachment":[{"href":"https:\/\/www.serverspan.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2484"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.serverspan.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2484"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.serverspan.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2484"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}