This is more a short story of getting nerdy with a NAS.  I wanted to figure out if I could really host a GIT repo locally on my NAS for private work or long term storage.  While I’ll be covering the usage in an upcoming WhizLabs course, I thought others might want to see how to accomplish the same.

Setting up GIT on Synology

First, let's talk hardware.  I'm using just a basic 4yo Synology DS216play NAS for this.  My router is an Asus AC1900 (RT-AC68U) and i wont talk much about my cable modem, but it's a business class and serves gig-e.

The GIT as provided in Synology Plugins is GIT SSH only - be aware of this as it creates a few hoops through which we we have to jump

In your package center, Install "Git Server"

There is a known bug, so if you click open right away, you won’t see any users. Luckily this article clued me into the fix.  Clear out the existing value in “appPriv”.. So appPriv should change to look like:

ijohnson@SassyNassy:~$ cat /var/packages/Git/target/webapi/SYNO.Git.lib
{"SYNO.Git.lib": {"allowUser": ["admin.local", "admin.domain", "admin.ldap"], "appPriv": "", "authLevel": 1, "lib": "/var/packages/Git/target/webapi/SYNO.Git.so", "maxVersion": 1, "methods": {"1": [{"enum_user": {"grantable": true}}, {"apply": {"grantable": true}}]}, "minVersion": 1, "priority": 0}}

Once changed, you can enable/disable git access for users:

Next, since GIT only runs on 22 and I’m not about to open an outside 22 port, create a forwarding rule in your router to reach the NAS.

I have an ASUS so it’s as easy as creating a new Virtual Server:

(IF you are using an Asus as I am, don't forget to hit "+" to save and then an apply button lest it doesn't actually take the new forwarding rule)

Next we need to login to the NAS and create a repo.

root@SassyNassy:/volume1/git_repos# git init --bare NewTest2
Initialized empty Git repository in /volume1/git_repos/NewTest2/
root@SassyNassy:/volume1/git_repos# cd NewTest2
root@SassyNassy:/volume1/git_repos/NewTest2# ls
branches  config  description  HEAD  hooks  info  objects  refs

Next chown so our accounts can write to it:

root@SassyNassy:/volume1/git_repos# sudo chown -R admin:users NewTest2
root@SassyNassy:/volume1/git_repos# sudo chmod -R g+rwx NewTest2

Last, to try and be observant of inclusive naming, I tend to change master to main:

root@SassyNassy:/volume1/git_repos# cat NewTest2/HEAD
ref: refs/heads/master
root@SassyNassy:/volume1/git_repos# vi NewTest2/HEAD
root@SassyNassy:/volume1/git_repos# cat NewTest2/HEAD
ref: refs/heads/main

Verification

Now that we have a local repo, let’s test it:

builder@DESKTOP-JBA79RT:~/Workspaces$ git clone ssh://ijohnson@sassynassy/volume1/git_repos/NewTest2 NewTest22
Cloning into 'NewTest22'...
ijohnson@sassynassy's password:
remote: Enumerating objects: 6, done.
remote: Counting objects: 100% (6/6), done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 6 (delta 0), reused 0 (delta 0), pack-reused 0
Receiving objects: 100% (6/6), done.
builder@DESKTOP-JBA79RT:~/Workspaces$ cd NewTest22
builder@DESKTOP-JBA79RT:~/Workspaces/NewTest22$ ls
README.md
builder@DESKTOP-JBA79RT:~/Workspaces/NewTest22$ vi README.md
builder@DESKTOP-JBA79RT:~/Workspaces/NewTest22$ git add README.md
builder@DESKTOP-JBA79RT:~/Workspaces/NewTest22$ git commit -m "make a change"
[main 84f86bb] make a change
 1 file changed, 1 insertion(+), 1 deletion(-)
builder@DESKTOP-JBA79RT:~/Workspaces/NewTest22$ git push
ijohnson@sassynassy's password:
Counting objects: 3, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 304 bytes | 304.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To ssh://sassynassy/volume1/git_repos/NewTest2
   23815bd..84f86bb  main -> main

Next I created a repo in Github that would consume from this one.

I made it private then used Azure Pipelines to onboard (and create the requisite AzDO to Github permissions)

The azure-pipelines file looks like:

$ cat azure-pipelines.yml
# Starter pipeline
# Start with a minimal pipeline that you can customize to build and deploy your code.
# Add steps that build, run tests, deploy, and more:
# https://aka.ms/yaml

trigger:
- main

pr:
 autoCancel: true
 branches:
   include:
   - feature/*
   - main
   - develop

variables:
- group: azdodev

pool:
  vmImage: 'ubuntu-latest'

steps:
- script: echo Hello, world!
  displayName: 'Run a one-line script'

- bash: |
    #!/bin/bash
    set -x

    sudo apt-get update
    sudo apt-get install -y sshpass

    export GIT_SSH_COMMAND="ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no"

    sshpass -p $(gitpw) git clone ssh://ijohnson@73.242.50.46:25580/volume1/git_repos/NewTest

    ls -ltra ./NewTest

- script: |
    echo Add other tasks to build, test, and deploy your project.
    echo See https://aka.ms/yaml
  displayName: 'Run a multi-line script'

I can either use the variable group under library to store the“gitpw”

Or you can use variables under settings:

This matches my login user.

In our code above we see how we can clone.  First we need to disable TLS since our git server doesn't have a proper cert and GIT will vomit on it.  We can use this env var (if Git is > 2.3)

 export GIT_SSH_COMMAND="ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no"

Next, because we used a custom port, we need to use sshpass to pass in our password.  Had we used the default 22, we wouldn't need to do this (we could instead use ssh://user:pass@host).  The forwarding port (25580) is part of the URL below.

sshpass -p $(gitpw) git clone ssh://ijohnson@73.242.50.46:25580/volume1/git_repos/NewTest

Running the pipeline

Now that we have the change, we can create a PR in Github which should trigger the onboarded pipeline:

Which then runs the Azure Pipelines job

Pushing content back

We can push content such as a new SHA or tag back in much the same way.  Just add steps such as:

    cd NewTest2

    git add BuildFile
    git config --global user.email "isaac.johnson@gmail.com"
    git config --global user.name "Isaac Johnson"

    git commit -m "BuildFile changed"
    sshpass -p $(gitpw) git push

And you’ll be able to transmit content back to the GIT on the NAS:

And we call pull locally to bring the commit down:

builder@DESKTOP-JBA79RT:~/Workspaces/NewTest6$ git pull
ijohnson@sassynassy's password:
remote: Enumerating objects: 14, done.
remote: Counting objects: 100% (14/14), done.
remote: Compressing objects: 100% (9/9), done.
remote: Total 12 (delta 1), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (12/12), done.
From ssh://sassynassy/volume1/git_repos/NewTest2
   6d597d6..9b6388c  main       -> origin/main
Updating 6d597d6..9b6388c
Fast-forward
 BuildFile | 6 ++++++
 README.md | 1 +
 2 files changed, 7 insertions(+)
 create mode 100644 BuildFile

Summary

We used a standard Synology NAS to host a GIT server and Azure DevOps to pull and push content as fronted via a GITHub based YAML pipeline.  This technique can be used to reference controlled content in a network - such as using a private agent pool that refers to a local git server (via local IP) instead of exposing publicly.

This can also be used to sync to local on-prem systems content built in the cloud for CICD systems that use GIT but have no external network access.