Homelab - Day 4 - Self-Hosting Gitea

Posted on Fri 07 March 2025 in homelab

Aims

Today’s goal was to deploy Gitea on my K3s cluster, ensuring that:

  • It used persistent storage via my NAS.
  • It was accessible externally through Traefik.
  • It could eventually replace GitHub for my FluxCD setup.

What I Did

Storage and Permissions Woes

Running Gitea as a stateless container worked fine initially, but as soon as I introduced persistence, things got tricky. I ran into permission issues almost immediately, thanks to the interplay between Kubernetes' user permissions and my NAS file system.

  • I set up a PersistentVolume (PV) backed by NFS, but the default Gitea user didn’t have the correct write permissions.
  • After some trial and error (and some questionable security decisions), I got it working by setting specific user IDs and group IDs on the NAS side to align with the Gitea container.
  • Long-term, I’ll need a more secure approach, likely involving init containers to set permissions properly.

Exposing Gitea with Traefik

  • Since K3s includes Traefik by default, I wanted to use it to expose Gitea externally.
  • Unlike Unifi, which required IngressRouteTCP, Gitea worked fine with a standard Ingress configuration.
  • I configured DNS to point git.example.com to my Traefik instance, and everything worked as expected.
  • Here’s the working setup:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: gitea-ingress
namespace: gitea
spec:
rules:
  - host: git.example.com
    http:
      paths:
        - path: /
          pathType: Prefix
          backend:
            service:
              name: gitea-web
              port:
                number: 3000

Next Steps: FluxCD Integration

Now that Gitea is running, the next challenge is configuring my FluxCD setup to pull from it rather than GitHub.

  • I’ll need to generate an SSH keypair for Flux and store the public key in Gitea.
  • Update my GitRepository resources in Flux to use the self-hosted Gitea instance.
  • Verify that Flux can pull manifests and reconcile changes correctly.

Lessons Learned

  • Storage & Permissions: Dealing with NAS-mounted volumes on Kubernetes often introduces user/group ID mismatches. Ensuring correct ownership at the NAS level is crucial.
  • Security Considerations: In my initial setup, I relaxed permissions too much just to get things running. A proper solution will involve configuring the correct UID/GID mappings in a way that doesn’t compromise security.
  • Ingress Simplicity: Unlike Unifi, which required TCP passthrough for TLS termination, Gitea was happy with a simple Ingress resource.

Final Thoughts

With Gitea running smoothly, I’m one step closer to fully self-hosting my development workflow. Getting FluxCD working with it will be the next major milestone. Beyond that, I’ll need to consider backups, access controls, and high availability—but that’s a problem for another day!