Configuring GitLab behind a reverse proxy

Many of you are discouraged by the arduous task of making a GitLab run behind a reverse HTTPS proxy. What is an reverse HTTPS proxy? It’s a (preferably letsencrypt hooked) Web server that terminates SSL and routes your URLs into correct services. This terminator should be a nginx (if not, please adjust respectively).

This article will show you how to make a GitLab 16.9 run behind as a docker container (because you are using Docker for deployment, like a real man) both supporting the GitLab Container Registry, as well as GitLab Pages.

The idea

The idea is to place a reverse proxy that will terminate the SSL certificates as well, as redirect chosen hosts as GitLab pages and the container registry. As in, we’ll have a ingress Nginx to route the connections to target places. Also, an assumption is made that your GitLab’s docker container has the hostname of gitlab. If, not, please change respective configuration entries. It’s assumed that you’ve implemented certificate rotation, perhaps integrated yourself with Let’s Encrypt.

Also, in order to do that, some basic configuration needs to be added to gitlab.rb:

nginx['listen_port'] = "80"
nginx['listen_https'] = false
letsencrypt['enable'] = false

Just make sure that container gitlab is reachable from your nginx. Among possible ways to check it are ping gitlab or wget http://gitlab.

GitLab Container. Registry

GitLab Container Registry is a Docker Registry hosted within the same instance as your GitLab. It allows you to host Docker images correlated with your repos. Also, your GitLab Runner-powered CI/CD will allow you to make use of those. To sum up, there’s hardly a reason to use it.

There are two ways to run it. Either you’ll run your registry as part of GitLab’s entrypoint (HTTP 80) nginx, or you’ll run it standalone. This tutorial chose the standalone way.

Let’s assume the following:

  • our external URL to the registry will be registry.example.com. This is the URL that you’ll prefix your docker images with, as in registry.example.com/group/project:latest

You should add the following to your gitlab.rb:

registry_external_url 'http://registry.example.com'

### Settings used by GitLab application
gitlab_rails['registry_enabled'] = true
gitlab_rails['registry_host'] = "registry.example.com"
gitlab_rails['registry_port'] = "4999"
gitlab_rails['registry_api_url'] = "http://registry.example.com"

registry['enable'] = true
registry['registry_http_addr'] = "127.0.0.1:4999"
registry_nginx['enable'] = true


registry_nginx['listen_port'] = 5050
registry['env'] = { "REGISTRY_HTTP_RELATIVEURLS" => true }

And you should be safe to reverse proxy your registry.example.com to GitLab’s container, port 5050, say in this way (attach this to your Nginx’s configuration):

server {
    listen 80;
    listen 443 ssl http2;
    add_header Strict-Transport-Security "max-age=63072000; preload";
    resolver 127.0.0.11 valid=30s;
    ssl_certificate /etc/letsencrypt/live/registry.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/registry.example.com/privkey.pem;
    client_max_body_size 5G;
    server_name registry.example.com;
    set $registrygitlab gitlab:5050;
    location / {
            proxy_read_timeout 600;
            proxy_pass http://$registrygitlab;
            proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
            proxy_redirect off;
            proxy_buffering off;
            proxy_set_header        Host    $host;
            proxy_set_header        X-Real-IP       $remote_addr;
            proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

GitLab Pages

GitLab Pages is a way to host a static HTML website for your repository. You basically define a job that will output multiple HTML files as an artifact, and it’s all yours. You could leverage Sphinx or OpenAPI. It’s an absolute blast way to host readable documentation for your.

Let’s assume that your GitLab Pages will work in such a way:

  • docs.example.com – this is the root domain name for the GitLab Pages
  • group.docs.example.com/project – this is the URL of the documentation for project project in the group group.

Note that it’s still the reverse proxy’s job to terminate SSL and route these connections.

There are two parts of this task – one is configuring GitLab Pages to all users access, but I think you’ll want at least authorization to work for these. No problem, just add the following to your gitlab.rb:

pages_nginx['enable'] = true
pages_nginx['listen_port'] = 80
pages_nginx['listen_https'] = false
pages_nginx['redirect_http_to_https'] = true
pages_external_url "https://docs.example.com/"
gitlab_pages['internal_gitlab_server'] = 'gitlab' # change to Docker container name

gitlab_pages['access_control'] = true
gitlab_pages['enable'] = true
gitlab_pages['redirect_http'] = false
gitlab_pages['inplace_chroot'] = true
gitlab_pages['listen_proxy'] = "0.0.0.0:8090"

##! Configure to expose GitLab Pages on external IP address, serving the HTTP
gitlab_pages['external_http'] = []

But still, there’s one thing you need to do. Navigate to your GitLab’s configuration folder and edit gitlab-secrets.json. Remove entire “gitlab_pages” key and execute the gitlab-ctl reconfigure. Everything should be working. Now you’ll only need to reverse proxy respective domains (please also reverse proxy projects.docs.example.com and also manually specify any project groups that you wish to add. You need to do this manually, until I can figure out a better Nginx configuration script for that. You should need to just target the port of 80 on the GitLab container, example:

server {
    listen 443 ssl http2;
    add_header Strict-Transport-Security "max-age=63072000; preload";
    resolver 127.0.0.11 valid=30s;
    ssl_certificate /etc/letsencrypt/live/smok5.docs.example.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/smok5.docs.example.com/privkey.pem; # managed by Certbot
    server_name group.docs.example.com;
    set $gitdms gitlab:80;
    location / {
            proxy_read_timeout 600;
            proxy_pass http://$gitdms;
            proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
            proxy_redirect off;
            proxy_buffering off;
            proxy_set_header        Host    $host;
            proxy_set_header        X-Real-IP       $remote_addr;
            proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}
Published

By Piotr Maślanka

Programmer, certified first aider, entrepreneur, biotechnologist, expert witness, mentor, former PhD student. Your favourite renaissance man.

Leave a comment

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.