diff --git a/.eslintignore b/.eslintignore
--- a/.eslintignore
+++ b/.eslintignore
@@ -6,17 +6,17 @@
 web/dist
 web/flow-typed
 web/node_modules
-server/app_compiled
-server/landing_compiled
-server/dist
-server/secrets
-server/facts
-server/fonts
-server/flow-typed
-server/node_modules
-server/src/landing
-server/src/lib
-server/src/web
+keyserver/app_compiled
+keyserver/landing_compiled
+keyserver/dist
+keyserver/secrets
+keyserver/facts
+keyserver/fonts
+keyserver/flow-typed
+keyserver/node_modules
+keyserver/src/landing
+keyserver/src/lib
+keyserver/src/web
 native/flow-typed
 native/node_modules
 native/codegen/dist
diff --git a/.eslintrc.json b/.eslintrc.json
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -51,6 +51,6 @@
       "version": "detect"
     },
     "import/ignore": ["react-native"],
-    "import/internal-regex": "^(lib|native|server|web)/"
+    "import/internal-regex": "^(lib|native|keyserver|web)/"
   }
 }
diff --git a/.github/workflows/android_ci.yml b/.github/workflows/android_ci.yml
--- a/.github/workflows/android_ci.yml
+++ b/.github/workflows/android_ci.yml
@@ -7,7 +7,7 @@
       - 'landing/**'
       - 'web/**'
       - 'docs/**'
-      - 'server/**'
+      - 'keyserver/**'
 
 jobs:
   build:
diff --git a/.github/workflows/eslint_flow_jest.yml b/.github/workflows/eslint_flow_jest.yml
--- a/.github/workflows/eslint_flow_jest.yml
+++ b/.github/workflows/eslint_flow_jest.yml
@@ -23,8 +23,8 @@
         working-directory: ./lib
         run: ./node_modules/.bin/flow
 
-      - name: '[server] flow'
-        working-directory: ./server
+      - name: '[keyserver] flow'
+        working-directory: ./keyserver
         run: |
           mkdir secrets
           touch secrets/db_config.json
diff --git a/.github/workflows/ios_ci.yml b/.github/workflows/ios_ci.yml
--- a/.github/workflows/ios_ci.yml
+++ b/.github/workflows/ios_ci.yml
@@ -7,7 +7,7 @@
       - 'landing/**'
       - 'web/**'
       - 'docs/**'
-      - 'server/**'
+      - 'keyserver/**'
 
 jobs:
   build:
diff --git a/.github/workflows/services_ci.yml b/.github/workflows/services_ci.yml
--- a/.github/workflows/services_ci.yml
+++ b/.github/workflows/services_ci.yml
@@ -7,7 +7,7 @@
       - 'landing/**'
       - 'web/**'
       - 'docs/**'
-      - 'server/**'
+      - 'keyserver/**'
 
 jobs:
   build:
diff --git a/.prettierignore b/.prettierignore
--- a/.prettierignore
+++ b/.prettierignore
@@ -3,17 +3,17 @@
 lib/flow-typed
 web/dist
 web/flow-typed
-server/app_compiled
-server/landing_compiled
-server/dist
-server/secrets
-server/facts
-server/images
-server/fonts
-server/flow-typed
-server/src/landing
-server/src/lib
-server/src/web
+keyserver/app_compiled
+keyserver/landing_compiled
+keyserver/dist
+keyserver/secrets
+keyserver/facts
+keyserver/images
+keyserver/fonts
+keyserver/flow-typed
+keyserver/src/landing
+keyserver/src/lib
+keyserver/src/web
 native/android
 native/flow-typed
 native/ios
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -7,7 +7,7 @@
 The whole project is written in Flow-typed Javascript. The code is organized in a monorepo structure using Yarn Workspaces.
 
 - `native` contains the code for the React Native app, which supports both iOS and Android.
