How to Set Up a Private GitLab Server for Your Homelab

Introduction

Today was one of those days where everything clicks into place.
After years of working with code, scripts, and configs in networking and System Engineering — sometimes organized, sometimes messy — I decided to get serious about source control, automation, and managing my own projects and dotfiles.

And let me tell you — setting up my own self-hosted GitLab, has been a game-changer. Here’s a breakdown of what I did, what I learned, and what’s next.


Why I Did This

  • I wanted better control over my own work, without always relying on third-party hosted repos.
  • I needed a way to work across multiple devices (my laptop, Linux rig, home servers) without getting lost in different versions.
  • I was tired of “where did I put that config again?” — version control for my entire lab and scripts is now a must-have.
  • Plus, I wanted to finally understand Git and branches properly, and protect important work.

Part 1: Spinning up a Self-Hosted GitLab

First up, I decided to host my own GitLab instance in Docker on my mon1 box. This means:

  • Full control over repos, branches, access control.
  • Ability to self-host private work (my scripts, Docker files, configs).
  • Separating personal/internal projects from public-facing content on GitHub.

Key lessons:

  • Using Docker Compose makes deploying GitLab manageable and reproducible.
  • Mounting proper volumes for GitLab data, configs, and logs means it’s safe and portable.
  • Adding SSH keys for secure access and enabling protected branches adds a layer of professionalism to my lab.
  • Getting familiar with GitLab’s UI — setting default branches, protected branches, and merge request workflows.

Part 2: Understanding Branching (Properly, Finally)

This was the real “aha” moment for me.

I used to just “commit to master” and hope for the best. Today, I learned how to manage proper dev branches:

  • Device-specific dev branches:

    • dev-laptop
    • dev-linux-rig
  • Protected “main” branches that hold my ready/working versions.

Flow:

  • Make and test changes in a dev-* branch.
  • When ready, create a merge request to main — for internal review and approval (even if it’s just me for now!).

Realizations:

  • Main is sacred — only polished work gets merged.
  • Dev branches allow freedom to experiment.
  • Merge requests simulate real team workflows — future-proof if I collaborate later.

Part 3: Linking GitHub and GitLab (Public vs Private)

Another big takeaway:

  • GitHub is my public face — for blogs, open-source, and polished work.
  • GitLab is my private dev lab — for experiments, scripts, sensitive files (think: Docker Compose files, .bashrc, SSH config).

I set up:

  • Private GitLab repo with branches (main/dev)
  • GitHub as public-facing repo for finalized blog posts and docs

Final workflow:

  1. Work in dev-linux-rig or dev-laptop.
  2. Merge into main on GitLab when stable.
  3. (Optional) Pull selected files and push to GitHub for public viewing.

Part 4: Managing Dotfiles and Automation Ideas

  • I set up dotfiles repo in GitLab for things like .bashrc, .vimrc, .ssh/config.
  • Learned about the idea of bare repos for dotfiles, but keeping it simple for now.
  • Thinking ahead:
    • Use cron jobs to auto-pull from Git (keeping servers updated).
    • Explore Ansible for proper config management and deployment.
Verified by MonsterInsights