Table of Contents

A self-hosted git service gives full control over source repositories. Compared with Gitlab, a popular alternative to Github, Gitea is memory friendly and easier to setup. According to the official documentation, pre-built binaries are not recommended for production environment, so we turn to source-based installation method instead.

screenshot of gitea

Install build dependencies

Make sure backports are enabled as described in here. After that, run the following commands to install necessary dependencies:

apt install build-essential
apt install -t buster-backports golang npm

With pam support:

apt install libpam0g-dev

Build from source

Clone the source repository from Github: 😥

cd /usr/src
git clone https://github.com/go-gitea/gitea

Checkout the latest stable release:

git checkout v1.12.2

Change the default working directory via LDFLAGS:

export LDFLAGS="-X \"code.gitea.io/gitea/modules/setting.AppWorkPath=/var/lib/gitea/\""

Run make to automate build process:

TAGS="pam" make build

Verify that the compiled binary works:

./gitea help

Manual installation

Feel free to replace /usr/local with another prefix.

Install the binary:

install gitea /usr/local/bin

Copy static assets:

mkdir -p /usr/local/share/gitea
cp -r {options,public,templates} /usr/local/share/gitea

Copy the default configuration:

mkdir -p /usr/local/etc/gitea
cp custom/conf/app.ini.sample /usr/local/etc/gitea/app.ini

Prepare database

Visit Database preparation for more information.

Edit configuration file

First create an unprivileged user for Gitea:

useradd gitea -c "Gitea" -m -d /var/lib/gitea -s /bin/bash

Assign write permission to the user:

chgrp gitea /usr/local/etc/gitea/app.ini
chmod g+w /usr/local/etc/gitea/app.ini

Then change the runtime user:

;RUN_USER = git
RUN_USER = gitea

…and change some default paths:

[repository]
ROOT = /var/lib/gitea/repos

[server]
STATIC_ROOT_PATH = /usr/local/share/gitea

Use domain socket for better performance:

[server]
;PROTOCOL = http
PROTOCOL = unix
;HTTP_ADDR = 0.0.0.0
HTTP_ADDR = /run/gitea/gitea.socket

To enable logging:

[log]
ROOT_PATH = /var/log/gitea
;MODE = console
MODE = console, file

More options can be found in the cheat sheet.

Create systemd service

Modification is based on Arch patch.

[Unit]
Description=Gitea (Git with a cup of tea)
After=syslog.target
After=network.target

# uncomment as needed
#After=mysqld.service
#After=postgresql.service
#After=memcached.service
#After=redis.service

[Service]
User=gitea
Group=gitea
Type=simple
WorkingDirectory=~
RuntimeDirectory=gitea
# uncomment if enabled logging
#LogsDirectory=gitea
StateDirectory=gitea
Environment=USER=gitea HOME=/var/lib/gitea GITEA_WORK_DIR=/var/lib/gitea
ExecStart=/usr/local/bin/gitea web -c /usr/local/etc/gitea/app.ini
Restart=always
RestartSec=2s

# security hardening
CapabilityBoundingSet=
NoNewPrivileges=True
PrivateUsers=true
PrivateDevices=true
PrivateTmp=true
ProtectHome=true
ProtectSystem=strict
ProtectControlGroups=yes
ProtectKernelTunables=true
ProtectKernelModules=yes
ReadWritePaths=/usr/local/etc/gitea/app.ini
LockPersonality=true
MemoryDenyWriteExecute=true
RestrictRealtime=true
SystemCallArchitectures=native
SystemCallFilter=@system-service

[Install]
WantedBy=multi-user.target

Save as /etc/systemd/system/gitea.service and reload systemd to take effect.

Running behind Nginx

Nginx can serve static resources directly.

server {
    listen 80;
    server_name git.example.com;

    location / {
        proxy_pass http://unix:/run/gitea/gitea.socket;
    }

    location /_/static {
        access_log off;
        log_not_found off;

        alias /usr/local/share/gitea/public;
    }
}

In the configuration file, remember to set STATIC_URL_PREFIX = /_/static.

Complete setup

Start the service and navigate to git.example.com/install. Done.