-- `server` contains the code for the Node/Express server.
+- `keyserver` contains the code for the Node/Express server.
 - `web` contains the code for the React desktop website.
 - `landing` contains the code for the [Comm landing page](https://comm.app).
 - `lib` contains code that is shared across multiple other workspaces, including most of the Redux stack that is shared across native/web.
diff --git a/keyserver/bash/deploy.sh b/keyserver/bash/deploy.sh
--- a/keyserver/bash/deploy.sh
+++ b/keyserver/bash/deploy.sh
@@ -24,14 +24,14 @@
 mkdir -p "$CHECKOUT_PATH"
 chown $DAEMON_USER:$DAEMON_USER "$CHECKOUT_PATH"
 su $DAEMON_USER -c "git clone $GIT_CLONE_PARAMS '$CHECKOUT_PATH'"
-su $DAEMON_USER -c "cp -r '$1'/server/secrets '$CHECKOUT_PATH'/server/secrets"
-su $DAEMON_USER -c "cp -r '$1'/server/facts '$CHECKOUT_PATH'/server/facts"
+su $DAEMON_USER -c "cp -r '$1'/keyserver/secrets '$CHECKOUT_PATH'/keyserver/secrets"
+su $DAEMON_USER -c "cp -r '$1'/keyserver/facts '$CHECKOUT_PATH'/keyserver/facts"
 cd "$CHECKOUT_PATH"
-su $DAEMON_USER -c "server/bash/setup.sh"
+su $DAEMON_USER -c "keyserver/bash/setup.sh"
 
 # STEP 2: test if the binary crashes within 60 seconds
 set +e
-su $DAEMON_USER -c "cd server && PORT=3001 timeout 60 bash/run-prod.sh"
+su $DAEMON_USER -c "cd keyserver && PORT=3001 timeout 60 bash/run-prod.sh"
 [[ $? -eq 124 ]] || exit 1
 set -e
 
diff --git a/keyserver/bash/setup.sh b/keyserver/bash/setup.sh
--- a/keyserver/bash/setup.sh
+++ b/keyserver/bash/setup.sh
@@ -8,10 +8,10 @@
 . ~/.nvm/nvm.sh
 
 chmod -R u=rwX,g=rX,o=rX .
-chmod -R u=rwX,g=,o= server/secrets
+chmod -R u=rwX,g=,o= keyserver/secrets
 
 pushd server && nvm install && popd
 yarn cleaninstall
 yarn workspace web prod
 yarn workspace landing prod
-yarn workspace server prod-build
+yarn workspace keyserver prod-build
diff --git a/keyserver/loader.mjs b/keyserver/loader.mjs
--- a/keyserver/loader.mjs
+++ b/keyserver/loader.mjs
@@ -1,3 +1,4 @@
+// @flow
 const localPackages = ['landing', 'lib', 'web'];
 
 async function resolve(specifier, context, defaultResolve) {
@@ -7,7 +8,7 @@
   if (localPackages.some(pkg => specifier.startsWith(`${pkg}/`))) {
     const url = defaultResult.url.replace(
       specifier,
-      `server/dist/${specifier}`,
+      `keyserver/dist/${specifier}`,
     );
     return { url };
   }
diff --git a/keyserver/package.json b/keyserver/package.json
--- a/keyserver/package.json
+++ b/keyserver/package.json
@@ -1,19 +1,19 @@
 {
-  "name": "server",
+  "name": "keyserver",
   "version": "0.0.1",
   "type": "module",
   "private": true,
   "license": "BSD-3-Clause",
-  "main": "dist/server",
+  "main": "dist/keyserver",
   "scripts": {
     "clean": "rm -rf dist/ && rm -rf node_modules/ && mkdir dist",
     "babel-build": "yarn --silent babel src/ --out-dir dist/ --config-file ./babel.config.cjs --verbose --ignore 'src/landing/flow-typed','src/landing/node_modules','src/landing/package.json','src/lib/flow-typed','src/lib/node_modules','src/lib/package.json','src/web/flow-typed','src/web/node_modules','src/web/package.json','src/web/dist','src/web/webpack.config.js','src/web/account-bar.react.js','src/web/app.react.js','src/web/calendar','src/web/chat','src/web/flow','src/web/loading-indicator.react.js','src/web/modals','src/web/root.js','src/web/router-history.js','src/web/script.js','src/web/selectors/chat-selectors.js','src/web/selectors/entry-selectors.js','src/web/splash','src/web/vector-utils.js','src/web/vectors.react.js'",
     "rsync": "rsync -rLpmuv --exclude '*/package.json' --exclude '*/node_modules/*' --include '*.json' --include '*.cjs' --exclude '*.*' src/ dist/",
     "prod-build": "yarn babel-build && yarn rsync && yarn update-geoip",
     "update-geoip": "yarn script dist/scripts/update-geoip.js",
-    "prod": "node --trace-warnings --experimental-json-modules --loader=./loader.mjs --experimental-specifier-resolution=node dist/server",
+    "prod": "node --trace-warnings --experimental-json-modules --loader=./loader.mjs --experimental-specifier-resolution=node dist/keyserver",
     "dev-rsync": "yarn --silent chokidar --initial --silent -s 'src/**/*.json' 'src/**/*.cjs' -c 'yarn rsync > /dev/null 2>&1'",
-    "dev": "yarn concurrently --names=\"BABEL,RSYNC,NODEM\" -c \"bgBlue.bold,bgMagenta.bold,bgGreen.bold\" \"yarn babel-build --watch\" \"yarn dev-rsync\" \". bash/source-nvm.sh && NODE_ENV=development nodemon -e js,json,cjs --watch dist --experimental-json-modules --loader=./loader.mjs --experimental-specifier-resolution=node dist/server\"",
+    "dev": "yarn concurrently --names=\"BABEL,RSYNC,NODEM\" -c \"bgBlue.bold,bgMagenta.bold,bgGreen.bold\" \"yarn babel-build --watch\" \"yarn dev-rsync\" \". bash/source-nvm.sh && NODE_ENV=development nodemon -e js,json,cjs --watch dist --experimental-json-modules --loader=./loader.mjs --experimental-specifier-resolution=node dist/keyserver\"",
     "script": ". bash/source-nvm.sh && NODE_ENV=development node --experimental-json-modules --loader=./loader.mjs --experimental-specifier-resolution=node",
     "test": "jest"
   },
diff --git a/keyserver/src/cron/update-geoip-db.js b/keyserver/src/cron/update-geoip-db.js
--- a/keyserver/src/cron/update-geoip-db.js
+++ b/keyserver/src/cron/update-geoip-db.js
@@ -28,7 +28,7 @@
 async function updateGeoipDB(): Promise<void> {
   const geoipLicense = await getGeoipLicense();
   if (!geoipLicense) {
-    console.log('no server/secrets/geoip_license.json so skipping update');
+    console.log('no keyserver/secrets/geoip_license.json so skipping update');
     return;
   }
   await spawnUpdater(geoipLicense);
diff --git a/keyserver/src/push/utils.js b/keyserver/src/push/utils.js
--- a/keyserver/src/push/utils.js
+++ b/keyserver/src/push/utils.js
@@ -42,10 +42,10 @@
   const pushProfile = getAPNPushProfileForCodeVersion(codeVersion);
   const apnProvider = await getAPNProvider(pushProfile);
   if (!apnProvider && process.env.NODE_ENV === 'development') {
-    console.log(`no server/secrets/${pushProfile}.json so ignoring notifs`);
+    console.log(`no keyserver/secrets/${pushProfile}.json so ignoring notifs`);
     return { success: true };
   }
-  invariant(apnProvider, `server/secrets/${pushProfile}.json should exist`);
+  invariant(apnProvider, `keyserver/secrets/${pushProfile}.json should exist`);
   const result = await apnProvider.send(notification, deviceTokens);
   const errors = [];
   const invalidTokens = [];
@@ -90,10 +90,10 @@
   const pushProfile = getFCMPushProfileForCodeVersion(codeVersion);
   const fcmProvider = await getFCMProvider(pushProfile);
   if (!fcmProvider && process.env.NODE_ENV === 'development') {
-    console.log(`no server/secrets/${pushProfile}.json so ignoring notifs`);
+    console.log(`no keyserver/secrets/${pushProfile}.json so ignoring notifs`);
     return { success: true };
   }
-  invariant(fcmProvider, `server/secrets/${pushProfile}.json should exist`);
+  invariant(fcmProvider, `keyserver/secrets/${pushProfile}.json should exist`);
   const options: Object = {
     priority: 'high',
   };
diff --git a/keyserver/src/scripts/generate-olm-config.js b/keyserver/src/scripts/generate-olm-config.js
--- a/keyserver/src/scripts/generate-olm-config.js
+++ b/keyserver/src/scripts/generate-olm-config.js
@@ -22,8 +22,10 @@
   };
   const scriptWorkingDirectory = path.resolve();
 
-  if (!scriptWorkingDirectory.endsWith('comm/server')) {
-    throw new Error('Script must be run in server directory in comm project.');
+  if (!scriptWorkingDirectory.endsWith('comm/keyserver')) {
+    throw new Error(
+      'Script must be run in keyserver directory in comm project.',
+    );
   }
 
   const olmConfigFilePath = path.join(
diff --git a/landing/webpack.config.cjs b/landing/webpack.config.cjs
--- a/landing/webpack.config.cjs
+++ b/landing/webpack.config.cjs
@@ -18,7 +18,7 @@
   },
   resolve: {
     alias: {
-      '../images': path.resolve('../server/images'),
+      '../images': path.resolve('../keyserver/images'),
     },
   },
 };
diff --git a/native/.flowconfig b/native/.flowconfig
--- a/native/.flowconfig
+++ b/native/.flowconfig
@@ -11,7 +11,7 @@
 .*/Libraries/Utilities/LoadingView.js
 
 .*/comm/web/.*
-.*/comm/server/.*
+.*/comm/keyserver/.*
 
 .*/android/app/build/.*
 
diff --git a/web/webpack.config.cjs b/web/webpack.config.cjs
--- a/web/webpack.config.cjs
+++ b/web/webpack.config.cjs
@@ -18,7 +18,7 @@
   },
   resolve: {
     alias: {
-      '../images': path.resolve('../server/images'),
+      '../images': path.resolve('../keyserver/images'),
     },
   },
 };
@@ -52,7 +52,7 @@
 const baseNodeServerRenderingConfig = {
   externals: ['react', 'react-dom', 'react-redux'],
   entry: {
-    server: ['./app.react.js'],
+    keyserver: ['./app.react.js'],
   },
   output: {
     filename: 'app.build.cjs',