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
Go to
AWS console
→EC2
→Instances
Click on
Launch Instance
Fill the requirements
Name:
GitLab Server
AMI:
Ubuntu Server 24.04
Instance type:
t2.2xlarge
Create a new
key pair
and save itConfigure the
Network settings
Configure storage (set
50+ GiB
of storage)Launch the Instance
Connect to the Gitlab Server
using SSH
Copy the
public IP
of the ServerOpen Your
local terminal
Connect to the Instance via
ssh
command:ssh -i <path_of_key_pair_file> ubuntu@<public_ip>
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 yourserver’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 yourdomain 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
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!