DevOps

Installing GitLab, Runner, and Container Registry on Your Home Server

Get up and running to install GitLab, the GitLab Runner, and GitLab Registry. Learn how to set up a code development environment and CI/CD pipeline for collaboration.

So, I wanted to create a concise guide to help you guys get up and running with GitLab, the GitLab Runner, and GitLab Registry. I spent quite a bit of time working on this in my home lab and hammering out the details so you don’t have to! Let’s look at everything you need to install GitLab, GitLab runner, and GitLab container registry.

Why GitLab?

Really, it is just because I like it. There are other great solutions, including Jenkins, Gitea, Bitbucket and others. However, GitLab is one of the most fully featured, outside of Jenkins that you can self-host in your home lab environment. 

With GitLab, you can set up a code development environment and CI/CD pipeline for collaboration to automate continuous deployment and continuous integration with version control. It can also run and host a container registry.

It is usually built on top of a virtualization environment running containerization for build and test purposes. 

My setup

I’m running Gitlab using the official containers from Gitlab Enterprise Edition. There is also a Community Edition as well. However, Enterprise Edition is also free to download and run with the advantages of having all the features, and you don’t have to migrate to a different base installation if you want to go to paid support.

Community Edition is fine too if you want to stand up GitLab. However, just keep in mind you will have to migrate to Enterprise Edition if you want to take it into production.

My configuration is running in an Ubuntu 22.04 LTS virtual machine with Docker installed. I am using Docker Compose to stand up my Gitlab Enterprise Edition container and a GitLab Runner.

These are running along with Nginx Proxy Manager that is also running in a Docker contianer. They are all connected to a single Docker network called nginxproxy so that the only way the traffic gets into the Gitlab Containers is through Nginx Proxy Manager.

Gitlab enterprise edition docker compose
Gitlab enterprise edition docker compose

Prerequisites and requirements

The below tutorial assumes you have a Docker host running with an Nginx Proxy Manager container already running and provisioned. If you need to know how to install Nginx Proxy Manager and Nginx proxy network, check out my tutorial on how to do that step-by-step here:

Installing GitLab in your home lab

There are a few things I learned by standing up GitLab in the home lab to stand up the GitLab EE container, GitLab Runner, and Container Registry to make all of these work together and get the configuration right for use with an external proxy.

Let me show you what my Docker Compose file looks like for the GitLab EE container and let’s talk about what each section does.

  • You can see we are pulling the latest gitlab/gitlab-ee:latest image
  • Setting the hostname and the restart policy
  • Now, the section that begins with GITLAB_OMNIBUS_CONFIG and everything between { and } is configuration needed for the Gitlab container registry. This is needed if you are using a reverseproxy to use with your GitLab container registry. Replace “gitlab.mydomain.com” with your domain name.
  • Networks, we are connecting to a Docker network called nginxproxy
  • Volumes are connected to a folder I have created in my home directory called homelabservices with a child gitlab folder.
  • Then we are setting the container name.
gitlab:
    image: gitlab/gitlab-ee:latest
    hostname: 'gitlab.mydomain.com'
    restart: always 
    environment:
      GITLAB_OMNIBUS_CONFIG: |
        external_url 'https://gitlab.mydomain.com'
        letsencrypt['enabled'] = false
        # Reverse proxy nginx config 
        nginx['listen_port'] = 80
        nginx['listen_https'] = false
        nginx['redirect_http_to_https'] = false
        nginx['proxy_set_headers'] = {
          "X-Forwarded-Proto" => "https",
          "X-Forwarded-Ssl" => "on",
          "Host" => "gitlab.mydomain.com",
          "X-Real-IP" => "$$remote_addr",
          "X-Forwarded-For" => "$$proxy_add_x_forwarded_for",
          "Upgrade" => "$$http_upgrade",
          "Connection" => "$$connection_upgrade"
        }
    networks:
      - nginxproxy
    volumes:
      - '~/homelabservices/gitlab/data:/var/opt/gitlab'
      - '~/homelabservices/gitlab/config:/etc/gitlab'
      - '~/homelabservices/gitlab/logs:/var/log/gitlab'
    container_name: gitlab

You can bring up the above configuration using

Below, you will see one of the repositories that I have running in my environment tracking changes with git, and enabled with GitLab CI.

Viewing the gitlab repository that is self hosted
Viewing the gitlab repository that is self hosted after you install Gitlab

Installing the GitLab runner

With GitLab, it uses a “runner” which is nothing more than another Docker container that actually does the work defined in your CI/CD pipeline. You can also install the GitLab runner as a Linux package on a full VM as well. However, this is not nearly as efficient as the Docker container.

I have found instances though where I needed to run the runner on a full Linux machine when running a CI/CD pipeline for Packer that builds a virtual machine. I wasn’t able to figure out how to get around an issue where the provisioning VM could not connect to the Packer web server running inside the GitLab Docker container due to the additional Docker network layer. This problem does happen with a full Linux VM as a runner.

In Docker Compose, let’s look at the code needed to stand up a GitLab runner:

