Hosting GitLab on Your Private Server with CI/CD: A How-To Guide

Self-hosting GitLab on a private server gives you full control over your code, repositories, and CI/CD pipelines. It’s a great solution for teams needing privacy and customization. In this guide, I’ll walk you through setting up GitLab with CI/CD using Docker, based on a project I recently completed.

Why Self-Host GitLab?

  • Privacy: Keep your code and data on your own infrastructure.

  • Customization: Tailor GitLab to your team’s needs.

  • CI/CD: Automate builds, tests, and deployments with GitLab Runners.

Prerequisites

  • A server with 8 vCPU, 7.2GB RAM, and 50GB+ disk space (e.g., Ubuntu 22.04).

  • Root or sudo access.

  • A domain name (e.g., git.example.com) or static IP.

Creating an EC2 server

  1. Go to AWS consoleEC2Instances

  2. Click on Launch Instance

  3. Fill the requirements

    • Name: GitLab Server

    • AMI: Ubuntu Server 24.04

    • Instance type: t2.2xlarge

    • Create a new key pair and save it

    • Configure the Network settings

    • Configure storage (set 50+ GiB of storage)

    • Launch the Instance

Connect to the Gitlab Server using SSH

  1. Copy the public IP of the Server

  2. Open Your local terminal

  3. Connect to the Instance via ssh command:

     ssh -i <path_of_key_pair_file> ubuntu@<public_ip>
    

  4. Congrats! 🎉 Gitlab server is now connected to the local server via SSH

Step 1: Prepare the Server

Start by updating your server and installing dependencies:

sudo apt-get update && sudo apt-get upgrade -y
sudo apt-get install -y curl openssh-server ca-certificates tzdata perl

Optionally, install Postfix for email notifications:

sudo apt-get install -y postfix

Select Internet Site and enter your server’s domain or IP.

Step 2: Install Docker

Install Docker to run GitLab in a container:

curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
sudo usermod -aG docker $USER

Log out and back in, then verify Docker:

docker --version

Log out and back in for the group change to take effect.

Step 3: Deploy GitLab

Create directories for persistent storage:

mkdir -p /srv/gitlab/config /srv/gitlab/logs /srv/gitlab/data

Run the GitLab container:

sudo docker run --detach \
  --hostname git.example.com \
  --publish 443:443 --publish 80:80 --publish 22:22 \
  --name gitlab \
  --restart always \
  --volume /srv/gitlab/config:/etc/gitlab \
  --volume /srv/gitlab/logs:/var/log/gitlab \
  --volume /srv/gitlab/data:/var/opt/gitlab \
  gitlab/gitlab-ce:latest

  • Replace git.example.com with your domain or server IP.

  • Wait 5-10 minutes for GitLab to initialize.

Check container status:

docker ps

Step 4: Secure the Instance

  • Access GitLab: Navigate to http://<server-ip> or https://git.example.com.

  • Set a password for the root user when prompted.

  • Log in: Use username root and the password you set.

Enable HTTPS by editing /srv/gitlab/config/gitlab.rb:

external_url 'https://git.example.com'
letsencrypt['enable'] = true
letsencrypt['contact_emails'] = ['your-email@example.com']

Reconfigure GitLab:

sudo docker exec -it gitlab gitlab-ctl reconfigure

Restrict access (optional): In the GitLab UI, go to Admin Area > Settings > General > Sign-up restrictions and disable sign-ups for a private setup.

Step 5: Set Up CI/CD with GitLab Runner

Install GitLab Runner:

curl -L "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh" | sudo bash
sudo apt-get install -y gitlab-runner

Register the Runner:

  • In GitLab UI, go to Settings > CI/CD > Runners to get the registration token and URL.

  • Register the runner:

sudo gitlab-runner register \
  --url https://git.example.com \
  --token <your-registration-token> \
  --description my-runner \
  --tag-list docker-runner \
  --executor docker \
  --docker-image alpine:latest

Verify Runner:

sudo gitlab-runner status

Test CI/CD with a Pipeline

Create a .gitlab-ci.yml file in your project to test the pipeline:

stages:
  - build
  - test

build:
  stage: build
  tags:
    - docker-runner
  script:
    - echo "Building the project..."
    - mkdir -p builds
    - touch builds/app.txt
  artifacts:
    paths:
      - builds/

test:
  stage: test
  tags:
    - docker-runner
  script:
    - echo "Running tests..."
    - test -f builds/app.txt

Push the file and check the pipeline in CI/CD > Pipelines

Conclusion

You now have a self-hosted GitLab instance with CI/CD, ready for private development and automation. Secure it with a firewall (ufw) and regular backups:

sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo docker exec -it gitlab gitlab-backup create
0
Subscribe to my newsletter

Read articles from Praduman Prajapati directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Praduman Prajapati
Praduman Prajapati

Bridging the gap between development and operations. Hey there! I’m a DevOps Engineer passionate about automation, cloud technologies, and making infrastructure scalable and efficient. I specialize in CI/CD, cloud automation, and infrastructure optimization, working with tools like AWS, Kubernetes, Terraform, Docker, Jenkins, and Ansible to streamline development and deployment processes. I also love sharing my knowledge through blogs on DevOps, Kubernetes, and cloud technologies—breaking down complex topics into easy-to-understand insights. Let’s connect and talk all things DevOps!