modified content here and there
authordanix <danix@danix.xyz>
Mon, 23 Jan 2023 18:28:25 +0000 (19:28 +0100)
committerdanix <danix@danix.xyz>
Mon, 23 Jan 2023 18:28:25 +0000 (19:28 +0100)
articles/_index.md [new file with mode: 0644]
articles/git-setup-own-server.md [new file with mode: 0644]
articles/hello-world.md

diff --git a/articles/_index.md b/articles/_index.md
new file mode 100644 (file)
index 0000000..fea8046
--- /dev/null
@@ -0,0 +1,13 @@
+---
+title: "Blog"
+date: 2021-06-16T15:37:53+02:00
+type: page
+draft: false
+menu: "main"
+excerpt: ""
+featured_image: ""
+tags: []
+categories: []
+---
+
+This is my Blog, there are many like it but this is mine!
diff --git a/articles/git-setup-own-server.md b/articles/git-setup-own-server.md
new file mode 100644 (file)
index 0000000..4109cbc
--- /dev/null
@@ -0,0 +1,434 @@
+---
+title: "Git Setup Your Own Server"
+date: 2021-06-13T12:07:49+02:00
+type: post
+draft: false
+excerpt: "I'll show you how to setup your own git server easily"
+featured_image: "img/gitout.jpg"
+tags: ["git", "server", "setup", "howto", "do it yourself", "ssh"]
+categories: ["code", "diy", "linux"]
+author_name: "danix"
+---
+
+Hello everyone,
+
+I recently decided to move all my code under GIT, I've used it before and I've used also SVN, but I find GIT to be more straightforward in some aspects.
+
+In order to use git I needed a place online where to store my projects, and I thought that github could be a good place, but the fact that you have to pay to keep a project private just didn't sound right in my opinion. Of course github is there to make money (specially now that M$ bought it), but I prefer to have a simpler setup and be able to do things my way as much as possible.
+
+So I started planning what I wanted my git server to have. Here's a list:
+
+  * **Security** - I decided to make it work only under ssh, that way only someone who has the key can clone or access the repository. I also added an unprivileged git user that has only access to very few commands, so even if somebody manages to access through ssh he'll find himrself with only very few options available.
+  * **Notifications** - my server already tells me a lot of what happens, so I wanted my git service to do the same. I implemented a mail service that notifies me every time a new repository is added or everytime there's a push to a repository.
+  * **Automation** - I wanted to have less steps possible between creation of the project and deployment to production. Now in two steps I can create a repository and clone it to my local computer, and when I'm done I just need to push my modifications and the code is deployed automatically.
+  * **Visibility** - I haven't yet decided if I want my code to be visible, so I haven't even started thinking about this possibility.
+
+<!--more-->
+
+## Installation
+
+Installing a git server is quite simple once you know how it works, on my server it was a matter of having a bare repository setup but in order to have the level of security that I wanted there were a few steps involved.
+
+> A bit of a disclaimer here, I use a Slackware64-14.2 on my server and Slackware64-current on my laptop, so all the commands here worked for me but I can't be sure if the procedures that I followed will work on different distros with different setups. If you have any trouble following what I've done let me know in the comments and I'll try to help you.
+
+I've added a new user and group to my server but before doing so I added /usr/bin/git-shell to /etc/shells in order to use it as login shell for my git user.
+
+```
+echo "/usr/bin/git-shell" >> /etc/shells
+groupadd git
+mkdir /var/git
+useradd -d /var/git -g git -M -s /usr/bin/git-shell
+```
+
+now the user is all set and ready to be used. Next step will be to create the .ssh directory and the authorized_keys file to hold the keys for the developers that have to access the git server. Here's how I did it:
+
+```
+mkdir /var/git/.ssh
+touch /var/git/.ssh/authorized_keys
+chown -R git:git /var/git
+chmod 0700 /var/git/.ssh
+chmod 0600 /var/git/.ssh/authorized_keys
+```
+
+ok, now the files are in place and the permissions are correct for ssh to work well.
+
+Let's head back to my working computer, I created an ssh keypair for my usual user and copied the public key to the authorized_keys file on the server. I won't go into much detail on how to do so, but just a suggestion, keep it without password, it'll be much faster to work later.
+
+Since I have ssh access to the same server for my normal user I used the ~/.ssh/config file on my computer to set a new host that will ease my access routine for the git user as well as my regular user, that's my config (more or less):
+
+```
+cat ~/.ssh/config
+Host regular_ssh
+        HostName server.tld
+        User myuser
+        IdentityFile ~/.ssh/id_rsa
+
+Host git_ssh
+        HostName server.tld
+        User git
+        IdentityFile ~/.ssh/git_rsa
+```
+
+Now when I need to access the server with my regular user I'll just run
+
+`ssh regular_ssh`
+
+and when I need to access as git user I'll run
+
+`ssh git_ssh`
+
+and ssh will take care of all the options and start the connection with the correct credentials for me. Neat!
+
+Now that the access for the git user is setup we have one last thing to do before being able to use it. We'll give him only limited commands to use, That way the git user will be even more limited and much more secure. Inside the documentation shipped with git there's a lot of scripts to get you started with this, so we'll copy them inside a special directory called git-shell-commands, like this:
+
+```
+cp -R /usr/doc/git-2.14.4/contrib/git-shell-commands /var/git
+chown -R git:git /var/git
+
+```
+
+Now we have 2 commands inside the git-shell-commands directory, list and help, the first will show all projects inside the /var/git directory and the other will show a simple help text and a list of all the commands available. Now to give you an example of how easy it is to add commands to the git-shell I will create a simple command that acts as the clear command, it will clean the screen, to do so, from inside the /var/git directory I did:
+
+```
+echo $(which clear) > git-shell-commands/clear
+chmod 0755 git-shell-commands/clear
+
+```
+
+and now I have a "clear" command available for my git user. Another useful command will be "create" to add a repository and a "destroy" to remove it. Let's see them in the next page.
+
+<!--nextpage-->
+
+Let's focus on the two most important scripts for our git server, the **create** and the **delete** script:
+
+### create
+
+<pre class="wp-block-code language-bash"><code>#! /bin/bash
+
+# usage:        create <PROJECT> - create a git bare repository named PROJECT.git
+#               this command will setup the repo and send a mail for confirmation.
+
+GITDIR="/var/git"
+MULTIMAIL="/usr/doc/git-2.14.4/contrib/hooks/multimail/git_multimail.py"
+GITUSER="git"
+GITGRP="git"
+
+function is_bare() {
+        repodir=$1
+        if "$(git --git-dir="$repodir" rev-parse --is-bare-repository)" = true
+        then
+                true
+        else
+                false
+        fi
+}
+
+function git_init() {
+        PROJECT=$1
+        echo "creating project \"${PROJECT}.git\""
+        if [ ! -d ${GITDIR}/${PROJECT}.git ]; then
+                mkdir ${GITDIR}/${PROJECT}.git
+        fi
+        cd ${GITDIR}/${PROJECT}.git
+        git init --bare
+        mkdir custom-hooks
+        ln -s $MULTIMAIL custom-hooks/
+        touch hooks/post-receive
+        cat > hooks/post-receive <<EOPR
+#!/bin/sh
+/usr/bin/pee ${GITDIR}/${PROJECT}.git/custom-hooks/deploy.sh \
+        ${GITDIR}/${PROJECT}.git/custom-hooks/git_multimail.py
+
+EOPR
+       cat >> config <<EOT
+
+[multimailhook]
+        mailer = "sendmail"
+        refchangeShowGraph = true
+        mailingList = "receiver@someemail.tld"
+        commitEmailFormat = "html"
+        htmlInIntro = true
+        htmlInFooter = true
+        from = "sender@someemail.tld"
+        administrator = "admin@someemail.tld"
+        quiet = true
+        logFile = "/var/log/multimail.log"
+        errorLogFile = "/var/log/multimail_err.log"
+EOT
+        touch custom-hooks/deploy.sh
+        cat > custom-hooks/deploy.sh <<EODP
+#!/bin/bash
+# Directory where to deploy files from repository
+DPTARGET=""
+# Directory containing repository
+DPGIT_DIR="${GITDIR}/${PROJECT}.git"
+# Branch that is going to be deployed to server
+DPBRANCH="master"
+
+while read oldrev newrev ref
+do
+        # if DPTARGET is empty we don't want deploy for this project
+        if [[ ! "" == \$DPTARGET ]]; then
+                # let's check that we are deploying to the correct branch
+                if [[ \$ref = refs/heads/\${DPBRANCH} ]]; then
+                        echo "Ref \$ref received. Deploying \${DPBRANCH} branch to production..."
+                        git --work-tree=\$DPTARGET --git-dir=\$DPGIT_DIR checkout -f $DPBRANCH
+                        NOW=\$(date +"%d%m%Y-%H%M")
+                        git tag release_\$NOW \$DPBRANCH
+                        echo "   /==============================="
+                        echo "   | DEPLOYMENT COMPLETED"
+                        echo "   | Target branch: \$DPTARGET"
+                        echo "   | Target folder: \$DPGIT_DIR"
+                        echo "   | Tag name     : release_\$NOW"
+                        echo "   \=============================="
+                else
+                        echo "Ref \$ref received. Doing nothing: only the \${DPBRANCH} branch may be deployed on this server."
+                fi
+        else
+                echo "Target directory not declared. Skipping deploy to server."
+        fi
+done
+
+EODP
+        chmod 0755 hooks/post-receive custom-hooks/deploy.sh
+        cd ${GITDIR}/
+        chown -R ${GITUSER}:${GITGRP} ${GITDIR}/${PROJECT}.git
+        echo "All done, you can now work on \"${PROJECT}.git\""
+        exit 0
+}
+
+if [ ! -z $1 ]; then
+        PROJECT=$1
+else
+        read -p 'Project name: ' PROJECT
+fi
+
+if [ ! -d ${GITDIR}/${PROJECT}.git ]; then
+        git_init $PROJECT
+else
+        echo "Project directory ${PROJECT}.git already exists."
+        if [ $(ls -A ${GITDIR}/${PROJECT}.git) ]; then
+                if is_bare ${GITDIR}/${PROJECT}.git
+                then
+                        echo "looks like \"${PROJECT}.git\" is an existing git project directory, choose another name."
+                        exit 171
+                else
+                        echo "\"${PROJECT}.git\" is not empty, I can't create a Git Project in it. Choose another name."
+                        exit 172
+                fi
+        else
+                echo "\"${PROJECT}.git\" is an empty directory. Do you want to initialize a Git Project here? [y/N]"
+                read answer
+                case $answer in
+                        Y|y)
+                                git_init $PROJECT       
+                                ;;
+                        N|n)
+                                echo "Aborting due to user request."
+                                exit 173
+                                ;;
+                        *)
+                                # we assume no as default answer.
+                                echo "you said \"$answer\" which I don't understand, so to me is no. Aborting."
+                                exit 177
+                                ;;
+                esac
+        fi
+fi</code></pre>
+
+This is the create script, as you can see it's a bit complex because it will do a few things for me:
+
+  * create the bare repository using the argument provided on the command line or asking for a project name
+  * check before creating the repo, if another repo with the same name exists or if a directory with files in it exists. That way I'll make sure to only create a repo inside an empty directory.
+  * add a custom-hooks directory that will hold a link to the multimail.py script as well as my deploy.sh script
+  * create a post-receive script that uses **pee** from the [moreutils][1] project to run multiple scripts at the same hook.
+  * ensure sane permissions on the whole project directory.
+  * always assume no (the safest option) when asking the user about the action to take.
+
+So after saving this script as create inside the git-shell-commands directory, we'll give it executable permissions and we can move to the delete script.
+
+<pre class="wp-block-code language-bash"><code># cat create-bare-repo.sh &gt; /var/git/git-shell-commands/create
+# chown git:git -R /var/git/git-shell-commands
+# chmod 0755 /var/git/git-shell-commands/create</code></pre>
+
+### delete
+
+Let's see the delete script:
+
+<pre class="wp-block-code language-bash"><code>#! /bin/bash
+
+# usage:        delete <REPOSITORY> - PERMANENTLY delete a repository if existing.
+#               CAREFUL, this action cannot be undone. This command will ask for confirmation.
+
+GITDIR="/var/git"
+
+function is_bare() {
+        repodir=$1
+        if "$(git --git-dir="$repodir" rev-parse --is-bare-repository)" = true
+        then
+                true
+        else
+                false
+        fi
+}
+
+if [ ! -z $1 ]; then
+        PROJECT=$1
+else
+        read -p 'Project to delete: ' PROJECT
+fi
+
+if [ -d ${GITDIR}/${PROJECT}.git ]; then
+        if [[ $(ls -A ${GITDIR}/${PROJECT}.git) ]]; then
+                if is_bare ${GITDIR}/${PROJECT}.git
+                then
+                        echo "You are going to delete the git repository \"${PROJECT}.git\" Do you really want to continue? Note, this action cannot be reverted. [y/N]"
+                        read delAnswer
+                        case $delAnswer in
+                                Y|y)
+                                        rm -rf ${PROJECT}.git
+                                        ;;
+                                N|n)
+                                        echo "Aborting due to user request."
+                                        exit 173
+                                        ;;
+                                *)
+                                        echo "you said \"$delAnswer\" which I don't understand. Assuming No. Aborting."
+                                        exit 177
+                                        ;;
+                        esac
+                else
+                        echo "\"${PROJECT}.git\" doesn't look like a git repository. Check with your System Administrator."
+                        exit 177
+                fi
+        else
+                echo "\"${PROJECT}.git\" is an empty directory, Skipping. Check with your System Administrator."
+                exit 177
+        fi
+fi</code></pre>
+
+This script is much simpler than the previous one, it'll accept the name of the project as argument on the command line or will ask for it and will only delete it if it is a proper git repository, otherwise it will just exit with an error code.
+
+I improved the way those scripts recognise a git repository from simply relying on the fact that there's a HEAD file inside the directory they're checking, which wasn't the best option, to using git itself to check if the directory is a bare repository. Much better!!
+
+Since we are here let's modify the help command to make it show a short description of every available command.
+
+<pre class="wp-block-code language-bash"><code>#!/bin/sh
+
+# usage:        help - Lists all the available commands
+#               help <command> - Detailled explanation of how "command" works
+
+if tty -s
+then
+        HELPTEXT="Hi $USER, Run 'help' for help, 'help <command>' for specific help on a command, run 'exit' to exit. Available commands:"
+else
+        HELPTEXT="Hi $USER, Run 'help' for help, 'help <command>' for specific help on a command. Available commands:"
+fi
+
+cd "$(dirname "$0")"
+
+if [[ ! -z $1 ]]; then
+        cmd=$1
+        if [[ -f $cmd && -x $cmd ]]; then
+                awk 'NR>=3&&NR<=4' $cmd | cut -c 3-
+        else
+                echo "command \"$cmd\" doesn't exists"
+        fi
+else
+        echo $HELPTEXT
+        for cmd in *
+        do
+                case "$cmd" in
+                help) ;;
+                *) [ -f "$cmd" ] && [ -x "$cmd" ] && echo "$cmd" ;;
+                esac
+        done
+fi</code></pre>
+
+The main thing I added is the support for a command line argument, now I'm able to run it by itself and display the usual output with a list of available commands, or followed by a command name to give a brief explanation like this:
+
+<pre class="wp-block-code language-bash"><code>git> help
+Hi git, Run 'help' for help, 'help <command>' for specific help on a command, run 'exit' to exit. Available commands:
+clear
+create
+delete
+list
+git> help create
+usage:  create  - create a git bare repository named PROJECT.git
+        this command will setup the repo and send a mail for confirmation.
+git>
+</code></pre>
+
+Pretty nice isn't it?! Now it's much more user friendly, and to show the description I used awk and cut to parse the comment at the top of every script I have in the `git-shell-commands` directory.
+
+In the next page we'll see the usual routine I follow when working with this new setup.
+
+<!--nextpage-->
+
+## My GIT Routine
+
+Let's say I had a new idea for a WordPress plugin, I can't wait to start writing, so the setup of the GIT environment should be as fast as possible. That's where my setup will come in handy. Let's open the terminal, I'll go inside my testing directory and from there I'll run:
+
+<pre class="wp-block-code language-bash"><code>ssh git_ssh 'create awesomePlugin'
+creating project "awesomePlugin.git"
+Initialized empty Git repository in /var/git/awesomePlugin.git/
+All done, you can now work on "awesomePlugin.git"
+</code></pre>
+
+The project is created, now I just need to clone it
+
+<pre class="wp-block-code language-bash"><code>git clone ssh://git_ssh:/var/git/awesomePLugin.git
+Cloning into 'awesomePlugin'...
+warning: Looks like you cloned an empty repository.
+</code></pre>
+
+And that's it, I now have a local and a remote copy of my git repository ready to work with.
+
+Let's say I'm working on this plugin and I get to the point where I feel like I can use it on my own blog, I want the deploy to be as fast as the rest of the process was, so I'll ssh as my normal user and modify the `deploy.sh` script inside the `custom-hooks` directory for this project to add the working directory and the branch I want to use for deploy (you can use master, but it's better to use a different branch only for this pourpose, this way you can keep the production code stable and use master for experimenting until ready to deploy)
+
+Inside the deploy.sh script I'll edit those 2 lines:
+
+<pre class="wp-block-code language-bash"><code># Directory where to deploy files from repository
+DPTARGET=""
+# Branch that is going to be deployed to server
+DPBRANCH="master"
+</code></pre>
+
+adding `/var/www/wp-content/plugins/awesomePlugin` as `DPTARGET` and production as `DPBRANCH`.
+
+now on my local system I'll add a new branch and use that before committing my stable code.
+
+<pre class="wp-block-code language-bash"><code>git checkout -b production
+Switched to a new branch 'production'
+
+git add .
+
+git commit -m "awesomePlugin is even more awesome"
+[production (root-commit) a3885a4] awesomePlugin is even more awesome
+ 1 file changed, 1 insertion(+)
+ create mode 100644 awesomePlugin.php
+
+git push origin production
+Counting objects: 3, done.
+Writing objects: 100% (3/3), 240 bytes | 240.00 KiB/s, done.
+Total 3 (delta 0), reused 0 (delta 0)
+remote: Ref refs/heads/production received. Deploying production branch to production...
+remote:    /===============================
+remote:    | DEPLOYMENT COMPLETED
+remote:    | Target branch: /var/www/htdocs/wp-content/plugins/awesomePlugin
+remote:    | Target folder: /var/git/awesomePlugin.git
+remote:    | Tag name     : release_12072018-1110
+remote:    \==============================
+To ssh://git_ssh:/var/git/awesomePlugin.git
+ * [new branch]      production -> production
+</code></pre>
+
+And that's it, now my new plugin is ready to go live as soon as I activate it inside my WordPress admin area.
+
+## Conclusion
+
+That's it for now, I'll add to this post as soon as I decide whether I want my code to be visible or not, but for now this is my setup and it's working greatly for me so far.
+
+If you made it this far I hope you'll spend a couple more minutes to let me know what you think about this setup, if you use something similar or if you had any problems setting this up, I'll try and help you as much as I can of course.
+
+ [1]: https://joeyh.name/code/moreutils/
index 97de30a..7a0e809 100644 (file)
@@ -1,6 +1,11 @@
 ---
 title: "Hello World"
 date: 2023-01-23T18:14:02+01:00
+type: post
+excerpt: "My first article"
+tags: ["hello world"]
+categories: ["ramblings",]
+author_name: "danix"
 draft: false
 ---