Skip to main content
This guide provides step-by-step instructions for deploying a standalone, self-hosted Gitea GitOps core natively on unprivileged rootless Podman infrastructure (using Podman Pods or systemd Quadlets) enforced over HTTPS.

1. Overview & Architecture

Gitea serves as the local “Sovereign” Source of Truth for all GitOps repositories and infrastructure-as-code.

Architecture Specifications

  • Target Host / Domain: 10.17.250.28 (or your host IP / FQDN)
  • Database Backend: PostgreSQL 15 (Alpine)
  • Application Server: Gitea 1.26.3
  • HTTP/HTTPS Port: 3000 (Mapped to container port 3000 over HTTPS)
  • SSH Port: 2222 (Mapped to container port 22 for Git over SSH)
  • Security & Protocol: HTTPS enforced with TLS certificates signed by Sovereign CA.
  • Automated Installation Bypass: The Gitea Web UI installer is bypassed programmatically via runtime environment variables (GITEA__security__INSTALL_LOCK: "true").

2. Prerequisites

Before running any installation steps, verify the host system requirements:
  1. Enable User Linger: Rootless container services run within unprivileged user space. Enabling linger ensures systemd user daemons and containers remain active across reboots and SSH session logouts:
  2. Verify Podman & Dependencies: Confirm that Podman (v4+ or v5+) and Podman Compose are installed:

3. Step-by-Step Installation Commands

Step A: Generate TLS Certificates & Directory Setup

  1. Create Configuration and Certificate Directories:
  2. Generate Private Key and Self-Signed / Sovereign Certificate:
    Security & Rootless UID Mapping Note: In rootless Podman, the invoking host user UID (e.g. 1000) maps to UID 0 (root) inside the container namespace, whereas Gitea runs internally as unprivileged user git (UID/GID 1000 inside container, mapped to host subuid range e.g. 100999). Because of this namespace mapping, a host key file with mode 0600 owned by host UID 1000 is inaccessible to container UID 1000 unless permissions are 0644 or group permissions allow access (chmod 0640 with appropriate group ownership). If Gitea reports permission denied reading gitea.key, verify user mapping via podman exec gitea-app id or podman exec gitea-stack-gitea-app id and adjust gitea.key read permissions accordingly.
  3. Install Sovereign CA in Host Trust Store:
    • On Debian / Ubuntu:
    • On Red Hat / AlmaLinux / CentOS:

Step B: Create Storage Volumes & Podman Pod

  1. Create Podman Pod with HTTP (3000) and SSH (2222) Port Mappings:
  2. Create Storage Volumes:

Step C: Secure Secrets Management (gitea.env)

To prevent embedding plaintext credentials in CLI parameters or systemd unit files, generate a high-entropy password and store environment secrets in a strict 0600 file:

Step D: Deploy PostgreSQL Database Container

Deploy PostgreSQL 15 within the rootless pod:

Step E: Deploy Gitea HTTPS Application Container

Deploy Gitea 1.26.3 with volume mounts for certificates (including :ro,Z for SELinux relabeling), application data, and timezone:

Step F: Systemd Quadlet & Unit File Integration

To manage the standalone stack via user-level systemd:

Option 1: Podman Native Systemd Generation

Option 2: Podman 5 Native Quadlet Kube (gitea-stack.kube & gitea-stack.yaml)

  1. Create ~/.config/containers/systemd/gitea-stack.kube:
  2. Create ~/.config/containers/systemd/gitea-stack.yaml with mode 0600 (substituting ${HOME} for your target user home path):
  3. Reload systemd user daemon and start Quadlet service:

4. Post-Installation Account, Token & Repository Setup (CLI & API)

Once Gitea is active over HTTPS on port 3000, perform initial administrative setup programmatically using podman exec (Gitea CLI) and curl (Gitea API).

A. Create Admin Account via Gitea CLI

Execute user creation directly inside the container. Note that under manual Podman Pod deployment the container is named gitea-app, whereas under Quadlet Kube deployment Podman names the container gitea-stack-gitea-app:

B. Create Access Token & Organisation via API

To prevent exposing credentials in process listings or command history, pass authentication via a mode-0600 curl config file (~/.gitea-auth-config):

C. Register Host SSH Public Key (Port 2222) & Revoke Token


5. Git Remote & Client Access (HTTPS & SSH)

HTTPS Setup

SSH Setup (Port 2222)


6. Maintenance & Troubleshooting

Service Status & Logs

Support commands cover both systemd unit names (pod-gitea-stack.service for generated systemd, gitea-stack.service for Quadlet Kube):

Troubleshooting: “Permission Denied” Reading gitea.key

If Gitea container fails to read key permissions on startup, check user namespace identity via podman exec gitea-app id or podman exec gitea-stack-gitea-app id:

Decommissioning & Cleanup

To ensure neither Option 1 nor Option 2 remains active after cleanup, stop and disable both unit names:

Deep State of Mind (DSOM) For My AI Protocol | Harisfazillah Jamel (LinuxMalaysia) | 2026-08-20 Standard: UK English | DBP-standard Bahasa Melayu Malaysia (Piawai) | GNU General Public License v3.0