diff --git a/desktop/src/main.js b/desktop/src/main.js
--- a/desktop/src/main.js
+++ b/desktop/src/main.js
@@ -22,7 +22,7 @@
 } from './push-notifications.js';
 
 const isDev = process.env.ENV === 'dev';
-const url = isDev ? 'http://localhost:3000/comm/' : 'https://web.comm.app';
+const url = isDev ? 'http://localhost:3000/webapp/' : 'https://web.comm.app';
 const isMac = process.platform === 'darwin';
 
 const scrollbarCSS = fs.promises.readFile(
diff --git a/keyserver/icons/site.webmanifest b/keyserver/icons/site.webmanifest
--- a/keyserver/icons/site.webmanifest
+++ b/keyserver/icons/site.webmanifest
@@ -3,12 +3,12 @@
   "short_name": "SquadCal",
   "icons": [
     {
-      "src": "/android-chrome-192x192.png",
+      "src": "android-chrome-192x192.png",
       "sizes": "192x192",
       "type": "image/png"
     },
     {
-      "src": "/android-chrome-512x512.png",
+      "src": "android-chrome-512x512.png",
       "sizes": "512x512",
       "type": "image/png"
     }
diff --git a/keyserver/src/creators/report-creator.js b/keyserver/src/creators/report-creator.js
--- a/keyserver/src/creators/report-creator.js
+++ b/keyserver/src/creators/report-creator.js
@@ -29,7 +29,7 @@
 import { handleAsyncPromise } from '../responders/handlers.js';
 import { createBotViewer } from '../session/bots.js';
 import type { Viewer } from '../session/viewer.js';
-import { getAndAssertCommAppURLFacts } from '../utils/urls.js';
+import { getAndAssertKeyserverURLFacts } from '../utils/urls.js';
 
 const { commbot } = bots;
 
@@ -144,7 +144,7 @@
   const { platform, codeVersion } = platformDetails;
   const platformString = codeVersion ? `${platform} v${codeVersion}` : platform;
   if (request.type === reportTypes.ERROR) {
-    const { baseDomain, basePath } = getAndAssertCommAppURLFacts();
+    const { baseDomain, basePath } = getAndAssertKeyserverURLFacts();
     return (
       `${name} got an error :(\n` +
       `using ${platformString}\n` +
diff --git a/keyserver/src/fetchers/upload-fetchers.js b/keyserver/src/fetchers/upload-fetchers.js
--- a/keyserver/src/fetchers/upload-fetchers.js
+++ b/keyserver/src/fetchers/upload-fetchers.js
@@ -18,7 +18,7 @@
 
 import { dbQuery, SQL } from '../database/database.js';
 import type { Viewer } from '../session/viewer.js';
-import { getAndAssertCommAppURLFacts } from '../utils/urls.js';
+import { getAndAssertKeyserverURLFacts } from '../utils/urls.js';
 
 type UploadInfo = {
   content: Buffer,
@@ -104,7 +104,7 @@
 }
 
 function getUploadURL(id: string, secret: string): string {
-  const { baseDomain, basePath } = getAndAssertCommAppURLFacts();
+  const { baseDomain, basePath } = getAndAssertKeyserverURLFacts();
   const uploadPath = `${basePath}upload/${id}/${secret}`;
   if (isDev) {
     const ipV4 = ip.v4.sync() || 'localhost';
diff --git a/keyserver/src/keyserver.js b/keyserver/src/keyserver.js
--- a/keyserver/src/keyserver.js
+++ b/keyserver/src/keyserver.js
@@ -7,12 +7,14 @@
 import cors from 'cors';
 import crypto from 'crypto';
 import express from 'express';
+import type { $Request, $Response } from 'express';
 import expressWs from 'express-ws';
 import os from 'os';
 import qrcode from 'qrcode';
 
 import './cron/cron.js';
 import { qrCodeLinkURL } from 'lib/facts/links.js';
+import { isDev } from 'lib/utils/dev-utils.js';
 
 import { migrate } from './database/migrations.js';
 import { jsonEndpoints } from './endpoints.js';
@@ -44,9 +46,9 @@
 import { getContentSigningKey } from './utils/olm-utils.js';
 import {
   prefetchAllURLFacts,
-  getSquadCalURLFacts,
+  getKeyserverURLFacts,
   getLandingURLFacts,
-  getCommAppURLFacts,
+  getWebAppURLFacts,
 } from './utils/urls.js';
 
 const shouldDisplayQRCodeInTerminal = false;
@@ -54,10 +56,10 @@
 (async () => {
   await Promise.all([olm.init(), prefetchAllURLFacts(), initENSCache()]);
 
-  const squadCalBaseRoutePath = getSquadCalURLFacts()?.baseRoutePath;
+  const keyserverBaseRoutePath = getKeyserverURLFacts()?.baseRoutePath;
   const landingBaseRoutePath = getLandingURLFacts()?.baseRoutePath;
-  const commAppURLFacts = getCommAppURLFacts();
-  const commAppBaseRoutePath = commAppURLFacts?.baseRoutePath;
+  const webAppURLFacts = getWebAppURLFacts();
+  const webAppBaseRoutePath = webAppURLFacts?.baseRoutePath;
 
   const compiledFolderOptions =
     process.env.NODE_ENV === 'development'
@@ -65,7 +67,7 @@
       : { maxAge: '1y', immutable: true };
 
   const corsOptions = {
-    origin: commAppURLFacts?.baseDomain ?? 'https://web.comm.app',
+    origin: webAppURLFacts?.baseDomain ?? 'https://web.comm.app',
     methods: ['GET', 'POST'],
   };
 
@@ -228,16 +230,25 @@
       server.use(landingBaseRoutePath, landingRouter);
     }
 
-    if (commAppBaseRoutePath) {
+    if (webAppBaseRoutePath) {
       const commAppRouter = express.Router();
       setupAppRouter(commAppRouter);
-      server.use(commAppBaseRoutePath, commAppRouter);
+      server.use(webAppBaseRoutePath, commAppRouter);
     }
 
-    if (squadCalBaseRoutePath) {
+    if (keyserverBaseRoutePath) {
       const squadCalRouter = express.Router();
       setupAppRouter(squadCalRouter);
-      server.use(squadCalBaseRoutePath, squadCalRouter);
+      server.use(keyserverBaseRoutePath, squadCalRouter);
+    }
+
+    if (isDev && webAppURLFacts) {
+      const oldPath = '/comm/';
+      server.all(`${oldPath}*`, (req: $Request, res: $Response) => {
+        const endpoint = req.url.slice(oldPath.length);
+        const newURL = `${webAppURLFacts.baseDomain}${webAppURLFacts.basePath}${endpoint}`;
+        res.redirect(newURL);
+      });
     }
 
     const listenAddress = (() => {
diff --git a/keyserver/src/responders/website-responders.js b/keyserver/src/responders/website-responders.js
--- a/keyserver/src/responders/website-responders.js
+++ b/keyserver/src/responders/website-responders.js
@@ -15,8 +15,9 @@
 
 import { waitForStream } from '../utils/json-stream.js';
 import {
+  getAndAssertKeyserverURLFacts,
   getAppURLFactsFromRequestURL,
-  getCommAppURLFacts,
+  getWebAppURLFacts,
 } from '../utils/urls.js';
 
 const { renderToNodeStream } = ReactDOMServer;
@@ -110,9 +111,18 @@
   }
 }
 
+function stripLastSlash(input: string): string {
+  return input.replace(/\/$/, '');
+}
+
 async function websiteResponder(req: $Request, res: $Response): Promise<void> {
   const { basePath } = getAppURLFactsFromRequestURL(req.originalUrl);
-  const baseURL = basePath.replace(/\/$/, '');
+  const baseURL = stripLastSlash(basePath);
+
+  const keyserverURLFacts = getAndAssertKeyserverURLFacts();
+  const keyserverURL = `${keyserverURLFacts.baseDomain}${stripLastSlash(
+    keyserverURLFacts.basePath,
+  )}`;
 
   const loadingPromise = getWebpackCompiledRootComponentForSSR();
 
@@ -171,6 +181,7 @@
   res.end(html`
     </div>
     <script>
+          var keyserverURL = "${keyserverURL}";
           var baseURL = "${baseURL}";
           var olmFilename = "${olmFilename}";
           var commQueryExecutorFilename = "${commQueryExecutorFilename}";
@@ -202,7 +213,7 @@
     res.end();
     return;
   } else if (detectionResult.os !== 'iOS') {
-    const urlFacts = getCommAppURLFacts();
+    const urlFacts = getWebAppURLFacts();
     const baseDomain = urlFacts?.baseDomain ?? '';
     const basePath = urlFacts?.basePath ?? '/';
     const redirectUrl = `${baseDomain}${basePath}handle/invite/${secret}`;
diff --git a/keyserver/src/utils/urls.js b/keyserver/src/utils/urls.js
--- a/keyserver/src/utils/urls.js
+++ b/keyserver/src/utils/urls.js
@@ -15,8 +15,8 @@
 const validProxies = new Set(['apache', 'none']);
 const sitesObj = Object.freeze({
   a: 'landing',
-  b: 'commapp',
-  c: 'squadcal',
+  b: 'webapp',
+  c: 'keyserver',
 });
 export type Site = $Values<typeof sitesObj>;
 const sites: $ReadOnlyArray<Site> = values(sitesObj);
@@ -46,30 +46,30 @@
   await Promise.all(sites.map(fetchURLFacts));
 }
 
-function getSquadCalURLFacts(): ?AppURLFacts {
-  return cachedURLFacts.get('squadcal');
+function getKeyserverURLFacts(): ?AppURLFacts {
+  return cachedURLFacts.get('keyserver');
 }
 
-function getCommAppURLFacts(): ?AppURLFacts {
-  return cachedURLFacts.get('commapp');
+function getWebAppURLFacts(): ?AppURLFacts {
+  return cachedURLFacts.get('webapp');
 }
 
-function getAndAssertCommAppURLFacts(): AppURLFacts {
-  const urlFacts = getCommAppURLFacts();
-  invariant(urlFacts, 'keyserver/facts/commapp_url.json missing');
+function getAndAssertKeyserverURLFacts(): AppURLFacts {
+  const urlFacts = getKeyserverURLFacts();
+  invariant(urlFacts, 'keyserver/facts/keyserver_url.json missing');
   return urlFacts;
 }
 
 // ESLint doesn't recognize that invariant always throws
 // eslint-disable-next-line consistent-return
 function getAppURLFactsFromRequestURL(url: string): AppURLFacts {
-  const commURLFacts = getCommAppURLFacts();
-  if (commURLFacts && url.startsWith(commURLFacts.baseRoutePath)) {
-    return commURLFacts;
+  const webAppURLFacts = getWebAppURLFacts();
+  if (webAppURLFacts && url.startsWith(webAppURLFacts.baseRoutePath)) {
+    return webAppURLFacts;
   }
-  const squadCalURLFacts = getSquadCalURLFacts();
-  if (squadCalURLFacts) {
-    return squadCalURLFacts;
+  const keyserverURLFacts = getKeyserverURLFacts();
+  if (keyserverURLFacts && url.startsWith(keyserverURLFacts.baseRoutePath)) {
+    return keyserverURLFacts;
   }
   invariant(false, 'request received but no URL facts are present');
 }
@@ -86,9 +86,9 @@
 
 export {
   prefetchAllURLFacts,
-  getSquadCalURLFacts,
-  getCommAppURLFacts,
-  getAndAssertCommAppURLFacts,
+  getKeyserverURLFacts,
+  getWebAppURLFacts,
+  getAndAssertKeyserverURLFacts,
   getLandingURLFacts,
   getAndAssertLandingURLFacts,
   getAppURLFactsFromRequestURL,
diff --git a/native/redux/persist.js b/native/redux/persist.js
--- a/native/redux/persist.js
+++ b/native/redux/persist.js
@@ -92,6 +92,7 @@
 import { defaultDeviceCameraInfo } from '../types/camera.js';
 import { defaultGlobalThemeInfo } from '../types/themes.js';
 import { isTaskCancelledError } from '../utils/error-handling.js';
+import { defaultURLPrefix } from '../utils/url-utils.js';
 
 const migrations = {
   [1]: (state: AppState) => ({
@@ -783,6 +784,22 @@
       threadHashingStatus: 'data_not_loaded',
     },
   }),
+  [53]: async (state: AppState): Promise<AppState> =>
+    __DEV__
+      ? {
+          ...state,
+          keyserverStore: {
+            ...state.keyserverStore,
+            keyserverInfos: {
+              ...state.keyserverStore.keyserverInfos,
+              [ashoatKeyserverID]: {
+                ...state.keyserverStore.keyserverInfos[ashoatKeyserverID],
+                urlPrefix: defaultURLPrefix,
+              },
+            },
+          },
+        }
+      : state,
 };
 
 // After migration 31, we'll no longer want to persist `messageStore.messages`
@@ -914,7 +931,7 @@
     'connection',
   ],
   debug: __DEV__,
-  version: 52,
+  version: 53,
   transforms: [
     messageStoreMessagesBlocklistTransform,
     reportStoreTransform,
diff --git a/native/utils/url-utils.js b/native/utils/url-utils.js
--- a/native/utils/url-utils.js
+++ b/native/utils/url-utils.js
@@ -32,7 +32,7 @@
 }
 
 function getDevNodeServerURLFromHostname(hostname: string): string {
-  return `http://${hostname}:3000/comm`;
+  return `http://${hostname}:3000/keyserver`;
 }
 
 function getDevLandingURLFromHostname(hostname: string): string {
diff --git a/web/push-notif/service-worker.js b/web/push-notif/service-worker.js
--- a/web/push-notif/service-worker.js
+++ b/web/push-notif/service-worker.js
@@ -72,7 +72,7 @@
         const url =
           (process.env.NODE_ENV === 'production'
             ? 'https://web.comm.app'
-            : 'http://localhost:3000/comm') + `/chat/thread/${threadID}/`;
+            : 'http://localhost:3000/webapp') + `/chat/thread/${threadID}/`;
         clients.openWindow(url);
       }
     })(),
diff --git a/web/redux/default-state.js b/web/redux/default-state.js
--- a/web/redux/default-state.js
+++ b/web/redux/default-state.js
@@ -3,12 +3,13 @@
 import { defaultEnabledApps } from 'lib/types/enabled-apps.js';
 import { defaultCalendarFilters } from 'lib/types/filter-types.js';
 import { defaultConnectionInfo } from 'lib/types/socket-types.js';
-import { isDev } from 'lib/utils/dev-utils.js';
 import { defaultNotifPermissionAlertInfo } from 'lib/utils/push-alerts.js';
 import { ashoatKeyserverID } from 'lib/utils/validation-utils.js';
 
 import type { AppState } from './redux-setup.js';
 
+declare var keyserverURL: string;
+
 const defaultWebState: AppState = Object.freeze({
   navInfo: {
     activeChatThreadID: null,
@@ -80,9 +81,7 @@
       [ashoatKeyserverID]: {
         cookie: null,
         updatesCurrentAsOf: 0,
-        urlPrefix: isDev
-          ? 'http://localhost:3000/comm'
-          : 'https://web.comm.app',
+        urlPrefix: keyserverURL,
         connection: { ...defaultConnectionInfo },
         lastCommunicatedPlatformDetails: null,
       },
diff --git a/web/redux/persist.js b/web/redux/persist.js
--- a/web/redux/persist.js
+++ b/web/redux/persist.js
@@ -37,6 +37,8 @@
 import { isSQLiteSupported } from '../database/utils/db-utils.js';
 import { workerRequestMessageTypes } from '../types/worker-types.js';
 
+declare var keyserverURL: string;
+
 const migrations = {
   [1]: async state => {
     const {
@@ -159,6 +161,19 @@
       },
     };
   },
+  [8]: async state => ({
+    ...state,
+    keyserverStore: {
+      ...state.keyserverStore,
+      keyserverInfos: {
+        ...state.keyserverStore.keyserverInfos,
+        [ashoatKeyserverID]: {
+          ...state.keyserverStore.keyserverInfos[ashoatKeyserverID],
+          urlPrefix: keyserverURL,
+        },
+      },
+    },
+  }),
 };
 
 const persistWhitelist = [
@@ -271,7 +286,7 @@
     { debug: isDev },
     migrateStorageToSQLite,
   ): any),
-  version: 7,
+  version: 8,
   transforms: [keyserverStoreTransform],
 };