5 minute read

Hello everyone!

I’m writing this article to quickly show you how-to self-host Forgejo, the Git software forge, and how to do common maintenance operations.

Introduction

Forgejo is a lightweight, private, easy to operate Git software forge. You can think of it as your private GitHub instance where you control 100% of your data.

To self-host Forgejo the only dependency you need is Forgejo! It’s a self-contained Golang binary that just works. It comes with SQLite by default, and it supports other databases like MariaDB, MySQL and PostgreSQL.

If you have less than 100 users then I think SQLite is sufficient.

A problem with Forgejo is the lack of interaction between users from various instances. If you host Forgejo and your neighbour hosts their then in order for you to like their repositories or follow them you need to create an account on their instance. This problem is currently being solved by federation: 😱:

https://forgejo.org/2023-01-10-answering-forgejo-federation-questions/

Soon you’ll be able to federate your instance with other instances like your neighbours, and it will allow you to see each other’s account, public activities and interact with each other, all from your own instance.

The federation protocol is called ForgeFed and it’s described here: https://forgefed.org/.

Self Hosting

I’ve created an Ansible Playbook in order to automate the self-hosting process. You can download it from my forge:

The playbook only works on RHEL based distros, like: Fedora, RockyLinux, CentOS, AlmaLinux, OpenSuse Thumbleweed, OpenSuse Leap.

To run the playbook you need to have Ansible installed, either install it with make install or run the commands from the Makefile manually.

install:	sudo dnf install ansible	ansible-galaxy collection install community.general	ansible-galaxy collection install containers.podman	ansible-galaxy collection install ansible.posix

Then update the inventory.ini with your server’s IP address and sudo user. The server on which you will install Forgejo on. Ansible will connect to it via SSH and install all the necessary packages.

# inventory.ini[nuculabs]host.example.com ansible_user=ansible[local]localhost

Next, please edit the variables.yaml file with your required values:

# variables.yaml# I would not expose Forgejo directly to the internet.# If setup_firewall is true it will open the ports on the system firewall.setup_firewall: falseforgejo:  # This is the base URL of your instance.  base_url: forgejo.example.com    # The HTTP port of your instance, used for UI, API and http cloning.  http_port: 3000  # The SSH port of your instance, used for cloning via SSH.  ssh_port: 3001    # The container image. At the time of this article version 12 is the latest.  container_image: "codeberg.org/forgejo/forgejo:12"    # The base directory where Forgejo's data will be stored, mine's on the root /forgejo.  base_directory: "/forgejo"

Once that file is edited you can execute make run or ansible-playbook -i inventory.ini playbook.yaml --ask-become-pass.

Ansible will now ask you for the sudo password of the ansible_user, and then it will start downloading and setting up the necessary dependencies.

Forgejo will run as a quadlet container managed by Systemd.

Setting up Nginx

You will now need to expose it to the internet, I recommend setting up a Nginx reverse proxy in front of it.

Your system probably has nginx installed, all you need is to create a file in the sites-available directory with the following contents then link it to the sites-enabled directory. Please remember to update the domain.

# cat /etc/nginx/sites-available/forge# sudo ln -s /etc/nginx/sites-available/forge/etc/nginx/sites-enabled/server {    server_name forge.nuculabs.dev;    client_max_body_size 30M;    location / {        proxy_pass http://localhost:3000; # Forward requests to localhost:4000        proxy_set_header Host $host;        proxy_set_header X-Real-IP $remote_addr;        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;        proxy_set_header X-Forwarded-Proto $scheme;    }    # Optional: Custom error pages    error_page 500 502 503 504 /50x.html;    location = /50x.html {        root /usr/share/nginx/html;    }}server {    if ($host = forge.nuculabs.dev) {        return 301 https://$host$request_uri;    } # managed by Certbot    listen 80;    server_name forge.nuculabs.dev;}

Then run certbot --nginx, select forge.nuculabs.dev as the domain to generate HTTPS certificates.

Configuration

After the successful installation you will need to update the app.ini file located in /forgejo/gitea/conf.

I’d set up some server settings, disable user registration and the mail settings:

#api.iniAPP_NAME = NucuLabsRUN_MODE = prodAPP_SLOGAN = Programming, Cloud and Engineering!RUN_USER = gitWORK_PATH = /data/gitea[server]APP_DATA_PATH = /data/giteaDOMAIN = forge.nuculabs.devSSH_DOMAIN = forge.nuculabs.devROOT_URL = https://forge.nuculabs.dev/# ....[service]DISABLE_REGISTRATION = true# ...# ...[mailer]ENABLED = trueSMTP_ADDR = xxxSMTP_PORT = 587FROM = [email protected]USER = xxxPASSWD = xxx# ...

You can leave the other values default and if you wish to customize more the Configuration Cheat Sheet explains all the configuration options that are available:

To make Forgejo pick-up file changes it’s important to restart it with systemctl restart forgejo.


If you plan to add a database to Forgejo the manual has good and clear instructions on how to prepare it:

You can also protect your Forgejo instance with Anubis, in order to discourage bots from accessing and indexing it. I wrote an article about this here:

Maintenance

These are common maintenance operations that I perform on my server.

Upgrading Versions

Upgrading versions is very simple. SSH into the hosting server and pull the latest Forgejo image podman pull codeberg.org/forgejo/forgejo:12.

Edit the systemd file /etc/containers/systemd/forgejo.container and update the image:

[Unit]Description=forgejo[Container]ContainerName=forgejoImage=codeberg.org/forgejo/forgejo:12#...

Reload systemd and restart Forgejo:

sudo systemctl daemon-reloadsystemctl restart forgejo

Modifying users via the CLI

If you already have an administrator account you can create new users using the site administration UI. If not or if you lose your password you can modify your user or reset its password with the help of forgejo-cli.

Grab the container name or id of the Forgejo instance.

podman ps48f58cc872f0  codeberg.org/forgejo/forgejo:12        /usr/bin/s6-svsca...  4 minutes ago  Up 4 minutes  0.0.0.0:3000->3000/tcp, forgejo

Grab a shell in the container: podman exec -it forgejo bin/bash and change into the git user su git.

Execute forgejo admin --help to see available commands:

# $ forgejo admin --helpNAME:   forgejo admin - Perform common administrative operationsUSAGE:   forgejo admin [command [command options]] COMMANDS:   user                Modify users   repo-sync-releases  Synchronize repository releases with tags   regenerate          Regenerate specific files   auth                Modify external auth providers   sendmail            Send a message to all users

And for user commands:

# $ forgejo admin user --helpNAME:   forgejo admin user - Modify usersUSAGE:   forgejo admin user [command [command options]] COMMANDS:   create                 Create a new user in database   list                   List users   change-password        Change a user's password   delete                 Delete specific user by id, name or email   generate-access-token  Generate an access token for a specific user   must-change-password   Set the must change password flag for the provided users or all users   reset-mfa              Remove all two-factor authentication configurations for a user

Conclusion

Forgejo is easy to self-host, has low resource requirements, and it’s maintenance burden is very low. Having the option to select SQLite storage is great for small to medium deployments and removes the need to deploy and maintain an additional database.

I hope you’ve enjoyed this article! Thank you for reading and see you in the next one! 😄