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
👋 Hi, I’m Praduman Prajapati — a DevOps Engineer with hands-on experience in building production-grade CI/CD pipelines, containerized applications, and scalable, secure, and automated cloud infrastructure. I’ve work on multiple real-world projects including: • Automated CI/CD pipelines using Jenkins, GitHub Actions, and ArgoCD • Kubernetes cluster provisioning and deployment on AWS (EKS and kubeadm) • Containerization and orchestration with Docker and Kubernetes • Infrastructure provisioning and automation using Terraform and Ansible • DevSecOps implementations with Trivy, SonarQube, OWASP, Prometheus, and Grafana • Production-grade deployments of applications on cloud infrastructure