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.posixThen 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]localhostNext, 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 forgejoModifying 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, forgejoGrab 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 usersAnd 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 userConclusion
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! 😄