This is how I set up my Gitea instance on my Ubuntu server. For more generic instructions, read the official documentation.

Create a MySQL database

Generate a random secure password:

cat /dev/urandom | tr -dc "a-zA-Z0-9" | head -c 20; echo

Create the MySQL user and database:

sudo mysql
CREATE DATABASE gitea CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_unicode_ci';
CREATE USER gitea@localhost IDENTIFIED BY '<password>';
GRANT ALL PRIVILEGES ON gitea.* TO gitea@localhost;
exit

Prepare the Linux environment

Create a user to run Gitea under:

sudo adduser --system --shell /bin/bash --gecos 'Gitea' --group --disabled-password --home /home/git git

Create the required directories:

sudo mkdir -p /var/lib/gitea/{custom,data,log}
sudo chown -R git:git /var/lib/gitea/
sudo chmod -R 750 /var/lib/gitea/

sudo mkdir /etc/gitea
sudo chown root:git /etc/gitea
sudo chmod 770 /etc/gitea

Download Gitea

Since there are no packages available for Ubuntu/Debian, we have to manually install the binary:

sudo wget -O /usr/local/bin/gitea https://dl.gitea.io/gitea/1.14.3/gitea-1.14.3-linux-amd64
sudo chmod +x /usr/local/bin/gitea

Verify it:

gpg --keyserver keys.openpgp.org --recv 7C9E68152594688862D62AF62D9AE806EC1592E2
gpg --verify <(curl -L https://dl.gitea.io/gitea/1.14.3/gitea-1.14.3-linux-amd64.asc) /usr/local/bin/gitea

Look for the text Good signature from "Teabot <teabot@gitea.io>".
Ignore the warning This key is not certified with a trusted signature.

Set up the Gitea service

Run:

sudo vim /etc/systemd/system/gitea.service

Enter the following:

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

Wants=mariadb.service
After=mariadb.service

[Service]
RestartSec=2s
Type=simple
User=git
Group=git
WorkingDirectory=/var/lib/gitea/
ExecStart=/usr/local/bin/gitea web --config /etc/gitea/app.ini
Restart=always
Environment=USER=git HOME=/home/git GITEA_WORK_DIR=/var/lib/gitea

[Install]
WantedBy=multi-user.target

Run:

sudo systemctl enable gitea --now
sudo systemctl status gitea

Configure Apache

I already run an Apache web server, so I created a new virtual host:

sudo vim /etc/apache2/sites-enabled/git.djm.me.conf

With content:

<VirtualHost *:80>
    ServerName git.djm.me
    RedirectPermanent / https://git.djm.me/
</VirtualHost>

<VirtualHost *:443>
    SSLEngine on
    ServerName git.djm.me
    ProxyPass / http://localhost:3000/ nocanon
    ProxyPassReverse / http://localhost:3000/
</VirtualHost>

Then reload Apache:

sudo systemctl reload apache2
sudo systemctl status apache2

Note: I already have a wildcard SSL certificate (from Let’s Encrypt) set up globally, so I didn’t need to configure that in the virtual host.

Run the installer

Now open Gitea in a browser (https://git.djm.me/) and fill in the following:

Database Settings

  • Password: As generated above.
  • Charset: utf8mb4

General Settings

  • Site Title: Dave James Miller's Git Repos
  • SSH Server Domain: git.djm.me
  • Gitea Base URL: https://git.djm.me/

Server and Third-Party Service Settings

  • Enable Local Mode: Tick
  • Disable Self-Registration: Tick
  • Hide Email Addresses by Default: Tick
  • Password Hash Algorithm: bcrypt

Administrator Account Settings

Enter admin user details.

Secure the config file

Remove Gitea’s write permissions:

sudo chown root:git /etc/gitea
sudo chmod g-w -R /etc/gitea

User setup

In Menu > Settings…

Profile

  • Full Name: Dave James Miller
  • Website: https://djm.me/
  • Location: Oxford, England
  • Language: English

Click “Update Profile”.

Upload an avatar.

Account

  • Add email addresses

Security

  • Enroll into Two-Factor Authentication.
  • Add a Security Key

SSH / GPG Keys

  • Add public keys

Advanced configuration

Run:

sudo vim /etc/gitea/app.ini

Add this at the end:

[repository]
ENABLE_PUSH_CREATE_USER = true
ENABLE_PUSH_CREATE_ORG = true
DISABLED_REPO_UNITS = repo.issues, repo.ext_issues, repo.pulls, repo.wiki, repo.ext_wiki, repo.projects
DEFAULT_REPO_UNITS = repo.code, repo.releases
DEFAULT_PRIVATE = private
DISABLE_STARS = true
DEFAULT_BRANCH = main

[ui]
EXPLORE_PAGING_NUM = 50
ISSUE_PAGING_NUM = 50
MEMBERS_PAGING_NUM = 50
FEED_MAX_COMMIT_NUM = 50
FEED_PAGING_NUM = 50
THEME_COLOR_META_TAG = #65c9ff
DEFAULT_SHOW_FULL_NAME = true

[ui.meta]
AUTHOR = Dave James Miller
DESCRIPTION = My Git repositories
KEYWORDS = dave,james,miller,git,repos,repositories

[server]
LANDING_PAGE = explore

[security]
MIN_PASSWORD_LENGTH = 10
PASSWORD_COMPLEXITY = lower,upper,digit,spec
PASSWORD_CHECK_PWN = true

[service]
ENABLE_BASIC_AUTHENTICATION = false
AUTO_WATCH_NEW_REPOS = false
DEFAULT_USER_VISIBILITY = private
DEFAULT_ORG_VISIBILITY = private

[picture]
REPOSITORY_AVATAR_FALLBACK = random

[other]
SHOW_FOOTER_VERSION = false
SHOW_FOOTER_TEMPLATE_LOAD_TIME = false

(For details of what each of these do, see the documentation.)

Then restart Gitea:

sudo systemctl restart gitea
sudo systemctl status gitea

Customise images and CSS styles

In /var/lib/gitea/custom/, create the following files:

/var/lib/gitea/custom/
├── public
│   ├── css
│   │   └── custom.css
│   └── img
│       ├── apple-touch-icon.png
│       ├── favicon.png
│       ├── logo.png
│       └── logo.svg
└── templates
    └── custom
        └── header.tmpl

In header.tmpl include:

<link rel="stylesheet" href="{{StaticUrlPrefix}}/css/custom.css?v=1">

For a list of customisable files/templates, run:

gitea embedded list

To view the default contents of a file, run:

gitea embedded view <filename>

Or look in the Gitea repo for the relevant version.

After changing a .tmpl file (or anything outside public/), restart Gitea:

sudo systemctl restart gitea
sudo systemctl status gitea

You can see all my customisations in my Gitea repo.

Translation

To fix the Americanisms…

sudo mkdir -p /var/lib/gitea/custom/options/locale
gitea embedded view options/locale/locale_en-US.ini | sudo tee /var/lib/gitea/custom/options/locale/locale_en-US.ini >/dev/null
sudo sed -Ei 's/( = .*[Aa])uthorization/\1uthorisation/' /var/lib/gitea/custom/options/locale/locale_en-US.ini
sudo sed -Ei 's/( = .*[Aa])uthorize/\1uthorise/' /var/lib/gitea/custom/options/locale/locale_en-US.ini
sudo sed -Ei 's/( = .*[Ii])nitialize/\1nitialise/' /var/lib/gitea/custom/options/locale/locale_en-US.ini
sudo sed -Ei 's/( = .*[Oo])rganization/\1rganisation/' /var/lib/gitea/custom/options/locale/locale_en-US.ini
sudo sed -Ei 's/( = .*[Oo])rganization/\1rganisation/' /var/lib/gitea/custom/options/locale/locale_en-US.ini
sudo sed -Ei 's/( = .*[Oo])rganize/\1rganise/' /var/lib/gitea/custom/options/locale/locale_en-US.ini
sudo sed -Ei 's/( = .*[Oo])rganize/\1rganise/' /var/lib/gitea/custom/options/locale/locale_en-US.ini
sudo sed -Ei 's/( = .*[Rr])ecognize/\1ecognise/' /var/lib/gitea/custom/options/locale/locale_en-US.ini
sudo sed -Ei 's/( = .*[Ss])ynchronization/\1ynchronisation/' /var/lib/gitea/custom/options/locale/locale_en-US.ini
sudo sed -Ei 's/( = .*[Ss])ynchronize/\1ynchronise/' /var/lib/gitea/custom/options/locale/locale_en-US.ini
sudo sed -Ei 's/( = .*[Uu])ncategorized/\1ncategorised/' /var/lib/gitea/custom/options/locale/locale_en-US.ini

Note: Some replacements have to be run more than once to catch sentences that contain the same word more than once. It was easier than writing a regex that replaces them all at once.

Then restart Gitea:

sudo systemctl restart gitea
sudo systemctl status gitea

Set up Fail2ban

Run:

sudo vim /etc/gitea/app.ini

Replace the following:

[log]
MODE = file

Run:

sudo vim /etc/fail2ban/filter.d/gitea.conf

Enter:

[Definition]
failregex =  .*(Failed authentication attempt|invalid credentials|Attempted access of unknown user).* from <HOST>
ignoreregex =

Run:

sudo vim /etc/fail2ban/jail.d/gitea.conf

Enter:

[gitea]
enabled = true
filter = gitea
logpath = /var/lib/gitea/log/gitea.log

Note: I have already configured global Fail2ban rate limits, so this doesn’t exactly match the Gitea documentation.

Run:

sudo systemctl restart gitea
sudo systemctl status gitea

sudo systemctl restart fail2ban
sudo systemctl status fail2ban

To test it, run:

tail -f /var/log/fail2ban.log

Then enter an incorrect password into Gitea. It should display something like:

2021-07-03 13:58:19,100 fail2ban.filter         [383962]: INFO    [gitea] Found 12.34.56.78 - 2021-07-03 13:58:19

Set up automatic updates

Gitea Auto Update makes it easy to upgrade Gitea.

sudo pip3 install gitea-auto-update
sudo vim /etc/gitea-auto-update.ini

Enter:

[Gitea]
site=https://git.djm.me/api/v1/version
apiUrl=https://api.github.com/repos/go-gitea/gitea/releases/latest
system=linux-amd64
file=/usr/local/bin/gitea
tmpDir=/tmp/
buildFromSource=
sourceDir=
logFile=/var/log/gitea-auto-update.log

Test it:

sudo gitea-auto-update --settings=/etc/gitea-auto-update.ini

Set up cron job:

sudo vim /etc/cron.d/gitea-auto-update

Enter:

0 3 * * * root /usr/local/bin/gitea-auto-update --settings=/etc/gitea-auto-update.ini | sed '/current version is uptodate/d'

(This way it emails me if there’s an update or a problem, but not every day.)