diff --git a/keyserver/src/session/cookies.js b/keyserver/src/session/cookies.js
--- a/keyserver/src/session/cookies.js
+++ b/keyserver/src/session/cookies.js
@@ -32,7 +32,7 @@
 import { clearDeviceToken } from '../updaters/device-token-updaters';
 import { updateThreadMembers } from '../updaters/thread-updaters';
 import { assertSecureRequest } from '../utils/security-utils';
-import { type AppURLFacts } from '../utils/urls';
+import { type AppURLFacts, getAppURLFactsFromRequestURL } from '../utils/urls';
 import { Viewer } from './viewer';
 import type { AnonymousViewerData, UserViewerData } from './viewer';
 
@@ -369,6 +369,18 @@
   };
 }
 
+function getRequestIPAddress(req: $Request) {
+  const { proxy } = getAppURLFactsFromRequestURL(req.originalUrl);
+  let ipAddress;
+  if (proxy === 'none') {
+    ipAddress = req.socket.remoteAddress;
+  } else if (proxy === 'apache') {
+    ipAddress = req.get('X-Forwarded-For');
+  }
+  invariant(ipAddress, 'could not determine requesting IP address');
+  return ipAddress;
+}
+
 function getSessionParameterInfoFromRequestBody(
   req: $Request,
 ): SessionParameterInfo {
@@ -384,13 +396,11 @@
     req.method === 'GET' || sessionID !== undefined
       ? sessionIdentifierTypes.BODY_SESSION_ID
       : sessionIdentifierTypes.COOKIE_ID;
-  const ipAddress = req.get('X-Forwarded-For');
-  invariant(ipAddress, 'X-Forwarded-For header missing');
   return {
     isSocket: false,
     sessionID,
     sessionIdentifierType,
-    ipAddress,
+    ipAddress: getRequestIPAddress(req),
     userAgent: req.get('User-Agent'),
   };
 }
@@ -423,8 +433,6 @@
   assertSecureRequest(req);
   const { sessionIdentification } = clientMessage.payload;
   const { sessionID } = sessionIdentification;
-  const ipAddress = req.get('X-Forwarded-For');
-  invariant(ipAddress, 'X-Forwarded-For header missing');
   const sessionParameterInfo = {
     isSocket: true,
     sessionID,
@@ -432,7 +440,7 @@
       sessionID !== undefined
         ? sessionIdentifierTypes.BODY_SESSION_ID
         : sessionIdentifierTypes.COOKIE_ID,
-    ipAddress,
+    ipAddress: getRequestIPAddress(req),
     userAgent: req.get('User-Agent'),
   };
 
diff --git a/keyserver/src/utils/security-utils.js b/keyserver/src/utils/security-utils.js
--- a/keyserver/src/utils/security-utils.js
+++ b/keyserver/src/utils/security-utils.js
@@ -5,8 +5,14 @@
 import { getAppURLFactsFromRequestURL } from './urls';
 
 function assertSecureRequest(req: $Request) {
-  const { https } = getAppURLFactsFromRequestURL(req.originalUrl);
-  if (https && req.get('X-Forwarded-SSL') !== 'on') {
+  const { https, proxy } = getAppURLFactsFromRequestURL(req.originalUrl);
+  if (!https) {
+    return;
+  }
+  if (
+    (proxy === 'none' && req.protocol !== 'https') ||
+    (proxy === 'apache' && req.get('X-Forwarded-SSL') !== 'on')
+  ) {
     throw new Error('insecure request');
   }
 }
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
@@ -11,7 +11,9 @@
   +basePath: string,
   +https: boolean,
   +baseRoutePath: string,
+  +proxy?: 'apache' | 'none', // defaults to apache
 };
+const validProxies = new Set(['apache', 'none']);
 const sitesObj = Object.freeze({
   a: 'landing',
   b: 'commapp',
@@ -26,10 +28,17 @@
   if (existing !== undefined) {
     return existing;
   }
-  const urlFacts: ?AppURLFacts = await importJSON({
+  let urlFacts: ?AppURLFacts = await importJSON({
     folder: 'facts',
     name: `${site}_url`,
   });
+  if (urlFacts) {
+    const { proxy } = urlFacts;
+    urlFacts = {
+      ...urlFacts,
+      proxy: validProxies.has(proxy) ? proxy : 'apache',
+    };
+  }
   cachedURLFacts.set(site, urlFacts);
   return urlFacts;
 }