Gitea is a self-hosted Git service with a functionality similar to GitHub, GitLab and BitBucket. It’s a fork of Gogs and uses the same MIT licence. As most applications written in Go it’s easy to install.


For this guide you should be familiar with the basic concepts of


You’ll need your MySQL credentials. Get them with my_print_defaults:

[isabell@stardust ~]$ my_print_defaults client
[isabell@stardust ~]$

Write down the password for later. Create a database (your username is inserted automatically):

[isabell@stardust ~]$ mysql --execute "CREATE DATABASE ${USER}_gitea"
[isabell@stardust ~]$

We can use the uberspace domain or your own domain:

[isabell@stardust ~]$ uberspace web domain list
[isabell@stardust ~]$



Check current version of Gitea at its releases page:

[isabell@stardust ~]$ VERSION=1.21.0
[isabell@stardust ~]$ mkdir ~/gitea
[isabell@stardust ~]$ wget -O ~/gitea/gitea${VERSION}/gitea-${VERSION}-linux-amd64
Saving to: ‘/home/isabell/gitea/gitea’

100%[========================================================>] 83,243,800  14.9MB/s   in 9.8s

2020-06-01 21:00:42 (8.11 MB/s) - ‘/home/isabell/gitea/gitea’ saved [83243800/83243800]
[isabell@stardust ~]$

Verifying (optional)

Optionally you can verify the downloaded file using gpg. To do so, download the pgp signature file and trust key and verify the binary:

[isabell@stardust ~]$ wget --output-document ~/gitea/gitea.asc${VERSION}/gitea-${VERSION}-linux-amd64.asc
[isabell@stardust ~]$ curl --silent | gpg --import
[isabell@stardust ~]$ gpg --verify ~/gitea/gitea.asc ~/gitea/gitea
gpg: Signature made Do 03 Mär 2022 15:48:38 CET using RSA key ID 9753F4B0
gpg: Good signature from "Teabot <>"
gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.
Primary key fingerprint: 7C9E 6815 2594 6888 62D6  2AF6 2D9A E806 EC15 92E2
     Subkey fingerprint: CC64 B1DB 67AB BEEC AB24  B645 5FC3 4632 9753 F4B0

If the verification is fine, we get a gpg: Good signature from "Teabot <>" line. You need to ignore the WARNING here.

Set permissions

Make the downloaded binary executable:

[isabell@stardust ~]$ chmod u+x ~/gitea/gitea
[isabell@stardust ~]$


We will need to create some random characters as a security key for the configuration:

[isabell@stardust ~]$ ~/gitea/gitea generate secret SECRET_KEY
[isabell@stardust ~]$

Copy the output for later.

Gitea configuration file

Create a custom directory for your configurations:

[isabell@stardust ~]$ mkdir --parents ~/gitea/custom/conf/
[isabell@stardust ~]$

Create a config file ~/gitea/custom/conf/app.ini with the content of the following code block:


In the highlighted lines, replace isabell with your username, fill the database password PASSWD = with yours and enter the generated random into SECRET_KEY =.

DOMAIN               =
ROOT_URL             = https://%(DOMAIN)s
OFFLINE_MODE         = true ; privacy option.
LFS_START_SERVER     = true ; Enables Git LFS support

DB_TYPE  = mysql
NAME     = isabell_gitea
USER     = isabell

INSTALL_LOCK        = true
PASSWORD_COMPLEXITY = lower ; This allows well to remember but still secure passwords
SECRET_KEY          = <RANDOM_64_CHARACTERS_FROM_GENERATOR> ; the before generated security key

DISABLE_REGISTRATION       = true ; security option, only admins can create new users.
DEFAULT_ORG_VISIBILITY     = private ; [public, limited, private]
NO_REPLY_ADDRESS           =

ENABLED  = true
PROTOCOL = sendmail
FROM     =

SHOW_FOOTER_VERSION = false ; hide version number from strangers - you can still see it in the admin panel at /admin


This config block contains a secure and convenient basic configuration. You may change it depending on your needs and knowledge. See the Gitea documentation and the Gitea configuration sample for more configuration possibilities.

