Use gitlab pages under the same domain as gitlab


Description

Allow the usage of one SSL certificate for both gitlab and gitlab pages

Proposal

You need to reserve a word and prevent the creation of a group with this name (like "admin" is not a valid group name). The main idea is to use a reverse proxy (we use an external nginx) to present the correct Host http header to the gitlab pages server without the user browser knowing it. You still need a DNS wildcard but no Wildcard SSL certificate and the link in Gitlab also works directly (redirects to the correct domain).

Links / references

These issues are partly related

Documentation

Example : gitlab instance runs at https://gitlab.example.org with a nginx reverse proxy in front of it

## gitlab.rb ##
external_url 'https://gitlab.example.org'
gitlab.example.org "http://gitlab.example.org/"
## nginx-vhost.conf ##
server {
    listen 80;
    # Rewrite
    # http://MYGROUP.gitlab.example.org/myproject/index.html
    # to
    # https://gitlab.example.org/pages/MYGROUP/myproject/index.html
    server_name ~^(?<subdomain>.*)\.gitlab.example.org$;
    rewrite ^/(.*)$ https://gitlab.example.org/pages/$subdomain/$1;
}

server {
    listen 80;
    return 301 https://$host$request_uri;
}


server {
    listen 443;

    error_log /var/log/nginx/gitlab.access.log;

    ssl on;
    ssl_certificate /etc/nginx/external/cert.pem;
    ssl_certificate_key /etc/nginx/external/key.pem;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # don’t use SSLv3 ref: POODLE

    location / {
		# our gitlab runs in another docker container available at gitlab
        proxy_pass http://gitlab:80/;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $http_host;

        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forward-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forward-Proto http;
        proxy_set_header X-Nginx-Proxy true;

        proxy_redirect off;
    }

    location /pages {
        # Redirect http://gitlab.example.org/pages/MYGROUP/MYPROJECT
        # to http://gitlab.example.org/pages/MYGROUP/MYPROJECT/index.html
        # because without the "/" the second rewrite is not working
        rewrite   ^(/pages/[^/]+/[^/]+)$ $1/index.html permanent;
        # Proxy set header with rewrite example:
        # http://gitlab.example.org/pages/MYGROUP/MYPROJECT/index.html
        # to
        # http://gitlab.example.org/MYPROJECT/index.html with header "Host: MYGROUP.gitlab.example.org"
        # see doc here: http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass
        rewrite   ^/pages/([^/]+)/(.*)$ /$2 break;
        proxy_set_header Host $1.gitlab.example.org;

        proxy_pass http://gitlab:80/;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $http_host;

        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forward-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forward-Proto http;
        proxy_set_header X-Nginx-Proxy true;

        proxy_redirect off;
    }
}

The two important bits of the Nginx config are

    server_name ~^(?<subdomain>.*)\.gitlab.example.org$;
    rewrite ^/(.*)$ https://gitlab.example.org/pages/$subdomain/$1;

http://group.gitlab.example.org/project is redirected to https://gitlab.example.org/pages/group/project We reserved the name "pages" so no group "pages" can be used in our gitlab instance

and

    location /pages {
        # Redirect http://gitlab.example.org/pages/MYGROUP/MYPROJECT
        # to http://gitlab.example.org/pages/MYGROUP/MYPROJECT/index.html
        # because without the "/" the second rewrite is not working
        rewrite   ^(/pages/[^/]+/[^/]+)$ $1/index.html permanent;
        # Proxy set header with rewrite example:
        # http://gitlab.example.org/pages/MYGROUP/MYPROJECT/index.html
        # to
        # http://gitlab.example.org/MYPROJECT/index.html with header "Host: MYGROUP.gitlab.example.org"
        # see doc here: http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass
        rewrite   ^/pages/([^/]+)/(.*)$ /$2 break;
        proxy_set_header Host $1.gitlab.example.org;

I will describe each request with its http header Host to ease comprehension :

https://gitlab.example.org/pages/group/project

Host : gitlab.example.org

is proxyfied as http://gitlab.example.org/project

Host : group.gitlab.example.org

At this point the request hits the nginx bundled with gitlab that forwards it to the gitlab pages server (the correct Host http header is present). I don't know how to integrate into the bundled nginx but I thought it is worth sharing with the community.