Avoid GitHub, selfhost a forgejo instance now

Posted on Apr 25, 2024

The idea

The coding community has deemed GitHub as the de facto platform for hosting code on.
However, there’s a catch - the backbone of GitHub belongs to Microsoft, who utilizes their power to impose restrictive license agreements on users. Unbeknownst to many, signing up with GitHub grants them permission to train your code for Copilot, which is then sold by Microsoft for profit.
By choosing to self-host a Git instance, you retain complete control over the safety and uptime of your data. This realization led me to leave GitHub behind and instead opt for alternative platforms like forgejo, which is set to introduce federation support in the near future - similar to the fediverse. This innovative concept will enable users to contribute to each other’s repositories through pull requests, issues, and comments by using their own instances, creating a more interconnected and collaborative environment. I will guide you through the process of hosting Forgejo on NixOS.

Forgejo vs Gitea

Gitea is a great software, sharing many similarities with Forgejo. However, the primary distinction lies in the backing of Gitea’s development - a for-profit company - which may lead to diverging priorities when it comes to users. In contrast, Forgejo is maintained by a non-profit organization, allowing for a more concerted effort towards community needs. This focus on community translates into a superior ability to address security concerns. Additionally, while Gitea relies on GitHub Actions for development, Forgejo leverages its own custom actions, providing an extra layer of autonomy. Moreover, Gitea abandoned their federation project around two years ago, whereas Forgejo is actively developing theirs.

NixOs

Forgejo

It’s really simple to host a forgejo instance on nix as there are already predefined options for it made by the community.

{ pkgs, config, ... }:{

  services.postgresql.enable = true;
  services.forgejo = {
    enable = true;
    settings = {
      server = {
        # You can just replace the following two if you don't have a hostname set.
        DOMAIN = "git.${config.networking.domain}";
        ROOT_URL = "https://git.${config.networking.domain}/";
        DISABLE_REGISTRATION = true;
        DISABLE_SSH = true;
      };
      DEFAULT.APP_NAME = "My git server";
      actions.ENABLED = true;
    };
    database = {
      type = "postgres";
      createDatabase = true;
    };
  };
}

Nginx reverse proxy

{ pkgs, config, ... }:
{
  services.nginx = {
    enable = true;
    virtualHosts = {
      "git.${config.networking.domain}" = {
        forceSSL = true;
        enableACME = true;
        locations."/" = {
          proxyPass = " http://127.0.0.1:3000";
        };
      };
    };
  };

  # enable automatic certification fetching via Let's Encrypt
  security.acme = {
    acceptTerms = true;
    defaults.email = "admin+acme@${config.networking.domain}";
  };
}

Deploying

After you have written these two configurations onto some file like configuration.nix, you can rebuild the system and see that forgejo is up and running.

sudo nixos-rebuild switch

Runners / Actions

Forgejo has runners that you can use with workflows to build software on every push, pull request merge. We will be setting that up too. If you noticed I already defined actions.ENABLED in the forgejo config.

  1. If you have not yet created a profile on the instance go ahead. If its the first profile it will automatically be asigned administrator
  2. Got to site administration (top right).
  3. Select actions on the left, then runners.
  4. Create a new runner token.
  5. Paste it in the following config under token
{pkgs, config, ...}:{
  services.gitea-actions-runner.instances = {
    root = {
      enable = true;
      url = "127.0.0.1:${toString services.forgejo.settings.server.HTTP_PORT}";
      token = "place your token here";
      settings = {
          container = {
            # internet access for container
            network = "bridge";
          };
      };
      labels = [
        "debian-latest:docker://node:18-bullseye"
        "ubuntu-latest:docker://node:18-bullseye"
      ];
      # define the hostname so we know what server the runner is on.
      name = "${config.networking.hostname}@${config.networking.hostName}";
    };
  };
}

If you want more runner images you can find them here

Rebuild once again

sudo nixos-rebuild switch

Enjoy

This is all it takes to fully set up the instance. After rebuilding you can see its up and running.

Written by human, not by Ai