Database initialization

Migrate the database configurations:

[isabell@stardust ~]$ ~/gitea/gitea migrate
2022/03/15 11:59:06 models/db/engine.go:194:InitEngineWithMigration() [I] [SQL] CREATE TABLE IF NOT EXISTS `upload` (`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL , `uuid` VARCHAR(40) NULL , `name` VARCHAR(255) NULL ) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 ROW_FORMAT=DYNAMIC [] - 44.298441ms
2022/03/15 11:59:06 models/db/engine.go:194:InitEngineWithMigration() [I] [SQL] CREATE UNIQUE INDEX `UQE_upload_uuid` ON `upload` (`uuid`) [] - 30.158825ms
[isabell@stardust ~]$

Gitea admin user

Set your admin login credentials:

[isabell@stardust ~]$ ADMIN_USERNAME=AdminUsername
[isabell@stardust ~]$ ADMIN_PASSWORD='SuperSecretAdminPassword'
[isabell@stardust ~]$ ~/gitea/gitea admin user create --username ${ADMIN_USERNAME} --password ${ADMIN_PASSWORD} --email ${USER} --admin
[isabell@stardust ~]$


Gitea does not allow admin as name, of course you should choose and replace the password.

Finishing installation

Service for Gitea

To keep Gitea up and running in the background, you need to create a service that takes care for it. Create a config file ~/etc/services.d/gitea.ini for the service:

command=%(ENV_HOME)s/gitea/gitea web

After creating the configuration, tell supervisord to refresh its configuration and start the service:

[isabell@stardust ~]$ supervisorctl reread
SERVICE: available
[isabell@stardust ~]$ supervisorctl update
SERVICE: added process group
[isabell@stardust ~]$ supervisorctl status
SERVICE                            RUNNING   pid 26020, uptime 0:03:14
[isabell@stardust ~]$


The status of gitea must be RUNNING. If its not check the log output at ~/logs/supervisord.log and the configuration file ~/gitea/custom/conf/app.ini.

Uberspace web backend


gitea is running on port 3000.

To make the application accessible from the outside, configure a web backend:

[isabell@stardust ~]$ uberspace web backend set / --http --port <port>
Set backend for / to port <port>; please make sure something is listening!
You can always check the status of your backend using "uberspace web backend list".
[isabell@stardust ~]$

Done. We can point our browser to

Installed files and folders are:

  • ~/gitea

  • ~/etc/services.d/gitea.ini


The Gitea CLI (command line interface) has a build-in backup command to create a full backup in a zip file with the database, repos, config, log, data


To restore a backup follow the backup and restore documentation

Execute the following command:

[isabell@stardust ~]$ ~/gitea/gitea dump
2022/03/08 17:26:01 ...dules/setting/log.go:283:newLogService() [I] Gitea v1.16.3 built with GNU Make 4.1, go1.17.7 : bindata, sqlite, sqlite_unlock_notify
2022/03/08 17:26:01 ...s/storage/storage.go:171:initAttachments() [I] Initialising Attachment storage with type:
2022/03/08 17:26:01 ...les/storage/local.go:46:NewLocalStorage() [I] Creating new Local Storage at /home/isabell/gitea/data/attachments
2022/03/08 17:26:01 ...s/storage/storage.go:165:initAvatars() [I] Initialising Avatar storage with type:
2022/03/08 17:26:01 ...les/storage/local.go:46:NewLocalStorage() [I] Creating new Local Storage at /home/isabell/gitea/data/avatars
2022/03/08 17:26:01 ...s/storage/storage.go:183:initRepoAvatars() [I] Initialising Repository Avatar storage with type:
2022/03/08 17:26:01 ...les/storage/local.go:46:NewLocalStorage() [I] Creating new Local Storage at /home/isabell/gitea/data/repo-avatars
2022/03/08 17:26:01 ...s/storage/storage.go:177:initLFS() [I] Initialising LFS storage with type:
2022/03/08 17:26:01 ...les/storage/local.go:46:NewLocalStorage() [I] Creating new Local Storage at /home/isabell/gitea/data/lfs
2022/03/08 17:26:01 ...s/storage/storage.go:189:initRepoArchives() [I] Initialising Repository Archive storage with type:
2022/03/08 17:26:01 ...les/storage/local.go:46:NewLocalStorage() [I] Creating new Local Storage at /home/isabell/gitea/data/repo-archive
2022/03/08 17:26:01 cmd/dump.go:270:runDump() [I] Dumping database...
2022/03/08 17:26:01 cmd/dump.go:282:runDump() [I] Adding custom configuration file from /home/isabell/gitea/custom/conf/app.ini
2022/03/08 17:26:01 cmd/dump.go:310:runDump() [I] Packing data directory.../home/isabell/gitea/data
2022/03/08 17:26:01 cmd/dump.go:379:runDump() [I] Finish dumping in file
[isabell@stardust ~]$



Check the update feed or releases page regularly to stay informed about the newest version.

Manual updating

  • Stop the application supervisorctl stop gitea

  • Do the Download (and optionally Verifying) part from above.

  • Check if you have to modify the config file. (See documentation and the file sample.)

  • Do the database migration: ~/gitea/gitea migrate

  • Start the application supervisorctl start gitea

  • Check if the application is running supervisorctl status gitea

Automated updating by custom script

You can also automate the update by using a custom script that automatically executes all the update steps. Create ~/bin/gitea-update with the following content:

#!/usr/bin/env bash


ORG=go-gitea # Organisation or GitHub user

function do_update_procedure
  curl --location --progress-bar --output "$TMP_LOCATION"/gitea "$DOWNLOAD_URL"
  $GITEA_BINARY manager flush-queues
  supervisorctl stop gitea
  mv --verbose "$TMP_LOCATION"/gitea "$GITEA_BINARY"
  chmod u+x --verbose "$GITEA_BINARY"
  echo "$APP_NAME service takes 30 seconds to start"
  supervisorctl start gitea
  supervisorctl status gitea

function set_local_version
    awk '{print $3}')

function set_latest_version
  curl --silent $GITHUB_API_URL > "$TMP_LOCATION"/github_api_response.json
  TAG_NAME=$(jq --raw-output '.tag_name' "$TMP_LOCATION"/github_api_response.json)
  DOWNLOAD_URL=$(jq --raw-output '.assets[].browser_download_url' "$TMP_LOCATION"/github_api_response.json |
    grep --max-count=1 "linux-amd64")

function download_signature_file
  SIGNATURE_FILE_URL=$(jq --raw-output '.assets[].browser_download_url' "$TMP_LOCATION"/github_api_response.json |
    grep "linux-amd64.asc")
  rm "$TMP_LOCATION"/github_api_response.json
  wget --quiet --progress=bar:force --output-document "$TMP_LOCATION"/gitea.asc "$SIGNATURE_FILE_URL"

function verify_file

  ## downloading public key if it does NOT already exist OR if it is expired
  if ! gpg --fingerprint $PGP_KEY_FINGERPRINT ||
    (gpg --fingerprint $PGP_KEY_FINGERPRINT | grep expired)
    ## currently the key download via gpg does not work on Uberspace
    #gpg --keyserver --recv $PGP_KEY_FINGERPRINT
    curl --silent$PGP_KEY_FINGERPRINT | gpg --import

  if ! gpg --export-ownertrust | grep --quiet $PGP_KEY_FINGERPRINT:6:
  then echo "$PGP_KEY_FINGERPRINT:6:" | gpg --import-ownertrust

  if gpg --verify "$TMP_LOCATION"/gitea.asc "$TMP_LOCATION"/gitea
  then rm "$TMP_LOCATION"/gitea.asc; return 0
  else echo "gpg verification results in a BAD signature"; exit 1

# version_lower_than A B
# returns whether A < B
function is_version_lower_than
  test "$(echo "$@" |                 # get all version arguments
    tr " " "\n" |                     # replace `space` with `new line`
    sed '/alpha/d; /beta/d; /rc/d' |  # remove pre-release versions (version-sort interprets suffixes as patch versions)
    sort --version-sort --reverse |   # latest version will be sorted to line 1
    head --lines=1)" != "$1"          # filter line 1 and compare it to A

function fix_stop_signal
  if (grep --quiet HUP "$HOME"/etc/services.d/gitea.ini)
    sed --in-place '/HUP/d' "$HOME"/etc/services.d/gitea.ini
    supervisorctl reread
    supervisorctl update

function is_update_available
  if is_version_lower_than "$LOCAL_VERSION" "$LATEST_VERSION"
  then return 0
  else return 1

function main

  if is_update_available
    echo "There is a new version available."
    echo "Doing update from $LOCAL_VERSION to $LATEST_VERSION"
    echo "Your $APP_NAME is already up to date."
    echo "You are running $APP_NAME $LOCAL_VERSION"

main "$@"
exit $?

Now make the script executable.

[isabell@stardust ~]$ chmod u+x ~/bin/gitea-update
[isabell@stardust ~]$

Run the updater

[isabell@stardust ~]$ gitea-update
There is a new version available.
Doing update from 1.19.1 to 1.19.2
###################################################################################### 100.0%
pub   4096R/EC1592E2 2018-06-24 [expires: 2024-06-21]
      Key fingerprint = 7C9E 6815 2594 6888 62D6  2AF6 2D9A E806 EC15 92E2
uid                  Teabot <>
sub   4096R/CBADB9A0 2018-06-24 [expires: 2024-06-21]
sub   4096R/9753F4B0 2018-06-24 [expires: 2024-06-21]

gpg: Signature made Wed 07 Sep 2022 00:26:25 CEST using RSA key ID 9753F4B0
gpg: Good signature from "Teabot <>"
gitea: stopped
‘/home/isabell/tmp/gitea’ -> ‘/home/isabell/gitea/gitea’
mode of ‘/home/isabell/gitea/gitea’ changed from 0664 (rw-rw-r--) to 0764 (rwxrw-r--)
Gitea service takes 30 seconds to start
gitea: started
gitea                            RUNNING   pid 26730, uptime 0:00:30
[isabell@stardust ~]$

Additional configuration

Gitea ssh setup (optional)

Gitea can manage the ssh keys. In order to not interfere with the server’s own ssh keys, we can use Gitea’s inbuilt ssh server. This requires a dedicated extra port, that we need to open first as described in the manual:

[isabell@stardust ~]$ uberspace port add
Port 12345 will be open for TCP and UDP traffic in a few minutes.
[isabell@stardust ~]$

Add this port number along with the following lines to your ~/gitea/custom/conf/app.ini in the [server] section at the beginning:

SSH_DOMAIN           = %(DOMAIN)s
DISABLE_SSH          = false
SSH_PORT             = 12345 ; replace with your port number

Now your Gitea users can add their ssh keys via the menu in the upper right corner: Settings -> tab: SSH/GPG Keys -> Add Key

Gitea using external renderer (optional)

Gitea supports custom file renderings (i.e. Jupyter notebooks, asciidoc, etc.) through external binaries to provide a preview.
In this case we install an external rendering extension for AsciiDoc.
AsciiDoctors location will be here: ~/.gem/ruby/2.7.0/*/asciidoctor*
[isabell@stardust ~]$ gem install asciidoctor
Fetching asciidoctor-2.0.10.gem
WARNING:  You don't have /home/isabell/.gem/ruby/2.7.0/bin in your PATH,
        gem executables will not run.
Successfully installed asciidoctor-2.0.10
1 gem installed
[isabell@stardust ~]$


Don’t be irritated by the warning that the bin folder isn’t in the path. Uberspace is taking care of it. You can check with [isabell@stardust ~]$ which asciidoctor.

Now we have to append the config file ~/gitea/custom/conf/app.ini with:

ENABLED = true
FILE_EXTENSIONS = .adoc,.asciidoc
RENDER_COMMAND = "asciidoctor -e -a leveloffset=-1 --out-file=- -"

Tested with Gitea 1.21.0, Uberspace 7.15.6

Written by: Frank ℤisko <>, EV21 <>, Christian Macht <>