More than five years have passed since my last blog series on Gitea.1 In the meantime, Gitea has gained a more powerful fork in Forgejo,2 which has long been part of my daily workflow. Having recently shut down my Gitea instance running as a jail on TrueNAS,3 I will outline how I have adapted a Forgejo instance to my specific needs.
A brief note for context: For simplicity I refer only to Forgejo. I am well aware that many aspects of Forgejo and Gitea remain identical (for now). Yet it should be clear that since Forgejo version 10, it has ceased to be a soft fork.4 In the long run the two projects will diverge.
The Underlying Concept
Forgejo follows a clear design philosophy. Many features that I previously managed in Gitea only through CSS or JavaScript hacks, such as Mermaid integration5 or an offline CSP,6 are now built in.
Everything that deviates from the defaults is placed—independently of the Go single binary into the custom subdirectory of the WORK_PATH at /var/lib/forgejo/custom. This significantly simplifies updates without requiring any recompilation. Another advantage: the contents of the custom directory can themselves be fully placed under version control in a Git repository.
Anyone familiar with the static site generator Hugo7 will recognise the TOML8 templates and Go-style scripting. The concept of combining multiple templates and page components into a final rendered website is almost identica and reminds me to the Server Side Includes (SSI) used 30 years ago.9
The APP.INI as the First Layer
Forgejo provides numerous toggles in the APP.INI that are sufficient for basic UI customisation. Replacing logos, adjusting links, altering registration options, everything is well documented.10
Things become more interesting once you want to go beyond what APP.INI can configure: For instance creating a completely blank landing page, a footer containing only legal information and language selection or custom logos and themes in full corporate design without visible Forgejo self-branding.
The Custom and Public Directories as the Second Layer
Upon startup, Forgejo automatically loads all templates in the custom directory and uses them to override its defaults. This provides far greater flexibility than the fixed settings of APP.INI.
A special role is played by the custom/public directory. This is the area for static files that Forgejo serves just like a web server would. All images, CSS, JavaScript files, as well as the SECURITY.TXT11 or the RFC 8615 .well-known directory12 belong here unless handled earlier by a reverse proxy.
The /custom/templates directory is where it becomes truly interesting. Here reside the TOML templates that govern the entire UI. Depending on subdirectory and filename, you can override specific views.13
Example
Though I publish some of my projects on Codeberg,14 the majority of them still reside on my protected private instance.15 This instance should be as minimalistic as possible without the Forgejo hero banner or the self-promotion on the landing page:

This can be achieved with a proper home.tmpl file in the custom subdirectory, in which I only render the header and footer:
{{template "base/head" .}}
{{template "base/footer" .}}
I also wanted the footer without technical details such as load time, version number, or a Swagger API link, but instead containing a link to my own legal notice. This is achieved with the footer_content.tmpl file located in the templates/base subdirectory. Crucially, you must retain the identical CSS classes, conditional placeholders, and language settings. In my case, I took the standard template from the Forgejo Codeberg repository, removed the licence and Swagger API links, and placed the modified version in my custom directory.16
Conclusion
For me Forgejo is an indispensable component of any software development, documentation or operational automation environment. The use of Git is a central heuristic of digital transformation.17
And yet, even in 2025, there remain alarmingly many, who attempt to undertake software or digitalisation projects without any form of version control.
Yours,
Tomas Jakobs
https://blog.jakobs.systems/blog/20200415-gitea-statt-github/ ↩︎
https://blog.jakobs.systems/blog/20200524-gitea-uml-mermaid/ ↩︎
https://blog.jakobs.systems/blog/20200818-hugo-als-blog-plattform/ ↩︎
https://forgejo.org/docs/latest/admin/config-cheat-sheet/ ↩︎
https://codeberg.org/forgejo/forgejo/src/branch/forgejo/templates ↩︎
https://codeberg.org/forgejo/forgejo/src/branch/forgejo/templates/base/footer_content.tmpl# ↩︎
https://blog.jakobs.systems/micro/20230208-heuristik-des-tages/ ↩︎