Renovate Bot behind a proxy on GitLab CI

How to set up self-hosted Renovate on in a enterprise, corporate, proxy environment

Renovate Bot, or simply Renovate, is a multi-language, automatic dependency manager that updates dependencies by opening pull/merge requests to a repository. It offers many configuration options and supports common package managers for a lot of languages as well as Docker image upgrades. The main benefit of using Renovate is to keep dependencies up to date and stay notified of security updates. This article will focus on configuring Renovate to run on GitLab CI behind a proxy and using custom SSL certificates.

Base CI Pipeline

While Renovate can be run as part of a project's own CI pipeline, you likely want to run it for more than one project. For this reason, we create a separate repository for configuring and running Renovate. Each project can still override the default values by having its renovate.json in the root of the project.

The first step is to set up the repository in GitLab. Let's name it renovate-bot. Next, create a base configuration for Renovate and GitLab CI. Renovate provides a configuration for GitLab CI, but it will not suffice in this case. However, it is a good starting point. So let's start by configuring the CI in gitlab-ci.yml. I've taken the base configuration from Renovate and changed a few lines to keep things as simple as possible.

variables:
  RENOVATE_BASE_DIR: $CI_PROJECT_DIR/renovate
  RENOVATE_ENDPOINT: $CI_API_V4_URL
  RENOVATE_PLATFORM: gitlab
  RENOVATE_REPOSITORY_CACHE: 'enabled'
  LOG_LEVEL: debug

default:
  cache:
    key: ${CI_COMMIT_REF_SLUG}-renovate
    paths:
      - renovate/cache/renovate/repository/

renovate:
  # Check latest tag: https://hub.docker.com/r/renovate/renovate/tags
  image: renovate/renovate:34.84.2
  script:
    - renovate
  rules:
    - if: '$CI_PIPELINE_SOURCE == "schedule"'

Creating a scheduled CI job

The CI configuration is set to only run on scheduled jobs. To set up a schedule for your CI, in the left sidebar, go to "CI/CD" --> Schedules --> Press "New schedule". Give the schedule a name, for instance, "Run Renovate bot" and set the interval to 0 * * * * (translates to "Run on the first minute of every hour for every day, month, and day of the week")

Access to GitLab and GitHub

To be able to create MRs, Renovate will need to have access to your repositories. For this, we need to create a Personal Access Token (PAT) to GitLab that we pass to Renovate. While you can create a PAT from your own GitLab user, I would recommend creating a new user (you most likely want to create a Bot user) as otherwise all of the MRs that Renovate will create will look like they came from you for instance. In addition to this, we should also give it a PAT to GitHub. The reason for this is that Renovate checks GitHub sources for a lot of the package dependencies and scans for change logs. While this is possible to do without a PAT, it would lead to rate-limiting very fast as there are strict restrictions on API calls made without a PAT.
The PATs should be added as CI variables in the renovate project. CI variables can be found by, in the sidebar, going to "Settings" --> "CI/CD" and then expanding the "Variables" section.

  1. To create the PAT for yourself you can do that from https://<YOUR_GITLAB_URL>/-/profile/personal_access_tokens. The PAT needs to have at least the api scope, and according to Renovate the scopes read_user, api, write_repository are recommended.
    Add the token to a CI variable called RENOVATE_TOKEN.

  2. For GitHub, you can create a PAT at https://github.com/settings/tokens and select the Public Repositories (read-only) scope.
    Add the token to a CI variable called GITHUB_COM_TOKEN

Renovate configuration

Next, we create the base configuration for Renovate. This will be used as the default if nothing else is set by a project's renovate.json configuration.

module.exports = {
  onboardingConfig: {
    extends: [
      "config:base",
    ],
  },
  ignorePrAuthor: true
  gitAuthor: "RenovateBot <renovatebot@example.com>",
  baseBranches: ["master", "main"],
  labels: ["dependencies"],
  repositories: [
    "<YOUR REPOSITORY>",
  ],
};

This is again a pretty minimal configuration for Renovate and does not include any extras. One change you will need to make to the configuration is to add the repositories that you want to run Renovate on. The repositories can be added in the format <GROUP>/<REPOSITORY_NAME> , i.e acme/superproject.

And if you are not behind any proxies or use custom SSL certificates, then all you need to do now is run the scheduled CI job and you should see a Renovate onboarding merge request in your project.

Running behind a proxy

If you are behind a proxy you most likely also have a custom certificate for that proxy that you use. For this reason, we need to make two changes to our setup to make Renovate work. First, we need to pass the certificate to Renovate, and second, we need to pass the proxy URL to Renovate. Luckily, Renovate is not completely blind to people running behind a proxy and does have some documentation regarding how to set things up, but it is scattered across multiple places and hard to find environment variables.

Before we start, there are two things that you need that I can't help with. One is knowing the URL to your proxy and the other is having access to the certificate for that proxy. You can technically get everything done without the certificate, but that would mean turning off checking of certificates, which I do not recommend anyone to do and I will not be covering that in this article.

Whitelisting URLs

If you are behind a proxy that blocks everything that is not whitelisted you will want to add a few URLs. Star (*) denotes a wildcard for "anything", in the list below.

  • https://api.github.com/* (Used for fetching package information)

  • https://github.com/containerbase/* (Used for fetching language-specific binaries)

  • https://objects.githubusercontent.com/* (Used for downloading the containerbase tarballs)

