Installing Gitea from source Ubuntu 18.04

What is Gitea?

Gitea is a painless self-hosted Git service that is a community managed lightweight code hosting solution written in Go.

Why install Gitea?

There are lots of free git services out there: GitHub, GitLab, Gogs, Bitbucket to name a few. Why is Gitea any different? Well, that is exactly the point: Gitea is, for all intents and purposes, the exact same and is even a fork of Gogs, but has all the same luxery features as a paid subscription and is #FOSS that is self-hosted.


I used several sources to make my guide and are very similar, but just tailored to my needs, wants, simplifications.



  • Ubuntu 18.04
  • Apache2
  • MySQL
  • Certbot

Installation guide

Install Go

Change directory to where you are going to install Go to:

cd /usr/local/

Download the latest version of Go (1.13.6):


Extract the tar.gz file:

tar -xzf go1.13.6.linux-amd64.tar.gz

Add Go to the user who will be compiling it’s PATH:

nano ~/.profile

Add near bottom of file:

export PATH=$PATH:/usr/local/go/bin

To immediately start using Go (else you will need to restart your computer or close all terminal windows):

source ~/.profile

Check you can use Go:

go version

You should get:

user@computer:~$ go version
go version go1.13.6 linux/amd64

For this guide, I don’t want to use the stable 1.10.2 branch nor the latest dev branch, so I’m going to use 1.11.0:

cd ~
mkdir gitea
cd gitea
git clone
cd gitea
git checkout release/v1.11

Now let’s create our binary. You are going to need nodejs with npm and make to do so.

TAGS="bindata sqlite sqlite_unlock_notify" make build

This will take a little while depending on your system. If you get an error about can’t find SQLite3 and you want to only use either a PostgreSQL or MySQL database, use this command instead:

TAGS="bindata" make build

Now test to see if it runs:

./gitea web -p 3333

You can change the port to be whatever you want, just make sure it isn’t being used yet. Navigate to http://localhost:3333/. If you get a webpage, great work! We are ready to move on.

Make sure you have created an A record pointing to your home server. Mine is named git for simplicity.

Create your system file that will start on system startup:

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

With contents of:

Description=Gitea (Git with a cup of tea) mysqld.service redis.service

ExecStart=/home/gituser/gitea/gitea/gitea web -c /home/gituser/gitea/gitea/custom/conf/app.ini

### Modify these two values and uncomment them if you have repos with lots of files and get an HTTP error 500 because of that
### If you want to bind Gitea to a port below 1024 uncomment the two values below


Test to make sure it works:

sudo systemctl daemon-reload
sudo systemctl start gitea

If when you navigate to http://localhost:3333/ it works, you can then enable the service:

sudo systemctl stop gitea
sudo systemctl enable gitea
sudo systemctl start gitea

Create a new apache2 config:

nano /etc/apache2/sites-available/git.conf

And paste contents:

DEFINE git_url
DEFINE git_port 3030
DEFINE public_url
DEFINE email git@my.domain
ServerTokens Prod
SSLStaplingCache "shmcb:${APACHE_LOG_DIR}/stapling-cache(150000)"
SSLSessionCache "shmcb:${APACHE_LOG_DIR}/ssl_scache(512000)"
SSLSessionCacheTimeout 300
### If you have Google's Mod PageSpeed, disable it
ModPagespeed Off

ServerName ${public_url}
DocumentRoot /var/www/offline
ServerAdmin ${email}
ErrorLog ${APACHE_LOG_DIR}/git.error.log
CustomLog ${APACHE_LOG_DIR}/git.access.log combined
RewriteEngine On
RewriteCond %{SERVER_NAME}
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]

