DEV Community

Cover image for Self Hosting Forgejo
Nucu Labs
Nucu Labs

Posted on

Self Hosting Forgejo

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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: false
forgejo:
  # 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"
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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.ini
APP_NAME = NucuLabs
RUN_MODE = prod
APP_SLOGAN = Programming, Cloud and Engineering!
RUN_USER = git
WORK_PATH = /data/gitea


[server]
APP_DATA_PATH = /data/gitea
DOMAIN = forge.nuculabs.dev
SSH_DOMAIN = forge.nuculabs.dev
ROOT_URL = https://forge.nuculabs.dev/
# ....

[service]
DISABLE_REGISTRATION = true
# ...

# ...
[mailer]
ENABLED = true
SMTP_ADDR = xxx
SMTP_PORT = 587
FROM = no-reply@nuculabs.dev
USER = xxx
PASSWD = xxx

# ...
Enter fullscreen mode Exit fullscreen mode

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/systansibleemd/forgejo.container and update the image:

[Unit]
Description=forgejo

[Container]
ContainerName=forgejo
Image=codeberg.org/forgejo/forgejo:12
#...
Enter fullscreen mode Exit fullscreen mode

Reload systemd and restart Forgejo:

sudo systemctl daemon-reload
systemctl restart forgejo
Enter fullscreen mode Exit fullscreen mode

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 ps

48f58cc872f0  codeberg.org/forgejo/forgejo:12        /usr/bin/s6-svsca...  4 minutes ago  Up 4 minutes  0.0.0.0:3000->3000/tcp, forgejo
Enter fullscreen mode Exit fullscreen mode

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 --help
NAME:
   forgejo admin - Perform common administrative operations

USAGE:
   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
Enter fullscreen mode Exit fullscreen mode

And for user commands:

# $ forgejo admin user --help
NAME:
   forgejo admin user - Modify users

USAGE:
   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
Enter fullscreen mode Exit fullscreen mode

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! 😄

Top comments (0)