Setting up a simple custom Git LFS server on Ubuntu

Git LFS is an amazing set of tools by the wonderful people over at Github. It allows you to handle and version large files, which is pretty nifty when you’re into gamedev and derivates. It’s not new, but it’s becoming the new industry standard for binary versionning, and it works like a charm, most of the time.

So yeah, from my perspective, the problem is sharing Unreal Engine 4 projects to remote colleagues. We use our own infrastructure because we’ve got a shitton of binary files and we’re not really amazed by what the git community leaders have to offer as a service for LFS. The main reason is that we have a ton of custom services that we setup a while ago, and it made no sense to upload LFS related content outside of our internal logic.

We use Gitlab, which has LFS support out of the box, but we chose to totally separate binary and code management to keep everything neatly boxed. Some will find that kind of weird, but I prefer having a specialized VM with specialized redundancy and securities for my larges files. So I needed a server, and if you know Git LFS already, you must know their server spec is a HTTP CRUD API. This is where the fun starts, and why I mostly chose not to become a sysadmin.

According to the Git LFS Wiki, there are quite a few implementation available. Lets take a look at the list :

  • Some are hosted services, most are pretty expensive
  • Others are platforms like Gitlab, but once again, we’re not interested by that
  • Lol, java implementations
  • I want local storage, I don’t want no fucking Mongo GridFS, no AWS S3, no other dependency

So that leaves us with Github’s go test server implementation and Cloudmazing’s extension on it. We sticked with the Github basic server on a Ubuntu 15.10 VM, mostly because it’s really the simplest thing ever (#PlebianDesires). It’s not recommended for prod, but it gets the job done and it’s only internal. I’m going to go out on a limb and assume you’re not a full time Go developer, so you have :

  • no idea why this is the first time you actually see something done with it
  • no idea how to make it run

First of all, you want to install the Go packages. It’s pretty straightforward. You’ll have to set up your path to point out to the Go root folder, where everything is kept :

export GOROOT=$HOME/go # don't forget to create a go/ folder in your home folder
export PATH=$PATH:$GOROOT/bin

We can now get our server from Github :

go get github.com/github/lfs-test-server
cd
cd go/github.com/github/lfs-test-server
go build

We should have an executable named lfs-test-server inside the folder. It’s our server, keep it warm for now. We’re going to create a simple startup bash script, so that we can also pass server config to it. Create a run.sh file in the same folder, make it executable and fill it with this (modify HOST, LOCALPATH, ADMIN and PASSWORD, be smart) :

#!/bin/bash

set -eu
set -o pipefail

LFS_LISTEN="tcp://:9999"
LFS_HOST="HOST:9999"
LFS_CONTENTPATH="LOCALPATH"
LFS_ADMINUSER="ADMIN"
LFS_ADMINPASS="PASSWORD"
LFS_SCHEME="http"

export LFS_LISTEN LFS_HOST LFS_CONTENTPATH LFS_ADMINUSER LFS_ADMINPASS LFS_SCHEME

./lfs-test-server

From there, you can already run it, and you can access it on http://HOST:9999, and files will be uploaded to LOCALPATH on your machine. But if we’re even smarter, we want a service, because services are cool. I suck at sysadmining, so I took the first startup script I found on Github. Here’s mine so that you understand how to configure it. Let’s set it up :

cd /etc/init.d
# ..create your file, mine is named gitlfsserver. If you change the name, don't forget to put the same name in the "Provides:" field of the file header
sudo chmod 0755 gitlfsserver
sudo /etc/init.d/gitlfsserver status
#Running
sudo update-rc.d gitlfsserver defaults

This starts it and sets it as a startup script, so you don’t need to worry about it when the VM restarts.

ALRIGHT! We’ve got ourselves a server! Check your server endpoints, firewall and shit to allow communication through port 9999 (or the one you chose), don’t stupidly lose your time on that. Now for the client configuration. First off, install Git LFS. Nothing to say here, it’s pretty simple whatever OS you’re on. Now to setup a git repo to push to LFS, first create a .lfsconfig at the base of your repo. Fill it with your information based on this template :

[lfs]
    url = "http://ADMIN:PASSWORD:9999/"

Now let’s configure LFS and push :

git lfs install --skip-smudge # only do this once, not for every repo. Skipping smudge because of weird bug with cloning
cd yourGitRepo/
git lfs track "*.EXT" # this is where you get crazy. Check the Git LFS doc for that
git add .
git commit -m "Git LFS, yay!"
git push origin master
# Git LFS: (x of x files) y MB / y MB
# ..rest of git push output

If you see the GitLFS upload shenanigans without any error, it means upload went well. The files uploaded to your git repo are just pointers to the files on the LFS server, so no space wrongfully taken. So how do you get them? That’s the catch about that cloning bug in LFS, and I also prefer to do it manually, probably because I’m weird. So, your machine still needs the LFS client executables, make sure you have them. If not done yet, execute once git lfs install --skip-smudge to set it up. We’re now ready to clone our repo :

git clone path.to.your.repo.git
cd your.repo/
git lfs pull

And there you go! It should take a while to download the binaries from your LFS server, depending on your connection speed of course.

It’s not perfect, it has a ton of flaws. I didn’t use HTTPS here for instance, which we set up on our infrastructure for basic security (check Git LFS’s github readme, they explain how to do it). Thing’s working pretty fine though, enough for our internal use. Bonus point, much like Github’s UI, Gitlab knows when your project uses LFS, and automatically creates previews for supported binary types when you check them out on the repo files dashboard. It’s useless, but hey, they had at least one random dev making that, hats off.

Anyways, you know the drill. Have fun, code safe.

Tuxic