<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Infrastructure on 0xMax42 - Flatfile purist. Autodidact. Systems thinker.</title><link>https://0xMax42.io/en/categories/infrastructure/</link><description>Recent content in Infrastructure on 0xMax42 - Flatfile purist. Autodidact. Systems thinker.</description><generator>Hugo -- gohugo.io</generator><language>en</language><lastBuildDate>Sat, 19 Apr 2025 00:00:00 +0000</lastBuildDate><atom:link href="https://0xMax42.io/en/categories/infrastructure/index.xml" rel="self" type="application/rss+xml"/><item><title>Custom Gitea Pages Stack with Wildcard Subdomains and ACME – My GitHub Pages Replacement</title><link>https://0xMax42.io/en/p/gitea-pages-stack/</link><pubDate>Sat, 19 Apr 2025 00:00:00 +0000</pubDate><guid>https://0xMax42.io/en/p/gitea-pages-stack/</guid><description>&lt;img src="https://0xMax42.io/p/gitea-pages-stack/cover.webp" alt="Featured image of post Custom Gitea Pages Stack with Wildcard Subdomains and ACME – My GitHub Pages Replacement" /&gt;&lt;h2 id="introduction"&gt;Introduction
&lt;/h2&gt;&lt;p&gt;This post documents my custom Gitea Pages stack – a privacy-friendly alternative to GitHub Pages. With GT-RUNNER, the Codeberg Pages server, and Traefik as a reverse proxy, I’ve built a self-managed hosting stack that fully automates domain management, TLS certificates, and deployment – without centralized dependencies and with complete control.&lt;/p&gt;
&lt;h2 id="architecture-overview"&gt;Architecture Overview
&lt;/h2&gt;&lt;p&gt;The following diagram shows the structure of my stack. All core components – Gitea, the runner, the Pages server, and the reverse proxy – are connected within a private network. TLS certificates are issued in two stages using Let&amp;rsquo;s Encrypt (Staging internally, Production externally):&lt;/p&gt;
&lt;p&gt;&lt;img src="https://0xMax42.io/p/gitea-pages-stack/Diagramm.drawio.webp"
width="8178"
height="3618"
srcset="https://0xMax42.io/p/gitea-pages-stack/Diagramm.drawio_hu_afafb47aed15c268.webp 480w, https://0xMax42.io/p/gitea-pages-stack/Diagramm.drawio_hu_7b0b67cc18f3f7d2.webp 1024w"
loading="lazy"
alt="Diagram of my setup"
class="gallery-image"
data-flex-grow="226"
data-flex-basis="542px"
&gt;&lt;/p&gt;
&lt;h2 id="detailed-functionality"&gt;Detailed Functionality
&lt;/h2&gt;&lt;p&gt;To be honest: at its core, it&amp;rsquo;s just a normal Git server. Gitea runs internally, and the GT-RUNNER is connected – based on &lt;code&gt;act&lt;/code&gt; with a fairly large image that provides everything GitHub Actions does. For my use case, that’s more than compatible enough.&lt;/p&gt;
&lt;p&gt;Next is the Codeberg Pages server – also internal. It communicates with Gitea via API, just as intended. Important: everything Gitea, the runner, and the Pages server do happens strictly inside the private network. Nothing leaks outside. That was important to me.&lt;/p&gt;
&lt;p&gt;Now about TLS: the Pages server can&amp;rsquo;t operate without certificates. So it gets them – in the standard way via my DNS provider, through its API and the ACME protocol. But only using Let&amp;rsquo;s Encrypt’s &lt;strong&gt;staging&lt;/strong&gt; certificates. Why? Because that&amp;rsquo;s enough. This is about internal TLS, not external trust.&lt;/p&gt;
&lt;p&gt;Once the Pages server has its certs, it can serve content cleanly – internally, over HTTPS, with a proper structure. My reverse proxy (Traefik) takes care of the rest.&lt;/p&gt;
&lt;p&gt;Traefik is configured to &lt;strong&gt;not care whether the internal cert is trusted&lt;/strong&gt;. It terminates TLS on the public side, fetches valid production certificates via DNS-01 and Let&amp;rsquo;s Encrypt, and rewrites the domain paths accordingly.&lt;/p&gt;
&lt;p&gt;To make this work, I rewrite the requests. For example, Traefik receives something like &lt;code&gt;home.pagessub.0xmax42.io&lt;/code&gt;, extracts which repository it’s supposed to serve, and rewrites the request internally to &lt;code&gt;user.pagessub.0xmax42.io/repo/&lt;/code&gt;. This lets the Pages server route the request correctly.&lt;/p&gt;
&lt;p&gt;From the outside, everything looks just like GitHub Pages – every subdomain serves its own static project. But this time: privacy-friendly, self-hosted, and with no vendor lock-in.&lt;/p&gt;
&lt;h2 id="outlook"&gt;Outlook
&lt;/h2&gt;&lt;p&gt;In the long term, I want repositories to define their own deployment domains – e.g. via a &lt;code&gt;.traffic&lt;/code&gt; file. The Gitea API could then automatically generate the corresponding Traefik config and hand it off. The goal: a fully automated, self-healing static web hosting stack.&lt;/p&gt;
&lt;h2 id="components-used"&gt;Components Used
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;🧃 &lt;strong&gt;&lt;a class="link" href="https://gitea.io/" target="_blank" rel="noopener"
&gt;Gitea&lt;/a&gt;&lt;/strong&gt; – Self-hosted Git service&lt;/li&gt;
&lt;li&gt;🌀 &lt;strong&gt;&lt;a class="link" href="https://traefik.io/" target="_blank" rel="noopener"
&gt;Traefik&lt;/a&gt;&lt;/strong&gt; – Reverse proxy with ACME support&lt;/li&gt;
&lt;li&gt;📦 &lt;strong&gt;&lt;a class="link" href="https://codeberg.org/Codeberg/pages-server" target="_blank" rel="noopener"
&gt;Codeberg Pages Server&lt;/a&gt;&lt;/strong&gt; – Static pages server&lt;/li&gt;
&lt;li&gt;🔀 &lt;strong&gt;&lt;a class="link" href="https://github.com/lukas-r/traefik-subdomain-path-rewrite-plugin" target="_blank" rel="noopener"
&gt;traefik-subdomain-path-rewrite-plugin&lt;/a&gt;&lt;/strong&gt; – For dynamic URL rewriting based on subdomains&lt;/li&gt;
&lt;li&gt;🔐 &lt;strong&gt;&lt;a class="link" href="https://letsencrypt.org/" target="_blank" rel="noopener"
&gt;Let’s Encrypt&lt;/a&gt;&lt;/strong&gt; – Free TLS certificate management via ACME&lt;/li&gt;
&lt;li&gt;🐳 &lt;strong&gt;&lt;a class="link" href="https://www.docker.com/" target="_blank" rel="noopener"
&gt;Docker&lt;/a&gt;&lt;/strong&gt; – Containerization of all components for easy management and isolation&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;blockquote&gt;
&lt;p&gt;📁 This setup is part of my infrastructure foundation for &lt;a class="link" href="https://0xmax42.io" target="_blank" rel="noopener"
&gt;0xMax42.io&lt;/a&gt;. More posts to follow.&lt;/p&gt;
&lt;/blockquote&gt;</description></item></channel></rss>