How-to

How to Enable HTTPS on a Self-Hosted GitLab Instance

Most self-hosted GitLab installs run the Omnibus package, which bundles its own internal Nginx and handles TLS configuration through a single file: /etc/gitlab/gitlab.rb.

Using your own certificate

  1. Set external_url 'https://gitlab.example.com' in gitlab.rb — this alone tells GitLab to expect and serve HTTPS on that hostname.
  2. Place your certificate and private key in /etc/gitlab/ssl/, named to match the hostname exactly: gitlab.example.com.crt and gitlab.example.com.key. GitLab's bundled Nginx looks for files matching this naming convention automatically.
  3. Run sudo gitlab-ctl reconfigure to apply the change.

If you also want plain HTTP requests redirected to HTTPS automatically, set nginx['redirect_http_to_https'] = true in the same file before reconfiguring.

Using GitLab's built-in Let's Encrypt integration

Omnibus GitLab includes an integrated ACME client for Let's Encrypt, enabled by setting letsencrypt['enable'] = true alongside the same external_url setting. This requires that the hostname in external_url actually resolves to the server and that it's reachable on port 80 for domain validation, the same requirement any ACME-based issuance has. Once enabled, GitLab handles both issuance and ongoing renewal itself, without needing a separate cron job or external ACME client.

Docker-based GitLab installs

For GitLab run via Docker rather than a direct Omnibus package install, the same gitlab.rb settings are typically supplied through the GITLAB_OMNIBUS_CONFIG environment variable on the container, with the actual certificate and key files mounted into the container at the same /etc/gitlab/ssl/ path described above. The underlying mechanism is identical; only how the configuration reaches the container differs.

Terminating TLS upstream instead

A common alternative, especially when GitLab sits behind an existing reverse proxy or load balancer (Nginx, Traefik, an internal load balancer already handling TLS for other services), is to let that upstream layer terminate TLS and forward plain HTTP to GitLab internally, while still setting external_url to an https:// address so GitLab generates correct links and knows it's being served over HTTPS externally. In this pattern, GitLab's own bundled Nginx doesn't need a certificate configured at all — the proxy in front of it holds the actual certificate.

What to check if reconfigure completes but HTTPS still fails

A reconfigure that completes without error doesn't guarantee the certificate files were found and loaded correctly — confirm the certificate and key filenames exactly match the hostname in external_url (including capitalization) and that GitLab's system user has read permission on both files; a silent fallback to a self-signed default certificate is the most common symptom of a filename or permissions mismatch rather than a problem with the certificate itself.

Comments

Loading comments…