diff --git a/.python-version b/.python-version
index 54c5196a2b9da061074225f39dc40aed04fec0b9..1e3345683185ff5fa1766bc32c8380795c7589c4 100644
--- a/.python-version
+++ b/.python-version
@@ -1 +1 @@
-3.10.9
+3.11.2
diff --git a/openbook/settings/__init__.py b/openbook/settings/__init__.py
index 67f3ed79f0429b9023003538f11cfa238eeee4a7..6c9aab1f62dc3e2d3bb437b481df3aa08b19bae2 100644
--- a/openbook/settings/__init__.py
+++ b/openbook/settings/__init__.py
@@ -75,10 +75,8 @@ INSTALLED_APPS = [
     "rest_framework.authtoken",
     "pytest_django",
     "ordered_model",
-    "storages",
     "video_encoding",
     "imagekit",
-    "django_media_fixtures",
     "cacheops",
     "django_rq",
     "django_extensions",
@@ -311,27 +309,8 @@ else:
 
     DATABASES = {
         "default": writer_db_config,
-        # 'Reader': {
-        #    'ENGINE': 'django.db.backends.mysql',
-        #    'NAME': RDS_DB_NAME,
-        #    'USER': RDS_USERNAME,
-        #    'PASSWORD': RDS_PASSWORD,
-        #    'HOST': RDS_HOSTNAME_READER,
-        #    'PORT': RDS_PORT,
-        #    'OPTIONS': db_options,
-        # }
     }
 
-    # DATABASE_ROUTERS = ['django_replicated.router.ReplicationRouter']
-
-    # REPLICATED_DATABASE_SLAVES = ['Reader', ]
-
-    # MIDDLEWARE.append('django_replicated.middleware.ReplicationMiddleware', )
-
-    # REPLICATED_VIEWS_OVERRIDES = {
-    #    '/admin/*': 'master',
-    # }
-
 # Password validation
 # https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators
 
@@ -585,30 +564,6 @@ AWS_DEFAULT_ACL = None
 
 DEFAULT_FILE_STORAGE = "openbook.storage_imagekit_io.ImagekitIoStorage"
 
-if False:  # IS_PRODUCTION:
-    AWS_ACCESS_KEY_ID = os.environ.get("AWS_ACCESS_KEY_ID")
-    AWS_SECRET_ACCESS_KEY = os.environ.get("AWS_SECRET_ACCESS_KEY")
-    AWS_STORAGE_BUCKET_NAME = os.environ.get("AWS_STORAGE_BUCKET_NAME")
-    AWS_S3_REGION_NAME = os.environ.get("AWS_S3_REGION_NAME")
-    AWS_S3_ENCRYPTION = True
-    AWS_S3_SIGNATURE_VERSION = "s3v4"
-    AWS_S3_HOST = os.environ.get("AWS_S3_HOST", "s3.amazonaws.com")
-    AWS_S3_CUSTOM_DOMAIN = f"{AWS_STORAGE_BUCKET_NAME}.{AWS_S3_HOST}"
-
-    AWS_S3_OBJECT_PARAMETERS = {
-        "CacheControl": "max-age=86400",
-    }
-
-    STATIC_URL = f"https://{AWS_S3_CUSTOM_DOMAIN}/{AWS_STATIC_LOCATION}/"
-
-    MEDIA_URL = f"https://{AWS_S3_CUSTOM_DOMAIN}/{AWS_PUBLIC_MEDIA_LOCATION}/"
-
-    STATICFILES_STORAGE = "openbook.storage_backends.S3StaticStorage"
-
-    DEFAULT_FILE_STORAGE = "openbook.storage_backends.S3PublicMediaStorage"
-
-    PRIVATE_FILE_STORAGE = "openbook.storage_backends.S3PrivateMediaStorage"
-
 # ONE SIGNAL
 ONE_SIGNAL_APP_ID = os.environ.get("ONE_SIGNAL_APP_ID")
 ONE_SIGNAL_API_KEY = os.environ.get("ONE_SIGNAL_API_KEY")
diff --git a/openbook/storage_backends.py b/openbook/storage_backends.py
deleted file mode 100644
index cacab0c4052e00b921acd0406793fdff89c706a6..0000000000000000000000000000000000000000
--- a/openbook/storage_backends.py
+++ /dev/null
@@ -1,49 +0,0 @@
-from botocore.config import Config
-from django.conf import settings
-from storages.backends.s3boto3 import S3Boto3Storage
-
-
-class S3StaticStorage(S3Boto3Storage):
-    location = settings.AWS_STATIC_LOCATION
-
-    def __init__(self, *args, **kwargs):
-        self.config = Config(
-            s3={
-                "addressing_style": self.addressing_style,
-                "use_accelerate_endpoint": True,
-            },
-            signature_version=self.signature_version,
-        )
-        super().__init__(*args, **kwargs)
-
-
-class S3PublicMediaStorage(S3Boto3Storage):
-    location = settings.AWS_PUBLIC_MEDIA_LOCATION
-    file_overwrite = False
-
-    def __init__(self, *args, **kwargs):
-        self.config = Config(
-            s3={
-                "addressing_style": self.addressing_style,
-                "use_accelerate_endpoint": True,
-            },
-            signature_version=self.signature_version,
-        )
-        super().__init__(*args, **kwargs)
-
-
-class S3PrivateMediaStorage(S3Boto3Storage):
-    location = settings.AWS_PRIVATE_MEDIA_LOCATION
-    default_acl = "private"
-    file_overwrite = False
-    custom_domain = False
-
-    def __init__(self, *args, **kwargs):
-        self.config = Config(
-            s3={
-                "addressing_style": self.addressing_style,
-                "use_accelerate_endpoint": True,
-            },
-            signature_version=self.signature_version,
-        )
-        super().__init__(*args, **kwargs)
diff --git a/openbook_hashtags/models.py b/openbook_hashtags/models.py
index f85b0da84a5ca63745be1a11f5e4f53a0cd050e7..b20f5cff9d47acf67a5dead44f6e0fa86bb15661 100644
--- a/openbook_hashtags/models.py
+++ b/openbook_hashtags/models.py
@@ -10,7 +10,6 @@ from django.utils.translation import gettext_lazy as _
 from imagekit.models import ProcessedImageField
 from pilkit.processors import ResizeToFit
 
-from openbook.storage_backends import S3PrivateMediaStorage
 from openbook_common.helpers import ExifRotate
 from openbook_common.models import Emoji, ModelWithUUID
 from openbook_common.utils.helpers import delete_file_field, get_random_pastel_color
diff --git a/openbook_posts/views/post/views.py b/openbook_posts/views/post/views.py
index d4a9bb54ad71e1fa3a5a13c3c29a6663d49719d2..e169eac3fb9295f11c9925e01d7c6f0d90766673 100644
--- a/openbook_posts/views/post/views.py
+++ b/openbook_posts/views/post/views.py
@@ -4,7 +4,6 @@ from rest_framework.permissions import IsAuthenticated
 from rest_framework.response import Response
 from rest_framework.views import APIView
 from django.utils.translation import gettext_lazy as _
-from webpreview import URLUnreachable, URLNotFound
 
 from openbook_common.responses import ApiMessageResponse
 from openbook_moderation.permissions import IsNotSuspended
diff --git a/requirements.txt b/requirements.txt
index a4acb093d2f8b8242f41f48c2596ef17d298c720..3d478ee7d807b9353a068cab7f03de7c89a2365c 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -8,11 +8,8 @@ blurhash-python==1.2.0
 boto3==1.26.159
 botocore==1.29.159
 certifi==2023.5.7
-chardet==5.1.0
 coverage==7.2.7
-croniter==1.4.1
 decorator==5.1.1
-django-amazon-ses==4.0.1
 django-appconf==1.0.5
 django-cacheops==7.0.1
 django-cors-headers==4.1.0
@@ -20,17 +17,13 @@ django-cursor-pagination==0.2.1
 django-debug-toolbar==4.1.0
 django-extensions==3.2.3
 django-imagekit==4.1.0
-django-media-fixtures==1.0.0
 django-model-utils==4.3.1
 django-modeltranslation==0.18.10
 django-nose==1.4.7
 django-ordered-model==3.7.4
-django-positions==0.6.0
 django-proxy==1.2.2
 django-redis==5.3.0
-django-replicated==2.7
 django-rq==2.8.1
-django-storages==1.13.2
 django-structlog==5.1.0
 django==4.2.2
 djangorestframework-camel-case==1.4.2
@@ -48,8 +41,6 @@ imagekitio==2.2.8 # version 3 contains many breaking changes
 langdetect==1.0.9
 log-symbols==0.0.14
 mixer==7.2.2
-natsort==8.4.0; python_version >= '3.4'
-networkx==3.1; python_version >= '3.6'
 nose-exclude==0.5.0
 nose==1.3.7
 onesignal-sdk==1.1.0 # internally used by okuna, not worth the update
@@ -73,12 +64,10 @@ redis==4.5.5
 requests-file==1.5.1
 rest-framework-generic-relations==2.1.0
 rq==1.15.1
-s3transfer==0.6.1
 safety==2.3.5
 sentry-sdk==1.26.0
 shutilwhich==1.1.0
 six==1.16.0
-soupsieve==2.4.1; python_version >= '3.0'
 spinners==0.0.24
 sqlparse==0.4.4; python_version >= '3.5'
 stevedore==5.1.0; python_version >= '3.6'
@@ -94,6 +83,5 @@ urlextract==1.8.0
 urllib3==1.26.15; python_version != '3.4' # imagekit requires <1.27
 uvicorn==0.22.0
 watchdog==3.0.0
-webpreview==1.7.2
 whitenoise==6.5.0
-zipp==3.15.0; python_version >= '3.6'
+zipp==3.15.0; python_version >= '3.6'
\ No newline at end of file
diff --git a/reset_environment.sh b/reset_environment.sh
index 171ec20a256d7a0a31a09bae041f53aafda5e5ba..7cffd105b694690e2493f4b3c7a0f5c08d1cebdc 100755
--- a/reset_environment.sh
+++ b/reset_environment.sh
@@ -12,7 +12,7 @@ if command -v pyenv &> /dev/null; then
   pyenv local "$project_python_version"
 fi
 
-current_python_interpreter=$(python -V | sed -e "s/^Python //")
+current_python_interpreter=$(python3 -V | sed -e "s/^Python //")
 
 if [[ "$project_python_version" != "$current_python_interpreter" ]]; then
   echo "❌ Current interpreter does not match project requirements, consider using pyenv"