diff --git a/lib/config/common.ts b/lib/config/common.ts
index e01092a96301291f7ba2fe4b4becbcfe107a3869..86032544dde66530a0ed9c794ad6a71e5b8e9e3e 100644
--- a/lib/config/common.ts
+++ b/lib/config/common.ts
@@ -170,6 +170,9 @@ export interface RenovateConfig
   packageRules?: PackageRule[];
   prConcurrentLimit?: number;
   prHourlyLimit?: number;
+
+  registryUrls?: string[];
+
   repoIsOnboarded?: boolean;
 
   updateType?: UpdateType;
diff --git a/lib/datasource/github-releases/index.ts b/lib/datasource/github-releases/index.ts
index a5b882b30c03bc26ff46a547870acf0ded270ed5..10359bf41b865af52b30239111932774c5f53477 100644
--- a/lib/datasource/github-releases/index.ts
+++ b/lib/datasource/github-releases/index.ts
@@ -1,14 +1,21 @@
-import URL from 'url';
 import * as packageCache from '../../util/cache/package';
 import { GithubHttp } from '../../util/http/github';
+import { ensureTrailingSlash } from '../../util/url';
 import { GetReleasesConfig, ReleaseResult } from '../common';
 
 export const id = 'github-releases';
+export const defaultRegistryUrls = ['https://github.com'];
+export const registryStrategy = 'first';
 
 const cacheNamespace = 'datasource-github-releases';
 
 const http = new GithubHttp();
 
