GitLab Community Edition is a self-hosted DevOps platform that combines Git repositories, merge requests, issue tracking, a container registry and CI/CD pipelines in one application. The official Linux package (also called Omnibus) bundles everything GitLab needs, including PostgreSQL, Redis, Puma, Sidekiq and its own Nginx, so you manage it all from one configuration file. In this tutorial you will install GitLab CE on Ubuntu 24.04, get a Let's Encrypt certificate automatically, configure outgoing email, reduce memory use for a small team, schedule backups and register a runner.
Prerequisites
To follow this guide you need:
- A dedicated server running Ubuntu 24.04 LTS, for example a CubePath VPS, with at least 4 vCPUs, 8 GB of RAM and 50 GB of disk. GitLab runs its own Nginx on ports 80 and 443, so do not install other web servers on the same machine.
- A non-root user with
sudoprivileges. - A domain or subdomain, such as
gitlab.your_domain, with a DNS A record pointing to your server's public IP. This guide usesyour_domainas a placeholder. - Access to an SMTP server (your mail provider or a transactional email service) for notification emails.
Step 1 - Preparing the server
Update the system and install the packages the GitLab installer depends on:
sudo apt update && sudo apt upgrade -y
sudo apt install -y curl openssh-server ca-certificates tzdata perl
Open SSH, HTTP and HTTPS in UFW. Port 80 must be reachable so Let's Encrypt can validate your domain:
sudo ufw allow OpenSSH
sudo ufw allow http
sudo ufw allow https
sudo ufw enable
sudo ufw status
Status: active
To Action From
-- ------ ----
OpenSSH ALLOW Anywhere
80/tcp ALLOW Anywhere
443/tcp ALLOW Anywhere
If your server has less than 8 GB of RAM, add a swap file so GitLab does not get killed during upgrades or heavy jobs:
sudo fallocate -l 4G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
Step 2 - Adding the GitLab package repository
GitLab provides a script that adds its APT repository and signing key. Download it and read it before running it as root:
curl -fsSL -o gitlab-repo.sh https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.deb.sh
less gitlab-repo.sh
sudo bash gitlab-repo.sh
Confirm that APT now sees the gitlab-ce package from the GitLab repository:
apt-cache policy gitlab-ce
gitlab-ce:
Installed: (none)
Candidate: 18.x.x-ce.0
Version table:
18.x.x-ce.0 500
500 https://packages.gitlab.com/gitlab/gitlab-ce/ubuntu noble/main amd64 Packages
The candidate version will be the latest release at the time you run it.
Step 3 - Installing GitLab CE
Install the package and pass your public URL in the EXTERNAL_URL variable. Because the URL starts with https://, GitLab requests a Let's Encrypt certificate for that domain during installation and renews it automatically afterwards:
sudo EXTERNAL_URL="https://your_domain" apt install -y gitlab-ce
The installation runs gitlab-ctl reconfigure at the end and takes several minutes. When it finishes, check that all components are running:
sudo gitlab-ctl status
run: alertmanager: (pid 5123) 60s; run: log: (pid 5040) 75s
run: gitaly: (pid 4890) 80s; run: log: (pid 4870) 82s
run: gitlab-workhorse: (pid 5010) 62s; run: log: (pid 4990) 70s
run: nginx: (pid 5020) 61s; run: log: (pid 4995) 70s
run: postgresql: (pid 4910) 79s; run: log: (pid 4900) 80s
run: puma: (pid 4960) 65s; run: log: (pid 4950) 72s
run: redis: (pid 4880) 81s; run: log: (pid 4860) 83s
run: sidekiq: (pid 4980) 64s; run: log: (pid 4970) 71s
...
Every line should start with run:. The installer generated a random password for the root account and stored it in a file that is deleted automatically after 24 hours:
sudo cat /etc/gitlab/initial_root_password
Open https://your_domain, log in as root with that password, and change it right away from Edit profile > Password.
Step 4 - Securing the instance from the Admin area
A fresh GitLab instance lets anyone create an account. In the web interface, open Admin (bottom of the left sidebar), go to Settings > General > Sign-up restrictions and either uncheck Sign-up enabled or keep it and enable Require admin approval for new sign-ups. Save the changes.
Then create a personal account for daily work under Admin > Users > New user and avoid using root for regular tasks.
Step 5 - Configuring outgoing email
GitLab sends password resets, notifications and invitations by email. All settings of the Linux package live in /etc/gitlab/gitlab.rb:
sudo nano /etc/gitlab/gitlab.rb
Add the following lines, adjusting them to your SMTP provider. This example uses port 587 with STARTTLS, which most providers support:
gitlab_rails['smtp_enable'] = true
gitlab_rails['smtp_address'] = "smtp.your_provider.com"
gitlab_rails['smtp_port'] = 587
gitlab_rails['smtp_user_name'] = "your_smtp_user"
gitlab_rails['smtp_password'] = "your_smtp_password"
gitlab_rails['smtp_domain'] = "your_domain"
gitlab_rails['smtp_authentication'] = "login"
gitlab_rails['smtp_enable_starttls_auto'] = true
gitlab_rails['smtp_tls'] = false
gitlab_rails['gitlab_email_from'] = "gitlab@your_domain"
gitlab_rails['gitlab_email_reply_to'] = "noreply@your_domain"
Apply the configuration:
sudo gitlab-ctl reconfigure
Send a test email from the Rails console. The console takes a minute to start:
sudo gitlab-rails console
At the irb prompt, run:
Notify.test_email('[email protected]', 'GitLab test', 'It works').deliver_now
Check your inbox, then leave the console with exit. If delivery fails, the console prints the SMTP error directly (for example an authentication failure or a certificate mismatch).
Step 6 - Reducing memory use for a small team
The default settings size Puma and Sidekiq for larger installations. For a team of up to a few dozen people you can lower memory use noticeably. Open /etc/gitlab/gitlab.rb again:
sudo nano /etc/gitlab/gitlab.rb
Add these settings:
puma['worker_processes'] = 2
sidekiq['concurrency'] = 10
prometheus_monitoring['enable'] = false
They start two Puma workers, limit Sidekiq to 10 concurrent jobs and disable the bundled Prometheus monitoring stack. Apply them:
sudo gitlab-ctl reconfigure
Compare memory use before and after with free -h. Skip this step if your server has 16 GB of RAM or more, or if you want the built-in monitoring dashboards.
Step 7 - Scheduling backups
A GitLab backup has two parts. gitlab-backup saves the database, repositories and uploads, but not the configuration and secrets, which are needed to decrypt data such as CI variables and two-factor settings.
First, tell GitLab to delete backups older than seven days. In /etc/gitlab/gitlab.rb add:
gitlab_rails['backup_keep_time'] = 604800
Apply it with sudo gitlab-ctl reconfigure, then create a first backup to check that it works:
sudo gitlab-backup create
sudo ls -lh /var/opt/gitlab/backups
-rw------- 1 git git 1.2M Sep 25 02:00 1758765600_2026_09_25_18.x.x_gitlab_backup.tar
Back up the configuration directory, which includes gitlab.rb and gitlab-secrets.json:
sudo gitlab-ctl backup-etc
sudo ls -lh /etc/gitlab/config_backup
Schedule both every night in a cron file:
sudo nano /etc/cron.d/gitlab-backup
0 2 * * * root /opt/gitlab/bin/gitlab-backup create CRON=1
15 2 * * * root /opt/gitlab/bin/gitlab-ctl backup-etc
CRON=1 hides progress output unless there are errors. Copy /var/opt/gitlab/backups and /etc/gitlab/config_backup off the server regularly, since both are stored on the same disk as GitLab.
Step 8 - Registering a GitLab Runner
CI/CD jobs are executed by GitLab Runner. For production, install it on a separate server so builds do not compete with GitLab for memory; the commands are the same. Add the runner repository, again reading the script first:
curl -fsSL -o runner-repo.sh https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh
less runner-repo.sh
sudo bash runner-repo.sh
sudo apt install -y gitlab-runner
In the web interface, go to Admin > CI/CD > Runners, click New instance runner, select Run untagged jobs, and click Create runner. GitLab shows a token that starts with glrt-. Register the runner with it, using the shell executor for simplicity:
sudo gitlab-runner register --non-interactive --url "https://your_domain" --token "glrt-your_token" --executor shell
Verify that the runner can reach GitLab:
sudo gitlab-runner verify
Verifying runner... is valid runner=abc123xy
The runner also appears as online in Admin > CI/CD > Runners. To test it, add a .gitlab-ci.yml file to any project:
test:
script:
- echo "Hello from $(hostname)"
Commit it, then open Build > Pipelines in the project to see the job run.
Troubleshooting
- Let's Encrypt fails during installation: the DNS record does not point to the server yet or port 80 is blocked. Fix it, then run
sudo gitlab-ctl reconfigureto retry. - 502 "Whoops, GitLab is taking too much time to respond": Puma is still starting or ran out of memory. Wait a minute, then check
sudo gitlab-ctl statusandsudo gitlab-ctl tail puma. - General health check:
sudo gitlab-rake gitlab:check SANITIZE=truetests repositories, permissions and services, and prints hints for each failure. - Lost root password: reset it with
sudo gitlab-rake "gitlab:password:reset[root]".
Conclusion
GitLab CE is now running on Ubuntu 24.04 with automatic HTTPS, working email, memory settings suited to a small team, nightly backups and a registered runner. Next, you can switch the runner to the Docker executor for isolated builds, enable the container registry with registry_external_url in gitlab.rb, and upgrade GitLab regularly with sudo apt update && sudo apt install gitlab-ce, following the supported upgrade path between major versions.
