diff --git a/lib/analytics.js b/core/server/analytics.js
similarity index 100%
rename from lib/analytics.js
rename to core/server/analytics.js
diff --git a/lib/in-process-server-test-helpers.js b/core/server/in-process-server-test-helpers.js
similarity index 100%
rename from lib/in-process-server-test-helpers.js
rename to core/server/in-process-server-test-helpers.js
diff --git a/lib/log.js b/core/server/log.js
similarity index 100%
rename from lib/log.js
rename to core/server/log.js
diff --git a/lib/log.spec.js b/core/server/log.spec.js
similarity index 100%
rename from lib/log.spec.js
rename to core/server/log.spec.js
diff --git a/lib/sys/monitor.js b/core/server/monitor.js
similarity index 96%
rename from lib/sys/monitor.js
rename to core/server/monitor.js
index 28d767198ab9a751537dfc25f2ca298b3ef43b11..28afc023f00166500bb024addc3836d3c4d50f09 100644
--- a/lib/sys/monitor.js
+++ b/core/server/monitor.js
@@ -1,9 +1,9 @@
 'use strict'
 
+const serverSecrets = require('../../lib/server-secrets')
 const secretIsValid = require('./secret-is-valid')
-const serverSecrets = require('../server-secrets')
 const RateLimit = require('./rate-limit')
