diff --git a/.dockerignore b/.dockerignore
index 99ae7af30..f5aeaa531 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -1,46 +1,45 @@
 .dockerignore
 .DS_Store
 .git
 .eslintcache
 .vscode
 !.vscode/extensions.json
 
 node_modules
 
 landing/node_modules
 landing/dist
 
 lib/node_modules
 
 native
 !native/package.json
 !native/.flowconfig
-!native/postinstall.sh
 !native/ios/Podfile
 !native/ios/pod-patch
 !native/cpp/CommonCpp/grpc
 !native/expo-modules/android-lifecycle/package.json
 
 web/node_modules
 web/dist
 
 keyserver/dist
 keyserver/node_modules
 keyserver/facts
 keyserver/secrets
 keyserver/*.env
 keyserver/*.env.*
 
 services/tunnelbroker/Dockerfile
 services/identity/target
 services/identity/Dockerfile
 services/backup/Dockerfile
 services/blob/target
 services/blob/Dockerfile
 services/electron-update-server/node_modules
 
 native/cpp/**/build
 services/*/build
 services/build
 services/lib/src/build
 shared/protos/build
diff --git a/keyserver/Dockerfile b/keyserver/Dockerfile
index d1b11e30d..f30c50754 100644
--- a/keyserver/Dockerfile
+++ b/keyserver/Dockerfile
@@ -1,170 +1,170 @@
 FROM node:16.18.0-bullseye
 
 #-------------------------------------------------------------------------------
 # STEP 0: SET UP USER
 # Set up Linux user and group for the container
 #-------------------------------------------------------------------------------
 
 # We use bind mounts for our backups folder, which means Docker on Linux will
 # blindly match the UID/GID for the backups folder on the container with the
 # host. In order to make sure the container is able to create backups with the
 # right UID/GID, we need to do two things:
 # 1. Make sure that the user that runs the Docker container on the host has
 #    permissions to write to the backups folder on the host. We rely on the host
 #    to configure this properly
 # 2. Make sure we're running this container with the same UID/GID that the host
 #    is using, so the UID/GID show up correctly on both sides of the bind mount
 # To handle 2 correctly, we have the host pass the UID/GID with which they're
 # running the container. Our approach is based on this one:
 # https://github.com/mhart/alpine-node/issues/48#issuecomment-430902787
 
 ARG HOST_UID
 ARG HOST_GID
 ARG COMM_ALCHEMY_KEY
 
 USER root
 RUN \
   if [ -z "`getent group $HOST_GID`" ]; then \
     addgroup --system --gid $HOST_GID comm; \
   else \
     groupmod --new-name comm `getent group $HOST_GID | cut -d: -f1`; \
   fi && \
   if [ -z "`getent passwd $HOST_UID`" ]; then \
     adduser --system --uid $HOST_UID --ingroup comm --shell /bin/bash comm; \
   else \
     usermod --login comm --gid $HOST_GID --home /home/comm --move-home \
       `getent passwd $HOST_UID | cut -d: -f1`; \
   fi
 
 #-------------------------------------------------------------------------------
 # STEP 1: INSTALL PREREQS
 # Install prereqs first so we don't have to reinstall them if anything changes
 #-------------------------------------------------------------------------------
 
 # We need to add the MariaDB repo to apt in order to install mariadb-client
 RUN wget https://downloads.mariadb.com/MariaDB/mariadb_repo_setup \
   && chmod +x mariadb_repo_setup \
   && ./mariadb_repo_setup \
   && rm mariadb_repo_setup
 
 # We need rsync in the prod-build yarn script
 # We need mariadb-client so we can use mysqldump for backups
 RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y \
   rsync \
   mariadb-client \
   && rm -rf /var/lib/apt/lists/*
 
 #-------------------------------------------------------------------------------
 # STEP 2: DEVOLVE PRIVILEGES
 # Create another user to run the rest of the commands
 #-------------------------------------------------------------------------------
 
 USER comm
 WORKDIR /home/comm/app
 
 #-------------------------------------------------------------------------------
 # STEP 3: SET UP MYSQL BACKUPS
 # Prepare the system to properly handle mysqldump backups
 #-------------------------------------------------------------------------------
 
 # Prepare the directory that will hold the backups
 RUN mkdir /home/comm/backups
 
 #-------------------------------------------------------------------------------
 # STEP 4: SET UP CARGO (RUST PACKAGE MANAGER)
 # We use Cargo to build pre-compiled Node.js addons in Rust
 #-------------------------------------------------------------------------------
 
 # Install Rust and add Cargo's bin directory to the $PATH environment variable
 RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
 ENV PATH /home/comm/.cargo/bin:$PATH
 
 #-------------------------------------------------------------------------------
 # STEP 5: SET UP NVM
 # We use nvm to make sure we're running the right Node version
 #-------------------------------------------------------------------------------
 
 # First we install nvm
 ENV NVM_DIR /home/comm/.nvm
 RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh \
   | bash
 
 # Then we use nvm to install the right version of Node. We call this early so
 # Docker build caching saves us from re-downloading Node when any file changes
 COPY --chown=comm keyserver/.nvmrc keyserver/
 COPY --chown=comm keyserver/bash/source-nvm.sh keyserver/bash/
 RUN cd keyserver && . bash/source-nvm.sh
 
 #-------------------------------------------------------------------------------
 # STEP 6: YARN CLEANINSTALL
 # We run yarn cleaninstall before copying most of the files in for build caching
 #-------------------------------------------------------------------------------
 
 # Copy in package.json and yarn.lock files
-COPY --chown=comm package.json yarn.lock ./
+COPY --chown=comm package.json yarn.lock postinstall.sh ./
 COPY --chown=comm keyserver/package.json keyserver/.flowconfig keyserver/
 COPY --chown=comm lib/package.json lib/.flowconfig lib/
 COPY --chown=comm web/package.json web/.flowconfig web/
-COPY --chown=comm native/package.json native/.flowconfig native/postinstall.sh native/
+COPY --chown=comm native/package.json native/.flowconfig native/
 COPY --chown=comm landing/package.json landing/.flowconfig landing/
 COPY --chown=comm desktop/package.json desktop/
 COPY --chown=comm keyserver/addons/rust-node-addon/package.json \
   keyserver/addons/rust-node-addon/
 COPY --chown=comm native/expo-modules/android-lifecycle/package.json \
   native/expo-modules/android-lifecycle/
 COPY --chown=comm services/electron-update-server/package.json \
   services/electron-update-server/
 
 # Create empty Rust library and copy in Cargo.toml file
 RUN cargo init keyserver/addons/rust-node-addon --lib
 COPY --chown=comm keyserver/addons/rust-node-addon/Cargo.toml \
   keyserver/addons/rust-node-addon/
 
 # Copy in files needed for patch-package
 COPY --chown=comm patches patches/
 
 # Actually run yarn
 RUN yarn cleaninstall
 
 #-------------------------------------------------------------------------------
 # STEP 7: WEBPACK BUILD
 # We do this first so Docker doesn't rebuild when only keyserver files change
 #-------------------------------------------------------------------------------
 
 COPY --chown=comm lib lib/
 COPY --chown=comm landing landing/
 RUN yarn workspace landing prod
 
 COPY --chown=comm web web/
 RUN yarn workspace web prod
 
 #-------------------------------------------------------------------------------
 # STEP 8: COPY IN SOURCE FILES
 # We run this later so the above layers are cached if only source files change
 #-------------------------------------------------------------------------------
 
 COPY --chown=comm . .
 
 #-------------------------------------------------------------------------------
 # STEP 9: BUILD NODE ADDON
 # Now that source files have been copied in, build rust-node-addon
 #-------------------------------------------------------------------------------
 
 RUN yarn workspace rust-node-addon build
 
 #-------------------------------------------------------------------------------
 # STEP 10: RUN BUILD SCRIPTS
 # We need to populate keyserver/dist, among other things
 #-------------------------------------------------------------------------------
 
 # Babel transpilation of keyserver src
 RUN yarn workspace keyserver prod-build
 
 #-------------------------------------------------------------------------------
 # STEP 11: RUN THE SERVER
 # Actually run the Node.js keyserver using nvm
 #-------------------------------------------------------------------------------
 
 EXPOSE 3000
 WORKDIR /home/comm/app/keyserver
 CMD bash/run-prod.sh
diff --git a/native/package.json b/native/package.json
index 7888df090..00842ed72 100644
--- a/native/package.json
+++ b/native/package.json
@@ -1,131 +1,127 @@
 {
   "name": "native",
   "version": "0.0.1",
   "private": true,
   "license": "BSD-3-Clause",
   "scripts": {
     "clean": "yarn clean-commoncpp && yarn clean-android && yarn clean-ios && rm -rf node_modules/ && rm -f ios/.xcode.env.local && (yarn clean-rust || true)",
     "clean-commoncpp": "rm -rf cpp/CommonCpp/build && rm -rf cpp/CommonCpp/CryptoTools/build && rm -rf cpp/CommonCpp/DatabaseManagers/build && rm -rf cpp/CommonCpp/NativeModules/build && rm -rf cpp/CommonCpp/Tools/build",
     "clean-rust": "cargo clean --manifest-path native_rust_library/Cargo.toml",
     "clean-android": "rm -rf android/build android/app/build android/app/.cxx",
     "clean-ios": "rm -rf ios/Pods/",
     "clean-all": "yarn clean && rm -rf ~/Library/Developer/Xcode/DerivedData/Comm-*; cd android && (./gradlew clean || true)",
-    "postinstall": "bash ./postinstall.sh",
     "start": "COMM_DEV=1 yarn expo start --dev-client",
     "dev": "yarn start",
     "test": "yarn jest",
     "run-ios": "COMM_DEV=1 yarn expo run:ios",
     "run-android": "COMM_DEV=1 yarn expo run:android",
     "logfirebase": "adb shell logcat | grep -E -i 'FIRMessagingModule|firebase'",
     "redux-devtools": "redux-devtools --port=8043 --open",
     "codegen-jsi": "flow && babel codegen/src/ -d codegen/dist/ && node codegen/dist",
     "react-native": "PATH=/usr/bin:\"$PATH\" react-native",
     "expo": "PATH=/usr/bin:\"$PATH\" expo"
   },
   "devDependencies": {
     "@babel/cli": "^7.8.4",
     "@babel/core": "^7.13.14",
     "@babel/node": "^7.8.7",
     "@babel/plugin-proposal-nullish-coalescing-operator": "^7.13.8",
     "@babel/plugin-proposal-optional-chaining": "^7.13.12",
     "@babel/preset-flow": "^7.9.0",
     "@redux-devtools/cli": "^1.0.7",
     "babel-jest": "^26.6.3",
     "babel-plugin-transform-remove-console": "^6.9.4",
     "babel-plugin-transform-remove-strict-mode": "0.0.2",
     "flow-bin": "^0.182.0",
-    "flow-mono-cli": "^1.5.0",
     "flow-typed": "^3.2.1",
     "fs-extra": "^8.1.0",
     "googleapis": "^89.0.0",
     "internal-ip": "4.3.0",
     "jest": "^26.6.3",
     "jetifier": "^1.6.4",
     "jsonwebtoken": "^9.0.0",
     "metro-react-native-babel-preset": "^0.72.3",
-    "patch-package": "^6.4.7",
-    "postinstall-postinstall": "^2.0.0",
     "react-devtools": "^4.27.0",
     "react-native-codegen": "^0.70.6",
     "react-test-renderer": "18.1.0",
     "remote-redux-devtools": "git+https://git@github.com/zalmoxisus/remote-redux-devtools.git",
     "remotedev": "git+https://git@github.com/zalmoxisus/remotedev.git"
   },
   "dependencies": {
     "@commapp/android-lifecycle": "0.0.1",
     "@commapp/sqlcipher-amalgamation": "^4.4.3-a",
     "@ethersproject/shims": "^5.7.0",
     "@expo/react-native-action-sheet": "^3.14.0",
     "@expo/vector-icons": "^13.0.0",
     "@gorhom/bottom-sheet": "^4.4.5",
     "@react-native-async-storage/async-storage": "^1.17.10",
     "@react-native-clipboard/clipboard": "^1.11.1",
     "@react-native-community/art": "^1.2.0",
     "@react-native-community/netinfo": "^9.3.7",
     "@react-native-masked-view/masked-view": "^0.2.8",
     "@react-navigation/bottom-tabs": "^6.4.0",
     "@react-navigation/devtools": "^6.0.10",
     "@react-navigation/drawer": "^6.5.0",
     "@react-navigation/elements": "^1.3.6",
     "@react-navigation/material-top-tabs": "^6.3.0",
     "@react-navigation/native": "^6.0.13",
     "@react-navigation/stack": "^6.3.2",
     "base-64": "^0.1.0",
     "ethers": "^5.7.2",
     "expo": "47.0.8",
     "expo-dev-client": "~2.0.1",
     "expo-font": "~11.0.1",
     "expo-haptics": "~12.0.1",
     "expo-image-manipulator": "~11.0.0",
     "expo-image-picker": "~14.0.2",
     "expo-media-library": "~15.0.0",
     "expo-secure-store": "~12.0.0",
     "expo-splash-screen": "~0.17.4",
     "find-root": "^1.1.0",
     "invariant": "^2.2.4",
     "lib": "0.0.1",
     "lodash": "^4.17.21",
     "lottie-react-native": "^5.1.4",
     "md5": "^2.2.1",
     "olm": "git+https://gitlab.matrix.org/matrix-org/olm.git#v3.2.4",
     "react": "18.1.0",
     "react-native": "^0.70.6",
     "react-native-background-upload": "^6.6.0",
     "react-native-camera": "^3.31.0",
     "react-native-device-info": "^10.3.0",
     "react-native-exit-app": "^1.1.0",
     "react-native-fast-image": "^8.3.0",
     "react-native-ffmpeg": "^0.4.4",
     "react-native-figma-squircle": "^0.1.2",
     "react-native-floating-action": "^1.22.0",
     "react-native-fs": "^2.20.0",
     "react-native-gesture-handler": "^2.8.0",
     "react-native-in-app-message": "^1.0.2",
     "react-native-keyboard-input": "6.0.1",
     "react-native-keychain": "^8.0.0",
     "react-native-orientation-locker": "^1.5.0",
     "react-native-pager-view": "^6.0.1",
     "react-native-progress": "^4.1.2",
     "react-native-reanimated": "^2.12.0",
     "react-native-safe-area-context": "^4.4.1",
     "react-native-screens": "^3.18.2",
     "react-native-svg": "^12.3.0",
     "react-native-tab-view": "^3.3.0",
     "react-native-video": "^5.2.1",
     "react-native-webview": "^11.23.0",
     "react-redux": "^7.1.1",
     "reactotron-react-native": "^5.0.3",
     "reactotron-redux": "^3.1.3",
     "redux": "^4.0.4",
     "redux-persist": "^6.0.0",
     "redux-thunk": "^2.2.0",
     "reselect": "^4.0.0",
     "rn-emoji-keyboard": "^1.2.0",
     "shallowequal": "^1.0.2",
     "simple-markdown": "^0.7.2",
     "tinycolor2": "^1.4.1"
   },
   "jest": {
     "preset": "react-native"
   }
 }
diff --git a/package.json b/package.json
index 24188e12e..933fc38b8 100644
--- a/package.json
+++ b/package.json
@@ -1,49 +1,53 @@
 {
   "private": true,
   "license": "BSD-3-Clause",
   "workspaces": [
     "lib",
     "web",
     "native",
     "keyserver",
     "landing",
     "desktop",
     "keyserver/addons/rust-node-addon",
     "native/expo-modules/android-lifecycle",
     "services/electron-update-server"
   ],
   "scripts": {
     "clean": "yarn workspace lib clean && yarn workspace web clean && yarn workspace native clean && yarn workspace keyserver clean && yarn workspace landing clean && yarn workspace desktop clean && yarn workspace rust-node-addon clean && yarn workspace electron-update-server clean && rm -rf node_modules/",
     "cleaninstall": "(killall flow || pkill flow || true) && yarn clean && yarn",
     "eslint": "eslint .",
     "eslint:fix": "eslint --fix .",
     "clang-format-all": "eval `node scripts/get_clang_paths_cli.js` | xargs clang-format -i",
     "rust-pre-commit": "./scripts/rust_pre_commit.sh",
     "terraform-pre-commit": "./scripts/terraform_pre_commit.sh",
     "prepare": "husky install",
-    "arcpatch": "git pull --all --tags && arc patch"
+    "arcpatch": "git pull --all --tags && arc patch",
+    "postinstall": "bash ./postinstall.sh"
   },
   "devDependencies": {
     "babel-eslint": "^10.1.0",
     "clang-format": "^1.8.0",
     "core-js": "^3.6.5",
     "eslint": "^7.32.0",
     "eslint-config-prettier": "^8.1.0",
     "eslint-plugin-flowtype": "^5.4.0",
     "eslint-plugin-import": "^2.22.1",
     "eslint-plugin-jest": "^24.2.2",
     "eslint-plugin-monorepo": "^0.3.2",
     "eslint-plugin-prettier": "^3.3.1",
     "eslint-plugin-react": "^7.22.0",
     "eslint-plugin-react-hooks": "^4.2.0",
     "eslint-plugin-react-native": "^3.10.0",
     "find-up": "^5.0.0",
+    "flow-mono-cli": "^1.5.0",
     "gaxios": "^4.3.2",
     "husky": "^7.0.0",
     "lint-staged": "^12.1.4",
+    "patch-package": "^6.4.7",
+    "postinstall-postinstall": "^2.0.0",
     "prettier": "^2.1.2"
   },
   "resolutions": {
     "react-native-flipper": "https://registry.yarnpkg.com/@favware/skip-dependency/-/skip-dependency-1.1.1.tgz"
   }
 }
diff --git a/native/postinstall.sh b/postinstall.sh
similarity index 76%
rename from native/postinstall.sh
rename to postinstall.sh
index 83b34fddb..48f1da65c 100644
--- a/native/postinstall.sh
+++ b/postinstall.sh
@@ -1,20 +1,18 @@
 #!/usr/bin/env bash
 
 set -Eeuo pipefail
 
 # Skip Windows
 if [[ "$OSTYPE" == "msys" ]]; then
   exit 0
 fi
 
-cd ../
 echo '{"name": "olm", "version": "3.2.4"}' > ./node_modules/olm/package.json
 yarn patch-package
 yarn flow-mono create-symlinks native
 
-cd native
-yarn jetify
+yarn workspace native jetify
 
 if [[ "$OSTYPE" == "darwin"* ]]; then
-  (cd ios && PATH=/usr/bin:"$PATH" pod install)
+  (cd native/ios && PATH=/usr/bin:"$PATH" pod install)
 fi