+function getCacheKey(depHost: string, repo: string): string {
+  const type = 'tags';
+  return `${depHost}:${repo}:${type}`;
+}
+
 type GithubRelease = {
   tag_name: string;
   published_at: string;
@@ -27,27 +34,32 @@ type GithubRelease = {
  */
 export async function getReleases({
   lookupName: repo,
-  registryUrl: depHost,
+  registryUrl,
 }: GetReleasesConfig): Promise<ReleaseResult | null> {
   const cachedResult = await packageCache.get<ReleaseResult>(
     cacheNamespace,
-    repo
+    getCacheKey(registryUrl, repo)
   );
   // istanbul ignore if
   if (cachedResult) {
     return cachedResult;
   }
-  const sourceUrlBase = depHost ?? `https://github.com/`;
-  const apiBaseUrl = depHost
-    ? URL.resolve(depHost, 'api/v3/')
-    : `https://api.github.com/`;
-  const url = URL.resolve(apiBaseUrl, `repos/${repo}/releases?per_page=100`);
+  // default to GitHub.com if no GHE host is specified.
+  const sourceUrlBase = ensureTrailingSlash(
+    registryUrl ?? 'https://github.com/'
+  );
+  const apiBaseUrl =
+    sourceUrlBase !== 'https://github.com/'
+      ? `${sourceUrlBase}api/v3/`
+      : `https://api.github.com/`;
+
+  const url = `${apiBaseUrl}repos/${repo}/releases?per_page=100`;
   const res = await http.getJson<GithubRelease[]>(url, {
     paginate: true,
   });
   const githubReleases = res.body;
   const dependency: ReleaseResult = {
-    sourceUrl: URL.resolve(sourceUrlBase, repo),
+    sourceUrl: `${sourceUrlBase}${repo}`,
     releases: null,
   };
   dependency.releases = githubReleases.map(
@@ -59,6 +71,11 @@ export async function getReleases({
     })
   );
   const cacheMinutes = 10;
-  await packageCache.set(cacheNamespace, repo, dependency, cacheMinutes);
+  await packageCache.set(
+    cacheNamespace,
+    getCacheKey(registryUrl, repo),
+    dependency,
+    cacheMinutes
+  );
   return dependency;
 }
diff --git a/lib/datasource/github-tags/__snapshots__/index.spec.ts.snap b/lib/datasource/github-tags/__snapshots__/index.spec.ts.snap
index 48cbabcbbfda162881e21fbe7ce3a2f1d914a58d..380e0f5ed2487ab748b340805f114e59f349badd 100644
--- a/lib/datasource/github-tags/__snapshots__/index.spec.ts.snap
+++ b/lib/datasource/github-tags/__snapshots__/index.spec.ts.snap
@@ -91,6 +91,33 @@ Array [
 ]
 `;
 
+exports[`datasource/github-tags getDigest supports ghe 1`] = `
+Array [
+  Object {
+    "headers": Object {
+      "accept": "application/vnd.github.v3+json",
+      "accept-encoding": "gzip, deflate",
+      "authorization": "token some-token",
+      "host": "git.enterprise.com",
+      "user-agent": "https://github.com/renovatebot/renovate",
+    },
+    "method": "GET",
+    "url": "https://git.enterprise.com/api/v3/repos/some/dep/commits?per_page=1",
+  },
+  Object {
+    "headers": Object {
+      "accept": "application/vnd.github.v3+json",
+      "accept-encoding": "gzip, deflate",
+      "authorization": "token some-token",
+      "host": "git.enterprise.com",
+      "user-agent": "https://github.com/renovatebot/renovate",
+    },
+    "method": "GET",
+    "url": "https://git.enterprise.com/api/v3/repos/some/dep/git/refs/tags/v1.2.0",
+  },
+]
+`;
+
 exports[`datasource/github-tags getDigest warns if unknown ref 1`] = `
 Array [
   Object {
diff --git a/lib/datasource/github-tags/index.spec.ts b/lib/datasource/github-tags/index.spec.ts
index 106718400554a999a743b353956fe1a58c8208d4..2bb236b19cd5e33d2236abc1f5909a169e37777e 100644
--- a/lib/datasource/github-tags/index.spec.ts
+++ b/lib/datasource/github-tags/index.spec.ts
@@ -82,6 +82,27 @@ describe('datasource/github-tags', () => {
       expect(res).toBeNull();
       expect(httpMock.getTrace()).toMatchSnapshot();
     });
+
+    it('supports ghe', async () => {
+      httpMock
+        .scope(githubEnterpriseApiHost)
+        .get(`/api/v3/repos/${lookupName}/git/refs/tags/${tag}`)
+        .reply(200, { object: { type: 'commit', sha: 'ddd111' } })
+        .get(`/api/v3/repos/${lookupName}/commits?per_page=1`)
+        .reply(200, [{ sha: 'abcdef' }]);
+
+      const sha1 = await github.getDigest(
+        { lookupName, registryUrl: githubEnterpriseApiHost },
+        null
+      );
+      const sha2 = await github.getDigest(
+        { lookupName: 'some/dep', registryUrl: githubEnterpriseApiHost },
+        'v1.2.0'
+      );
+      expect(httpMock.getTrace()).toMatchSnapshot();
+      expect(sha1).toBe('abcdef');
+      expect(sha2).toBe('ddd111');
+    });
   });
   describe('getReleases', () => {
     beforeEach(() => {
diff --git a/lib/datasource/github-tags/index.ts b/lib/datasource/github-tags/index.ts
index 050b0a7613cdae3694f84f11a97309f54d48728b..5940685d51c5f61dc479a66f6e7d9765f3285621 100644
--- a/lib/datasource/github-tags/index.ts
+++ b/lib/datasource/github-tags/index.ts
@@ -1,17 +1,19 @@
-import URL from 'url';
 import { logger } from '../../logger';
 import * as packageCache from '../../util/cache/package';
 import { GithubHttp } from '../../util/http/github';
+import { ensureTrailingSlash } from '../../util/url';
 import { DigestConfig, GetReleasesConfig, ReleaseResult } from '../common';
 import * as githubReleases from '../github-releases';
 
 export const id = 'github-tags';
+export const defaultRegistryUrls = ['https://github.com'];
+export const registryStrategy = 'first';
 
 const http = new GithubHttp();
 
 const cacheNamespace = 'datasource-github-tags';
-function getCacheKey(repo: string, type: string): string {
-  return `${repo}:${type}`;
+function getCacheKey(registryUrl: string, repo: string, type: string): string {
+  return `${registryUrl}:${repo}:${type}`;
 }
 
 interface TagResponse {
@@ -23,20 +25,30 @@ interface TagResponse {
 }
 
 async function getTagCommit(
+  registryUrl: string,
   githubRepo: string,
   tag: string
 ): Promise<string | null> {
   const cachedResult = await packageCache.get<string>(
     cacheNamespace,
-    getCacheKey(githubRepo, `tag-${tag}`)
+    getCacheKey(registryUrl, githubRepo, `tag-${tag}`)
   );
   // istanbul ignore if
   if (cachedResult) {
     return cachedResult;
   }
+
+  // default to GitHub.com if no GHE host is specified.
+  const sourceUrlBase = ensureTrailingSlash(
+    registryUrl ?? 'https://github.com/'
+  );
+  const apiBaseUrl =
+    sourceUrlBase !== 'https://github.com/'
+      ? `${sourceUrlBase}api/v3/`
+      : `https://api.github.com/`;
   let digest: string;
   try {
-    const url = `https://api.github.com/repos/${githubRepo}/git/refs/tags/${tag}`;
+    const url = `${apiBaseUrl}repos/${githubRepo}/git/refs/tags/${tag}`;
     const res = (await http.getJson<TagResponse>(url)).body.object;
     if (res.type === 'commit') {
       digest = res.sha;
@@ -57,7 +69,7 @@ async function getTagCommit(
   const cacheMinutes = 120;
   await packageCache.set(
     cacheNamespace,
-    getCacheKey(githubRepo, `tag-${tag}`),
+    getCacheKey(registryUrl, githubRepo, `tag-${tag}`),
     digest,
     cacheMinutes
   );
@@ -72,28 +84,36 @@ async function getTagCommit(
  * This function will simply return the latest commit hash for the configured repository.
  */
 export async function getDigest(
-  { lookupName: githubRepo }: Partial<DigestConfig>,
+  { lookupName: repo, registryUrl }: Partial<DigestConfig>,
   newValue?: string
 ): Promise<string | null> {
   if (newValue?.length) {
-    return getTagCommit(githubRepo, newValue);
+    return getTagCommit(registryUrl, repo, newValue);
   }
   const cachedResult = await packageCache.get<string>(
     cacheNamespace,
-    getCacheKey(githubRepo, 'commit')
+    getCacheKey(registryUrl, repo, 'commit')
   );
   // istanbul ignore if
   if (cachedResult) {
     return cachedResult;
   }
+  // default to GitHub.com if no GHE host is specified.
+  const sourceUrlBase = ensureTrailingSlash(
+    registryUrl ?? 'https://github.com/'
+  );
+  const apiBaseUrl =
+    sourceUrlBase !== 'https://github.com/'
+      ? `${sourceUrlBase}api/v3/`
+      : `https://api.github.com/`;
   let digest: string;
   try {
-    const url = `https://api.github.com/repos/${githubRepo}/commits?per_page=1`;
+    const url = `${apiBaseUrl}repos/${repo}/commits?per_page=1`;
     const res = await http.getJson<{ sha: string }[]>(url);
     digest = res.body[0].sha;
   } catch (err) {
     logger.debug(
-      { githubRepo, err },
+      { githubRepo: repo, err, registryUrl },
       'Error getting latest commit from GitHub repo'
     );
   }
@@ -103,7 +123,7 @@ export async function getDigest(
   const cacheMinutes = 10;
   await packageCache.set(
     cacheNamespace,
-    getCacheKey(githubRepo, 'commit'),
+    getCacheKey(registryUrl, repo, 'commit'),
     digest,
     cacheMinutes
   );
@@ -111,12 +131,12 @@ export async function getDigest(
 }
 
 async function getTags({
-  registryUrl: depHost,
+  registryUrl,
   lookupName: repo,
 }: GetReleasesConfig): Promise<ReleaseResult | null> {
   const cachedResult = await packageCache.get<ReleaseResult>(
     cacheNamespace,
-    getCacheKey(repo, 'tags')
+    getCacheKey(registryUrl, repo, 'tags')
   );
   // istanbul ignore if
   if (cachedResult) {
@@ -124,13 +144,16 @@ async function getTags({
   }
 
   // default to GitHub.com if no GHE host is specified.
-  const sourceUrlBase = depHost ?? `https://github.com/`;
-  const apiBaseUrl = depHost
-    ? URL.resolve(depHost, 'api/v3/')
-    : `https://api.github.com/`;
+  const sourceUrlBase = ensureTrailingSlash(
+    registryUrl ?? 'https://github.com/'
+  );
+  const apiBaseUrl =
+    sourceUrlBase !== 'https://github.com/'
+      ? `${sourceUrlBase}api/v3/`
+      : `https://api.github.com/`;
 
   // tag
-  const url = URL.resolve(apiBaseUrl, `repos/${repo}/tags?per_page=100`);
+  const url = `${apiBaseUrl}repos/${repo}/tags?per_page=100`;
   type GitHubTag = {
     name: string;
   }[];
@@ -141,7 +164,7 @@ async function getTags({
     })
   ).body.map((o) => o.name);
   const dependency: ReleaseResult = {
-    sourceUrl: URL.resolve(sourceUrlBase, repo),
+    sourceUrl: `${sourceUrlBase}${repo}`,
     releases: null,
   };
   dependency.releases = versions.map((version) => ({
@@ -151,7 +174,7 @@ async function getTags({
   const cacheMinutes = 10;
   await packageCache.set(
     cacheNamespace,
-    getCacheKey(repo, 'tags'),
+    getCacheKey(registryUrl, repo, 'tags'),
     dependency,
     cacheMinutes
   );
@@ -164,25 +187,23 @@ export async function getReleases(
   const tagsResult = await getTags(config);
 
   try {
-    if (tagsResult?.releases) {
-      // Fetch additional data from releases endpoint when possible
-      const releasesResult = await githubReleases.getReleases(config);
-      const releaseByVersion = {};
-      releasesResult?.releases?.forEach((release) => {
-        const key = release.version;
-        const value = { ...release };
-        delete value.version;
-        releaseByVersion[key] = value;
-      });
-
-      const mergedReleases = [];
-      tagsResult.releases.forEach((tag) => {
-        const release = releaseByVersion[tag.version];
-        mergedReleases.push({ ...release, ...tag });
-      });
-
-      tagsResult.releases = mergedReleases;
-    }
+    // Fetch additional data from releases endpoint when possible
+    const releasesResult = await githubReleases.getReleases(config);
+    const releaseByVersion = {};
+    releasesResult?.releases?.forEach((release) => {
+      const key = release.version;
+      const value = { ...release };
+      delete value.version;
+      releaseByVersion[key] = value;
+    });
+
+    const mergedReleases = [];
+    tagsResult.releases.forEach((tag) => {
+      const release = releaseByVersion[tag.version];
+      mergedReleases.push({ ...release, ...tag });
+    });
+
+    tagsResult.releases = mergedReleases;
   } catch (e) {
     // no-op
   }
diff --git a/lib/workers/repository/process/lookup/index.spec.ts b/lib/workers/repository/process/lookup/index.spec.ts
index 47e706e95cd54e8b556ad263a55963095d17f4be..34f169598608bd8994e0d8901a7cd6a4471e3eb5 100644
--- a/lib/workers/repository/process/lookup/index.spec.ts
+++ b/lib/workers/repository/process/lookup/index.spec.ts
@@ -35,6 +35,8 @@ docker.defaultRegistryUrls = ['https://index.docker.io'];
 const gitSubmodules = mocked(datasourceGitSubmodules);
 const githubReleases = mocked(datasourceGithubReleases);
 
+Object.assign(githubReleases, { defaultRegistryUrls: ['https://github.com'] });
+
 let config: lookup.LookupUpdateConfig;
 
 describe('workers/repository/process/lookup', () => {