aboutsummaryrefslogtreecommitdiff
path: root/content/blog/2022-07-01-git-server.md
diff options
context:
space:
mode:
Diffstat (limited to 'content/blog/2022-07-01-git-server.md')
-rw-r--r--content/blog/2022-07-01-git-server.md624
1 files changed, 0 insertions, 624 deletions
diff --git a/content/blog/2022-07-01-git-server.md b/content/blog/2022-07-01-git-server.md
deleted file mode 100644
index 5299fdb..0000000
--- a/content/blog/2022-07-01-git-server.md
+++ /dev/null
@@ -1,624 +0,0 @@
-+++
-date = 2022-07-01
-title = "Self-Hosting a Personal Git Server"
-description = ""
-draft = false
-+++
-
-# My Approach to Self-Hosting Git
-
-I have often tried to self-host my Git repositories, but have always fallen
-short when I tried to find a suitable web interface to show on the front-end.
-
-After a few years, I have finally found a combination of methods that allow me
-to easily self-host my projects, view them on the web, and access them from
-anywhere.
-
-Before I dive into the details, I want to state a high-level summary of my
-self-hosted Git approach:
-
-- This method uses the `ssh://` (read & write) and `git://` (read-only)
- protocols for push and pull access.
- - For the `git://` protocol, I create a `git-daemon-export-ok` file in any
- repository that I want to be cloneable by anyone.
- - The web interface I am using (`cgit`) allows simple HTTP cloning by
- default. I do not disable this setting as I want beginners to be able to
- clone one of my repositories even if they don't know the proper method.
-- I am not enabling Smart HTTPS for any repositories. Updates to repositories
- must be pushed via SSH.
-- Beyond the actual repository management, I am using `cgit` for the front-end
- web interface.
- - If you use the `scan-path=<path>` configuration in the `cgitrc`
- configuration file to automatically find repositories, you can't exclude
- a repository from `cgit` if it's stored within the path that `cgit`
- reads. To host private repositories, you'd need to set up another
- directory that `cgit` can't read.
-
-# Assumptions
-
-For the purposes of this walkthrough, I am assuming you have a URL
-(`git.example.com`) or IP address (`207.84.26.991`) addressed to the server that
-you will be using to host your git repositories.
-
-# Adding a Git User
-
-In order to use the SSH method associated with git, we will need to add a user
-named `git`. If you have used the SSH method for other git hosting sites, you
-are probably used to the following syntax:
-
-```sh
-git clone [user@]server:project.git
-```
-
-The syntax above is an `scp`-like syntax for using SSH on the `git` user on the
-server to access your repository.
-
-Let's delete any remnants of an old `git` user, if any, and create the new user
-account:
-
-```sh
-sudo deluser --remove-home git
-sudo adduser git
-```
-
-## Import Your SSH Keys to the Git User
-
-Once the `git` user is created, you will need to copy your public SSH key on
-your local development machine to the `git` user on the server.
-
-If you don't have an SSH key yet, create one with this command:
-
-```sh
-ssh-keygen
-```
-
-Once you create the key pair, the public should be saved to `~/.ssh/id_rsa.pub`.
-
-If your server still has password-based authentication available, you can copy
-it over to your user's home directory like this:
-
-```sh
-ssh-copy-id git@server
-```
-
-Otherwise, copy it over to any user that you can access.
-
-```sh
-scp ~/.ssh/id_rsa.pub your_user@your_server:
-```
-
-Once on the server, you will need to copy the contents into the `git` user's
-`authorized_keys` file:
-
-```sh
-cat id_rsa.pub > /home/git/.ssh/authorized_keys
-```
-
-## (Optional) Disable Password-Based SSH
-
-If you want to lock down your server and ensure that no one can authenticate in
-via SSH with a password, you will need to edit your SSH configuration.
-
-```sh
-sudo nano /etc/ssh/sshd_config
-```
-
-Within this file, find the following settings and set them to the values I am
-showing below:
-
-```conf
-PermitRootLogin no
-PasswordAuthentication no
-AuthenticationMethods publickey
-```
-
-You may have other Authentication Methods required in your personal set-up, so
-the key here is just to ensure that `AuthenticationMethods` does not allow
-passwords.
-
-### Setting up the Base Directory
-
-Now that we have set up a `git` user to handle all transport methods, we need to
-set up the directory that we will be using as our base of all repositories.
-
-In my case, I am using `/git` as my source folder. To create this folder and
-assign it to the user we created, execute the following commands:
-
-```sh
-sudo mkdir /git
-sudo chown -R git:git /git
-```
-
-### Creating a Test Repository
-
-On your server, switch over to the `git` user in order to start managing git
-files.
-
-```sh
-su git
-```
-
-Once logged-in as the `git` user, go to your base directory and create a test
-repository.
-
-```sh
-cd /git
-mkdir test.git && cd test.git
-git init --bare
-```
-
-If you want to make this repo viewable/cloneable to the public via the `git://`
-protocol, you need to create a `git-daemon-export-ok` file inside the
-repository.
-
-```sh
-touch git-daemon-export-ok
-```
-
-# Change the Login Shell for `git`
-
-To make sure that the `git` user is only used for git operations and nothing
-else, you need to change the user's login shell. To do this, simply use the
-`chsh` command:
-
-```sh
-sudo chsh git
-```
-
-The interactive prompt will ask which shell you want the `git` user to use. You
-must use the following value:
-
-```sh
-/usr/bin/git-shell
-```
-
-Once done, no one will be able to SSH to the `git` user or execute commands
-other than the standard git commands.
-
-# Opening the Firewall
-
-Don't forget to open up ports on the device firewall and network firewall if you
-want to access these repositories publicly. If you're using default ports,
-forward ports `22` (ssh) and `9418` (git) from your router to your server's IP
-address.
-
-If your server also has a firewall, ensure that the firewall allows the same
-ports that are forwarded from the router. For example, if you use `ufw`:
-
-```sh
-sudo ufw allow 22
-sudo ufw allow 9418
-```
-
-## Non-Standard SSH Ports
-
-If you use a non-standard port for SSH, such as `9876`, you will need to create
-an SSH configuration file on your local development machine in order to connect
-to your server's git repositories.
-
-To do this, you'll need to define your custom port on your client machine in
-your `~/.ssh/config` file:
-
-```sh
-nano ~/.ssh/config
-```
-
-```conf
-Host git.example.com
- # HostName can be a URL or an IP address
- HostName git.example.com
- Port 9876
- User git
-```
-
-## Testing SSH
-
-There are two main syntaxes you can use to manage git over SSH:
-
-- `git clone [user@]server:project.git`
-- `git clone ssh://[user@]server/project.git`
-
-I prefer the first, which is an `scp`-like syntax. To test it, try to clone the
-test repository you set up on the server:
-
-```sh
-git clone git@git.example.com:/git/test.git
-```
-
-# Enabling Read-Only Access
-
-If you want people to be able to clone any repository where you've placed a
-`git-daemon-export-ok` file, you will need to start the git daemon.
-
-To do this on a system with `systemd`, create a service file:
-
-```sh
-sudo nano /etc/systemd/system/git-daemon.service
-```
-
-Inside the `git-daemon.service` file, paste the following:
-
-```conf
-[Unit]
-Description=Start Git Daemon
-
-[Service]
-ExecStart=/usr/bin/git daemon --reuseaddr --base-path=/git/ /git/
-
-Restart=always
-RestartSec=500ms
-
-StandardOutput=syslog
-StandardError=syslog
-SyslogIdentifier=git-daemon
-
-User=git
-Group=git
-
-[Install]
-WantedBy=multi-user.target
-```
-
-Once created, enable and start the service:
-
-```sh
-sudo systemctl enable git-daemon.service
-sudo systemctl start git-daemon.service
-```
-
-To clone read-only via the `git://` protocol, you can use the following syntax:
-
-```sh
-git clone git://git.example.com/test.git
-```
-
-# Migrating Repositories
-
-At this point, we have a working git server that works with both SSH and
-read-only access.
-
-For each of the repositories I had hosted a different provider, I executed the
-following commands in order to place a copy on my server as my new source of
-truth:
-
-Server:
-
-```sh
-su git
-mkdir /git/<REPOSITORY_NAME>.git && cd /git/<REPOSITORY_NAME>.git
-git init --bare
-
-# If you want to make this repo viewable/cloneable to the public
-touch git-daemon-export-ok
-```
-
-Client:
-
-```sh
-git clone git@<PREVIOUS_HOST>:<REPOSITORY_NAME>
-git remote set-url origin git@git.EXAMPLE.COM:/git/<REPOSITORY_NAME>.git
-git push
-```
-
-# Optional Web View: `cgit`
-
-If you want a web viewer for your repositories, you can use various tools, such
-as `gitweb`, `cgit`, or `klaus`. I chose `cgit` due to its simple interface and
-fairly easy set-up (compared to others). Not to mention that the [Linux kernel
-uses `cgit`](https://git.kernel.org/).
-
-## Docker Compose
-
-Instead of using my previous method of using a `docker run` command, I've
-updated this section to use `docker-compose` instead for an easier installation
-and simpler management and configuration.
-
-In order to use Docker Compose, you will set up a `docker-compose.yml` file to
-automatically connect resources like the repositories, `cgitrc`, and various
-files or folders to the `cgit` container you're creating:
-
-```sh
-mkdir ~/cgit && cd ~/cgit
-nano docker-compose.yml
-```
-
-```conf
-# docker-compose.yml
-version: '3'
-
-services:
- cgit:
- image: invokr/cgit
- volumes:
- - /git:/git
- - ./cgitrc:/etc/cgitrc
- - ./logo.png:/var/www/htdocs/cgit/logo.png
- - ./favicon.png:/var/www/htdocs/cgit/favicon.png
- - ./filters:/var/www/htdocs/cgit/filters
- ports:
- - "8763:80"
- restart: always
-```
-
-Then, just start the container:
-
-```sh
-sudo docker-compose up -d
-```
-
-Once it's finished installing, you can access the site at `<SERVER_IP>:8763` or
-use a reverse-proxy service to forward `cgit` to a URL, such as
-`git.example.com`. See the next section for more details on reverse proxying a
-URL to a local port.
-
-## Nginx Reverse Proxy
-
-I am using Nginx as my reverse proxy so that the `cgit` Docker container can use
-`git.example.com` as its URL. To do so, I simply created the following
-configuration file:
-
-```sh
-sudo nano /etc/nginx/sites-available/git.example.com
-```
-
-```conf
-server {
- listen 80;
- server_name git.example.com;
-
- if ($host = git.example.com) {
- return 301 https://$host$request_uri;
- }
-
- return 404;
-}
-
-server {
- server_name git.example.com;
- listen 443 ssl http2;
-
- location / {
- # The final `/` is important.
- proxy_pass http://localhost:8763/;
- add_header X-Frame-Options SAMEORIGIN;
- add_header X-XSS-Protection "1; mode=block";
- proxy_redirect off;
- proxy_buffering off;
- proxy_set_header Host $host;
- proxy_set_header X-Real-IP $remote_addr;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- proxy_set_header X-Forwarded-Proto $scheme;
- proxy_set_header X-Forwarded-Port $server_port;
- }
-
- # INCLUDE ANY SSL CERTS HERE
- include /etc/letsencrypt/options-ssl-nginx.conf;
- ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
-}
-```
-
-Once created, symlink it and restart the web server.
-
-```sh
-sudo ln -s /etc/nginx/sites-available/git.example.com /etc/nginx/sites-enabled/
-sudo systemctl restart nginx.service
-```
-
-As we can see below, my site at `git.example.com` is available and running:
-
-## Settings Up Git Details
-
-Once you have `cgit` running, you can add some small details, such as repository
-owners and descriptions by editing the following files within each repository.
-
-Alternatively, you can use the `cgitrc` file to edit these details if you only
-care to edit them for the purpose of seeing them on your website.
-
-The `description` file within the repository on your server will display the
-description online.
-
-```sh
-cd /git/example.git
-nano description
-```
-
-You can add a `[gitweb]` block to the `config` file in order to display the
-owner of the repository.
-
-```sh
-cd /git/example.git
-nano config
-```
-
-```conf
-[gitweb]
- owner = "YourName"
-```
-
-Note that you can ignore the configuration within each repository and simply set
-up this information in the `cgitrc` file, if you want to do it that way.
-
-## Editing `cgit`
-
-In order to edit certain items within `cgit`, you need to edit the `cgitrc`
-file.
-
-```sh
-nano ~/cgit/cgitrc
-```
-
-Below is an example configuration for `cgitrc`. You can find all the
-configuration options within the [configuration manual]
-(<https://git.zx2c4.com/cgit/plain/cgitrc.5.txt>).
-
-```conf
-css=/cgit.css
-logo=/logo.png
-favicon=/favicon.png
-robots=noindex, nofollow
-
-enable-index-links=1
-enable-commit-graph=1
-enable-blame=1
-enable-log-filecount=1
-enable-log-linecount=1
-enable-git-config=1
-
-clone-url=git://git.example.com/$CGIT_REPO_URL ssh://git@git.example.com:/git/$CGIT_REPO_URL
-
-root-title=My Git Website
-root-desc=My personal git repositories.
-
-# Allow download of tar.gz, tar.bz2 and zip-files
-snapshots=tar.gz tar.bz2 zip
-
-##
-## List of common mimetypes
-##
-mimetype.gif=image/gif
-mimetype.html=text/html
-mimetype.jpg=image/jpeg
-mimetype.jpeg=image/jpeg
-mimetype.pdf=application/pdf
-mimetype.png=image/png
-mimetype.svg=image/svg+xml
-
-# Highlight source code
-# source-filter=/var/www/htdocs/cgit/filters/syntax-highlighting.sh
-source-filter=/var/www/htdocs/cgit/filters/syntax-highlighting.py
-
-# Format markdown, restructuredtext, manpages, text files, and html files
-# through the right converters
-about-filter=/var/www/htdocs/cgit/filters/about-formatting.sh
-
-##
-## Search for these files in the root of the default branch of repositories
-## for coming up with the about page:
-##
-readme=:README.md
-readme=:readme.md
-readme=:README.mkd
-readme=:readme.mkd
-readme=:README.rst
-readme=:readme.rst
-readme=:README.html
-readme=:readme.html
-readme=:README.htm
-readme=:readme.htm
-readme=:README.txt
-readme=:readme.txt
-readme=:README
-readme=:readme
-
-# Repositories
-
-# Uncomment the following line to scan a path instead of adding repositories manually
-# scan-path=/git
-
-## Test Section
-section=git/test-section
-
-repo.url=test.git
-repo.path=/git/test.git
-repo.readme=:README.md
-repo.owner=John Doe
-repo.desc=An example repository!
-```
-
-## Final Fixes: Syntax Highlighting & README Rendering
-
-After completing my initial install and playing around with it for a few days, I
-noticed two issues:
-
-1. Syntax highlighting did not work when viewing the source code within a file.
-2. The `about` tab within a repository was not rendered to HTML.
-
-The following process fixes these issues. To start, let's go to the `cgit`
-directory where we were editing our configuration file earlier.
-
-```sh
-cd ~/cgit
-```
-
-In here, create two folders that will hold our syntax files:
-
-```sh
-mkdir filters && mkdir filters/html-converters && cd filters
-```
-
-Next, download the default filters:
-
-```sh
-curl https://git.zx2c4.com/cgit/plain/filters/about-formatting.sh > about-formatting.sh
-chmod 755 about-formatting.sh
-curl https://git.zx2c4.com/cgit/plain/filters/syntax-highlighting.py > syntax-highlighting.py
-chmod 755 syntax-highlighting.py
-```
-
-Finally, download the HTML conversion files you need. The example below
-downloads the Markdown converter:
-
-```sh
-cd html-converters
-curl https://git.zx2c4.com/cgit/plain/filters/html-converters/md2html > md2html
-chmod 755 md2html
-```
-
-If you need other filters or html-converters found within [the cgit project
-files](https://git.zx2c4.com/cgit/tree/filters), repeat the `curl` and `chmod`
-process above for whichever files you need.
-
-However, formatting will not work quite yet since the Docker cgit container
-we're using doesn't have the formatting package installed. You can install this
-easily by install Python 3+ and the `pygments` package:
-
-```sh
-# Enter the container's command line
-sudo docker exec -it cgit bash
-```
-
-```sh
-# Install the necessary packages and then exit
-yum update -y && \
-yum upgrade -y && \
-yum install python3 python3-pip -y && \
-pip3 install markdown pygments && \
-exit
-```
-
-**You will need to enter the cgit docker container and re-run these `yum`
-commands every time you kill and restart the container!**
-
-If not done already, we need to add the following variables to our `cgitrc` file
-in order for `cgit` to know where our filtering files are:
-
-```conf
-# Highlight source code with python pygments-based highlighter
-source-filter=/var/www/htdocs/cgit/filters/syntax-highlighting.py
-
-# Format markdown, restructuredtext, manpages, text files, and html files
-# through the right converters
-about-filter=/var/www/htdocs/cgit/filters/about-formatting.sh
-```
-
-Now you should see that syntax highlighting and README rendering to the `about`
-tab is fixed.
-
-## Theming
-
-I won't go into much detail in this section, but you can fully theme your
-installation of `cgit` since you have access to the `cgit.css` file in your web
-root. This is another file you can add as a volume to the `docker-compose.yml`
-file if you want to edit this without entering the container's command line.
-
-### :warning: Remember to Back Up Your Data!
-
-The last thing to note is that running services on your own equipment means that
-you're assuming a level of risk that exists regarding data loss, catastrophes,
-etc. In order to reduce the impact of any such occurrence, I suggest backing up
-your data regularly.
-
-Backups can be automated via `cron`, by hooking your base directory up to a
-cloud provider, or even setting up hooks to push all repository info to git
-mirrors on other git hosts. Whatever the method, make sure that your data
-doesn't vanish in the event that your drives or servers fail.