ServerName ${public_url}
DocumentRoot /var/www/offline
ServerAdmin ${email}
ErrorLog ${APACHE_LOG_DIR}/git.error.log
CustomLog ${APACHE_LOG_DIR}/git.access.log combined
SSLEngine On
SSLCertificateFile /etc/letsencrypt/live/my.domain/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/my.domain/privkey.pem
#Include /etc/letsencrypt/options-ssl-apache.conf
### Forbid the http1.0 protocol ###
Protocols h2 http/1.1
Timeout 360
ProxyRequests Off
ProxyPreserveHost On
ProxyTimeout 600
ProxyReceiveBufferSize 4096
SSLProxyEngine On
RequestHeader set Front-End-Https "On"
ServerSignature Off
SSLCompression Off
SSLUseStapling On
SSLStaplingResponderTimeout 5
SSLStaplingReturnResponderErrors Off
SSLSessionTickets Off
RequestHeader set X-Forwarded-Proto 'https' env=HTTPS
Header always set Strict-Transport-Security "max-age=15552000; preload"
Header always set X-Content-Type-Options nosniff
Header always set X-Robots-Tag none
Header always set X-XSS-Protection "1; mode=block"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
#Header always set Content-Security-Policy "default-src 'self' https:; font-src 'self' data: ${git_url} ${public_url}; media-src 'self' blob: data: https: ${git_url} ${public_url} * *; script-src 'self' 'unsafe-inline' 'unsafe-eval' ${git_url} ${public_url} * * *; style-src 'self' ${git_url} ${public_url} *; img-src 'self' data: blob: ${git_url} ${public_url} * *; worker-src *; frame-src 'none'; connect-src 'self' wss: https: ${git_url} ${public_url} * *;"
## If you want to be safer, remove the 'unsafe-inline' 'unsafe-eval' from above and use Chrome to get the sha-256 sums and input below (below was for Server version:; Web version: 3.108.2)
#Header always set Content-Security-Policy "default-src 'self' https:; font-src 'self' data: ${git_url} ${public_url}; media-src 'self' blob: data: https: ${git_url} ${public_url} * *; script-src 'self' 'sha256-nUnhwEm5UMap/qFerb+ou1VJWqowlB1QcbhbmFX7Eu4=' 'sha256-8yKKbip2qr14RHV8H1qDEbRAm9Mmf5ePeQh+wB5pMCw=' 'sha256-pKO/nNgeauDINvYfxdygP3mGssdVQRpRNxaF7uPRoGM=' 'sha256-mrLkgfrqAhdxc2TvIODT0I7QtvuQLMS9AgtfLL9eMXo=' ${git_url} ${public_url} * * *; style-src 'self' ${git_url} ${public_url} *; img-src 'self' data: blob: ${git_url} ${public_url} * *; worker-src *; frame-src 'none'; connect-src 'self' wss: https: ${git_url} ${public_url} * *;"
# Header always set Content-Security-Policy "default-src 'self' https:; font-src 'self' data: ${git_url} ${public_url}; media-src 'self' blob: data: https: ${git_url} ${public_url}; script-src 'self' 'sha256-uYJY2d7sk6QFUzcXCKI85Pm4RSPHRwyIqrkBIAUJ1Fs=' 'sha256-gIDc2qaNPEs8UNPqvHmddLHDq9UE3/EwvEDoUm4+n34=' ${git_url} ${public_url}; img-src 'self' data: https: blob:; style-src 'sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=' 'sha256-9EnfnzP6nTxX6KkJJU81izMTrktSKcXJrHMDpgcxmSk=' 'sha256-9EnfnzP6nTxX6KkJJU81izMTrktSKcXJrHMDpgcxmSk=' 'sha256-9EnfnzP6nTxX6KkJJU81izMTrktSKcXJrHMDpgcxmSk=';style-src-elem 'self' 'unsafe-inline';"
Header always set Feature-Policy "geolocation 'self'; midi 'self'; sync-xhr 'self'; microphone 'self'; camera 'self'; magnetometer 'self'; gyroscope 'self'; speaker 'self'; fullscreen 'self'; payment 'self'"
### Use next two for very secure connections ###
SSLHonorCipherOrder Off
SSLProtocol All -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
### Use next two for secure connections and supports more endpoints ###
#SSLProtocol All -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
### Actually proxy the traffic and really the only important part ###
AllowEncodedSlashes NoDecode
ProxyPass / http://${git_url}:${git_port}/ nocanon
ProxyPassReverse / http://${git_url}:${git_port}/
## If using a subdirectory
#ProxyPass /git http://${git_url}:${git_port} nocanon
#ProxyPassReverse /git http://${git_url}:${git_port}

Enable the site:

sudo a2ensite git.conf

Create your database:

mysql -u root -p

Create MB4 database and user:

CREATE DATABASE gitea CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
CREATE USER 'gituser'@'localhost' IDENTIFIED BY 'change_me_please';
GRANT ALL ON gitea.* TO 'gituser'@'localhost';

Now navigate to your real address to install


You now have a fully functioning Git service. There are infinite possibilities to customize your install. Here are all the possible options you can have. Here are a few from me:

custom/conf/app.ini – where you will make all your customizations
custom/templates – edit header and footer info
custom/public – store custom js, img, and others at the root of your website (useful for custom images and javascript you might want to run)

Leave a Reply

Your email address will not be published. Required fields are marked *