2026-08-01 19:02:52 +02:00
2026-03-17 23:59:16 +01:00
2026-03-17 23:59:16 +01:00
2026-03-17 23:59:16 +01:00
2026-03-17 23:59:16 +01:00
2026-03-17 23:59:16 +01:00
2026-03-17 23:59:16 +01:00
2026-03-17 23:59:16 +01:00
2026-03-17 23:59:16 +01:00
2026-03-17 23:59:16 +01:00
2026-03-17 23:59:16 +01:00
2026-03-17 23:59:16 +01:00
2026-03-17 23:59:16 +01:00
2026-03-17 23:59:16 +01:00
2026-06-25 10:09:21 +02:00
2026-03-17 23:59:16 +01:00
2026-03-17 23:59:16 +01:00
2026-06-25 10:09:21 +02:00
2026-03-17 23:59:16 +01:00
2026-03-17 23:59:16 +01:00
2026-08-01 19:02:52 +02:00

Gitea RPM Package

Self-hosted Git service packaged as an RPM for Fedora. Ships as a base package with two mutually exclusive subpackages: gitea-service (native binary) and gitea-container (Podman quadlet with rootless image).

Package structure

gitea              Base: git user (UID 124), dirs, /etc/gitea/app.ini
gitea-service      Native binary under systemd
gitea-container    Podman quadlet (gitea + postgres containers in a pod)

Path resolution and environment variables

Gitea resolves its key paths through a priority chain. Understanding this is essential because the native install, rootful Docker, and rootless Docker each set these differently. Run gitea --help to see the computed defaults:

DEFAULT CONFIGURATION:
   AppPath:    /usr/libexec/gitea                          # absolute path to binary
   WorkPath:   /var/lib/gitea                              # resolved AppWorkPath
   CustomPath: /var/lib/gitea/custom                       # {WorkPath}/custom
   ConfigFile: /var/lib/gitea/custom/conf/app.ini          # {CustomPath}/conf/app.ini