These are just the base URLs that are called, in addition to this you will need to whitelist various sources depending on which package managers you need support for. For instance, for Docker, you would also need to add https://index.docker.io/v2/*.

Adding custom certificates

To get custom certificates into Renovate, we need to get those certificates into the running Renovate CI container. There are several ways to do this, such as injecting and building the cert chain at run time, mounting them, or injecting them into the Docker image at build time. The first two methods can be tricky, as the Docker image that Renovate is using does not run as root, meaning that you can't run commands such as update-ca-certificates. This may not be needed depending on what you check with Renovate, but it could be a deal breaker.

If you have your full cert chain somewhere mounted and have the separate non-standard certificates somewhere else, you could get it to work. In the CI configuration, set the NODE_EXTRA_CA_CERTS variable to point to your custom certificates. However, this will only help Node, and you might need other tools such as git when running Renovate, which would also need these certificates. To get those working, you would need to find their settings for setting extra certificates.

To have the least amount of things to set up, I would recommend creating a custom Docker image, based on the Renovate one. Renovate does document how to do this in the easiest way here. But it does not include the use case when we have more than one certificate, so let's modify what they have a bit.

# Dockerfile
FROM renovate/renovate:34.84.2

# Changes to the certificate authority require root permissions
USER root

# Copy and install the self signed certificates
COPY self-signed-certificate_1.crt /usr/local/share/ca-certificates/
COPY self-signed-certificate_2.crt /usr/local/share/ca-certificates/
RUN update-ca-certificates

# Combine all of the custom certificates
RUN cat /usr/local/share/ca-certificates/self-signed-certificate_1.crt /usr/local/share/ca-certificates/self-signed-certificate_1.crt /home/ubuntu/combined-self-signed-certificates.crt

# Change back to the Ubuntu user
USER 1000

# Node comes with an own certificate authority store and thus needs to trust the self-signed certificate explicitly
ENV NODE_EXTRA_CA_CERTS=/home/ubuntu/combined-self-signed-certificates.crt

The reason we need to combine the certificates here is that Node only accepts a single extra certificate and not a list of certificates.

We then need to build and push this image to a registry that you and the CI can access. This can be either GitLab's container registry, Dockerhub, or some other registry. How to do that is outside the scope of this article, but what you most likely will need to do is, and you most likely want to set up CI to build the image for you.

docker login <if_not_dockerhub_add_registry_url_here>
docker build -t <registry>/renovate:<same_tag_as_in_the_dockerfile> .
docker push <registry>/renovate:<same_tag_as_in_the_dockerfile>

Certificate bundles for other package managers

When Renovate updates packages for various languages and package managers it will do so with the specific package manager that it needs. Say you are using Python and pip then it would run pip to check packages.

You might be tempted to add environment variables to cert bundles the same way for these tools the same way as for Node. For instance, if you have Python requirements and are using pip you would need to set REQUESTS_CA_BUNDLE to point to /etc/ssl/certs/ca-certificates.crt . But this will not work the way one might expect it to. This is because Renovate does not run package managers in the same environment as Renovate itself, it runs a subprocess that does not have the same environment variables as what you have set in the Docker base environment.

To set environment variables that will be read by subprocesses of Renovate, we will have to set the RENOVATE_CUSTOM_ENV_VARIABLES variable and set it to a JS object with the environment variable name as the key and its value as the object value. So taking our pip example above, you would then everything in the Dockerfile as

RENOVATE_CUSTOM_ENV_VARIABLES={"REQUESTS_CA_BUNDLE":"/etc/ssl/certs/ca-certificates.crt"}

Adding proxy settings

If you are behind a proxy you already know about the environment variables http_proxy and https_proxy. These variable tells the OS to use the proxy assigned to the variables for all HTTP(S) traffic. These are the ones that we need to set for Renovate to work as well. There are several ways of doing this:

  1. Set the variables in GitLabs CI variables in GitLab.

  2. Set the variable in the gitlab-ci.yml file in the variables section of the renovate job.

  3. Set the variables globally for all CI jobs in the CI configuration.

  4. Set the variables as GitLab instance-level variables.

For 1. you need to add the variables "Settings" --> "CI/CD" and then expand the "Variables" section in either the renovate repository, or as group variables under the group that the Renovate project is in.

For 2. all you do is add the following to the CI configuration:

renovate:
  # Check latest tag: https://hub.docker.com/r/renovate/renovate/tags
  image: renovate/renovate:34.84.2
  script:
    - renovate
  rules:
    - if: '$CI_PIPELINE_SOURCE == "schedule"'
  variables:
    http_proxy: "<PROXY_URL>"
    https_proxy: "<PROXY_URL>"

For 3. you need to have access to the configuration of your CI runner. Then you need to change the environment setting in the CI runner configuration.

[[runners]]
  name = "<RUNNER_NAME>"
  url = "<YOUR_GITLAB_URL>"
  token = "<RUNNER_TOKEN>"
  executor = "docker"
  environment = ["https_proxy=<PROXY_URL>", "http_proxy=<PROXY_URL>>

You should now have a working CI job, that runs behind a proxy.