Skip to main content
Simon posted in: Developer

Whilst GitHub offers a fantastic service, it can be limiting if you don't want to take a paid plan. Other free hosted services are available with GitLaband BitBucket as two of the larger alternatives.

Data protection restrictions, however, may make it impossible to entrust your data to a third-party service. Fortunately, there are various projects which offer the ability to self-host your own repositories; which one you choose is mostly dependent on your requirements.If you need a fully-featured alternative to GitHub then GitLab's self-hosted offering is a great choice; it also includes features such as time tracking, static websites and the ability to integrate CI/CD pipelines into your repositories with Runners.

At the other end of the spectrum is Gitea. Gitea describes its purpose as 'to provide the easiest, fastest, and most painless way of setting up a self-hosted Git service'. As Gitea is written in Go it is widely supported on all common platforms and architectures (you can even run it on a Raspberry Pi!). 

First, we'll go through getting GitLab EE Core up and running, and then we'll do the same with Gitea. Both guides were written using Ubuntu Xenial for the OS, but each project provides a wide range of installation options. Due to its relative complexity, GitLab requires more resources; GitLab was set up on a 4Gb Cloud IaaS instance whereas Gitea runs fine on a 1Gb instance.

Installing GitLab

GitLab provide a script you can pass to curl in order to set everything up for you, however as piping to bash could be used to run malicious code on your system it is not recommended. If you do decide to use the aforementioned script then open it in your web browser and ensure you fully understand what it is going to do before running it. Fortunately, getting GitLab set up is quite trivial to complete manually. The following steps assume you are using the root user.

First, install the packages it requires (you can accept the defaults for Postfix when prompted):

apt-get update && apt-get install -y curl openssh-server ca-certificates debian-archive-keyring apt-transport-https postfix

Add GitLab's package signing key to apt's keyring:

curl -L 2> /dev/null | apt-key add -

Then add GitLab'spackage repository: 

cat << EOF > /etc/apt/sources.list.d/gitlab_gitlab-ee.list
deb xenial main
deb-src xenial main

Finally, update apt's cache again and install GitLab (you must also provide the URL you wish to access GitLab on once it is installed):

apt-get update && EXTERNAL_URL="" apt-get install gitlab-ee

Setup will take a few minutes; once completed navigate to, set a password for the root account and then proceed to log in.

Installing Gitea

First, ensure Git is installed:

$ apt-get update && apt-get install -y git

At the time of writing, Gitea isn't packaged so we need to download the binary:

$ wget -O /usr/local/bin/gitea && chmod +x /usr/local/bin/gitea

Ensure it has been installed correctly:

$ gitea --version
Gitea version 1.4.2 built with: bindata, sqlite

Gitea requires a user to run as:

$ adduser --system --shell /bin/bash --gecos 'Gitea user' --group --disabled-password --home /home/gitea gitea

And we'll need to create some directories for it to use:

mkdir -p /var/lib/gitea/{custom,data,indexers,public,log}
chown -R gitea:gitea /var/lib/gitea
chmod 0750 /var/lib/gitea/{data,indexers,log}

Now we have everything ready for Gitea, we'll start it manually. First, we need to change users to the gitea user we created earlier (note the change in the SSH prompt):

root@gitea:~# su gitea

As the gitea user, run Gitea in the foreground so we can carry out the initial setup:

gitea@gitea:~$ GITEA_WORK_DIR=/var/lib/gitea/ gitea web
2018/06/06 08:58:02 [W] Custom config '/var/lib/gitea/custom/conf/app.ini' not found, ignore this if you're running first time
2018/06/06 08:58:02 [T] AppPath: /usr/local/bin/gitea
2018/06/06 08:58:02 [T] AppWorkPath: /var/lib/gitea/
2018/06/06 08:58:02 [T] Custom path: /var/lib/gitea/custom
2018/06/06 08:58:02 [T] Log path: /var/lib/gitea/log
2018/06/06 08:58:02 [I] Gitea v1.4.2 built with: bindata, sqlite
2018/06/06 08:58:02 [I] Log Mode: Console(Info)
2018/06/06 08:58:02 [I] XORM Log Mode: Console(Info)
2018/06/06 08:58:02 [I] Cache Service Enabled
2018/06/06 08:58:02 [I] Session Service Enabled
2018/06/06 08:58:02 [I] SQLite3 Supported
2018/06/06 08:58:02 [I] Run Mode: Development
2018/06/06 08:58:03 Serving [::]:3000 with pid 2007
2018/06/06 08:58:03 [I] Listen:

At this point we can now navigate to the GUI with a browser. For this example, I used the domain, so Gitea was accessible at For the purpose of kicking the tyres, I used SQLite as the database; this creates a database file on disk. For permanent installations it is advisable to use a database application such as MYSQL/MariaDB or PostgreSQL. When using SQLite you'll need to adjust the path to the database file; it should be /var/lib/gitea/data/gitea.db. Ensure that you also change localhost to in the Domain and Application URL options.

Once complete, click the install button; this will redirect you to the login page. As Gitea is initialised without any users, you'll need to first register an account and then use it to log in. The first account registered after setup is complete will also be the administrator.

Finally, we need to ensure that Gitea runs on boot. Back in the SSH session, use ctrl+c to stop Gitea and then ctrl+d to drop back to the root user. We'll then create a Systemd service:

cat << EOF > /etc/systemd/system/gitea.service
Description=Gitea (Git with a cup of tea)

ExecStart=/usr/local/bin/gitea web
Environment=USER=gitea HOME=/home/gitea GITEA_WORK_DIR=/var/lib/gitea
# If you want to bind Gitea to a port below 1024 uncomment
# the two values below


And finally enable it to run on boot (and also start it immediately):

systemctl daemon-reload && systemctl enable gitea --now

Mirroring a repo from GitHub

With our Git repo now running, we can transfer code from GitHub. The following assumes you've created a user in GitLab/Gitea and added your SSH key. It also assumes you've created a repository to mirror the code to (GitLab calls them Projects).

Initially, we can see our checkout has GitHub as the only available remote:

$ git remote -v
origin (fetch)
origin (push)

We first need to add our new server as a remote (I've added both for this example):

$ git remote add gitea
$ git remote add gitlab
$ git remote -v
gitea (fetch)
gitea (push)
gitlab (fetch)
gitlab (push)
origin (fetch)
origin (push)

With the remotes in place, we can now push the code to them:

$ git push gitea master
Counting objects: 3, done.
Writing objects: 100% (3/3), 227 bytes | 227.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)
 * [new branch]      master -> master
$ git push gitlab master
Counting objects: 3, done.
Writing objects: 100% (3/3), 227 bytes | 227.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)
 * [new branch]      master -> master

Finally, we can remove GitHub as a remote and replace it with our new repo:

$ git remote remove origin
$ git remote rename gitlab origin
$ git remote -v
gitea (fetch)
gitea (push)
origin (fetch)
origin (push)

Now when we run a git push, it will push to our GitLab server by default.