-const log = require('../log')
+const log = require('./log')
 
 function secretInvalid(req, res) {
   if (!secretIsValid(req.password)) {
diff --git a/lib/sys/prometheus-metrics.js b/core/server/prometheus-metrics.js
similarity index 100%
rename from lib/sys/prometheus-metrics.js
rename to core/server/prometheus-metrics.js
diff --git a/lib/sys/prometheus-metrics.spec.js b/core/server/prometheus-metrics.spec.js
similarity index 100%
rename from lib/sys/prometheus-metrics.spec.js
rename to core/server/prometheus-metrics.spec.js
diff --git a/lib/sys/rate-limit.js b/core/server/rate-limit.js
similarity index 100%
rename from lib/sys/rate-limit.js
rename to core/server/rate-limit.js
diff --git a/lib/sys/secret-is-valid.js b/core/server/secret-is-valid.js
similarity index 87%
rename from lib/sys/secret-is-valid.js
rename to core/server/secret-is-valid.js
index e4c4eec41fa3e8a3d8a653a94e06b623b2188c4d..49cdc27dcd5ed6aeaf433b692a8b61aa53e091cf 100644
--- a/lib/sys/secret-is-valid.js
+++ b/core/server/secret-is-valid.js
@@ -1,6 +1,6 @@
 'use strict'
 
-const serverSecrets = require('../server-secrets')
+const serverSecrets = require('../../lib/server-secrets')
 
 function secretIsValid(secret = '') {
   return (
diff --git a/lib/server.js b/core/server/server.js
similarity index 90%
rename from lib/server.js
rename to core/server/server.js
index a37836243dbabfd8f2c1e4ce3a7c8ad0f9d6770b..8e0a4b891413a59f030fbaa8c3e16645bf6d2176 100644
--- a/lib/server.js
+++ b/core/server/server.js
@@ -5,19 +5,22 @@ const path = require('path')
 const url = require('url')
 const Joi = require('joi')
 const Camp = require('camp')
-const makeBadge = require('../gh-badges/lib/make-badge')
-const GithubConstellation = require('../services/github/github-constellation')
-const { loadServiceClasses } = require('../services')
+const makeBadge = require('../../gh-badges/lib/make-badge')
+const GithubConstellation = require('../../services/github/github-constellation')
+const { loadServiceClasses } = require('../../services')
+const { makeBadgeData } = require('../../lib/badge-data')
+const { staticBadgeUrl } = require('../../lib/make-badge-url')
+const suggest = require('../../lib/suggest')
+const { makeSend } = require('../../lib/result-sender')
+const {
+  handleRequest,
+  clearRequestCache,
+} = require('../../lib/request-handler')
+const { clearRegularUpdateCache } = require('../../lib/regular-update')
 const analytics = require('./analytics')
-const { makeBadgeData } = require('./badge-data')
 const log = require('./log')
-const { staticBadgeUrl } = require('./make-badge-url')
-const suggest = require('./suggest')
-const sysMonitor = require('./sys/monitor')
-const PrometheusMetrics = require('./sys/prometheus-metrics')
-const { makeSend } = require('./result-sender')
-const { handleRequest, clearRequestCache } = require('./request-handler')
-const { clearRegularUpdateCache } = require('./regular-update')
+const sysMonitor = require('./monitor')
+const PrometheusMetrics = require('./prometheus-metrics')
 
 const optionalUrl = Joi.string().uri({ scheme: ['http', 'https'] })
 const requiredUrl = optionalUrl.required()
@@ -235,7 +238,7 @@ module.exports = class Server {
     log(`Server is starting up: ${this.baseUrl}`)
 
     const camp = (this.camp = Camp.start({
-      documentRoot: path.join(__dirname, '..', 'public'),
+      documentRoot: path.join(__dirname, '..', '..', 'public'),
       port,
       hostname,
       secure,
diff --git a/lib/server.spec.js b/core/server/server.spec.js
similarity index 97%
rename from lib/server.spec.js
rename to core/server/server.spec.js
index 8dc0d18acc4cdbcf753456b8a90f3ebc20ac2647..95da4cee5a4d1bf37af4998f94552f6766ca5e31 100644
--- a/lib/server.spec.js
+++ b/core/server/server.spec.js
@@ -9,7 +9,7 @@ const isSvg = require('is-svg')
 const path = require('path')
 const sinon = require('sinon')
 const portfinder = require('portfinder')
-const svg2img = require('../gh-badges/lib/svg-to-img')
+const svg2img = require('../../gh-badges/lib/svg-to-img')
 const { createTestServer } = require('./in-process-server-test-helpers')
 
 describe('The server', function() {
@@ -105,7 +105,7 @@ describe('The server', function() {
 
   context('with svg2img error', function() {
     const expectedError = fs.readFileSync(
-      path.resolve(__dirname, '..', 'public', '500.html')
+      path.resolve(__dirname, '..', '..', 'public', '500.html')
     )
 
     let toBufferStub
diff --git a/lib/service-test-runner/cli.js b/core/service-test-runner/cli.js
similarity index 98%
rename from lib/service-test-runner/cli.js
rename to core/service-test-runner/cli.js
index 266bdeb5135d840b52f5d623bac2af4008487ed3..0825ec87c3a174290ddbf977e385faf3125f9e54 100644
--- a/lib/service-test-runner/cli.js
+++ b/core/service-test-runner/cli.js
@@ -55,7 +55,7 @@ const minimist = require('minimist')
 const envFlag = require('node-env-flag')
 const readAllStdinSync = require('read-all-stdin-sync')
 const Runner = require('./runner')
-const { createTestServer } = require('../../lib/in-process-server-test-helpers')
+const { createTestServer } = require('../server/in-process-server-test-helpers')
 
 require('../../lib/unhandled-rejection.spec')
 
diff --git a/lib/service-test-runner/infer-pull-request.js b/core/service-test-runner/infer-pull-request.js
similarity index 100%
rename from lib/service-test-runner/infer-pull-request.js
rename to core/service-test-runner/infer-pull-request.js
diff --git a/lib/service-test-runner/infer-pull-request.spec.js b/core/service-test-runner/infer-pull-request.spec.js
similarity index 100%
rename from lib/service-test-runner/infer-pull-request.spec.js
rename to core/service-test-runner/infer-pull-request.spec.js
diff --git a/lib/service-test-runner/pull-request-services-cli.js b/core/service-test-runner/pull-request-services-cli.js
similarity index 100%
rename from lib/service-test-runner/pull-request-services-cli.js
rename to core/service-test-runner/pull-request-services-cli.js
diff --git a/lib/service-test-runner/runner.js b/core/service-test-runner/runner.js
similarity index 100%
rename from lib/service-test-runner/runner.js
rename to core/service-test-runner/runner.js
diff --git a/lib/service-test-runner/services-for-title.js b/core/service-test-runner/services-for-title.js
similarity index 100%
rename from lib/service-test-runner/services-for-title.js
rename to core/service-test-runner/services-for-title.js
diff --git a/lib/service-test-runner/services-for-title.spec.js b/core/service-test-runner/services-for-title.spec.js
similarity index 100%
rename from lib/service-test-runner/services-for-title.spec.js
rename to core/service-test-runner/services-for-title.spec.js
diff --git a/lib/redis-token-persistence.js b/lib/redis-token-persistence.js
index ba82ab02776307bbde5c74ee8c24c47fbd19e199..56666c5b95c7b9cc31afb243d9ea8c83df98cf4f 100644
--- a/lib/redis-token-persistence.js
+++ b/lib/redis-token-persistence.js
@@ -2,7 +2,7 @@
 
 const redis = require('redis')
 const { promisify } = require('util')
-const log = require('./log')
+const log = require('../core/server/log')
 const TokenPersistence = require('./token-persistence')
 
 class RedisTokenPersistence extends TokenPersistence {
diff --git a/lib/request-handler.js b/lib/request-handler.js
index 49b61801c13f2d0660dfca84d7239e03d9794212..c49c8c6366f8097462bcd281aa3cad7203f6fd94 100644
--- a/lib/request-handler.js
+++ b/lib/request-handler.js
@@ -3,19 +3,19 @@
 // eslint-disable-next-line node/no-deprecated-api
 const domain = require('domain')
 const request = require('request')
-const { makeBadgeData: getBadgeData } = require('./badge-data')
-const log = require('./log')
+const queryString = require('query-string')
+const log = require('../core/server/log')
+const analytics = require('../core/server/analytics')
 const LruCache = require('../gh-badges/lib/lru-cache')
 const makeBadge = require('../gh-badges/lib/make-badge')
-const analytics = require('./analytics')
-const { makeSend } = require('./result-sender')
-const queryString = require('query-string')
 const {
   Inaccessible,
   InvalidResponse,
   ShieldsRuntimeError,
 } = require('../services/errors')
 const { setCacheHeaders } = require('../services/cache-headers')
+const { makeBadgeData: getBadgeData } = require('./badge-data')
+const { makeSend } = require('./result-sender')
 
 // We avoid calling the vendor's server for computation of the information in a
 // number of badges.
diff --git a/lib/request-handler.spec.js b/lib/request-handler.spec.js
index 4957c64cd0edd10db969de63656176ddf194de45..3ca26550f2e9a1688ebf2be1c3ceeed9656258e0 100644
--- a/lib/request-handler.spec.js
+++ b/lib/request-handler.spec.js
@@ -4,8 +4,8 @@ const { expect } = require('chai')
 const fetch = require('node-fetch')
 const nock = require('nock')
 const portfinder = require('portfinder')
-const analytics = require('./analytics')
 const Camp = require('camp')
+const analytics = require('../core/server/analytics')
 const { makeBadgeData: getBadgeData } = require('./badge-data')
 const {
   handleRequest,
diff --git a/lib/result-sender.js b/lib/result-sender.js
index 36e09859ba6d63c3c0e4a88318153745194cda7b..9730cb0230e8ef08be24cf7898370b2155977985 100644
--- a/lib/result-sender.js
+++ b/lib/result-sender.js
@@ -1,7 +1,7 @@
 'use strict'
 
 const stream = require('stream')
-const log = require('./log')
+const log = require('../core/server/log')
 const svg2img = require('../gh-badges/lib/svg-to-img')
 
 function streamFromString(str) {
diff --git a/lib/token-persistence.js b/lib/token-persistence.js
index 1ad2256566a5fa84bba639d3c78c847107a07ee3..cfcea2c5b9d0d55cbabeff6bef597aa2777ec308 100644
--- a/lib/token-persistence.js
+++ b/lib/token-persistence.js
@@ -1,6 +1,6 @@
 'use strict'
 
-const log = require('./log')
+const log = require('../core/server/log')
 
 // This is currently bound to the legacy github auth code. That will be
 // replaced with a dependency-injected token provider.
diff --git a/package.json b/package.json
index 90dc07566bd563c7207816fa8c94de6d9e79978f..5c40df614689226fd2ab6f0e3e376f5752382ac3 100644
--- a/package.json
+++ b/package.json
@@ -80,14 +80,14 @@
     "test:js:frontend": "echo \"Deprecated; run `npm run test:frontend` instead.\" && npm run test:frontend",
     "test:js:package": "echo \"Deprecated; run `npm run test:package` instead.\" && npm run test:package",
     "test:frontend": "cross-env BABEL_ENV=test mocha --opts mocha.opts --require @babel/polyfill --require @babel/register --require mocha-yaml-loader \"frontend/**/*.spec.js\"",
-    "test:server": "cross-env NODE_CONFIG_ENV=test mocha --opts mocha.opts \"lib/**/*.spec.js\" \"services/**/*.spec.js\"",
+    "test:server": "cross-env NODE_CONFIG_ENV=test mocha --opts mocha.opts \"core/**/*.spec.js\" \"lib/**/*.spec.js\" \"services/**/*.spec.js\"",
     "test:package": "mocha --opts mocha.opts \"gh-badges/**/*.spec.js\"",
     "test:entrypoint": "cross-env NODE_CONFIG_ENV=test mocha --opts mocha.opts entrypoint.spec.js",
     "test:integration": "cross-env NODE_CONFIG_ENV=test mocha --opts mocha.opts \"lib/**/*.integration.js\" \"services/**/*.integration.js\"",
-    "test:services": "cross-env NODE_CONFIG_ENV=test mocha --opts mocha.opts --delay lib/service-test-runner/cli.js",
+    "test:services": "cross-env NODE_CONFIG_ENV=test mocha --opts mocha.opts --delay core/service-test-runner/cli.js",
     "test:services:trace": "cross-env NODE_CONFIG_ENV=test TRACE_SERVICES=true npm run test:services -- $*",
-    "test:services:pr:prepare": "node lib/service-test-runner/pull-request-services-cli.js > pull-request-services.log",
-    "test:services:pr:run": "cross-env NODE_CONFIG_ENV=test mocha --opts mocha.opts --delay lib/service-test-runner/cli.js --stdin < pull-request-services.log",
+    "test:services:pr:prepare": "node core/service-test-runner/pull-request-services-cli.js > pull-request-services.log",
+    "test:services:pr:run": "cross-env NODE_CONFIG_ENV=test mocha --opts mocha.opts --delay core/service-test-runner/cli.js --stdin < pull-request-services.log",
     "test:services:pr": "run-s --silent test:services:pr:prepare test:services:pr:run",
     "pretest": "run-s --silent defs features",
     "test": "run-s --silent --continue-on-error lint test:frontend test:package test:server test:entrypoint prettier-check",
diff --git a/server.js b/server.js
index ea51631ab963e9e49bd17355f3b94abd1fec7b63..1b77c7e6442ab568dea7547820ac5c695c18bed7 100644
--- a/server.js
+++ b/server.js
@@ -20,7 +20,7 @@ if (process.argv[3]) {
 console.log('Configuration:')
 console.dir(config.public, { depth: null })
 
-const Server = require('./lib/server')
+const Server = require('./core/server/server')
 const server = (module.exports = new Server(config))
 
 ;(async () => {
diff --git a/services/base-static.js b/services/base-static.js
index 6d146ce21e264da4c579eb3a6f8475fe8c4a3d26..638d420bdd9aaa0373c4a9cdfd3d622ce5a84580 100644
--- a/services/base-static.js
+++ b/services/base-static.js
@@ -2,7 +2,7 @@
 
 const makeBadge = require('../gh-badges/lib/make-badge')
 const { makeSend } = require('../lib/result-sender')
-const analytics = require('../lib/analytics')
+const analytics = require('../core/server/analytics')
 const BaseService = require('./base')
 const {
   serverHasBeenUpSinceResourceCached,
diff --git a/services/github/auth/acceptor.js b/services/github/auth/acceptor.js
index 95b4d36574648661e3698387677b5849d8ec55a9..a5588c7cdec16a17b9f2459a822c55f533666676 100644
--- a/services/github/auth/acceptor.js
+++ b/services/github/auth/acceptor.js
@@ -2,9 +2,9 @@
 
 const queryString = require('query-string')
 const request = require('request')
-const log = require('../../../lib/log')
+const log = require('../../../core/server/log')
+const secretIsValid = require('../../../core/server/secret-is-valid')
 const serverSecrets = require('../../../lib/server-secrets')
-const secretIsValid = require('../../../lib/sys/secret-is-valid')
 
 function sendTokenToAllServers(token) {
   const {
diff --git a/services/github/auth/admin.js b/services/github/auth/admin.js
index 081abe7055fc8d27e79a2ff178654ec7d7405038..8993a1c659c71f16b20192e776d4fd668b5757bb 100644
--- a/services/github/auth/admin.js
+++ b/services/github/auth/admin.js
@@ -1,6 +1,6 @@
 'use strict'
 
-const secretIsValid = require('../../../lib/sys/secret-is-valid')
+const secretIsValid = require('../../../core/server/secret-is-valid')
 
 function setRoutes(apiProvider, server) {
   // Allow the admin to obtain the tokens for operational and debugging
diff --git a/services/github/github-constellation.js b/services/github/github-constellation.js
index 3674cf793b2ac7a46fba4f3b36c982edbe14e640..1b5e460dd9f38a8f0ffe291ec6eb7467ff0c9167 100644
--- a/services/github/github-constellation.js
+++ b/services/github/github-constellation.js
@@ -2,7 +2,7 @@
 
 const path = require('path')
 const serverSecrets = require('../../lib/server-secrets')
-const log = require('../../lib/log')
+const log = require('../../core/server/log')
 const RedisTokenPersistence = require('../../lib/redis-token-persistence')
 const FsTokenPersistence = require('../../lib/fs-token-persistence')
 const GithubApiProvider = require('./github-api-provider')
diff --git a/services/maintenance/maintenance.service.js b/services/maintenance/maintenance.service.js
index 60147dc2d9e3cc65c78124465f78d471e40f27c2..cf6ca3ceac74dbc570e67fde21af468bc7214380 100644
--- a/services/maintenance/maintenance.service.js
+++ b/services/maintenance/maintenance.service.js
@@ -2,7 +2,7 @@
 
 const LegacyService = require('../legacy-service')
 const { makeBadgeData: getBadgeData } = require('../../lib/badge-data')
-const log = require('../../lib/log')
+const log = require('../../core/server/log')
 
 // This legacy service should be rewritten to use e.g. BaseJsonService.
 //
diff --git a/services/packagist/packagist-php-version.service.js b/services/packagist/packagist-php-version.service.js
index a70b76d4ebde4980c4e7a94685e2b4f2cf57f532..5206187e2dec1f9cb95757251ef65112d152adee 100644
--- a/services/packagist/packagist-php-version.service.js
+++ b/services/packagist/packagist-php-version.service.js
@@ -2,7 +2,7 @@
 
 const LegacyService = require('../legacy-service')
 const { makeBadgeData: getBadgeData } = require('../../lib/badge-data')
-const log = require('../../lib/log')
+const log = require('../../core/server/log')
 
 // This legacy service should be rewritten to use e.g. BaseJsonService.
 //
diff --git a/services/php-eye/php-eye-php-version.service.js b/services/php-eye/php-eye-php-version.service.js
index a00672a2989bd169b8734a874c2e845135a9dbeb..089d2418943fe975508a9224009ae95e90785a6e 100644
--- a/services/php-eye/php-eye-php-version.service.js
+++ b/services/php-eye/php-eye-php-version.service.js
@@ -6,7 +6,7 @@ const {
   versionReduction: phpVersionReduction,
   getPhpReleases,
 } = require('../../lib/php-version')
-const log = require('../../lib/log')
+const log = require('../../core/server/log')
 
 // This legacy service should be rewritten to use e.g. BaseJsonService.
 //
diff --git a/services/travis/travis-php-version.service.js b/services/travis/travis-php-version.service.js
index 6ca312d93cf70e4dd2588a09b2970b0c97b96fee..fa0cdc2c9f0adec4ca1339c612202c39656e5b36 100644
--- a/services/travis/travis-php-version.service.js
+++ b/services/travis/travis-php-version.service.js
@@ -2,7 +2,7 @@
 
 const LegacyService = require('../legacy-service')
 const { makeBadgeData: getBadgeData } = require('../../lib/badge-data')
-const log = require('../../lib/log')
+const log = require('../../core/server/log')
 const {
   minorVersion: phpMinorVersion,
   versionReduction: phpVersionReduction,