From bb8d6c2aaeb841139966e13fe62e8f85f264bb97 Mon Sep 17 00:00:00 2001 From: Charles Date: Sun, 26 Jul 2020 11:01:10 +0200 Subject: Cleaning git server article, Tweeking the style sheet --- .gitignore | 1 + blog/git_server.html | 197 ++++++++++++++++++++++++-------------------- blog_src/git_server.md | 219 +++++++++++++++++++++++++++++-------------------- index.html | 6 +- index.template.html | 4 +- style.css | 15 +++- 6 files changed, 261 insertions(+), 181 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..751553b --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.bak diff --git a/blog/git_server.html b/blog/git_server.html index 49a9566..010e6de 100644 --- a/blog/git_server.html +++ b/blog/git_server.html @@ -12,118 +12,139 @@

How to make your own git server/website

-

Server setup

-

We’re going to create a git user and group, will be used for accessing our git repositories without needing to be root.

-
useradd -m git
-mkdir /srv/git
-chown git:git /srv/git
-

The repositories will be stored as bare, this mean that we will only store the .git folder to save space.

+

Basic ssh server

+

Every repository on the server will be owned by a git user.

+
useradd -m git
+

Create a new directory to store the repositories owned by the git user.

+
mkdir /srv/git
+chown git:git /srv/git
+

Login as the git user so the new repositories will be owned by him.

+
su git
+cd /srv/git
+

Creating a repository

+

They will be stored as bare, meaning we will only store the .git folder not the actual files (called the workspace) to save space.
+It’s a convention to to suffix a bare repository with the .git extension.

+
mkdir repo.git
+cd repo.git
+git init --bare
+

Or clone a distant one:

+
git clone --bare <location>
-

To create a bare repo: git init --bare

+

Look at the content of a bare repository and the .git directory in a regular one to convince yourself that they’re the same.

-
-

To clone a repo as bare: git clone bare <location>

-
-

You can either add a password for the git user or put your ssh public key in /home/git/.ssh/authentication_keys and disable password authentication for ssh.

-

You can now clone from your server with git clone git@<hostname>:/srv/git/<reponame>

+

SSH Authentication

+

You could add a password for the git user but it’s ultimately safer to user a key pair.

+

If you don’t know what that is you generate it with ssh-keygen.
+Follow the steps and it will create id_rsa (private key) and id_rsa.pub (public key) in ~/.ssh.
+On your server you append your public key to /home/git/.ssh/authorized_keys

+

At this point you should be able to login as the git user via ssh

+
ssh git@<host>
+

You can clone from your server.

+
git clone git@<hostname>:/srv/git/<reponame>.git

Better server interaction with git-shell

-

Permit the git user to have a regular shell can be a security issue, we would like that to restrict him to a few action, like creating/deleting a repository, importing a repository, listing the repo currently stored

-

Make the git-shell a valid shell echo $(which git-shell) >> /etc/shells

-

Change the shell of the git user chsh -s $(which git-shell) git

+

Permitting the git user to have a regular shell can be too permissive, we would like to restrict him to a few repository actions, like creation/deletion, importing (clone), listing.

