GitLab

About our GitLab configuration

Our GitLab installation is designed to provide a secure, lightweight platform for hosting Git repositories and reviewing code. GitLab includes many additional capabilities—including continuous integration, package registries, container registries, wikis, and deployment tools—but most are disabled by default to keep the interface focused on source code management.

Configuration is managed entirely through Ansible using the GitLab Omnibus package for Debian.

Configuration management

The Debian apt package does not directly write to the main configuration file /etc/gitlab/gitlab.rb so rather than modifying this file line by line, we manage the entire file as an Ansible template.

- name: Configure GitLab
  ansible.builtin.template:
    src: gitlab.rb.j2
    dest: /etc/gitlab/gitlab.rb
  notify: reconfigure gitlab

GitLab ships a complete gitlab.rb.template containing every supported option for reference but only the settings that differ from the defaults are included in our template. This keeps the configuration concise while making upgrades easier to review against the latest GitLab template.

HTTPS

GitLab’s bundled NGINX server terminates HTTPS using certificates placed directly on the host.

nginx['ssl_certificate'] = '/etc/ssl/mayfirst/{{ gitlab_site_domain }}/fullchain.pem'
nginx['ssl_certificate_key'] = '/etc/ssl/mayfirst/{{ gitlab_site_domain }}/privkey.pem'
nginx['ssl_dhparam'] = '/etc/ssl/dhparam.pem'

Email

GitLab sends notifications through May First’s mail servers and is configured to accept replies through an IMAP mailbox.

gitlab_rails['smtp_enable'] = true
gitlab_rails['incoming_email_enabled'] = true

The IMAP password is stored in Ansible Vault rather than in the playbook or repository.

Default project features

New projects begin with only the features most repositories require.

gitlab_rails['gitlab_default_projects_features_issues'] = false
gitlab_rails['gitlab_default_projects_features_merge_requests'] = true
gitlab_rails['gitlab_default_projects_features_wiki'] = false
gitlab_rails['gitlab_default_projects_features_snippets'] = false
gitlab_rails['gitlab_default_projects_features_builds'] = false
gitlab_rails['gitlab_default_projects_features_container_registry'] = false

By default, repositories support merge requests but do not enable issues, wikis, CI/CD, snippets, or the container registry. Individual projects can enable these features later through the GitLab web interface when needed.

Disabled services

Services that are not used are disabled entirely.

gitlab_rails['registry_enabled'] = false
gitlab_pages['enable'] = false

Disabling unused services reduces resource usage and the number of externally accessible components that must be maintained.

Anubis reverse proxy

All web traffic passes through Anubis before reaching GitLab.

GitLab’s bundled NGINX is set to listen on an alternate port while a custom Anubis nginx config is setup to accept public HTTPS connections on port 443.

nginx['listen_port'] = 8443

nginx['custom_nginx_config'] =
  'include /var/opt/gitlab/nginx/conf/anubis-custom.conf;'

The custom NGINX configuration is installed by the Ansible role before GitLab is reconfigured, ensuring the include file exists when GitLab regenerates its configuration.

This arrangement allows Anubis to filter automated traffic before requests reach GitLab.

Rate limiting

GitLab’s own unauthenticated web and API rate limits remain enabled as a second layer of protection behind Anubis.

The values we have changed from default 3600 requests per hour per ip are:

Setting Value
Unauthenticated API 300 requests/hour/IP
Unauthenticated web 600 requests/hour/IP

These limits are configured through the GitLab administration interface rather than gitlab.rb.

Administrative policy

Several security policies are managed through the GitLab administration interface because they are application settings rather than Omnibus configuration.

After deployment, review the following settings:

  • Disable user self-registration.
  • Set the default project visibility to Private.
  • Restrict group creation to administrators.
  • Disable Auto DevOps.
  • Disable shared runners unless CI/CD is introduced.

Together with the gitlab.rb configuration, these settings produce a GitLab instance that is focused on collaborative source code management while minimizing unnecessary features, services, and administrative overhead.

Reconfiguration

Changes to gitlab.rb require GitLab to regenerate the configuration for several bundled services. For this reason, the Ansible role runs gitlab-ctl reconfigure whenever the template changes, rather than simply restarting the service.

handlers:
  - name: Reconfigure GitLab
    ansible.builtin.command:
      cmd: gitlab-ctl reconfigure
  • filter automated traffic before it reaches GitLab
  • apply rate limits to anonymous traffic

This approach reduces administrative overhead, minimizes the exposed attack surface, and presents users with a simpler interface focused on collaborative source code management while still allowing additional GitLab capabilities to be enabled selectively as organizational needs evolve.