175 lines
7 KiB
Text
175 lines
7 KiB
Text
---
|
|
title: "hosting a git server"
|
|
date: "07/05/2025"
|
|
---
|
|
|
|
# why
|
|
|
|
No reason. Perhaps to host personal files in the future. AWS's micro free tier is great, too.
|
|
|
|
# what
|
|
|
|
- Write my own git web ui
|
|
- Support clones from my own website
|
|
- Host private files on my git ui
|
|
|
|
# the process
|
|
|
|
I detail self-hosting a git server on an AWS t2.micro instance ("free" for 1 year) as of May 2025. [Git's instructions](https://git-scm.com/book/en/v2/Git-on-the-Server-The-Protocols) were vastly outdated so hopefully this saves a lucky reader some time.
|
|
|
|
2. Create the ec2 instance with setup wizard and add \{in,out\}bound rules for \{SSH,HTTP,HTTPS,your ip\} in the wizard security group.
|
|
3. Use an elastic ip (free) to address public ip reassigning—this is a bother when ssh'ing (new verb?) into the box locally and/or configuring an Apache HTTP server.
|
|
4. Understand bare git repositories and the ssh protocol.
|
|
5. Configure an keypair and ssh in (the official instructions are fine for this). I moved it to `~/.ssh` and added an alias in `~/.ssh/config` for convenience. Clone a repo on the server to test.
|
|
6. Set up a git daemon for `git://` protocol cloning at your own risk.
|
|
7. Set up an Apache HTTPD server.
|
|
8. Configure file permissions for the new user:
|
|
1. `sudo chown -R git:git /srv/git`
|
|
2. `sudo chgrp -R apache /srv/git`
|
|
9. To deal with "dubious ownership" issues when cloning with HTTPS, I needed to add **exactly** the following configuration to `/etc/gitconfig`. _No group permission finagling will work_! Git only allows cloning repositories that are owned by the user. If you wish to clone via SSH with, say, user A, this same user must also be employed by your HTTP server to clone the files (customize HTTPD/whatever you're using accordingly).
|
|
|
|
```gitconfig
|
|
[safe]
|
|
directory = *
|
|
```
|
|
|
|
10. Security-wise, set up TLS/HTTPS with [Let's Encrypt](https://letsencrypt.org/). Further, only allow authorized people to actually _push_ to the server. The following is my HTTPD configuration file `/etc/apache/conf.d/git-server.conf` hosting the web ui at the root and clone urls at `/git`:
|
|
|
|
```apacheconf
|
|
<VirtualHost *:443>
|
|
ServerName <servername>
|
|
|
|
SSLEngine on
|
|
SSLCertificateFile /etc/letsencrypt/live/<servername>/fullchain.pem
|
|
SSLCertificateKeyFile /etc/letsencrypt/live/<servername>/privkey.pem
|
|
|
|
SetEnv GIT_PROJECT_ROOT /srv/git
|
|
SetEnv REMOTE_USER $REDIRECT_REMOTE_USER
|
|
|
|
ScriptAlias /git/ /usr/libexec/git-core/git-http-backend/
|
|
|
|
<Directory "/usr/libexec/git-core">
|
|
Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
|
|
Require all granted
|
|
AllowOverride None
|
|
</Directory>
|
|
|
|
<Files "git-http-backend">
|
|
AuthType Basic
|
|
AuthName "Git Access"
|
|
AuthUserFile /srv/git/.htpasswd
|
|
Require expr !(%{QUERY_STRING} -strmatch '*service=git-receive-pack*' || %{REQUEST_URI} =~ m#/git-receive-pack$#)
|
|
Require valid-user
|
|
</Files>
|
|
ProxyPassMatch ^/git/ !
|
|
ProxyPreserveHost On
|
|
ProxyPass / http://127.0.0.1:8000/
|
|
ProxyPassReverse / http://127.0.0.1:8000/
|
|
</VirtualHost>
|
|
```
|
|
|
|
11. There are a variety of choices for web ui, including [cgit](https://git.zx2c4.com/cgit/), [gitweb](https://git-scm.com/docs/gitweb) (I do not recommend this—the scripts are ancient and require manual tuning), and some even heavier options that allow for further customization. I am not a fan of viewing code on the web, so you cannot in [my custom ui](https://git.barrettruth.com). I spin up a simple python server to walk the projects in `/srv/git` and configured a systemd service to run it in the ec2 box:
|
|
|
|
```systemd
|
|
[Unit]
|
|
Description=Git Server UI
|
|
After=network.target
|
|
|
|
[Service]
|
|
User=apache
|
|
WorkingDirectory=/srv/git/git-server-ui
|
|
ExecStart=/usr/local/bin/gunicorn --workers 3 --bind 0.0.0.0:8000 --chdir /srv/git/git-server-ui wsgi:app
|
|
Restart=on-failure
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
```
|
|
|
|
12. I use the name `main` instead of `master` as my default branch (it's less letters, ok?)--set this up on the server too:
|
|
|
|
```console
|
|
$ sudo git config --system init.defaultBranch main
|
|
```
|
|
|
|
# lessons
|
|
|
|
- **It feels great to do things yourself**: I used GPT-4o for linux server command help, that was about it
|
|
- **Always ask "what is this?" before using something**: this would've saved me hours of realizing a 12 year old perl script should not have been running my git ui.
|
|
|
|
# upd: moving to lightsail <span class="date">09/11/2025</span>
|
|
|
|
Welp, ec2 costed way too much (~\$15/mo!). Enter [AWS Lightsail](https://aws.amazon.com/lightsail/): small compute with a flat $5/mo charge. This is a reasonably "scalable" solution for my website—unfortunately I do not have too much traffic as of now.
|
|
|
|
Anyways, the migration is complete. Everything is nearly identical but my HTTPD config has been minimally updated as follows:
|
|
|
|
- Now that I host project descriptions on `https://barrettruth.com/git/<project>.html` and gists on `https://barrettruth.com/gist/<code>`, support redirects for `{git,gist}.barrettruth.com->barrettruth.com/{git,gist}.html`
|
|
- Minify and simplify letsencrypt logic for the domain
|
|
|
|
Here's the updated config:
|
|
|
|
```apacheconf
|
|
<VirtualHost *:80>
|
|
ServerName git.barrettruth.com
|
|
Redirect permanent / https://git.barrettruth.com/
|
|
</VirtualHost>
|
|
|
|
<VirtualHost *:80>
|
|
ServerName gist.barrettruth.com
|
|
Redirect permanent / https://barrettruth.com/gist.html
|
|
</VirtualHost>
|
|
|
|
<VirtualHost *:443>
|
|
ServerName git.barrettruth.com
|
|
|
|
SSLEngine on
|
|
SSLCertificateFile /etc/letsencrypt/live/git.barrettruth.com/fullchain.pem
|
|
SSLCertificateKeyFile /etc/letsencrypt/live/git.barrettruth.com/privkey.pem
|
|
Include /etc/letsencrypt/options-ssl-apache.conf
|
|
|
|
DocumentRoot /srv/git
|
|
SetEnv GIT_PROJECT_ROOT /srv/git
|
|
SetEnv GIT_HTTP_EXPORT_ALL
|
|
ScriptAlias / /usr/libexec/git-core/git-http-backend/
|
|
|
|
<Directory "/usr/libexec/git-core">
|
|
Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
|
|
Require all granted
|
|
</Directory>
|
|
|
|
ErrorLog /var/log/httpd/git_error.log
|
|
CustomLog /var/log/httpd/git_access.log combined
|
|
</VirtualHost>
|
|
|
|
<VirtualHost *:443>
|
|
ServerName gist.barrettruth.com
|
|
|
|
SSLEngine on
|
|
SSLCertificateFile /etc/letsencrypt/live/git.barrettruth.com/fullchain.pem
|
|
SSLCertificateKeyFile /etc/letsencrypt/live/git.barrettruth.com/privkey.pem
|
|
Include /etc/letsencrypt/options-ssl-apache.conf
|
|
|
|
Redirect "/" "https://barrettruth.com/gist.html"
|
|
|
|
ErrorLog /var/log/httpd/unified.log
|
|
CustomLog /var/log/httpd/unified.log combined
|
|
</VirtualHost>
|
|
|
|
<VirtualHost *:443>
|
|
ServerName barrettruth.com
|
|
|
|
SSLEngine on
|
|
SSLCertificateFile /etc/letsencrypt/live/git.barrettruth.com/fullchain.pem
|
|
SSLCertificateKeyFile /etc/letsencrypt/live/git.barrettruth.com/privkey.pem
|
|
Include /etc/letsencrypt/options-ssl-apache.conf
|
|
|
|
DocumentRoot /var/www/html
|
|
<Directory /var/www/html>
|
|
Options -Indexes +FollowSymLinks
|
|
AllowOverride All
|
|
Require all granted
|
|
</Directory>
|
|
|
|
ErrorLog /var/log/httpd/unified.log
|
|
CustomLog /var/log/httpd/unified.log combined
|
|
</VirtualHost>
|
|
```
|