Skip to content


Initial Installation

First we download the package (check for the latest version at :

sudo -s
cd /opt
wget -O gitea

Also install git if you haven't already previously:

apt update && apt install git

Create a user to run Gitea:

adduser \
   --system \
   --shell /bin/bash \
   --gecos 'Git Version Control' \
   --group \
   --disabled-password \
   --home /home/git \

Create the directory structure and apply permissions:

mkdir -p /var/lib/gitea/{custom,data,log}
chown -R git:git /var/lib/gitea/
chmod g+s,u+s /var/lib/gitea
chmod g+s,u+s /var/lib/gitea/{custom,data,log}
chmod -R 750 /var/lib/gitea
mkdir /etc/gitea
chown root:git /etc/gitea
chmod g+s,u+s /etc/gitea
chmod 770 /etc/gitea

Create the Service

nano /etc/systemd/system/gitea.service

Enter the following:

Description=Gitea (Git with a cup of tea)

# Modify these two values and uncomment them if you have
# repos with lots of files and get an HTTP error 500 because
# of that
ExecStart=/usr/local/bin/gitea web -c /etc/gitea/app.ini
Environment=USER=git HOME=/home/git GITEA_WORK_DIR=/var/lib/gitea


Save and reload systemd:

systemctl daemon-reload

Create the Database

mysql -u root -p

Run the following commands in Mariadb:

CREATE DATABASE gitea DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_520_ci;

GRANT ALL PRIVILEGES ON gitea.* TO 'giteauser'@'localhost' identified by 'YOUR-PASSWORD';



Create the Certificates

Make sure you've already set an A (and optionally an AAAA) record in your DNS management console. Create the certificates with:

~/ --issue --dns dns_cloudns -d --keylength 4096 --key-file /etc/letsencrypt/rsa-certs/ --ca-file /etc/letsencrypt/rsa-certs/ --cert-file /etc/letsencrypt/rsa-certs/ --fullchain-file /etc/letsencrypt/rsa-certs/ --pre-hook "mkdir -p /etc/letsencrypt/rsa-certs/" --post-hook "find /etc/letsencrypt/rsa-certs/ -name '*.pem' -type f -exec chmod 600 {} \;" --renew-hook "find /etc/letsencrypt/rsa-certs/ -name '*.pem' -type f -exec chmod 600 {} \; -exec service nginx reload \;"


~/ --issue --dns dns_cloudns -d --keylength ec-384 --key-file /etc/letsencrypt/ecc-certs/ --ca-file /etc/letsencrypt/ecc-certs/ --cert-file /etc/letsencrypt/ecc-certs/ --fullchain-file /etc/letsencrypt/ecc-certs/ --pre-hook "mkdir -p /etc/letsencrypt/ecc-certs/" --post-hook "find /etc/letsencrypt/ecc-certs/ -name '*.pem' -type f -exec chmod 600 {} \;" --renew-hook "find /etc/letsencrypt/ecc-certs/ -name '*.pem' -type f -exec chmod 600 {} \; -exec service nginx reload \;"

Create the Nginx Server Block

nano /etc/nginx/sites-available/

Enter the following (this assumes that previous Nginx tutorials have been followed):

upstream gitea {

server {

    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    gzip on;


    ssl_certificate /etc/letsencrypt/rsa-certs/;
    ssl_certificate_key /etc/letsencrypt/rsa-certs/;
    ssl_certificate /etc/letsencrypt/ecc-certs/;
    ssl_certificate_key /etc/letsencrypt/ecc-certs/;
    ssl_trusted_certificate /etc/letsencrypt/ecc-certs/;

    include /etc/nginx/custom-config/ssl.conf;
    include /etc/nginx/custom-config/header.conf;
    include /etc/nginx/bots.d/ddos.conf;
    include /etc/nginx/bots.d/blockbots.conf;

    if ($allowed_country = no) {
        return 403;

    if ( $bad_querystring !~* "\[OK\]" ) {
        set $blockreason $bad_querystring;
        return 403;

    if ( $bad_request !~* "\[OK\]|\[bad_request_rule_25\]|\[bad_request_rule_17\]|\[bad_request_rule_22\]|\[bad_request_rule_8\]") {
        set $blockreason $bad_request;
        return 403;

    if ( $bad_request_method !~* "\[OK\]" ) {
        set $blockreason $bad_request_method;
        return 403;

    location / {
        client_max_body_size 50M;
        include /etc/nginx/custom-config/proxy.conf;
        proxy_pass http://gitea;


Enable the site:

ln -s /etc/nginx/sites-available/ /etc/nginx/sites-enabled/

Finish Installation

Enable and start the gitea service:

systemctl enable gitea.service --now

Reload Nginx and check config:

service nginx reload
nginx -t

Load the webpage in your browser at

Click on 'sign-in' at the top right of the page. This will take you to the initial setup page wher eyou will enter the relevant details including the database details you set earlier. Once complete, your Gitea site will be ready to use!

We should now make the config file read only:

chmod 750 /etc/gitea
chmod 640 /etc/gitea/app.ini

Create an apparmor profile:

nano /etc/apparmor.d/usr.local.bin.gitea

Enter the following:

#include <tunables/global>

/usr/local/bin/gitea flags=(complain) {
  #include <abstractions/base>
  #include <abstractions/mysql>
  #include <abstractions/nameservice>

  /dev/tty rw,
  /etc/gitea/app.ini r,
  /home/git/gitea-repositories/*/*.git/hooks/* mrix,
  /home/git/gitea-repositories/*/*.git/hooks/* r,
  /home/git/gitea-repositories/*/*.git/hooks/*.d/* mrix,
  /home/git/gitea-repositories/*/*.git/hooks/*.d/* r,
  /proc/sys/net/core/somaxconn r,
  /sys/kernel/mm/transparent_hugepage/hpage_pmd_size r,
  /usr/bin/basename mrix,
  /usr/bin/bash mrix,
  /usr/bin/cat mrix,
  /usr/bin/dash mrix,
  /usr/bin/env rix,
  /usr/bin/git mrix,
  /usr/lib/git-core/git mrix,
  /usr/local/bin/gitea mr,
  /usr/share/git-core/templates/ r,
  /usr/share/git-core/templates/** r,
  owner /home/git/.gitconfig rw,
  owner /home/git/.gitconfig.lock rw,
  owner /home/git/gitea-repositories/** rw,
  owner /home/git/gitea-repositories/*/*.git/objects/** l,
  owner /var/lib/gitea/** rw,
  owner /var/lib/gitea/data/**/{store,LOCK} rwk,
  owner /var/lib/gitea/data/tmp/** rwl,


Reload apparmor

service apparmor reload

Restart the Gitea service and use. Check the apparmor logs with aa-logprof and amend if necessary. Once happy, enforce the profile with aa-enforce usr.local.bin.gitea

Creating a Fail2Ban Jail

Create the jail:

nano /etc/fail2ban/jail.d/gitea.local

Enter the following:

enabled = true
filter = gitea
logpath = /var/lib/gitea/log/gitea.log
maxretry = 5
findtime = 3600
bantime = 21600
action = iptables-allports

now create the filter:

nano /etc/fail2ban/filter.d/gitea.conf

Enter the following:

failregex =  .*Failed authentication attempt for .* from <HOST>
ignoreregex =

Reload Fail2Ban to activate the new jail:

fail2ban-client reload