+
echo $(which git-shell) >> /etc/shells`  # Register the git-shell as a valid shell
+chsh -s $(which git-shell) git           # Change the shell of the git user

If you try to ssh as the git user, you will be greeted with something along the line of:

fatal: Interactive git shell is not enabled.
 hint: ~/git-shell-commands should exist and have read and execute access.
 Connection to <host> closed.
-

As suggested by the hint we have to create the directory /home/git/git-shell-commands and put the commands (executable) that the git user is allowed to execute in.

-

Here is a script to create a repo:

-
#!/bin/sh
-[ $# -ne 1 ] && echo "Usage: $0 name" && exit 1
-repo_path="/srv/git/$1.git"
-[ -d "$repo_path" ] && echo "$0: Error: $repo_path already exist" && exit 2
-mkdir "$repo_path"
-git -C "$repo_path" init --bare
-

Put it under git-shell-commands/create and make it executable then try to ssh as the git user once again.

-

You should have a prompt like git>, you can call the create command with a repo name as the first argument and it should create a new repository for you.

+

As suggested by the hint we have to create the directory /home/git/git-shell-commands and put the commands (executable) available to the git user.

+
#!/bin/sh
+[ $# -ne 1 ] &&
+    echo "Usage: $0 repository" && exit 1
+repo_path="/srv/git/$1.git"
+[ -d "$repo_path" ] &&
+    echo "$0: Error: $repo_path already exist" && exit 2
+mkdir "$repo_path"
+git -C "$repo_path" init --bare
+

This script create a new repository in /srv/git.
+Put it under git-shell-commands/create and make it executable then try to ssh as the git user once again.
+You will be prompted with git>, you can only execute the create <repository> and exit command.

+
+

You can probably create the delete, import and list scripts yourself.
+If you add a help script, it will be ran at the beginning of the connection. It can be used to add a greeting message.

+

Allow anyone to clone with git-daemon

-

The git daemon will allow annone to clone your repos with something like git clone git://<host>/<repo>

-

git daemon --reuseaddr --base-path=/srv/git/ /srv/git/ and that’s it

-

You should make it a service in your service supervisor, example with systemctl:

-
[Unit]
-Description=Start Git Daemon
-[Service]
-ExecStart=/usr/bin/git daemon --reuseaddr --base-path=/srv/git/ /srv/git/
-Restart=always
-RestartSec=500ms
-StandardOutput=syslog
-StandardError=syslog
-SyslogIdentifier=git-daemon
-User=git
-Group=git
-[Install]
-WantedBy=multi-user.target
-

Put it in /etc/systemctl/system/git-daemon.service and run systemctl enable git-daemon then systemctl start git-daemon.

-

Public/private repo

-

You may want to introduce a distiction of which repo is public and which is private

-

A simple way to do this is by creating a public directory in /srv/git which will contain symbolic link to the repo in /srv/git

-
/srv/git
-|- foo.git
-|- bar.git
-|- qux.git
-|- public
-    |- foo.git -> /srv/git/foo.git
-    |- bar.git -> /srv/git/bar.git
-

You can change the git daemon to only serve the public repositories git daemon --reuseaddr --base-path=/srv/git/public /srv/git/public

+

Cloning with ssh is fine but only the people with ssh access can do it, we would like anyone to clone.
+git-daemon does precisely that, after running it you will be able to run git clone git://<host>/<repository>

+
git daemon --reuseaddr --base-path=/srv/git/ /srv/git/
+

Follow the instruction of this tutorial if you want to know how to make it a service

+

Public/private repository

+

You may want to introduce a public/private distinction for your repositories.
+A simple way to do this is by creating a public directory in /srv/git which will contain symbolic link to the repository in /srv/git.

+
/srv/git/
+    |- foo.git/
+    |- bar.git/
+    |- qux.git/
+    |- public/
+        |- foo.git -> /srv/git/foo.git
+        |- bar.git -> /srv/git/bar.git
+
+

Change the git daemon to only serve the public repositories git daemon --reuseaddr --base-path=/srv/git/public /srv/git/public.

+
+
+

Add a publish and unpublish script in git-shell-commands/.

+

Generate a static website

-

Here we will create a site that look’s like this with nginx, stagit and a few scripts.

-

If you don’t like the minimalistic appearence of the site, here is a list of alternative.

-

Install nginx (on Debian based distro): apt install nginx

-

Create a basic configuration file for your site:

+

Here we will create a site that look’s like this with nginx, stagit and a few scripts.
+If you don’t like the minimalist appearance of the site, here is a list of alternatives.

+

nginx

server {
-    root /var/www/git;
-    index index.html index.htm;
-
+    root /var/www/git;  # where our website's files will be located
+    index index.html;
+    # It's a convention to put it in a git. subdomain.
     server_name git.<hostname> www.git.<hostname>;
-
     location / {
         try_files $uri $uri/ =404;
     }
 }
-

It’s a convention to put it in a git. subdomain. systemctl enable nginx && systemctl start nginx

-

Install stagit:

+

Put this configuration file in /etc/nginx/sites-available.
+Enable the site ln -s /etc/nginx/sites-available /etc/nginx/sites-enable

+

stagit

+

Stagit is pretty small tool so it won’t take long to install it from sources.

git clone git://git.codemadness.org/stagit
 cd stagit
 make
 make install
-

To generate a static page for a repo stagit /path/to/repo. To generate an index for multiple repositories stagit-index repo1 repo2 repo3 > index.html

-

Here is a script to generate a site for all repo in /srv/git/public

-
#!/bin/sh
-
-repos=$(find /srv/git/public/ -type l)
-current=$(pwd)
-
-for repo in $repos; do
-    repo_name=$(basename "$repo" | sed 's/\.git//')
-    repo_static_path="/var/www/git/$repo_name"
-    mkdir -p "$repo_static_path"
-    cd "$repo_static_path" || exit 1
-    echo "git://cacharle.xyz/$repo_name" > "$repo/url"
-    stagit "$repo"
-    ln -sf "$repo_static_path/log.html" "$repo_static_path/index.html"
-    echo "Generated $repo_static_path"
-done
-
-echo "Creating index"
-stagit-index $repos > /var/www/git/index.html
-
-cd "$current" || exit 1
-chown -R git:git /srv/git
-

There is more smart ways to handle this to rebuild the webpages each time someone pushes to the repo with git hooks.

+ +
+

Read the man page of both of these commands for more information

+
+

git hooks

+

Git hooks are scripts located in <repository>/.git/hooks that will be run on a certain action.
+The hook we’re interested in is post-receive, it will be ran after someone pushes to the repository.
+We can use it to regenerate the repository’s pages and the website’s index.

+
#!/bin/sh
+
+# Insert repo_name variable here
+# <REPO_NAME> -- replace with repo_name=name
+
+[ -z "$repo_name" ] && exit 1
+[ ! -d "/srv/git/public/$repo_name.git" ] && exit
+
+repo_web_path="/var/www/git/$repo_name"
+mkdir -p "$repo_web_path"
+cd "$repo_web_path" || exit 1
+stagit "/srv/git/$repo_name.git"
+stagit-index /srv/git/public/* > /var/www/git/index.html
+

This is a template for the post-receive hook. Every time you publish a repository you can change his post-receive hook.

+
post_receive_path="<repository>/hooks/post-receive"
+sed '/REPO_NAME/ c repo_name='"$repo" < post-receive.template > "$post_receive_path"
+chmod +x "$post_receive_path"
+"$post_receive_path"
+
+

Add this code to your publish script

+

Sources

diff --git a/blog_src/git_server.md b/blog_src/git_server.md index 4fc5505..67191c6 100644 --- a/blog_src/git_server.md +++ b/blog_src/git_server.md @@ -1,34 +1,77 @@ -# How to make your own git server/website +# How to make your own git server/website -## Server setup +## Basic ssh server -We're going to create a `git` user and group, will be used for accessing our git repositories without needing to be root. +Every repository on the server will be owned by a git user. ```sh useradd -m git +``` + +Create a new directory to store the repositories owned by the git user. + +```sh mkdir /srv/git chown git:git /srv/git ``` -The repositories will be stored as bare, this mean that we will only store the `.git` folder to save space. +Login as the git user so the new repositories will be owned by him. ->To create a bare repo: `git init --bare` +```sh +su git +cd /srv/git +``` ->To clone a repo as bare: `git clone bare ` +### Creating a repository -You can either add a password for the git user or put your ssh public key in `/home/git/.ssh/authentication_keys` and disable password authentication for ssh. +They will be stored as bare, meaning we will only store the `.git` +folder not the actual files (called the *workspace*) to save space. +It's a convention to to suffix a bare repository with the `.git` extension. -You can now clone from your server with `git clone git@:/srv/git/` +```sh +mkdir repo.git +cd repo.git +git init --bare +``` -## Better server interaction with git-shell +Or clone a distant one: + +```sh +git clone --bare +``` + +> Look at the content of a bare repository and the `.git` directory in a regular one +> to convince yourself that they're the same. + +### SSH Authentication -Permit the git user to have a regular shell can be a security issue, -we would like that to restrict him to a few action, -like creating/deleting a repository, importing a repository, listing the repo currently stored +You could add a password for the git user but it's ultimately safer to user a key pair. -Make the git-shell a valid shell `echo $(which git-shell) >> /etc/shells` +If you don't know what that is you generate it with `ssh-keygen`. +Follow the steps and it will create `id_rsa` (private key) and `id_rsa.pub` (public key) in `~/.ssh`. +On your server you append your **public** key to `/home/git/.ssh/authorized_keys` -Change the shell of the git user `chsh -s $(which git-shell) git` +At this point you should be able to login as the git user via ssh + +```sh +ssh git@ +``` + +You can clone from your server. + +```sh +git clone git@:/srv/git/.git +``` + +## Better server interaction with git-shell + +Permitting the git user to have a regular shell can be too permissive, +we would like to restrict him to a few repository actions, like creation/deletion, importing (clone), listing. + +``` sh +echo $(which git-shell) >> /etc/shells` # Register the git-shell as a valid shell +chsh -s $(which git-shell) git # Change the shell of the git user +``` If you try to ssh as the git user, you will be greeted with something along the line of: @@ -38,94 +81,88 @@ hint: ~/git-shell-commands should exist and have read and execute access. Connection to closed. ``` -As suggested by the hint we have to create the directory `/home/git/git-shell-commands` and put the commands (executable) that the git user is allowed to execute in. - -Here is a script to create a repo: +As suggested by the hint we have to create the directory `/home/git/git-shell-commands` +and put the commands (executable) available to the git user. ```sh #!/bin/sh -[ $# -ne 1 ] && echo "Usage: $0 name" && exit 1 +[ $# -ne 1 ] && + echo "Usage: $0 repository" && exit 1 repo_path="/srv/git/$1.git" -[ -d "$repo_path" ] && echo "$0: Error: $repo_path already exist" && exit 2 +[ -d "$repo_path" ] && + echo "$0: Error: $repo_path already exist" && exit 2 mkdir "$repo_path" git -C "$repo_path" init --bare ``` -Put it under `git-shell-commands/create` and make it executable then try to ssh as the git user once again. +This script create a new repository in `/srv/git`. +Put it under `git-shell-commands/create` and make it executable then try to ssh as the git user once again. +You will be prompted with `git> `, you can only execute the `create ` and `exit` command. -You should have a prompt like `git> `, you can call the `create` command with a repo name as the first argument and it should create a new repository for you. +> You can probably create the `delete`, `import` and `list` scripts yourself. +> If you add a `help` script, it will be ran at the beginning of the connection. +> It can be used to add a greeting message. ## Allow anyone to clone with git-daemon -The git daemon will allow annone to clone your repos with something like `git clone git:///` - -`git daemon --reuseaddr --base-path=/srv/git/ /srv/git/` and that's it +Cloning with ssh is fine but only the people with ssh access can do it, we would like anyone to clone. +git-daemon does precisely that, after running it you will be able to run `git clone git:///` -You should make it a service in your service supervisor, example with systemctl: - -``` -[Unit] -Description=Start Git Daemon -[Service] -ExecStart=/usr/bin/git daemon --reuseaddr --base-path=/srv/git/ /srv/git/ -Restart=always -RestartSec=500ms -StandardOutput=syslog -StandardError=syslog -SyslogIdentifier=git-daemon -User=git -Group=git -[Install] -WantedBy=multi-user.target +```sh +git daemon --reuseaddr --base-path=/srv/git/ /srv/git/ ``` -Put it in `/etc/systemctl/system/git-daemon.service` and run `systemctl enable git-daemon` then `systemctl start git-daemon`. +Follow the instruction of [this](https://git-scm.com/book/en/v2/Git-on-the-Server-Git-Daemon) tutorial if you want to know how to make it a service -### Public/private repo +### Public/private repository -You may want to introduce a distiction of which repo is public and which is private - -A simple way to do this is by creating a `public` directory in `/srv/git` which will contain symbolic link to the repo in `/srv/git` +You may want to introduce a public/private distinction for your repositories. +A simple way to do this is by creating a `public` directory in `/srv/git` +which will contain symbolic link to the repository in `/srv/git`. ``` -/srv/git -|- foo.git -|- bar.git -|- qux.git -|- public - |- foo.git -> /srv/git/foo.git - |- bar.git -> /srv/git/bar.git +/srv/git/ + |- foo.git/ + |- bar.git/ + |- qux.git/ + |- public/ + |- foo.git -> /srv/git/foo.git + |- bar.git -> /srv/git/bar.git ``` -You can change the git daemon to only serve the public repositories `git daemon --reuseaddr --base-path=/srv/git/public /srv/git/public` +> Change the git daemon to only serve the public repositories +> `git daemon --reuseaddr --base-path=/srv/git/public /srv/git/public`. -## Generate a static website +> Add a `publish` and `unpublish` script in `git-shell-commands/`. -Here we will create a site that look's like [this](https://git.suckless.org) with [nginx](https://nginx.org), [stagit](https://git.codemadness.org/stagit/) and a few scripts. - -If you don't like the minimalistic appearence of the site, [here](https://git.wiki.kernel.org/index.php/Interfaces,_frontends,_and_tools#Web_Interfaces) is a list of alternative. +## Generate a static website -Install nginx (on Debian based distro): `apt install nginx` +Here we will create a site that look's like [this](https://git.suckless.org) +with [nginx](https://nginx.org), [stagit](https://git.codemadness.org/stagit/) and a few scripts. +If you don't like the minimalist appearance of the site, +[here](https://git.wiki.kernel.org/index.php/Interfaces,_frontends,_and_tools#Web_Interfaces) +is a list of alternatives. -Create a basic configuration file for your site: +### nginx ``` server { - root /var/www/git; - index index.html index.htm; - + root /var/www/git; # where our website's files will be located + index index.html; + # It's a convention to put it in a git. subdomain. server_name git. www.git.; - location / { try_files $uri $uri/ =404; } } ``` -It's a convention to put it in a `git.` subdomain. -`systemctl enable nginx && systemctl start nginx` +Put this configuration file in `/etc/nginx/sites-available`. +Enable the site `ln -s /etc/nginx/sites-available /etc/nginx/sites-enable` + +### stagit -Install stagit: +Stagit is pretty small tool so it won't take long to install it from sources. ``` git clone git://git.codemadness.org/stagit @@ -134,41 +171,49 @@ make make install ``` -To generate a static page for a repo `stagit /path/to/repo`. -To generate an index for multiple repositories `stagit-index repo1 repo2 repo3 > index.html` +* `stagit /path/to/repository`. - generate a static pages for a repository in the current directory. +* `stagit-index repo1 repo2 repo3 > index.html` - generate an index for multiple repositories. -Here is a script to generate a site for all repo in `/srv/git/public` +> Read the man page of both of these commands for more information + +#### git hooks + +Git hooks are scripts located in `/.git/hooks` that will be run on a certain action. +The hook we're interested in is `post-receive`, it will be ran after someone pushes to the repository. +We can use it to regenerate the repository's pages and the website's index. ```sh #!/bin/sh -repos=$(find /srv/git/public/ -type l) -current=$(pwd) +# Insert repo_name variable here +# -- replace with repo_name=name -for repo in $repos; do - repo_name=$(basename "$repo" | sed 's/\.git//') - repo_static_path="/var/www/git/$repo_name" - mkdir -p "$repo_static_path" - cd "$repo_static_path" || exit 1 - echo "git://cacharle.xyz/$repo_name" > "$repo/url" - stagit "$repo" - ln -sf "$repo_static_path/log.html" "$repo_static_path/index.html" - echo "Generated $repo_static_path" -done +[ -z "$repo_name" ] && exit 1 +[ ! -d "/srv/git/public/$repo_name.git" ] && exit -echo "Creating index" -stagit-index $repos > /var/www/git/index.html +repo_web_path="/var/www/git/$repo_name" +mkdir -p "$repo_web_path" +cd "$repo_web_path" || exit 1 +stagit "/srv/git/$repo_name.git" +stagit-index /srv/git/public/* > /var/www/git/index.html +``` -cd "$current" || exit 1 -chown -R git:git /srv/git +This is a template for the `post-receive` hook. +Every time you publish a repository you can change his `post-receive` hook. + +```sh +post_receive_path="/hooks/post-receive" +sed '/REPO_NAME/ c repo_name='"$repo" < post-receive.template > "$post_receive_path" +chmod +x "$post_receive_path" +"$post_receive_path" ``` -There is more smart ways to handle this to rebuild the webpages each time someone pushes to the repo with [git hooks](https://git.codemadness.org/stagit/file/README.html#l92). +> Add this code to your `publish` script ## Sources * [Setting up \*Your Own\* Git Server](https://www.youtube.com/watch?v=ju9loeXNVW0) * [Git book - setting up the server](https://git-scm.com/book/en/v2/Git-on-the-Server-Setting-Up-the-Server) * [Git book - git daemon](https://git-scm.com/book/en/v2/Git-on-the-Server-Git-Daemon) -* [stagit - Static website generator for git repository](https://git.codemadness.org/stagit/) +* [stagit README](https://git.codemadness.org/stagit/file/README.html) * [git-shell man](https://git-scm.com/docs/git-shell.html) diff --git a/index.html b/index.html index dfdf5b6..f256f73 100644 --- a/index.html +++ b/index.html @@ -19,13 +19,13 @@

Blog articles

Links

  • github
  • -
  • my git server
  • +
  • git server
  • -

    The style sheet of this site can be found here

    +

    The style sheet used for this site can be found here

    diff --git a/index.template.html b/index.template.html index ff851c3..940bc6f 100644 --- a/index.template.html +++ b/index.template.html @@ -23,8 +23,8 @@

    Links

  • github
  • -
  • my git server
  • +
  • git server
  • -

    The style sheet of this site can be found here

    +

    The style sheet used for this site can be found here

    diff --git a/style.css b/style.css index 3649192..3405794 100644 --- a/style.css +++ b/style.css @@ -6,10 +6,23 @@ pre, code { font-family: Menlo, Monaco, "Courier New", monospace; } +code { + background-color: #333; + padding: .1rem; + border: 1px solid #FFFFFF2F; + border-radius: 3px; + font-size: 85%; +} + pre { padding: .5rem; line-height: 1.25; - overflow-x: scroll; + overflow-x: auto; +} + +pre > code { + border: none; + font-size: 100%; } @media print { -- cgit