diff --git a/core/server/server.js b/core/server/server.js
index c2bc06927946fbd05794e37e1570bda9b1c3a4a3..b054785e9ced5469448418bb712ccc93cde6947a 100644
--- a/core/server/server.js
+++ b/core/server/server.js
@@ -146,6 +146,9 @@ const publicConfigSchema = Joi.object({
   rateLimit: Joi.boolean().required(),
   handleInternalErrors: Joi.boolean().required(),
   fetchLimit: Joi.string().regex(/^[0-9]+(b|kb|mb|gb|tb)$/i),
+  documentRoot: Joi.string().default(
+    path.resolve(__dirname, '..', '..', 'public')
+  ),
   requireCloudflare: Joi.boolean().required(),
 }).required()
 
@@ -437,10 +440,11 @@ class Server {
     log(`Server is starting up: ${this.baseUrl}`)
 
     const camp = (this.camp = Camp.create({
-      documentRoot: path.resolve(__dirname, '..', '..', 'public'),
+      documentRoot: this.config.public.documentRoot,
       port,
       hostname,
       secure,
+      staticMaxAge: 300,
       cert,
       key,
     }))
diff --git a/core/server/server.spec.js b/core/server/server.spec.js
index cd375ff8e7de80cc2f4fbea7a6626c84f544bb7e..a899c8a7d05a4c95d623a64965ca01cc77d8ae65 100644
--- a/core/server/server.spec.js
+++ b/core/server/server.spec.js
@@ -1,5 +1,6 @@
 'use strict'
 
+const path = require('path')
 const { expect } = require('chai')
 const isSvg = require('is-svg')
 const config = require('config')
@@ -13,7 +14,11 @@ describe('The server', function () {
     before('Start the server', async function () {
       // Fixes https://github.com/badges/shields/issues/2611
       this.timeout(10000)
-      server = await createTestServer()
+      server = await createTestServer({
+        public: {
+          documentRoot: path.resolve(__dirname, 'test-public'),
+        },
+      })
       baseUrl = server.baseUrl
       await server.start()
     })
@@ -45,6 +50,16 @@ describe('The server', function () {
         .and.to.include('apple')
     })
 
+    it('should serve front-end with default maxAge', async function () {
+      const { headers } = await got(`${baseUrl}/`)
+      expect(headers['cache-control']).to.equal('max-age=300, s-maxage=300')
+    })
+
+    it('should serve badges with custom maxAge', async function () {
+      const { headers } = await got(`${baseUrl}npm/l/express`)
+      expect(headers['cache-control']).to.equal('max-age=3600, s-maxage=3600')
+    })
+
     it('should redirect colorscheme PNG badges as configured', async function () {
       const { statusCode, headers } = await got(
         `${baseUrl}:fruit-apple-green.png`,
diff --git a/core/server/test-public/index.html b/core/server/test-public/index.html
new file mode 100644
index 0000000000000000000000000000000000000000..706f8467b06f52280b71ba41d99e62e87b752881
--- /dev/null
+++ b/core/server/test-public/index.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="utf-8">
+    <title>shields.io</title>
+  </head>
+  <body>
+    concise, consistent, legible
+  </body>
+</html>
diff --git a/package-lock.json b/package-lock.json
index 08d562e80c073e93fafe96f8d87f879d5a9c323e..3a80d0fa8d7c68db6264b8194c07b1ef12381466 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -7414,9 +7414,9 @@
       }
     },
     "@shields_io/camp": {
-      "version": "18.0.0",
-      "resolved": "https://registry.npmjs.org/@shields_io/camp/-/camp-18.0.0.tgz",
-      "integrity": "sha512-faQpvSVqqFX3LfRRdGQQHgXO1s2hsK+QWCZWXdM+3226fdikRCPT+O1YPyDMZdrG/vP5sL9PdOvajgGNwLlU6A==",
+      "version": "18.1.0",
+      "resolved": "https://registry.npmjs.org/@shields_io/camp/-/camp-18.1.0.tgz",
+      "integrity": "sha512-5YlcS1o1prpthiV+2hSI+SxO51e2zJ4Uc7dEh0qh2ST6NwiJM1lKhVQDKOQWqsR9dbtiDobOkCWyqTsDeVPK8w==",
       "requires": {
         "cookies": "~0.7.1",
         "fleau": "~16.2.0",
diff --git a/package.json b/package.json
index c8d2fd8f56c889dc60f80e6f875b59b766e5a503..0482d16661539ff25f30f1f418cdf404660cb1f7 100644
--- a/package.json
+++ b/package.json
@@ -23,7 +23,7 @@
   },
   "dependencies": {
     "@sentry/node": "^5.27.1",
-    "@shields_io/camp": "^18.0.0",
+    "@shields_io/camp": "^18.1.0",
     "badge-maker": "file:badge-maker",
     "bytes": "^3.1.0",
     "camelcase": "^6.2.0",