gitlab-runner:
    image: gitlab/gitlab-runner:latest
    restart: always
    networks:
      - nginxproxy
    volumes:
      - '~/homelabservices/gitlab-runner/config:/etc/gitlab-runner'
      - '/var/run/docker.sock:/var/run/docker.sock'
    container_name: gitlab_runner
Viewing docker containers running for gitlab
Viewing docker containers running for gitlab
Viewing runners for a project
Viewing runners for a project

GitLab Container Registry

This part took the most head scratching and trial and error. It took a while putting together different documentation and trying differen things to come up with a config that worked. Part of the config needed is the GITLAB_OMNIBUS_CONFIG found in the Docker Compose YAML for the GitLab EE container.

The GitLab container registry is not another Docker container as you might think. Rather it is a configuration that you enable on the GitLab side to allow it to listen for registry requests to push/pull images from its configured storage.

The following config is just the lines that I have uncommented and changed the value for in the file /homelabservices/gitlab/config/gitlab.rb in their respective sections in that file, which I have copied the default comment sections for each section to make it easier to find in the file (the file is huge with a lot of configuration settings).

Keep in mind the below settings are not the only settings in each section. I am just showing the configuration I uncommented and configured for each section below.

################################################################################
## Container Registry settings
##! Docs: https://docs.gitlab.com/ee/administration/packages/container_registry.html
################################################################################
registry_external_url 'https://registry.mydomain.com'
gitlab_rails['registry_enabled'] = true
gitlab_rails['registry_host'] = "registry.mydomain.com"
gitlab_rails['registry_port'] = "5000"
registry['enable'] = true


### Settings used by Registry application
registry['log_directory'] = "/var/log/gitlab/registry"
registry['env_directory'] = "/opt/gitlab/etc/registry/env"

### Registry backend storage
registry['storage'] = {
  'filesystem' => {
    'rootdirectory' => '/var/opt/gitlab/gitlab-rails/shared/registry',
  }
}

# Below you can find settings that are exclusive to "Registry NGINX"
registry_nginx['enable'] = true

registry_nginx['proxy_set_headers'] = {
  "Host" => "$http_host",
  "X-Real-IP" => "$remote_addr",
  "X-Forwarded-For" => "$proxy_add_x_forwarded_for",
  "X-Forwarded-Proto" => "https",
  "X-Forwarded-Ssl" => "on"
}

# When the registry is automatically enabled using the same domain as `external_url`,
# it listens on this port
registry_nginx['listen_port'] = 5050
registry_nginx['listen_https'] = false

If you change this configuration before you stand up GitLab first (which I would recommend as it is easiest to take it a step at a time), you will need to run the command on your Docker container host housing your GitLab container:

docker exec -it gitlab gitlab-ctl reconfigure

This will reconfigure your GitLab container with your new settings in the gitlab.rb file. Once GitLab is reconfigured, which will take a couple of minutes, you should be able to login to your GitLab instance and under the Deploy menu, you should have the option for Container Registry.

On this blank page shown below, it will give you instructions at the bottom on how to connect to your registry and push images to it. One thing I want to mention that I haven’t figured out as of yet. The instructions will include the port configuration appended to the end of the URL. This threw me for a loop at first since I couldn’t connect.

However, in thinking about it, I took the port off the config since NginxProxyManager was handling the forwarding to the internal port and everything started working. Maybe someone has a trick to take this out of the UI to display the URL without the port without needing to change the backend config.

Viewing the gitlab container registry self hosted in gitlab
Viewing the gitlab container registry self hosted in gitlab

Nginx Proxy Manager configuration

Ok, so the final part of the solution is configuring your Nginx Proxy Manager to properly forward over traffic to the “internal” Nginx config of the GitLab proxy that is internal to the solution for the registry. As you can see below, I am forwarding the container registry over to port 5050, which is configured in the registry_nginx[‘listen_port’] setting in the gitlab.rb file.

With the configuration below, Nginx will listen for requests that come in on straight SSL 443, with no port defined from the outside, so like registry.mydomain.com. It will then on the internal side, forward those requests to port 5050 which is the Nginx listener configured on the GitLab side for the container registry.

Nginx proxy manager proxy hosts configuration for gitlab and gitlab runner
Nginx proxy manager proxy hosts configuration for gitlab and gitlab runner

Wrapping up how to install GitLab, Runner, and Container Registry

I have found self-hosting GitLab in the lab environment has been a great project for learning, not only how to use Infrastructure as Code better, but also CI/CD and the inner workings and architecture of these types of systems. Hopefully, the above code examples will help any who might be struggling to install GitLab, configure runners, but especially configure the container registry.

Subscribe to VirtualizationHowto via Email 🔔

Enter your email address to subscribe to this blog and receive notifications of new posts by email.

Brandon Lee

Brandon Lee is the Senior Writer, Engineer and owner at Virtualizationhowto.com and has over two decades of experience in Information Technology. Having worked for numerous Fortune 500 companies as well as in various industries, Brandon has extensive experience in various IT segments and is a strong advocate for open source technologies. Brandon holds many industry certifications, loves the outdoors and spending time with family.

Related Articles

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.