Using Gitlab Nginx as SSL Reverse Proxy

2019-03-01

Gitlab bundles nginx as a web server. It can also be used as a reverse proxy to host other services while listening on the same port and make use of other SSL certificates.

We assume that Gitlab is installed correctly and working. Custom nginx configuration files will be stored in /etc/nginx/conf.d/ for a custom domain sub.example.com which also refers to the IP where Gitlab is installed. Let’s encrypt will be used to obtain the SSL certificate. The following configuration is for Debian 9 (stretch), but can be modified easily for other distributions.

Set up a basic domain

  • Edit /etc/gitlab/gitlab.rb to add a custom nginx config for all files in /etc/nginx/conf.d/:
    nginx['custom_nginx_config'] = "include /etc/nginx/conf.d/*.conf;"
  • Create the domain file for sub.example.com in /etc/nginx/conf.d/sub.example.conf:
    server {
        listen 80;
        listen [::]:80;
    
        root /var/www/sub.example.com/html;
        index index.html index.htm index.nginx-debian.html;
    
        server_name sub.example.com;
    
        location ^~ /.well-known/acme-challenge {
            allow all;
            root /var/www/sub.example.com/html/;
        }
    }
  • Create the directory /var/www/sub.example.com/html
  • Restart Gitlab nginx: sudo gitlab-ctl restart nginx
  • Make sure http://sub.example.com is responding on port 80

Obtain an SSL certificate for the domain

  • Add certbot sources list in /etc/apt/sources.list to obtain ssl certificates:
    deb http://deb.debian.org/debian stretch-backports main contrib non-free
  • Install certbot: sudo apt install certbot -t stretch-backports
  • Run certbot for sub.example.com:
    $ sudo certbot certonly --webroot -w /var/www/sub.example.com/html/ -d sub.example.com
    To add other domains at the same time, append them on the command line:
    $ sudo certbot certonly --webroot -w /var/www/sub0.example.com/html/ -d sub0.example.com -w /var/www/sub1.example.com/html/ -d sub1.example.com
  • Once the certificate is obtained, update the nginx configuration for the domain in /etc/nginx/conf.d/sub.example.conf to activate SSL, replace ${SERVICE_URL} by the hosted service (http://127.0.0.1:8080 for example):
    server {
        listen 80;
        listen [::]:80;
    
        root /var/www/sub.example.com/html;
        index index.html index.htm index.nginx-debian.html;
    
        server_name sub.example.com;
    
        return 301 https://$host$request_uri;
    
        location ^~ /.well-known/acme-challenge {
            allow all;
            root /var/www/sub.example.com/html/;
        }
    }
    
    server {
        listen 443 ssl;
        server_name sub.example.com;
        ssl_certificate /etc/letsencrypt/live/sub.example.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/sub.example.com/privkey.pem;
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers HIGH:!aNULL:!MD5;
        location / {
            proxy_pass ${SERVICE_URL};
        }
        location ^~ /.well-known/acme-challenge {
            allow all;
            root /var/www/sub.example.com/html/;
        }
    }
  • Restart Gitlab nginx: sudo gitlab-ctl restart nginx
  • Test the service is working properly with https
  • Check the renewal is working properly: sudo certbot renew --dry-run
  • Add the renewal to a crontab with sudo crontab -e:
    30 5 * * 1 certbot renew -q --deploy-hook="gitlab-ctl restart nginx"