(When run without overrides, WorkPath defaults to the binary's directory.)

AppPath

Absolute path to the Gitea binary itself. Not configurable at runtime — it is always the real path of the running executable. All other paths that are relative get resolved against the directory of AppPath.

AppWorkPath (WORK_PATH)

The working directory that serves as the base for all relative paths. Resolved in this order (first wins):

  1. --work-path / -w CLI flag
  2. GITEA_WORK_DIR environment variable
  3. WORK_PATH in app.ini
  4. Built-in value (set at compile time via LDFLAGS)
  5. Directory containing AppPath (the binary)

If any of the above are relative, they become absolute against AppPath's directory.

Deployment How it's set Effective value
Gitea default Falls through to rule 5 (binary dir) (binary dir)
Native install (RPM) Environment=GITEA_WORK_DIR=/var/lib/gitea in unit /var/lib/gitea
Docker rootful Built into image (LDFLAGS at compile time) /data
Docker rootless Built into image (LDFLAGS at compile time) /data

CustomPath (GITEA_CUSTOM)

Base directory for custom templates, public files, and (by default) app.ini. Resolved in this order:

  1. --custom-path / -C CLI flag
  2. GITEA_CUSTOM environment variable
  3. Built-in value (compile time)
  4. {AppWorkPath}/custom

CustomConf (app.ini location)

  1. --config / -c CLI flag
  2. Built-in value (compile time)
  3. {CustomPath}/conf/app.ini

Note: this RPM uses -c /etc/gitea/app.ini in the systemd unit to override the default {CustomPath}/conf/app.ini path.

APP_DATA_PATH

Defined in [server]. Defaults to {AppWorkPath}/data (or /data/gitea on rootful Docker). All relative paths in storage-related settings resolve against this. Serves as root for: LFS, avatars, packages, attachments, queues, indexers, etc.

HOME directory and RUN_USER

RUN_USER in app.ini specifies which OS user Gitea expects to run as (default: git). Gitea uses ~ / HOME for:

  • SSH_ROOT_PATH defaults to ~/.ssh
  • SSH_SERVER_HOST_KEY defaults to ~/.ssh/id_rsa
  • authorized_keys management (when SSH_CREATE_AUTHORIZED_KEYS_FILE = true)
Deployment RUN_USER HOME
Native install (RPM) git /var/lib/gitea
Docker rootful git /data/gitea
Docker rootless git /var/lib/gitea

Docker-specific environment variables

Variable Purpose
USER Username inside container (default: git)
USER_UID Unix UID, must match volume ownership (default: 1000)
USER_GID Unix GID, must match volume ownership (default: 1000)
GITEA__section__KEY Override any app.ini value (e.g. GITEA__database__HOST=db:5432)
GITEA__section__KEY__FILE Same but reads value from a file path (for secrets)

This RPM sets USER_UID=124 / USER_GID=124 in the quadlet to match the system git user created by sysusers.d.

Directory layout

Gitea default (built-in, relative to WORK_PATH)

When Gitea runs without any overrides, all paths are relative to the working directory (typically where the binary lives or GITEA_WORK_DIR).

WORK_PATH/
  custom/            # custom templates, public files
  data/              # APP_DATA_PATH
    gitea-repositories/  # [repository] ROOT
    lfs/                 # [lfs] PATH
    avatars/             # [picture] AVATAR_UPLOAD_PATH
    repo-avatars/        # [picture] REPOSITORY_AVATAR_UPLOAD_PATH
    packages/            # [packages] STORAGE_PATH
    attachments/         # [attachment] PATH
    sessions/            # [session] PROVIDER_CONFIG (file mode)
    indexers/            # bleve search indexes
    queues/              # async task queues
    tmp/                 # temporary archives, uploads
  log/                   # [log] ROOT_PATH (default: WORK_PATH/log)

Native install from binary (this RPM: gitea-service)

FHS-compliant layout using systemd, sysusers, tmpfiles.

/usr/libexec/gitea                              # binary
/etc/gitea/app.ini                              # config (root:git 0640)
/var/lib/gitea/                                 # WORK_PATH (git:git 0750)
  custom/
  data/                                         # APP_DATA_PATH = data (relative)
    git/
      repositories/                             # [repository] ROOT = data/git/repositories
      lfs/                                      # [lfs] PATH = data/git/lfs
    avatars/                                    # default: data/avatars
    repo-avatars/                               # default: data/repo-avatars
    packages/                                   # default: data/packages
    attachments/                                # default: data/attachments
    sessions/                                   # [session] PROVIDER = file
    indexers/
    queues/
    actions_artifacts/
    tmp/
  log/                                          # [log] ROOT_PATH = log (relative)
/run/gitea/                                     # tmpfiles.d, runtime

Systemd unit: gitea.service

  • User=git, Group=git (UID/GID 124 via sysusers.d)
  • WorkingDirectory=/var/lib/gitea
  • Environment=GITEA_WORK_DIR=/var/lib/gitea
  • Database drop-in: /usr/lib/systemd/system/gitea.service.d/database.conf (uncomment Wants/After for postgresql, redis, etc.)

SSH passthrough: /etc/ssh/sshd_config.d/50-gitea.conf

Match User git
    AuthorizedKeysCommand /usr/libexec/gitea keys -c /etc/gitea/app.ini -e git -u %u -t %t -k %k
    AuthorizedKeysCommandUser git

Docker / Podman rootful (gitea/gitea:1.25)

The standard Docker image runs as root and remaps paths under /data:

/data/
  gitea/
    conf/app.ini                                # config
    avatars/                                    # AVATAR_UPLOAD_PATH
    packages/                                   # STORAGE_PATH
    ...                                         # APP_DATA_PATH = /data/gitea
  git/
    repositories/                               # [repository] ROOT
    lfs/                                        # [lfs] PATH

Volume: -v /host/path:/data

Docker / Podman rootless (gitea/gitea:1.25-rootless)

The rootless image flattens everything under /var/lib/gitea and /data:

/data/                                          # main volume
  gitea/
    conf/app.ini                                # config (mounted from host or volume)
    db/                                         # sqlite (if used)
  git/
    repositories/                               # [repository] ROOT
  ...
/var/lib/gitea/                                 # APP_DATA_PATH (secondary volume or subpath)
  avatars/
  repo-avatars/
  packages/
  attachments/
  indexers/
  queues/
  actions_artifacts/
  data/lfs/                                     # [lfs] PATH
  tmp/

This RPM's quadlet (gitea.container) uses the rootless image and maps:

Host path Container path Purpose
/var/lib/gitea /data Repositories, config, git data
/etc/gitea /data/gitea/conf app.ini (read-only intent)

Elektronika Smodlaka (rootless container, custom app.ini)

Uses the rootless image via quadlet with APP_DATA_PATH = /var/lib/gitea and explicit absolute paths. Git data is separated under git/ alongside data/.

/var/lib/gitea/                                 # WORK_PATH & APP_DATA_PATH
  git/
    repositories/                               # [repository] ROOT
    lfs/                                        # [lfs] PATH
  data/
    gitea.db                                    # [database] PATH (sqlite fallback)
    avatars/                                    # [picture] AVATAR_UPLOAD_PATH
    repo-avatars/                               # [picture] REPOSITORY_AVATAR_UPLOAD_PATH
    attachments/                                # [attachment] PATH
    sessions/                                   # [session] PROVIDER_CONFIG (file)
    log/                                        # [log] ROOT_PATH
  custom/                                       # templates, public overrides
  indexers/
  queues/
  actions_artifacts/
  packages/
  tmp/
/tmp/gitea/
  local-repo/                                   # [repository.local] LOCAL_COPY_PATH
  uploads/                                      # [repository.upload] TEMP_PATH

Key differences from defaults:

  • APP_DATA_PATH = /var/lib/gitea (not data/ relative) — everything under one root
  • git/ directory sits alongside data/ (repos and LFS separated from app data)
  • [log] ROOT_PATH goes to /var/lib/gitea/data/log (inside data/, not alongside)
  • Uses postgres (HOST = 127.0.0.1), but [database] PATH is set for sqlite fallback
  • Built-in SSH server on port 30009 (START_SSH_SERVER = true)

Path comparison table

Setting Gitea Default RPM app.ini Docker Rootful Docker Rootless Elektronika Smodlaka
WORK_PATH (binary dir) /var/lib/gitea /data /data /var/lib/gitea
APP_DATA_PATH data (relative) (default) data.../gitea/data /data/gitea /var/lib/gitea /var/lib/gitea
[repository] ROOT data/gitea-repositories data/git/repositories /data/git/repositories /data/git/repositories /var/lib/gitea/git/repositories
[repository.local] LOCAL_COPY_PATH /tmp/gitea/local-repo (default) (default) (default) /tmp/gitea/local-repo
[repository.upload] TEMP_PATH /tmp/gitea/uploads (default) (default) (default) /tmp/gitea/uploads
[lfs] PATH data/lfs data/git/lfs /data/git/lfs /var/lib/gitea/data/lfs /var/lib/gitea/git/lfs
[picture] AVATAR_UPLOAD_PATH data/avatars (default) data/avatars /data/gitea/avatars /var/lib/gitea/avatars /var/lib/gitea/data/avatars
[picture] REPOSITORY_AVATAR_UPLOAD_PATH data/repo-avatars (default) data/repo-avatars /data/gitea/repo-avatars /var/lib/gitea/repo-avatars /var/lib/gitea/data/repo-avatars
[attachment] PATH data/attachments (default) data/attachments (default) (default) /var/lib/gitea/data/attachments
[session] PROVIDER_CONFIG data/sessions (default) data/sessions (default) (default) /var/lib/gitea/data/sessions
[packages] STORAGE_PATH data/packages (default) data/packages /data/gitea/packages /var/lib/gitea/packages (default)
[log] ROOT_PATH WORK_PATH/log log/var/lib/gitea/log /data/gitea/log /var/lib/gitea/log /var/lib/gitea/data/log
[database] PATH (sqlite) data/gitea.db (default) data/gitea.db (default) (default) /var/lib/gitea/data/gitea.db

Directories that grow

Directory What it stores Growth driver
gitea-repositories/ Bare git repos Number and size of repos
lfs/ Git LFS objects Large file usage
packages/ Package registry artifacts Package publishing
indexers/ Bleve/Elasticsearch search indexes Number of repos (if code indexer enabled)
actions_artifacts/ CI/CD build artifacts Gitea Actions usage
queues/ Async task data Usually small, grows during backlogs
tmp/ Archive downloads, upload staging Transient, reclaimed automatically

To move heavy directories to separate storage, use absolute paths in app.ini:

[repository]
ROOT = /mnt/large_disk/repositories

[packages]
STORAGE_PATH = /mnt/large_disk/packages

Quadlet setup (gitea-container)

The container subpackage installs Podman quadlet files to /usr/share/containers/systemd/:

File Purpose
gitea.pod Pod definition, publishes port 1240:3000
gitea.container Gitea rootless container
gitea-db.container PostgreSQL 18 container

Enabled via drop-in: /etc/containers/systemd/gitea.pod.d/enable.conf (WantedBy=multi-user.target)

Database credentials are passed as environment variables in the container definition. For production, replace these with Podman secrets or a POSTGRES_PASSWORD_FILE approach.

SSH passthrough for containers uses a shim script:

  • /usr/libexec/gitea-keys - calls podman exec into the container
  • /usr/libexec/gitea-container - shim so gitea CLI commands work from host
# /etc/ssh/sshd_config.d/50-gitea.conf (container variant)
Match User git
    AuthorizedKeysCommand /usr/libexec/gitea-keys %u %t %k
    AuthorizedKeysCommandUser root

Note: AuthorizedKeysCommandUser is root (not git) because podman exec requires elevated privileges when run from sshd.

Quick start

Native binary

sudo dnf install gitea gitea-service
# Edit /etc/gitea/app.ini (database, domain, etc.)
# Uncomment database dependency in /usr/lib/systemd/system/gitea.service.d/database.conf
sudo systemctl daemon-reload
sudo systemctl enable --now gitea

Container (Podman quadlet)

sudo dnf install gitea gitea-container
# Edit /etc/gitea/app.ini
# The pod auto-starts via the enable.conf drop-in
sudo systemctl daemon-reload
sudo systemctl start gitea-pod

Gitea will be available at http://localhost:1240 (container) or http://localhost:3000 (native).

Migration: Elektronika Smodlaka → RPM native layout

Copies data from the Elektronika Smodlaka container layout (/srv/storage/gitea-data/data) to the RPM's native install structure (/var/lib/gitea). The RPM app.ini groups repos and LFS under data/git/.

Source (Elektronika) Destination (RPM) Notes
git/repositories/ data/git/repositories/ Same name, different parent
git/lfs/ data/git/lfs/ Same name, different parent
data/avatars/ data/avatars/ Same relative path
data/repo-avatars/ data/repo-avatars/ Same relative path
data/attachments/ data/attachments/ Same relative path
data/sessions/ data/sessions/ Same relative path
data/log/ log/ RPM uses WORK_PATH/log
indexers/ data/indexers/ Moves under APP_DATA_PATH
queues/ data/queues/ Moves under APP_DATA_PATH
actions_artifacts/ data/actions_artifacts/ Moves under APP_DATA_PATH
packages/ data/packages/ Moves under APP_DATA_PATH
custom/ custom/ Same relative path
#!/bin/bash
set -euo pipefail

SRC="/srv/storage/gitea-data/data"
DST="/var/lib/gitea"

# Stop gitea before migration
# systemctl stop gitea

# Git data (repositories + LFS) → data/git/
rsync -av --progress "$SRC/git/repositories/" "$DST/data/git/repositories/"
rsync -av --progress "$SRC/git/lfs/" "$DST/data/git/lfs/"

# App data dirs that keep the same relative path under data/
for dir in avatars repo-avatars attachments sessions; do
    if [ -d "$SRC/data/$dir" ]; then
        rsync -av --progress "$SRC/data/$dir/" "$DST/data/$dir/"
    fi
done

# Logs (data/log → log — RPM default is WORK_PATH/log)
if [ -d "$SRC/data/log" ]; then
    rsync -av --progress "$SRC/data/log/" "$DST/log/"
fi

# Dirs that were at root in Elektronika, move under data/ for RPM
for dir in indexers queues actions_artifacts packages; do
    if [ -d "$SRC/$dir" ]; then
        rsync -av --progress "$SRC/$dir/" "$DST/data/$dir/"
    fi
done

# Custom templates/public files
if [ -d "$SRC/custom" ]; then
    rsync -av --progress "$SRC/custom/" "$DST/custom/"
fi

# SQLite database (only if present, RPM uses postgres by default)
if [ -f "$SRC/data/gitea.db" ]; then
    rsync -av --progress "$SRC/data/gitea.db" "$DST/data/gitea.db"
fi

# Fix ownership
chown -R git:git "$DST"

echo "Migration complete. Verify /etc/gitea/app.ini paths match RPM app.ini."

The RPM app.ini only sets two paths explicitly (rest are defaults):

[repository]
ROOT = data/git/repositories    ;; was: /var/lib/gitea/git/repositories (absolute)

[lfs]
PATH = data/git/lfs             ;; was: /var/lib/gitea/git/lfs (absolute)

;; [log] ROOT_PATH = log        ;; RPM default, resolves to /var/lib/gitea/log
;;                               ;; Elektronika had: /var/lib/gitea/data/log
S
Description
No description provided
Readme
185 KiB
Languages
Shell 100%