From f00413c298ad63e1ff0bf03d4dba7c1db3ca5be4 Mon Sep 17 00:00:00 2001
From: Rhys Arkins <rhys@arkins.net>
Date: Thu, 13 May 2021 22:53:18 +0200
Subject: [PATCH] feat(host-rules): use only matchHost (#9892)

Co-authored-by: Michael Kriese <michael.kriese@visualon.de>
---
 docs/usage/configuration-options.md           |  35 ++----
 docs/usage/docker.md                          |   4 +-
 docs/usage/java.md                            |   2 +-
 docs/usage/nuget.md                           |   2 +-
 docs/usage/php.md                             |   4 +-
 docs/usage/private-modules.md                 |  17 ++-
 docs/usage/private-npm-modules.md             |   8 +-
 docs/usage/self-hosted-configuration.md       |   2 +-
 docs/usage/setup-azure-devops.md              |   8 +-
 lib/config/__snapshots__/env.spec.ts.snap     |   2 +-
 .../__snapshots__/migration.spec.ts.snap      |  20 +++
 lib/config/cli.spec.ts                        |   4 +-
 lib/config/cli.ts                             |   4 +-
 lib/config/definitions.ts                     |  29 +----
 lib/config/env.ts                             |   2 +-
 lib/config/migration.spec.ts                  |  24 ++++
 lib/config/migration.ts                       |  13 +-
 lib/config/presets/internal/default.ts        |   8 +-
 lib/datasource/maven/index.spec.ts            |   4 +-
 lib/datasource/npm/get.spec.ts                |   6 +-
 lib/datasource/npm/index.spec.ts              |   4 +-
 lib/datasource/pypi/index.spec.ts             |   7 +-
 lib/logger/err-serializer.spec.ts             |   2 +-
 lib/manager/bundler/artifacts.spec.ts         |   8 +-
 lib/manager/bundler/host-rules.spec.ts        |  44 ++-----
 lib/manager/bundler/readme.md                 |   2 +-
 lib/manager/composer/artifacts.spec.ts        |   8 +-
 lib/manager/composer/artifacts.ts             |   2 +-
 lib/manager/git-submodules/extract.spec.ts    |   2 +-
 lib/manager/npm/post-update/index.ts          |   2 +-
 lib/platform/__snapshots__/index.spec.ts.snap |   4 +-
 lib/platform/azure/azure-got-wrapper.spec.ts  |   6 +-
 lib/platform/index.ts                         |   2 +-
 lib/types/host-rules.ts                       |   3 -
 .../__snapshots__/host-rules.spec.ts.snap     |   2 +-
 lib/util/host-rules.spec.ts                   |  36 +++---
 lib/util/host-rules.ts                        | 117 +++++-------------
 lib/util/http/bitbucket-server.spec.ts        |   2 +-
 lib/util/http/bitbucket.spec.ts               |   2 +-
 lib/util/http/index.spec.ts                   |   4 +-
 lib/workers/pr/changelog/github.spec.ts       |   6 +-
 lib/workers/pr/changelog/gitlab.spec.ts       |  18 +--
 lib/workers/pr/changelog/index.spec.ts        |   8 +-
 43 files changed, 207 insertions(+), 282 deletions(-)

diff --git a/docs/usage/configuration-options.md b/docs/usage/configuration-options.md
index dde6ef708c..3184ba17df 100644
--- a/docs/usage/configuration-options.md
+++ b/docs/usage/configuration-options.md
@@ -742,11 +742,10 @@ Example: If you have set `branchPrefix: "deps-"` and `hashedBranchLength: 12` it
 
 ## hostRules
 
-Currently the purpose of `hostRules` is to configure credentials for host authentication.
+The primary purpose of `hostRules` is to configure credentials for host authentication.
 You tell Renovate how to match against the host you need authenticated, and then you also tell it which credentials to use.
 
-The lookup keys for a hostRule are: `hostType`, `domainName`, `hostName`, and `baseUrl`.
-All are optional, but you can only have one of the last three per rule.
+The lookup keys for `hostRules` are: `hostType` and `matchHost`, both of which are optional.
 
 Supported credential fields are `token`, `username`, `password`, `timeout`, `enabled` and `insecureRegistry`.
 
@@ -756,7 +755,7 @@ Example for configuring `docker` auth:
 {
   "hostRules": [
     {
-      "domainName": "docker.io",
+      "matchHost": "docker.io",
       "username": "<some-username>",
       "password": "<some-password>"
     }
@@ -770,7 +769,7 @@ To disable requests to a particular host, you can configure a rule like:
 {
   "hostRules": [
     {
-      "hostName": "registry.npmjs.org",
+      "matchHost": "registry.npmjs.org",
       "enabled": false
     }
   ]
@@ -842,7 +841,7 @@ To abort Renovate for errors for a specific `docker` host:
 {
   "hostRules": [
     {
-      "hostName": "docker.company.com",
+      "matchHost": "docker.company.com",
       "abortOnError": true
     }
   ]
@@ -861,7 +860,7 @@ An example for npm basic auth with token:
 {
   "hostRules": [
     {
-      "domainName": "npm.custom.org",
+      "matchHost": "npm.custom.org",
       "token": "<some-token>",
       "authType": "Basic"
     }
@@ -871,13 +870,6 @@ An example for npm basic auth with token:
 
 This will generate the following header: `authorization: Basic <some-token>`.
 
-### baseUrl
-
-Use this instead of `domainName` or `hostName` if you need a rule to apply to a specific path on a host.
-For example, `"baseUrl": "https://api.github.com"` is equivalent to `"hostName": "api.github.com"` but `"baseUrl": "https://api.github.com/google/"` is not.
-
-Renovate does not do a "longest match" algorithm to pick between multiple matching `baseUrl` values in different rules, so put the longer `baseUrl` rule _after_ the shorter one in your `hostRules`.
-
 ### concurrentRequestLimit
 
 Usually the default setting is fine, but you can use `concurrentRequestLimit` to limit the number of concurrent outstanding requests.
@@ -890,29 +882,22 @@ Example config:
 {
   "hostRules": [
     {
-      "hostName": "github.com",
+      "matchHost": "github.com",
       "concurrentRequestLimit": 2
     }
   ]
 }
 ```
 
-### domainName
-
-If you have any uncertainty about exactly which hosts a service uses, then it can be more reliable to use `domainName` instead of `hostName` or `baseUrl`.
-e.g. configure `"hostName": "docker.io"` to cover both `index.docker.io` and `auth.docker.io` and any other host that's in use.
-
 ### enableHttp2
 
 Enable got [http2](https://github.com/sindresorhus/got/blob/v11.5.2/readme.md#http2) support.
 
-### hostName
-
 ### hostType
 
 `hostType` is another way to filter rules and can be either a platform such as `github` and `bitbucket-server`, or it can be a datasource such as `docker` and `rubygems`.
-You usually don't need to configure it in a host rule if you have already configured `domainName`, `hostName` or `baseUrl` and only one host type is in use for those, as is usually the case.
-`hostType` can help for cases like an enterprise registry that serves multiple package types and has different authentication for each, although it's often the case that multiple `baseUrl` rules could achieve the same thing.
+You usually don't need to configure it in a host rule if you have already configured `matchHost` and only one host type is in use for those, as is usually the case.
+`hostType` can help for cases like an enterprise registry that serves multiple package types and has different authentication for each, although it's often the case that multiple `matchHost` rules could achieve the same thing.
 
 ### insecureRegistry
 
@@ -927,7 +912,7 @@ Example:
 {
   "hostRules": [
     {
-      "hostName": "reg.insecure.com",
+      "matchHost": "reg.insecure.com",
       "insecureRegistry": true
     }
   ]
diff --git a/docs/usage/docker.md b/docs/usage/docker.md
index 005beb4d54..38a6cec386 100644
--- a/docs/usage/docker.md
+++ b/docs/usage/docker.md
@@ -198,7 +198,7 @@ module.exports = {
   hostRules: [
     {
       hostType: 'docker',
-      hostName: 'your.host.io',
+      matchHost: 'your.host.io',
       username: '<your-username>',
       password: process.env.SELF_HOSTED_DOCKER_IMAGES_PASSWORD,
     },
@@ -215,7 +215,7 @@ This is how you connect to a private Helm repository:
 module.exports = {
   hostRules: [
     {
-      hostName: 'your.host.io',
+      matchHost: 'your.host.io',
       username: '<your-username>',
       password: process.env.SELF_HOSTED_HELM_CHARTS_PASSWORD,
     },
diff --git a/docs/usage/java.md b/docs/usage/java.md
index 27c492555e..082501663d 100644
--- a/docs/usage/java.md
+++ b/docs/usage/java.md
@@ -46,7 +46,7 @@ module.exports = {
   hostRules: [
     {
       hostType: 'maven',
-      baseUrl: 'https://artifactory.yourcompany.com/',
+      matchHost: 'https://artifactory.yourcompany.com/',
       username: process.env.ARTIFACTORY_USERNAME,
       password: process.env.ARTIFACTORY_PASSWORD,
     },
diff --git a/docs/usage/nuget.md b/docs/usage/nuget.md
index d9a5dd1fa4..607c084a18 100644
--- a/docs/usage/nuget.md
+++ b/docs/usage/nuget.md
@@ -65,7 +65,7 @@ Credentials for authenticated/private feeds can be provided via host rules in th
 "hostRules": [
   {
     "hostType": "nuget",
-    "baseUrl": "http://example1.com/nuget",
+    "matchHost": "http://example1.com/nuget",
     "username": "root",
     "password": "p4$$w0rd"
   }
diff --git a/docs/usage/php.md b/docs/usage/php.md
index 275c1b5a5e..5634e6adc7 100644
--- a/docs/usage/php.md
+++ b/docs/usage/php.md
@@ -27,7 +27,7 @@ If you are using a [privately hosted Composer package](https://getcomposer.org/d
 {
   "hostRules": [
     {
-      "hostName": "some.vendor.com",
+      "matchHost": "some.vendor.com",
       "hostType": "packagist",
       "username": "<your-username>",
       "password": "<your-password>"
@@ -46,7 +46,7 @@ You may encrypt your `password` only, but you can encrypt your `username` as wel
 {
   "hostRules": [
     {
-      "hostName": "some.vendor.com",
+      "matchHost": "some.vendor.com",
       "hostType": "packagist",
       "encrypted": {
         "username": "<your-encrypted-password",
diff --git a/docs/usage/private-modules.md b/docs/usage/private-modules.md
index a694b8a13c..e12ef14ef8 100644
--- a/docs/usage/private-modules.md
+++ b/docs/usage/private-modules.md
@@ -56,15 +56,14 @@ If such a package is private, then Renovate must be configured with the relevant
 Renovate does not use any package managers for this step and performs all HTTP(S) lookups itself, including insertion of authentication headers.
 
 Configuring Renovate with credentials requires `hostRules`.
-Each host rule consists of a `hostType` value and/or a way to match against hosts using `baseUrl`, `hostName` or `domainName`.
+Each host rule consists of a `hostType` value and/or a way to match against hosts using `matchHost`.
 
 `hostType` is not particularly important at this step unless you have different credentials for the same host, however it is sometimes useful in later steps so is good to include if you can.
 It can be either a "platform" name (e.g. `github`, `azure`, etc) or a "datasource" name (e.g. `npm`, `maven`, `github-tags`, etc).
 
-`baseUrl` can be used if you want to only apply the credentials for a nested path within the host, e.g. `https://registry.company.com/nested/path/`.
-If the same credentials apply to all paths on a host, then use `hostName` instead, e.g. `registry.company.com`.
-Finally, to apply credentials to all hosts within the domain, use `domainName`, e.g. `company.com`.
-You need to pick _only one_ of these and not configure more than one of these fields within the same host rule, otherwise it will error.
+If you want to apply credentials only for a nested path within a host then write `matchHost` as a base URL like `https://registry.company.com/nested/path/`.
+If the same credentials apply to all paths on a host and not on any subdomains of it then configure `matchHost` with a protocol like `https://registry.company.com`.
+Finally, to apply credentials to all hosts within the domain, use a `matchHost` value with no `https://` prefix, e.g. `company.com` or `registry.company.com`, both of which would apply to a host like `beta.registry.company.com`.
 
 In addition to the above options to match against a host, you need to add the credentials.
 Typically they are either `token`, or `username` + `password`.
@@ -76,11 +75,11 @@ Here is an example of some host rules:
 {
   "hostRules": [
     {
-      "hostName": "registry.npmjs.org",
+      "matchHost": "registry.npmjs.org",
       "token": "abc123"
     },
     {
-      "baseUrl": "https://registry.company.com/pypi-simple/",
+      "matchHost": "https://registry.company.com/pypi-simple/",
       "username": "engineering",
       "password": "abc123"
     }
@@ -174,13 +173,13 @@ If you need to provide credentials to the hosted Renovate App, please do this:
 {
   "hostRules": [
     {
-      "hostName": "registry.npmjs.org",
+      "matchHost": "registry.npmjs.org",
       "encrypted": {
         "token": "3f832f2983yf89hsd98ahadsjfasdfjaslf............"
       }
     },
     {
-      "baseUrl": "https://custom.registry.company.com/pypi/",
+      "matchHost": "https://custom.registry.company.com/pypi/",
       "username": "bot1",
       "encrypted": {
         "password": "p278djfdsi9832jnfdshufwji2r389fdskj........."
diff --git a/docs/usage/private-npm-modules.md b/docs/usage/private-npm-modules.md
index 7512b37928..3eff4152c1 100644
--- a/docs/usage/private-npm-modules.md
+++ b/docs/usage/private-npm-modules.md
@@ -40,7 +40,7 @@ It's therefore better to provide Renovate with all the credentials it needs to l
 
 The recommended approaches in order of preference are:
 
-1. **Self-hosted hostRules**: Configure a hostRules entry in the bot's `config.js` with the `hostType`, `hostName` and `token` specified
+1. **Self-hosted hostRules**: Configure a hostRules entry in the bot's `config.js` with the `hostType`, `matchHost` and `token` specified
 1. **Renovate App with private modules from npmjs.org**: Add an encrypted `npmToken` to your Renovate config
 1. **Renovate App with a private registry**: Add an unencrypted `npmrc` plus an encrypted `npmToken` in config
 
@@ -55,12 +55,12 @@ module.exports = {
   hostRules: [
     {
       hostType: 'npm',
-      hostName: 'registry.npmjs.org',
+      matchHost: 'registry.npmjs.org',
       token: process.env.NPMJS_TOKEN,
     },
     {
       hostType: 'npm',
-      baseUrl:
+      matchHost:
         'https://pkgs.dev.azure.com/{organization}/_packaging/{feed}/npm/registry/',
       username: 'VssSessionToken',
       password: process.env.AZURE_NPM_TOKEN,
@@ -69,7 +69,7 @@ module.exports = {
       // https://www.jfrog.com/confluence/display/JFROG/npm+Registry
       // Will be passed as `//artifactory.my-company.com/artifactory/api/npm/npm:_auth=<TOKEN>` to `.npmrc`
       hostType: 'npm',
-      baseUrl: 'https://artifactory.my-company.com/artifactory/api/npm/npm',
+      matchHost: 'https://artifactory.my-company.com/artifactory/api/npm/npm',
       token: process.env.ARTIFACTORY_NPM_TOKEN,
       authType: 'Basic',
     },
diff --git a/docs/usage/self-hosted-configuration.md b/docs/usage/self-hosted-configuration.md
index 78ce9a7458..256560aef4 100644
--- a/docs/usage/self-hosted-configuration.md
+++ b/docs/usage/self-hosted-configuration.md
@@ -367,7 +367,7 @@ It could then be used in a repository config or preset like so:
 {
   "hostRules": [
     {
-      "domainName": "google.com",
+      "matchHost": "google.com",
       "token": "{{ secrets.GOOGLE_TOKEN }}"
     }
   ]
diff --git a/docs/usage/setup-azure-devops.md b/docs/usage/setup-azure-devops.md
index 1b8c20d159..047979889a 100644
--- a/docs/usage/setup-azure-devops.md
+++ b/docs/usage/setup-azure-devops.md
@@ -67,7 +67,7 @@ module.exports = {
   hostRules: [
     {
       hostType: 'npm',
-      hostName: 'pkgs.dev.azure.com',
+      matchHost: 'pkgs.dev.azure.com',
       username: 'apikey',
       password: process.env.TOKEN,
     },
@@ -82,7 +82,7 @@ For the `repositories` key, replace `YOUR-PROJECT/YOUR-REPO` with your Azure Dev
 ### Yarn users
 
 To do a succesfull `yarn install` you need to match the URL of the registry fully.
-Use the `baseUrl` config option to specify the full path to the registry.
+Use the `matchHost` config option to specify the full path to the registry.
 
 ```javascript
 module.exports = {
@@ -91,13 +91,13 @@ module.exports = {
   token: process.env.TOKEN,
   hostRules: [
     {
-      baseUrl:
+      matchHost:
         'https://myorg.pkgs.visualstudio.com/_packaging/myorg/npm/registry/',
       token: process.env.TOKEN,
       hostType: 'npm',
     },
     {
-      domainName: 'github.com',
+      matchHost: 'github.com',
       token: process.env.GITHUB_COM_TOKEN,
     },
   ],
diff --git a/lib/config/__snapshots__/env.spec.ts.snap b/lib/config/__snapshots__/env.spec.ts.snap
index a777b350fa..c33d6580cc 100644
--- a/lib/config/__snapshots__/env.spec.ts.snap
+++ b/lib/config/__snapshots__/env.spec.ts.snap
@@ -41,8 +41,8 @@ Object {
   "endpoint": "a ghe endpoint",
   "hostRules": Array [
     Object {
-      "domainName": "github.com",
       "hostType": "github",
+      "matchHost": "github.com",
       "token": "a github.com token",
     },
   ],
diff --git a/lib/config/__snapshots__/migration.spec.ts.snap b/lib/config/__snapshots__/migration.spec.ts.snap
index f1833e7c0c..6538b95026 100644
--- a/lib/config/__snapshots__/migration.spec.ts.snap
+++ b/lib/config/__snapshots__/migration.spec.ts.snap
@@ -1,5 +1,25 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
+exports[`config/migration it migrates hostRules fields 1`] = `
+Object {
+  "hostRules": Array [
+    Object {
+      "matchHost": "https://some.domain.com",
+      "token": "abc123",
+    },
+    Object {
+      "matchHost": "domain.com",
+      "token": "abc123",
+    },
+    Object {
+      "hostName": "some.domain.com",
+      "matchHost": "some.domain.com",
+      "token": "abc123",
+    },
+  ],
+}
+`;
+
 exports[`config/migration it migrates nested packageRules 1`] = `
 Object {
   "packageRules": Array [
diff --git a/lib/config/cli.spec.ts b/lib/config/cli.spec.ts
index 7e97cb21c5..b9e630c2c4 100644
--- a/lib/config/cli.spec.ts
+++ b/lib/config/cli.spec.ts
@@ -79,12 +79,12 @@ describe(getName(), () => {
     });
     it('parses json lists correctly', () => {
       argv.push(
-        `--host-rules=[{"domainName":"docker.io","hostType":"${datasourceDocker.id}","username":"user","password":"password"}]`
+        `--host-rules=[{"matchHost":"docker.io","hostType":"${datasourceDocker.id}","username":"user","password":"password"}]`
       );
       expect(cli.getConfig(argv)).toEqual({
         hostRules: [
           {
-            domainName: 'docker.io',
+            matchHost: 'docker.io',
             hostType: datasourceDocker.id,
             username: 'user',
             password: 'password',
diff --git a/lib/config/cli.ts b/lib/config/cli.ts
index 1c6c371de7..c00a9c0b30 100644
--- a/lib/config/cli.ts
+++ b/lib/config/cli.ts
@@ -21,8 +21,8 @@ export function getConfig(input: string[]): GlobalConfig {
         .replace('--expose-env', '--trust-level=high')
         .replace('--renovate-fork', '--include-forks')
         .replace('"platform":"', '"hostType":"')
-        .replace('"endpoint":"', '"baseUrl":"')
-        .replace('"host":"', '"hostName":"')
+        .replace('"endpoint":"', '"matchHost":"')
+        .replace('"host":"', '"matchHost":"')
     )
     .filter((a) => !a.startsWith('--git-fs'));
   const options = getOptions();
diff --git a/lib/config/definitions.ts b/lib/config/definitions.ts
index b844829aee..39ca97d184 100644
--- a/lib/config/definitions.ts
+++ b/lib/config/definitions.ts
@@ -1709,36 +1709,9 @@ const options: RenovateOptions[] = [
     cli: false,
     env: false,
   },
-  {
-    name: 'domainName',
-    description: 'Domain name for a host rule. e.g. "docker.io".',
-    type: 'string',
-    stage: 'repository',
-    parent: 'hostRules',
-    cli: false,
-    env: false,
-  },
-  {
-    name: 'hostName',
-    description: 'Hostname for a host rule. e.g. "index.docker.io".',
-    type: 'string',
-    stage: 'repository',
-    parent: 'hostRules',
-    cli: false,
-    env: false,
-  },
-  {
-    name: 'baseUrl',
-    description: 'baseUrl for a host rule. e.g. "https://api.github.com/".',
-    type: 'string',
-    stage: 'repository',
-    parent: 'hostRules',
-    cli: false,
-    env: false,
-  },
   {
     name: 'matchHost',
-    description: 'A host name or base URL to match against',
+    description: 'A domain name, host name or base URL to match against',
     type: 'string',
     stage: 'repository',
     parent: 'hostRules',
diff --git a/lib/config/env.ts b/lib/config/env.ts
index c27e092eea..fd960cbb75 100644
--- a/lib/config/env.ts
+++ b/lib/config/env.ts
@@ -81,7 +81,7 @@ export function getConfig(env: NodeJS.ProcessEnv): GlobalConfig {
   if (env.GITHUB_COM_TOKEN) {
     config.hostRules.push({
       hostType: PLATFORM_TYPE_GITHUB,
-      domainName: 'github.com',
+      matchHost: 'github.com',
       token: env.GITHUB_COM_TOKEN,
     });
   }
diff --git a/lib/config/migration.spec.ts b/lib/config/migration.spec.ts
index 7dcd84fbf2..34420eeecb 100644
--- a/lib/config/migration.spec.ts
+++ b/lib/config/migration.spec.ts
@@ -659,4 +659,28 @@ describe(getName(), () => {
     expect(migratedConfig).toMatchSnapshot();
     expect(migratedConfig.packageRules).toHaveLength(3);
   });
+  it('it migrates hostRules fields', () => {
+    const config: RenovateConfig = {
+      hostRules: [
+        {
+          baseUrl: 'https://some.domain.com',
+          token: 'abc123',
+        },
+        {
+          domainName: 'domain.com',
+          token: 'abc123',
+        },
+        {
+          hostName: 'some.domain.com',
+          token: 'abc123',
+        },
+      ],
+    } as any;
+    const { isMigrated, migratedConfig } = configMigration.migrateConfig(
+      config,
+      defaultConfig
+    );
+    expect(isMigrated).toBe(true);
+    expect(migratedConfig).toMatchSnapshot();
+  });
 });
diff --git a/lib/config/migration.ts b/lib/config/migration.ts
index 09bc1d87b1..e8338012ef 100644
--- a/lib/config/migration.ts
+++ b/lib/config/migration.ts
@@ -97,11 +97,20 @@ export function migrateConfig(
         migratedConfig.hostType = val;
         delete migratedConfig.platform;
       } else if (parentKey === 'hostRules' && key === 'endpoint') {
-        migratedConfig.baseUrl = val;
+        migratedConfig.matchHost ||= val;
         delete migratedConfig.endpoint;
       } else if (parentKey === 'hostRules' && key === 'host') {
-        migratedConfig.hostName = val;
+        migratedConfig.matchHost ||= val;
         delete migratedConfig.host;
+      } else if (parentKey === 'hostRules' && key === 'baseUrl') {
+        migratedConfig.matchHost ||= val;
+        delete migratedConfig.baseUrl;
+      } else if (parentKey === 'hostRules' && key === 'hostName') {
+        migratedConfig.matchHost ||= val;
+        delete migratedConfig.baseUrl;
+      } else if (parentKey === 'hostRules' && key === 'domainName') {
+        migratedConfig.matchHost ||= val;
+        delete migratedConfig.domainName;
       } else if (key === 'packageRules' && is.plainObject(val)) {
         migratedConfig.packageRules = is.array(migratedConfig.packageRules)
           ? migratedConfig.packageRules
diff --git a/lib/config/presets/internal/default.ts b/lib/config/presets/internal/default.ts
index b7829d5ebb..eb48c14c86 100644
--- a/lib/config/presets/internal/default.ts
+++ b/lib/config/presets/internal/default.ts
@@ -19,16 +19,16 @@ export const presets: Record<string, Preset> = {
     description: 'Disable requests to a particular domain',
     hostRules: [
       {
-        domainName: '{{arg0}}',
+        matchHost: '{{arg0}}',
         enabled: false,
       },
     ],
   },
   disableHost: {
-    description: 'Disable requests to a particular hostName',
+    description: 'Disable requests to a particular host',
     hostRules: [
       {
-        hostName: '{{arg0}}',
+        matchHost: 'https://{{arg0}}',
         enabled: false,
       },
     ],
@@ -555,7 +555,7 @@ export const presets: Record<string, Preset> = {
     description: 'Use provided token for github.com lookups',
     hostRules: [
       {
-        domainName: 'github.com',
+        matchHost: 'github.com',
         encrypted: {
           token: '{{arg0}}',
         },
diff --git a/lib/datasource/maven/index.spec.ts b/lib/datasource/maven/index.spec.ts
index 4448ff8f5c..868de5c27d 100644
--- a/lib/datasource/maven/index.spec.ts
+++ b/lib/datasource/maven/index.spec.ts
@@ -82,7 +82,7 @@ describe(getName(), () => {
   beforeEach(() => {
     hostRules.add({
       hostType: datasource,
-      hostName: 'custom.registry.renovatebot.com',
+      matchHost: 'custom.registry.renovatebot.com',
       token: 'abc123',
     });
     jest.resetAllMocks();
@@ -281,7 +281,7 @@ describe(getName(), () => {
 
     hostRules.add({
       hostType: datasource,
-      hostName: frontendHost,
+      matchHost: frontendHost,
       username: 'username',
       password: 'password',
       timeout: 20000,
diff --git a/lib/datasource/npm/get.spec.ts b/lib/datasource/npm/get.spec.ts
index ad56a801cd..0c444d8800 100644
--- a/lib/datasource/npm/get.spec.ts
+++ b/lib/datasource/npm/get.spec.ts
@@ -114,7 +114,7 @@ describe(getName(), () => {
     expect.assertions(1);
     const npmrc = `registry=https://test.org`;
     hostRules.add({
-      baseUrl: 'https://test.org',
+      matchHost: 'https://test.org',
       username: 'test',
       password: 'test',
     });
@@ -136,7 +136,7 @@ describe(getName(), () => {
     expect.assertions(1);
     const npmrc = ``;
     hostRules.add({
-      baseUrl: 'https://registry.npmjs.org',
+      matchHost: 'https://registry.npmjs.org',
       token: 'XXX',
     });
 
@@ -157,7 +157,7 @@ describe(getName(), () => {
     expect.assertions(1);
     const npmrc = ``;
     hostRules.add({
-      baseUrl: 'https://registry.npmjs.org',
+      matchHost: 'https://registry.npmjs.org',
       token: 'XXX',
       authType: 'Basic',
     });
diff --git a/lib/datasource/npm/index.spec.ts b/lib/datasource/npm/index.spec.ts
index a9869c62a3..cdfcf43fa0 100644
--- a/lib/datasource/npm/index.spec.ts
+++ b/lib/datasource/npm/index.spec.ts
@@ -271,7 +271,7 @@ describe(getName(), () => {
   it('should use host rules by hostName if provided', async () => {
     hostRules.add({
       hostType: 'npm',
-      hostName: 'npm.mycustomregistry.com',
+      matchHost: 'npm.mycustomregistry.com',
       token: 'abcde',
     });
     httpMock
@@ -289,7 +289,7 @@ describe(getName(), () => {
   it('should use host rules by baseUrl if provided', async () => {
     hostRules.add({
       hostType: 'npm',
-      baseUrl:
+      matchHost:
         'https://npm.mycustomregistry.com/_packaging/mycustomregistry/npm/registry/',
       token: 'abcde',
     });
diff --git a/lib/datasource/pypi/index.spec.ts b/lib/datasource/pypi/index.spec.ts
index 7254733ac0..880faa3bb0 100644
--- a/lib/datasource/pypi/index.spec.ts
+++ b/lib/datasource/pypi/index.spec.ts
@@ -82,7 +82,7 @@ describe(getName(), () => {
     });
 
     it('sets private if authorization privided', async () => {
-      hostRules.add({ hostName: 'customprivate.pypi.net', token: 'abc123' });
+      hostRules.add({ matchHost: 'customprivate.pypi.net', token: 'abc123' });
       httpMock
         .scope('https://customprivate.pypi.net/foo')
         .get('/azure-cli-monitor/json')
@@ -257,7 +257,10 @@ describe(getName(), () => {
       expect(httpMock.getTrace()).toMatchSnapshot();
     });
     it('sets private simple if authorization provided', async () => {
-      hostRules.add({ hostName: 'some.private.registry.org', token: 'abc123' });
+      hostRules.add({
+        matchHost: 'some.private.registry.org',
+        token: 'abc123',
+      });
       httpMock
         .scope('https://some.private.registry.org/+simple/')
         .get('/dj-database-url/')
diff --git a/lib/logger/err-serializer.spec.ts b/lib/logger/err-serializer.spec.ts
index 0e0ed66ea7..afb2d1d65d 100644
--- a/lib/logger/err-serializer.spec.ts
+++ b/lib/logger/err-serializer.spec.ts
@@ -43,7 +43,7 @@ describe(getName(), () => {
       hostRules.clear();
       hostRules.add({
         hostType: 'any',
-        baseUrl,
+        matchHost: baseUrl,
         token: 'token',
       });
     });
diff --git a/lib/manager/bundler/artifacts.spec.ts b/lib/manager/bundler/artifacts.spec.ts
index 58e5055efb..7b7ea59220 100644
--- a/lib/manager/bundler/artifacts.spec.ts
+++ b/lib/manager/bundler/artifacts.spec.ts
@@ -231,7 +231,7 @@ describe('bundler.updateArtifacts()', () => {
       bundlerHostRules.findAllAuthenticatable.mockReturnValue([
         {
           hostType: 'bundler',
-          hostName: 'gems.private.com',
+          matchHost: 'gems.private.com',
           resolvedHost: 'gems.private.com',
           username: 'some-user',
           password: 'some-password',
@@ -273,7 +273,7 @@ describe('bundler.updateArtifacts()', () => {
       bundlerHostRules.findAllAuthenticatable.mockReturnValue([
         {
           hostType: 'bundler',
-          hostName: 'gems-private.com',
+          matchHost: 'gems-private.com',
           resolvedHost: 'gems-private.com',
           username: 'some-user',
           password: 'some-password',
@@ -318,7 +318,7 @@ describe('bundler.updateArtifacts()', () => {
       bundlerHostRules.findAllAuthenticatable.mockReturnValue([
         {
           hostType: 'bundler',
-          hostName: 'gems-private.com',
+          matchHost: 'gems-private.com',
           resolvedHost: 'gems-private.com',
           username: 'some-user',
           password: 'some-password',
@@ -363,7 +363,7 @@ describe('bundler.updateArtifacts()', () => {
       bundlerHostRules.findAllAuthenticatable.mockReturnValue([
         {
           hostType: 'bundler',
-          hostName: 'gems-private.com',
+          matchHost: 'gems-private.com',
           resolvedHost: 'gems-private.com',
           username: 'some-user',
           password: 'some-password',
diff --git a/lib/manager/bundler/host-rules.spec.ts b/lib/manager/bundler/host-rules.spec.ts
index f1fe253861..bc8ca325b5 100644
--- a/lib/manager/bundler/host-rules.spec.ts
+++ b/lib/manager/bundler/host-rules.spec.ts
@@ -34,48 +34,32 @@ describe(getName(), () => {
     beforeEach(() => {
       hostRule = {
         hostType: 'nuget',
-        hostName: 'nuget.org',
-        domainName: 'api.nuget.org',
+        matchHost: 'nuget.org',
         username: 'root',
         password: 'p4$$w0rd',
         token: 'token',
       };
     });
-    it('returns an empty array if domainName, hostName and baseUrl are missing', () => {
-      delete hostRule.hostName;
-      delete hostRule.domainName;
-
+    it('returns an empty array if matchHost is missing', () => {
+      delete hostRule.matchHost;
       add(hostRule);
       expect(findAllAuthenticatable({ hostType: 'nuget' } as any)).toEqual([]);
     });
     it('returns an empty array if username is missing and password is present', () => {
-      delete hostRule.domainName;
       delete hostRule.username;
-      delete hostRule.password;
       delete hostRule.token;
 
       add(hostRule);
       expect(findAllAuthenticatable({ hostType: 'nuget' } as any)).toEqual([]);
     });
     it('returns an empty array if password and token are missing', () => {
-      delete hostRule.domainName;
       delete hostRule.password;
       delete hostRule.token;
 
       add(hostRule);
       expect(findAllAuthenticatable({ hostType: 'nuget' } as any)).toEqual([]);
     });
-    it('returns the hostRule if using hostName and password', () => {
-      delete hostRule.domainName;
-      delete hostRule.token;
-
-      add(hostRule);
-      expect(
-        findAllAuthenticatable({ hostType: 'nuget' } as any)
-      ).toMatchObject([hostRule]);
-    });
-    it('returns the hostRule if using domainName and password', () => {
-      delete hostRule.hostName;
+    it('returns the hostRule if using matchHost and password', () => {
       delete hostRule.token;
 
       add(hostRule);
@@ -83,17 +67,7 @@ describe(getName(), () => {
         findAllAuthenticatable({ hostType: 'nuget' } as any)
       ).toMatchObject([hostRule]);
     });
-    it('returns the hostRule if using hostName and token', () => {
-      delete hostRule.domainName;
-      delete hostRule.password;
-
-      add(hostRule);
-      expect(
-        findAllAuthenticatable({ hostType: 'nuget' } as any)
-      ).toMatchObject([hostRule]);
-    });
-    it('returns the hostRule if using domainName and token', () => {
-      delete hostRule.hostName;
+    it('returns the hostRule if using matchHost and token', () => {
       delete hostRule.password;
 
       add(hostRule);
@@ -102,9 +76,7 @@ describe(getName(), () => {
       ).toMatchObject([hostRule]);
     });
     it('returns the hostRule if using baseUrl and password', () => {
-      hostRule.baseUrl = 'https://nuget.com';
-      delete hostRule.domainName;
-      delete hostRule.hostName;
+      hostRule.matchHost = 'https://nuget.com';
 
       add(hostRule);
       expect(
@@ -112,9 +84,7 @@ describe(getName(), () => {
       ).toMatchObject([hostRule]);
     });
     it('returns the hostRule if using baseUrl and token', () => {
-      hostRule.baseUrl = 'https://nuget.com';
-      delete hostRule.hostName;
-      delete hostRule.domainName;
+      hostRule.matchHost = 'https://nuget.com';
 
       add(hostRule);
       expect(
diff --git a/lib/manager/bundler/readme.md b/lib/manager/bundler/readme.md
index 0b5f179017..dc27354b99 100644
--- a/lib/manager/bundler/readme.md
+++ b/lib/manager/bundler/readme.md
@@ -8,7 +8,7 @@ If you need Bundler to authenticate with a private registry - and it's not the s
 {
   "hostRules": [
     {
-      "hostName": "private-registry.company.com",
+      "matchHost": "private-registry.company.com",
       "hostType": "bundler",
       "token": "abc123"
     }
diff --git a/lib/manager/composer/artifacts.spec.ts b/lib/manager/composer/artifacts.spec.ts
index a4f7e8d6ce..a9082620ad 100644
--- a/lib/manager/composer/artifacts.spec.ts
+++ b/lib/manager/composer/artifacts.spec.ts
@@ -80,23 +80,23 @@ describe('.updateArtifacts()', () => {
   it('uses hostRules to set COMPOSER_AUTH', async () => {
     hostRules.add({
       hostType: PLATFORM_TYPE_GITHUB,
-      hostName: 'api.github.com',
+      matchHost: 'api.github.com',
       token: 'github-token',
     });
     hostRules.add({
       hostType: PLATFORM_TYPE_GITLAB,
-      hostName: 'gitlab.com',
+      matchHost: 'gitlab.com',
       token: 'gitlab-token',
     });
     hostRules.add({
       hostType: datasourcePackagist.id,
-      hostName: 'packagist.renovatebot.com',
+      matchHost: 'packagist.renovatebot.com',
       username: 'some-username',
       password: 'some-password',
     });
     hostRules.add({
       hostType: datasourcePackagist.id,
-      baseUrl: 'https://artifactory.yyyyyyy.com/artifactory/api/composer/',
+      matchHost: 'https://artifactory.yyyyyyy.com/artifactory/api/composer/',
       username: 'some-other-username',
       password: 'some-other-password',
     });
diff --git a/lib/manager/composer/artifacts.ts b/lib/manager/composer/artifacts.ts
index eee7d89949..ed430b707b 100644
--- a/lib/manager/composer/artifacts.ts
+++ b/lib/manager/composer/artifacts.ts
@@ -45,7 +45,7 @@ function getAuthJson(): string | null {
     .findAll({ hostType: PLATFORM_TYPE_GITLAB })
     ?.forEach((gitlabHostRule) => {
       if (gitlabHostRule?.token) {
-        const host = gitlabHostRule.hostName || 'gitlab.com';
+        const host = gitlabHostRule.resolvedHost || 'gitlab.com';
         authJson['gitlab-token'] = authJson['gitlab-token'] || {};
         authJson['gitlab-token'][host] = gitlabHostRule.token;
         // https://getcomposer.org/doc/articles/authentication-for-private-packages.md#gitlab-token
diff --git a/lib/manager/git-submodules/extract.spec.ts b/lib/manager/git-submodules/extract.spec.ts
index 2eabddfaa7..c277c84667 100644
--- a/lib/manager/git-submodules/extract.spec.ts
+++ b/lib/manager/git-submodules/extract.spec.ts
@@ -45,7 +45,7 @@ describe(getName(), () => {
   });
   describe('extractPackageFile()', () => {
     it('extracts submodules', async () => {
-      hostRules.add({ hostName: 'github.com', token: 'abc123' });
+      hostRules.add({ matchHost: 'github.com', token: 'abc123' });
       let res: PackageFile;
       expect(
         await extractPackageFile('', '.gitmodules.1', { localDir })
diff --git a/lib/manager/npm/post-update/index.ts b/lib/manager/npm/post-update/index.ts
index 8de797b7e2..e09018a449 100644
--- a/lib/manager/npm/post-update/index.ts
+++ b/lib/manager/npm/post-update/index.ts
@@ -428,7 +428,7 @@ export async function getAdditionalFiles(
   });
   for (const hostRule of npmHostRules) {
     if (hostRule.resolvedHost) {
-      let uri = hostRule.baseUrl || hostRule.matchHost || hostRule.resolvedHost;
+      let uri = hostRule.matchHost;
       uri = validateUrl(uri) ? uri.replace(/^https?:/, '') : `//${uri}/`;
       if (hostRule.token) {
         const key = hostRule.authType === 'Basic' ? '_auth' : '_authToken';
diff --git a/lib/platform/__snapshots__/index.spec.ts.snap b/lib/platform/__snapshots__/index.spec.ts.snap
index 3f2dbd6f9e..0774541c0c 100644
--- a/lib/platform/__snapshots__/index.spec.ts.snap
+++ b/lib/platform/__snapshots__/index.spec.ts.snap
@@ -8,8 +8,8 @@ Object {
   "gitAuthor": "user@domain.com",
   "hostRules": Array [
     Object {
-      "hostName": "api.bitbucket.org",
       "hostType": "bitbucket",
+      "matchHost": "api.bitbucket.org",
       "password": "123",
       "username": "abc",
     },
@@ -23,8 +23,8 @@ Object {
   "endpoint": "https://api.bitbucket.org/",
   "hostRules": Array [
     Object {
-      "hostName": "api.bitbucket.org",
       "hostType": "bitbucket",
+      "matchHost": "api.bitbucket.org",
       "password": "123",
       "username": "abc",
     },
diff --git a/lib/platform/azure/azure-got-wrapper.spec.ts b/lib/platform/azure/azure-got-wrapper.spec.ts
index 9cef708062..1c8800bb80 100644
--- a/lib/platform/azure/azure-got-wrapper.spec.ts
+++ b/lib/platform/azure/azure-got-wrapper.spec.ts
@@ -22,7 +22,7 @@ describe(getName(), () => {
       hostRules.add({
         hostType: PLATFORM_TYPE_AZURE,
         token: '1234567890123456789012345678901234567890123456789012',
-        baseUrl: 'https://dev.azure.com/renovate1',
+        matchHost: 'https://dev.azure.com/renovate1',
       });
       azure.setEndpoint('https://dev.azure.com/renovate1');
 
@@ -38,7 +38,7 @@ describe(getName(), () => {
       hostRules.add({
         hostType: PLATFORM_TYPE_AZURE,
         token: 'token',
-        baseUrl: 'https://dev.azure.com/renovate2',
+        matchHost: 'https://dev.azure.com/renovate2',
       });
       azure.setEndpoint('https://dev.azure.com/renovate2');
 
@@ -56,7 +56,7 @@ describe(getName(), () => {
         hostType: PLATFORM_TYPE_AZURE,
         username: 'user',
         password: 'pass',
-        baseUrl: 'https://dev.azure.com/renovate3',
+        matchHost: 'https://dev.azure.com/renovate3',
       });
       azure.setEndpoint('https://dev.azure.com/renovate3');
 
diff --git a/lib/platform/index.ts b/lib/platform/index.ts
index 1ed921fa67..33deb51533 100644
--- a/lib/platform/index.ts
+++ b/lib/platform/index.ts
@@ -115,7 +115,7 @@ export async function initPlatform(
 
   const platformRule: HostRule = {
     hostType: returnConfig.platform,
-    hostName: URL.parse(returnConfig.endpoint).hostname,
+    matchHost: URL.parse(returnConfig.endpoint).hostname,
   };
   ['token', 'username', 'password'].forEach((field) => {
     if (config[field]) {
diff --git a/lib/types/host-rules.ts b/lib/types/host-rules.ts
index 39ad48b56f..414a80cae6 100644
--- a/lib/types/host-rules.ts
+++ b/lib/types/host-rules.ts
@@ -1,9 +1,6 @@
 export interface HostRule {
   authType?: string;
   hostType?: string;
-  domainName?: string;
-  hostName?: string;
-  baseUrl?: string;
   matchHost?: string;
   token?: string;
   username?: string;
diff --git a/lib/util/__snapshots__/host-rules.spec.ts.snap b/lib/util/__snapshots__/host-rules.spec.ts.snap
index 615196fffe..f4d1483d24 100644
--- a/lib/util/__snapshots__/host-rules.spec.ts.snap
+++ b/lib/util/__snapshots__/host-rules.spec.ts.snap
@@ -38,8 +38,8 @@ Array [
 
 exports[`util/host-rules findAll() needs exact host matches 1`] = `
 Object {
-  "hostName": "nuget.org",
   "hostType": "nuget",
+  "matchHost": "nuget.org",
   "password": "p4$$w0rd",
   "resolvedHost": "nuget.org",
   "username": "root",
diff --git a/lib/util/host-rules.spec.ts b/lib/util/host-rules.spec.ts
index 0d8d3af789..d8bc898e7c 100644
--- a/lib/util/host-rules.spec.ts
+++ b/lib/util/host-rules.spec.ts
@@ -14,7 +14,7 @@ describe(getName(), () => {
           hostType: PLATFORM_TYPE_AZURE,
           domainName: 'github.com',
           hostName: 'api.github.com',
-        })
+        } as any)
       ).toThrow();
     });
     it('throws if both domainName and baseUrl', () => {
@@ -22,8 +22,8 @@ describe(getName(), () => {
         add({
           hostType: PLATFORM_TYPE_AZURE,
           domainName: 'github.com',
-          baseUrl: 'https://api.github.com',
-        })
+          matchHost: 'https://api.github.com',
+        } as any)
       ).toThrow();
     });
     it('throws if both hostName and baseUrl', () => {
@@ -31,16 +31,16 @@ describe(getName(), () => {
         add({
           hostType: PLATFORM_TYPE_AZURE,
           hostName: 'api.github.com',
-          baseUrl: 'https://api.github.com',
-        })
+          matchHost: 'https://api.github.com',
+        } as any)
       ).toThrow();
     });
     it('supports baseUrl-only', () => {
       add({
-        baseUrl: 'https://some.endpoint',
+        matchHost: 'https://some.endpoint',
         username: 'user1',
         password: 'pass1',
-      });
+      } as any);
       expect(find({ url: 'https://some.endpoint/v3/' })).toMatchSnapshot();
     });
   });
@@ -58,14 +58,14 @@ describe(getName(), () => {
         username: 'root',
         password: 'p4$$w0rd',
         token: undefined,
-      });
+      } as any);
       expect(find({ hostType: datasourceNuget.id })).toMatchSnapshot();
       expect(
         find({ hostType: datasourceNuget.id, url: 'https://nuget.org' })
       ).not.toEqual({});
       expect(
         find({ hostType: datasourceNuget.id, url: 'https://not.nuget.org' })
-      ).toEqual({});
+      ).not.toEqual({});
       expect(
         find({ hostType: datasourceNuget.id, url: 'https://not-nuget.org' })
       ).toEqual({});
@@ -91,7 +91,7 @@ describe(getName(), () => {
       add({
         domainName: 'github.com',
         token: 'def',
-      });
+      } as any);
       expect(
         find({ hostType: datasourceNuget.id, url: 'https://api.github.com' })
           .token
@@ -108,7 +108,7 @@ describe(getName(), () => {
       add({
         hostName: 'nuget.local',
         token: 'abc',
-      });
+      } as any);
       expect(
         find({ hostType: datasourceNuget.id, url: 'https://nuget.local/api' })
       ).toMatchSnapshot();
@@ -139,9 +139,9 @@ describe(getName(), () => {
     it('matches on hostType and endpoint', () => {
       add({
         hostType: datasourceNuget.id,
-        baseUrl: 'https://nuget.local/api',
+        matchHost: 'https://nuget.local/api',
         token: 'abc',
-      });
+      } as any);
       expect(
         find({ hostType: datasourceNuget.id, url: 'https://nuget.local/api' })
           .token
@@ -150,9 +150,9 @@ describe(getName(), () => {
     it('matches on endpoint subresource', () => {
       add({
         hostType: datasourceNuget.id,
-        baseUrl: 'https://nuget.local/api',
+        matchHost: 'https://nuget.local/api',
         token: 'abc',
-      });
+      } as any);
       expect(
         find({
           hostType: datasourceNuget.id,
@@ -167,14 +167,14 @@ describe(getName(), () => {
       });
       add({
         hostType: datasourceNuget.id,
-        baseUrl: 'https://nuget.local/api',
+        matchHost: 'https://nuget.local/api',
         token: 'abc',
-      });
+      } as any);
       add({
         hostType: datasourceNuget.id,
         hostName: 'my.local.registry',
         token: 'def',
-      });
+      } as any);
       add({
         hostType: datasourceNuget.id,
         matchHost: 'another.local.registry',
diff --git a/lib/util/host-rules.ts b/lib/util/host-rules.ts
index 895766cec3..79190b06c0 100644
--- a/lib/util/host-rules.ts
+++ b/lib/util/host-rules.ts
@@ -1,4 +1,3 @@
-import URL from 'url';
 import merge from 'deepmerge';
 import { logger } from '../logger';
 import { HostRule } from '../types';
@@ -8,47 +7,54 @@ import { parseUrl, validateUrl } from './url';
 
 let hostRules: HostRule[] = [];
 
-const matchFields = ['matchHost', 'hostName', 'domainName', 'baseUrl'];
+const legacyHostFields = ['hostName', 'domainName', 'baseUrl'];
 
 export function add(params: HostRule): void {
-  const matchedFields = matchFields.filter((field) => params[field]);
-  if (matchedFields.length > 1) {
-    throw new Error(
-      `hostRules cannot contain more than one host-matching field. Found: [${matchedFields.join(
-        ', '
-      )}]`
+  const rule = clone(params);
+  const matchedFields = legacyHostFields.filter((field) => rule[field]);
+  if (matchedFields.length) {
+    logger.warn(
+      `Legacy hostRules fields ${matchedFields.join(
+        '+'
+      )} should be migrated to "matchHost"`
     );
+    if (rule.matchHost || matchedFields.length > 1) {
+      matchedFields.push('matchHost');
+      throw new Error(
+        `hostRules cannot contain more than one host-matching field - use "matchHost" only. Found: [${matchedFields.join(
+          ', '
+        )}]`
+      );
+    }
+    rule.matchHost = rule[matchedFields[0]];
+    delete rule[matchedFields[0]];
   }
+
   const confidentialFields = ['password', 'token'];
-  let resolvedHost =
-    params.baseUrl || params.hostName || params.domainName || params.matchHost;
-  if (resolvedHost) {
-    resolvedHost = URL.parse(resolvedHost).hostname || resolvedHost;
+  if (rule.matchHost) {
+    const parsedUrl = parseUrl(rule.matchHost);
+    rule.resolvedHost = parsedUrl?.hostname || rule.matchHost;
     confidentialFields.forEach((field) => {
-      if (params[field]) {
+      if (rule[field]) {
         logger.debug(
-          `Adding ${field} authentication for ${resolvedHost} to hostRules`
+          `Adding ${field} authentication for ${rule.matchHost} to hostRules`
         );
       }
     });
   }
   confidentialFields.forEach((field) => {
-    const secret = params[field];
+    const secret = rule[field];
     if (secret && secret.length > 3) {
       sanitize.add(secret);
     }
   });
-  if (params.username && params.password) {
-    const secret = Buffer.from(
-      `${params.username}:${params.password}`
-    ).toString('base64');
+  if (rule.username && rule.password) {
+    const secret = Buffer.from(`${rule.username}:${rule.password}`).toString(
+      'base64'
+    );
     sanitize.add(secret);
   }
-  const hostRule = clone(params);
-  if (resolvedHost) {
-    hostRule.resolvedHost = resolvedHost;
-  }
-  hostRules.push(hostRule);
+  hostRules.push(rule);
 }
 
 export interface HostRuleSearch {
@@ -64,18 +70,6 @@ function isHostTypeRule(rule: HostRule): boolean {
   return rule.hostType && !rule.resolvedHost;
 }
 
-function isDomainNameRule(rule: HostRule): boolean {
-  return !rule.hostType && !!rule.domainName;
-}
-
-function isHostNameRule(rule: HostRule): boolean {
-  return !rule.hostType && !!rule.hostName;
-}
-
-function isBaseUrlRule(rule: HostRule): boolean {
-  return !rule.hostType && !!rule.baseUrl;
-}
-
 function isHostOnlyRule(rule: HostRule): boolean {
   return !rule.hostType && !!rule.matchHost;
 }
@@ -88,32 +82,7 @@ function matchesHostType(rule: HostRule, search: HostRuleSearch): boolean {
   return rule.hostType === search.hostType;
 }
 
-function matchesDomainName(rule: HostRule, search: HostRuleSearch): boolean {
-  const hostname = search.url && URL.parse(search.url).hostname;
-  return (
-    search.url &&
-    rule.domainName &&
-    hostname &&
-    (hostname === rule.domainName || hostname.endsWith(`.${rule.domainName}`))
-  );
-}
-
-function matchesHostName(rule: HostRule, search: HostRuleSearch): boolean {
-  return (
-    search.url &&
-    rule.hostName &&
-    URL.parse(search.url).hostname === rule.hostName
-  );
-}
-
-function matchesBaseUrl(rule: HostRule, search: HostRuleSearch): boolean {
-  return search.url && rule.baseUrl && search.url.startsWith(rule.baseUrl);
-}
-
 function matchesHost(rule: HostRule, search: HostRuleSearch): boolean {
-  if (!rule.matchHost) {
-    return false;
-  }
   if (validateUrl(rule.matchHost)) {
     return search.url.startsWith(rule.matchHost);
   }
@@ -143,24 +112,6 @@ export function find(search: HostRuleSearch): HostRule {
     .forEach((rule) => {
       res = merge(res, rule);
     });
-  // Next, find domainName-only matches
-  hostRules
-    .filter((rule) => isDomainNameRule(rule) && matchesDomainName(rule, search))
-    .forEach((rule) => {
-      res = merge(res, rule);
-    });
-  // Next, find hostName-only matches
-  hostRules
-    .filter((rule) => isHostNameRule(rule) && matchesHostName(rule, search))
-    .forEach((rule) => {
-      res = merge(res, rule);
-    });
-  // Next, find baseUrl-only matches
-  hostRules
-    .filter((rule) => isBaseUrlRule(rule) && matchesBaseUrl(rule, search))
-    .forEach((rule) => {
-      res = merge(res, rule);
-    });
   hostRules
     .filter((rule) => isHostOnlyRule(rule) && matchesHost(rule, search))
     .forEach((rule) => {
@@ -172,18 +123,12 @@ export function find(search: HostRuleSearch): HostRule {
       (rule) =>
         isMultiRule(rule) &&
         matchesHostType(rule, search) &&
-        (matchesDomainName(rule, search) ||
-          matchesHost(rule, search) ||
-          matchesHostName(rule, search) ||
-          matchesBaseUrl(rule, search))
+        matchesHost(rule, search)
     )
     .forEach((rule) => {
       res = merge(res, rule);
     });
   delete res.hostType;
-  delete res.domainName;
-  delete res.hostName;
-  delete res.baseUrl;
   delete res.resolvedHost;
   delete res.matchHost;
   return res;
diff --git a/lib/util/http/bitbucket-server.spec.ts b/lib/util/http/bitbucket-server.spec.ts
index efd46a0ac1..f93832f00b 100644
--- a/lib/util/http/bitbucket-server.spec.ts
+++ b/lib/util/http/bitbucket-server.spec.ts
@@ -18,7 +18,7 @@ describe(getName(), () => {
     hostRules.clear();
     hostRules.add({
       hostType: PLATFORM_TYPE_BITBUCKET_SERVER,
-      baseUrl,
+      matchHost: baseUrl,
       token: 'token',
     });
 
diff --git a/lib/util/http/bitbucket.spec.ts b/lib/util/http/bitbucket.spec.ts
index 2ee810f52b..3c17426d8e 100644
--- a/lib/util/http/bitbucket.spec.ts
+++ b/lib/util/http/bitbucket.spec.ts
@@ -18,7 +18,7 @@ describe(getName(), () => {
     hostRules.clear();
     hostRules.add({
       hostType: PLATFORM_TYPE_BITBUCKET,
-      baseUrl,
+      matchHost: baseUrl,
       token: 'token',
     });
 
diff --git a/lib/util/http/index.spec.ts b/lib/util/http/index.spec.ts
index f4bf4fe2c7..8915a8a6dd 100644
--- a/lib/util/http/index.spec.ts
+++ b/lib/util/http/index.spec.ts
@@ -40,7 +40,7 @@ describe(getName(), () => {
     expect(nock.isDone()).toBe(true);
   });
   it('disables hosts', async () => {
-    hostRules.add({ hostName: 'renovate.com', enabled: false });
+    hostRules.add({ matchHost: 'renovate.com', enabled: false });
     await expect(http.get('http://renovate.com/test')).rejects.toThrow(
       HOST_DISABLED
     );
@@ -135,7 +135,7 @@ describe(getName(), () => {
   });
 
   it('limits concurrency by host', async () => {
-    hostRules.add({ hostName: 'renovate.com', concurrentRequestLimit: 1 });
+    hostRules.add({ matchHost: 'renovate.com', concurrentRequestLimit: 1 });
 
     let foo = false;
     let bar = false;
diff --git a/lib/workers/pr/changelog/github.spec.ts b/lib/workers/pr/changelog/github.spec.ts
index 9a8cf92ec6..7a25c62c73 100644
--- a/lib/workers/pr/changelog/github.spec.ts
+++ b/lib/workers/pr/changelog/github.spec.ts
@@ -35,7 +35,7 @@ describe(getName(), () => {
       hostRules.clear();
       hostRules.add({
         hostType: PLATFORM_TYPE_GITHUB,
-        baseUrl: 'https://api.github.com/',
+        matchHost: 'https://api.github.com/',
         token: 'abc',
       });
     });
@@ -146,7 +146,7 @@ describe(getName(), () => {
       hostRules.add({
         hostType: PLATFORM_TYPE_GITHUB,
         token: 'super_secret',
-        baseUrl: 'https://github-enterprise.example.com/',
+        matchHost: 'https://github-enterprise.example.com/',
       });
       expect(
         await getChangeLogJSON({
@@ -158,7 +158,7 @@ describe(getName(), () => {
     it('supports github enterprise and github enterprise changelog', async () => {
       hostRules.add({
         hostType: PLATFORM_TYPE_GITHUB,
-        baseUrl: 'https://github-enterprise.example.com/',
+        matchHost: 'https://github-enterprise.example.com/',
         token: 'abc',
       });
       process.env.GITHUB_ENDPOINT = '';
diff --git a/lib/workers/pr/changelog/gitlab.spec.ts b/lib/workers/pr/changelog/gitlab.spec.ts
index 2144c81d88..b629a1f8c6 100644
--- a/lib/workers/pr/changelog/gitlab.spec.ts
+++ b/lib/workers/pr/changelog/gitlab.spec.ts
@@ -29,7 +29,7 @@ const upgrade: BranchUpgradeConfig = {
   ],
 };
 
-const baseUrl = 'https://gitlab.com/';
+const matchHost = 'https://gitlab.com/';
 
 describe(getName(), () => {
   describe('getChangeLogJSON', () => {
@@ -38,7 +38,7 @@ describe(getName(), () => {
       hostRules.clear();
       hostRules.add({
         hostType: PLATFORM_TYPE_GITLAB,
-        baseUrl,
+        matchHost,
         token: 'abc',
       });
     });
@@ -46,7 +46,7 @@ describe(getName(), () => {
       httpMock.reset();
     });
     it('returns null if @types', async () => {
-      httpMock.scope(baseUrl);
+      httpMock.scope(matchHost);
       expect(
         await getChangeLogJSON({
           ...upgrade,
@@ -56,7 +56,7 @@ describe(getName(), () => {
       expect(httpMock.getTrace()).toBeEmpty();
     });
     it('returns null if currentVersion equals newVersion', async () => {
-      httpMock.scope(baseUrl);
+      httpMock.scope(matchHost);
       expect(
         await getChangeLogJSON({
           ...upgrade,
@@ -83,7 +83,7 @@ describe(getName(), () => {
     });
     it('uses GitLab tags', async () => {
       httpMock
-        .scope(baseUrl)
+        .scope(matchHost)
         .get('/api/v4/projects/meno%2fdropzone/repository/tags?per_page=100')
         .reply(200, [
           { name: 'v5.2.0' },
@@ -108,7 +108,7 @@ describe(getName(), () => {
     });
     it('handles empty GitLab tags response', async () => {
       httpMock
-        .scope(baseUrl)
+        .scope(matchHost)
         .get('/api/v4/projects/meno%2fdropzone/repository/tags?per_page=100')
         .reply(200, [])
         .persist()
@@ -126,7 +126,7 @@ describe(getName(), () => {
     });
     it('uses GitLab tags with error', async () => {
       httpMock
-        .scope(baseUrl)
+        .scope(matchHost)
         .get('/api/v4/projects/meno%2fdropzone/repository/tags?per_page=100')
         .replyWithError('Unknown GitLab Repo')
         .persist()
@@ -177,7 +177,7 @@ describe(getName(), () => {
     it('supports gitlab enterprise and gitlab enterprise changelog', async () => {
       hostRules.add({
         hostType: PLATFORM_TYPE_GITLAB,
-        baseUrl: 'https://gitlab-enterprise.example.com/',
+        matchHost: 'https://gitlab-enterprise.example.com/',
         token: 'abc',
       });
       process.env.GITHUB_ENDPOINT = '';
@@ -193,7 +193,7 @@ describe(getName(), () => {
       httpMock.scope('https://git.test.com').persist().get(/.*/).reply(200, []);
       hostRules.add({
         hostType: PLATFORM_TYPE_GITLAB,
-        baseUrl: 'https://git.test.com/',
+        matchHost: 'https://git.test.com/',
         token: 'abc',
       });
       process.env.GITHUB_ENDPOINT = '';
diff --git a/lib/workers/pr/changelog/index.spec.ts b/lib/workers/pr/changelog/index.spec.ts
index e461f91f2b..62a2e9e297 100644
--- a/lib/workers/pr/changelog/index.spec.ts
+++ b/lib/workers/pr/changelog/index.spec.ts
@@ -38,7 +38,7 @@ describe(getName(), () => {
       hostRules.clear();
       hostRules.add({
         hostType: PLATFORM_TYPE_GITHUB,
-        baseUrl: 'https://api.github.com/',
+        matchHost: 'https://api.github.com/',
         token: 'abc',
       });
     });
@@ -194,7 +194,7 @@ describe(getName(), () => {
       hostRules.add({
         hostType: PLATFORM_TYPE_GITHUB,
         token: 'super_secret',
-        baseUrl: 'https://github-enterprise.example.com/',
+        matchHost: 'https://github-enterprise.example.com/',
       });
       expect(
         await getChangeLogJSON({
@@ -212,7 +212,7 @@ describe(getName(), () => {
         .reply(200, []);
       hostRules.add({
         hostType: PLATFORM_TYPE_GITHUB,
-        baseUrl: 'https://github-enterprise.example.com/',
+        matchHost: 'https://github-enterprise.example.com/',
         token: 'abc',
       });
       process.env.GITHUB_ENDPOINT = '';
@@ -234,7 +234,7 @@ describe(getName(), () => {
         .reply(200, []);
       hostRules.add({
         hostType: PLATFORM_TYPE_GITHUB,
-        baseUrl: 'https://github-enterprise.example.com/',
+        matchHost: 'https://github-enterprise.example.com/',
         token: 'abc',
       });
       expect(
-- 
GitLab