It is always a good idea to keep your projects under version control. Once you get into the habit of using Git, you might warm to the idea of pushing your repository to a web-hosted service such as Github or Gitlab. They are undoubtedly useful for collaboration, sharing and much more.
But for some projects, whether personal or business, using a hosted service is not acceptable (remember, “the cloud” is just someone else’s computer). Even so, you can still get a nice web-based front-end for your Git repos. You will just have to self-host it. Ideally on hardware that you own, but in lieu of that a VPS will do.
My own motivation for self-hosting a Git server is that I would like to have access to the capabilities such a service offers while I work on my thesis, which I’m not comfortable hosting in the cloud (not until it is done, anyway).
Currently, your choice of front-ends boils down to Gitlab CE, Gogs or Gitea.1 Gitea is a fork of Gogs. Both of them are very light on system resources. Gitlab Community Edition is a monster in comparison. For a non-professional coder like myself, Gitea will be just fine.
The rest of this post describes how I setup Gitea on a server of mine. You can have a look at the finished product at https://git.solarchemist.se (it’s not much to look at though, as most repos are private). Before jumping off, I should note that there are already several “how to setup Gitea” guides published by others, so this will not be a step-by-step instruction. For that, I can recommend any of the following:
- “How to setup Gitea on an Ubuntu Server” by Ryan Gilbert. This is a well-written, easy-to-follow step-by-step instruction. It is also the most recent.
- “Setting Up a Self-Hosted Github Clone with Gitea” by Charlesreid1. Also well-written and with lots of screenshots and even an illustration.
- “Set up Gitea with Nginx” by Rune Olsen. This tutorial concentrates on the settings for the web server, using Nginx as a reverse proxy for Gitea.
- “How To Start your own Git Server in less than 30 Minutes” by CHEF-KOCH. Has a section with enlightening discussion on Github alternatives. Also goes through Gitea setup in some detail, including setup of PostgreSQL database.
- And of course, the Gitea Docs themselves.
MySQL database for Gitea
# install mysql from ubuntu repos
sudo apt install mysql-server mysql-client libmysqlclient-dev
# check the installed mysql version
mysql --version
# secure the mysql installation
sudo mysql_secure_installation
# login to mysql as root
sudo mysql -u root -p
While logged in as MySQL root user, create the user and database for Gitea.
CREATE USER 'gitea'@'localhost' IDENTIFIED BY 'somelongandcomplexpassword';
CREATE DATABASE gitea DEFAULT CHARACTER SET 'utf8' COLLATE 'utf8_general_ci';
GRANT ALL ON gitea.* TO 'gitea'@'localhost';
FLUSH PRIVILEGES;
We explicitly set UTF8 for the Gitea database above because the Gitea docs explicitly recommend using InnoDB and UTF8 with MySQL. Recent versions of MySQL should default to using InnoDB (instead of MyISAM), but we can check that ourselves by (still logged in as MySQL root):
mysql> show engines;
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
| Engine | Support | Comment | Transactions | XA | Savepoints |
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
| InnoDB | DEFAULT | Supports transactions, row-level locking, and foreign keys | YES | YES | YES |
| MRG_MYISAM | YES | Collection of identical MyISAM tables | NO | NO | NO |
| MEMORY | YES | Hash based, stored in memory, useful for temporary tables | NO | NO | NO |
| BLACKHOLE | YES | /dev/null storage engine (anything you write to it disappears) | NO | NO | NO |
| MyISAM | YES | MyISAM storage engine | NO | NO | NO |
| CSV | YES | CSV storage engine | NO | NO | NO |
| ARCHIVE | YES | Archive storage engine | NO | NO | NO |
| PERFORMANCE_SCHEMA | YES | Performance Schema | NO | NO | NO |
| FEDERATED | NO | Federated MySQL storage engine | NULL | NULL | NULL |
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
9 rows in set (0.00 sec)
Apache vhost with Let’s Encrypt certificate
This virtualhost configuration is for Apache v2.4.X. Created the file /etc/apache2/sites-available/git.solarchemist.se.conf
, with the following contents:
<VirtualHost *:80>
ServerAdmin email@solarchemist.se
ServerName git.solarchemist.se
ServerAlias gitea.solarchemist.se
Redirect permanent / https://git.solarchemist.se/
ErrorLog ${APACHE_LOG_DIR}/git.solarchemist.se_error.log
CustomLog ${APACHE_LOG_DIR}/git.solarchemist.se_access.log combined
</VirtualHost>
<VirtualHost *:443>
ServerAdmin email@solarchemist.se
ServerName git.solarchemist.se
ServerAlias gitea.solarchemist.se
SSLEngine on
SSLCertificateKeyFile /etc/letsencrypt/live/git.solarchemist.se/privkey.pem
SSLCertificateFile /etc/letsencrypt/live/git.solarchemist.se/cert.pem
SSLCertificateChainFile /etc/letsencrypt/live/git.solarchemist.se/chain.pem
ProxyPreserveHost On
ProxyRequests Off
ProxyPass / http://192.168.1.444:3000/
ProxyPassReverse / http://192.168.1.444:3000/
ErrorLog ${APACHE_LOG_DIR}/git.solarchemist.se_error.log
CustomLog ${APACHE_LOG_DIR}/git.solarchemist.se_access.log combined
</VirtualHost>
Before enabling this site, we need to have DNS records setup for the defined sub-domains.
Once the DNS records have propagated, we can use certbot
to fetch our Let’s Encrypt certificates.
# this one-liner stops the Apache server, fetches the certs, and restarts Apache
sudo certbot certonly --authenticator standalone --pre-hook "systemctl stop apache2.service" --post-hook "systemctl start apache2.service" --email email@solarchemist.se -d git.solarchemist.se
With that out of the way, it’s time to enable the Apache site configuration:
sudo a2ensite git.solarchemist.se.conf
When everything else is setup, you can let the Apache config take effect by issuing sudo systemctl reload apache2.service
.
Running Gitea as a systemd job
[Unit]
Description=Gitea (Git with a cup of tea)
After=syslog.target
After=network.target
After=mysqld.service
[Service]
RestartSec=2s
Type=simple
User=gitea
Group=gitea
WorkingDirectory=/var/lib/gitea/
ExecStart=/usr/local/bin/gitea web -c /etc/gitea/app.ini
Restart=always
Environment=USER=gitea HOME=/home/gitea GITEA_WORK_DIR=/var/lib/gitea
[Install]
WantedBy=multi-user.target
There is nothing special here, this systemd configuration is directly from the Gitea docs. I would just like to say a few words regarding the Gitea system user. As you can see, the systemd job specifies that Gitea is running as the user gitea
. This should correspond to the user in RUN_USER
in the /etc/gitea/app.ini
file (unless you are doing something very special, I guess).
Here I would like to point something out that I learned the hard way. The Gitea process should run in a dedicated user account, as defined in systemd or similar and /etc/gitea/app.ini
. Otherwise Git over SSH (i.e., pushing/pulling/cloning of your Gitea repos) will be a complete mess, or most likely, not work at all. This was perhaps not obvious from reading the docs, but is pointed out clearly enough in the Gitea forums.
Gitea also expects to handle the /home/gitea/.ssh/authorized_keys
file by itself, so don’t even bother trying to setup SSH keys for this user yourself. If you did, follow the instructions here to reset this file.
Sources
- Gitea Docs
- “How to setup Gitea on an Ubuntu Server” by Ryan Gilbert
- “Setting Up a Self-Hosted Github Clone with Gitea” by Charlesreid1
- “Set up Gitea with Nginx” by Rune Olsen
- “How To Start your own Git Server in less than 30 Minutes” by CHEF-KOCH
- “Setup Gitea on Raspberry Pi”
- “Installing Gitea on Debian”
- “Gitea fork thread on Reddit”
- “Keybase launches encrypted git”
- MySQL database setup for GitLab
- Gitea user forum: Using regular Git SSH not working
- Gitea user forum: Wrong SSH URL path
There is actually an alternative to self-hosting: encrypt the contents of your git repo and keep using a hosted service as usual. Hard to do properly on your own, though. But keybase has a neat implementation of that.↩︎