diff --git a/common/djangoapps/course_modes/views.py b/common/djangoapps/course_modes/views.py
index 517d05afa6de51bf0a002461ff3f2b5abe312a07..389c5a59f72cdc03ffc80fec5597375cff8ead68 100644
--- a/common/djangoapps/course_modes/views.py
+++ b/common/djangoapps/course_modes/views.py
@@ -21,7 +21,7 @@ from django.utils.translation import get_language, to_locale
 from django.utils.translation import ugettext as _
 from django.views.generic.base import View
 from edx_django_utils.monitoring.utils import increment
-from ipware.ip import get_ip
+from ipware.ip import get_client_ip
 from opaque_keys.edx.keys import CourseKey
 from six import text_type
 
@@ -90,7 +90,7 @@ class ChooseModeView(View):
         embargo_redirect = embargo_api.redirect_if_blocked(
             course_key,
             user=request.user,
-            ip_address=get_ip(request),
+            ip_address=get_client_ip(request)[0],
             url=request.path
         )
         if embargo_redirect:
diff --git a/common/djangoapps/student/views/management.py b/common/djangoapps/student/views/management.py
index 0a62a604de2e6f64e3cc721ae11c6e74c3e1b7c0..ea2ce144657a4a37455c46398185bb9ab23f45ce 100644
--- a/common/djangoapps/student/views/management.py
+++ b/common/djangoapps/student/views/management.py
@@ -29,7 +29,7 @@ from edx_ace import ace
 from edx_ace.recipient import Recipient
 from edx_django_utils import monitoring as monitoring_utils
 from eventtracking import tracker
-from ipware.ip import get_ip
+from ipware.ip import get_client_ip
 # Note that this lives in LMS, so this dependency should be refactored.
 from opaque_keys import InvalidKeyError
 from opaque_keys.edx.keys import CourseKey
@@ -340,7 +340,7 @@ def change_enrollment(request, check_access=True):
         # or if the user is enrolling in a country in which the course
         # is not available.
         redirect_url = embargo_api.redirect_if_blocked(
-            course_id, user=user, ip_address=get_ip(request),
+            course_id, user=user, ip_address=get_client_ip(request)[0],
             url=request.path
         )
         if redirect_url:
diff --git a/common/djangoapps/track/middleware.py b/common/djangoapps/track/middleware.py
index 20a84f104ab78e5642bfdaed90cc3676c0c61b69..df125afea34043bdfe785af4fccec66953bc9bfb 100644
--- a/common/djangoapps/track/middleware.py
+++ b/common/djangoapps/track/middleware.py
@@ -16,7 +16,7 @@ import six
 from django.conf import settings
 from django.utils.deprecation import MiddlewareMixin
 from eventtracking import tracker
-from ipware.ip import get_ip
+from ipware.ip import get_client_ip
 
 from common.djangoapps.track import contexts, views
 
@@ -229,7 +229,7 @@ class TrackMiddleware(MiddlewareMixin):
 
     def get_request_ip_address(self, request):
         """Gets the IP address of the request"""
-        ip_address = get_ip(request)
+        ip_address = get_client_ip(request)[0]
         if ip_address is not None:
             return ip_address
         else:
diff --git a/common/djangoapps/track/views/__init__.py b/common/djangoapps/track/views/__init__.py
index 011bb9cc4d1afad78a90889ac0c54de5e67fd287..0d6552b5276e0a51b4b13d036e2fbdbb47dadbc9 100644
--- a/common/djangoapps/track/views/__init__.py
+++ b/common/djangoapps/track/views/__init__.py
@@ -6,7 +6,7 @@ import six
 from django.contrib.auth.models import User  # lint-amnesty, pylint: disable=imported-auth-user
 from django.http import HttpResponse
 from eventtracking import tracker as eventtracker
-from ipware.ip import get_ip
+from ipware.ip import get_client_ip
 
 from common.djangoapps.track import contexts, shim, tracker
 
@@ -22,7 +22,7 @@ def _get_request_header(request, header_name, default=''):
 def _get_request_ip(request, default=''):
     """Helper method to get IP from a request's META dict, if present."""
     if request is not None and hasattr(request, 'META'):
-        return get_ip(request)
+        return get_client_ip(request)[0]
     else:
         return default
 
diff --git a/lms/djangoapps/courseware/views/views.py b/lms/djangoapps/courseware/views/views.py
index acecda81cdbbb71525ce752bf673964947b4eb32..096445c64b52cc394f622bb20bc37454a1609401 100644
--- a/lms/djangoapps/courseware/views/views.py
+++ b/lms/djangoapps/courseware/views/views.py
@@ -34,7 +34,7 @@ from django.views.decorators.http import require_GET, require_http_methods, requ
 from django.views.generic import View
 from edx_django_utils import monitoring as monitoring_utils
 from edx_django_utils.monitoring import set_custom_attribute, set_custom_attributes_for_course_key
-from ipware.ip import get_ip
+from ipware.ip import get_client_ip
 from markupsafe import escape
 from opaque_keys import InvalidKeyError
 from opaque_keys.edx.keys import CourseKey, UsageKey
@@ -1911,7 +1911,7 @@ def financial_assistance_request(request):
         goals = data['goals']
         effort = data['effort']
         marketing_permission = data['mktg-permission']
-        ip_address = get_ip(request)
+        ip_address = get_client_ip(request)[0]
     except ValueError:
         # Thrown if JSON parsing fails
         return HttpResponseBadRequest(u'Could not parse request JSON.')
diff --git a/lms/djangoapps/verify_student/views.py b/lms/djangoapps/verify_student/views.py
index d8f32afe3e0ca24766944e790d1d341494262394..8b9195238c08c0461d380bb73d6865ed53395101 100644
--- a/lms/djangoapps/verify_student/views.py
+++ b/lms/djangoapps/verify_student/views.py
@@ -23,7 +23,7 @@ from django.views.decorators.csrf import csrf_exempt
 from django.views.decorators.http import require_POST
 from django.views.generic.base import View
 from edx_rest_api_client.exceptions import SlumberBaseException
-from ipware.ip import get_ip
+from ipware.ip import get_client_ip
 from opaque_keys.edx.keys import CourseKey
 from rest_framework.response import Response
 from rest_framework.views import APIView
@@ -243,7 +243,7 @@ class PayAndVerifyView(View):
         redirect_url = embargo_api.redirect_if_blocked(
             course_key,
             user=request.user,
-            ip_address=get_ip(request),
+            ip_address=get_client_ip(request)[0],
             url=request.path
         )
         if redirect_url:
diff --git a/openedx/core/djangoapps/embargo/api.py b/openedx/core/djangoapps/embargo/api.py
index 7c9a73ad00004c1a378c33bf13760dac4dea7a17..73d29d11ad65a4073fcea0335a1f465f176a71a6 100644
--- a/openedx/core/djangoapps/embargo/api.py
+++ b/openedx/core/djangoapps/embargo/api.py
@@ -10,7 +10,7 @@ import logging
 
 from django.conf import settings
 from django.core.cache import cache
-from ipware.ip import get_ip
+from ipware.ip import get_client_ip
 from rest_framework import status
 from rest_framework.response import Response
 
@@ -197,7 +197,7 @@ def get_embargo_response(request, course_id, user):
 
     """
     redirect_url = redirect_if_blocked(
-        course_id, user=user, ip_address=get_ip(request), url=request.path)
+        course_id, user=user, ip_address=get_client_ip(request)[0], url=request.path)
     if redirect_url:
         return Response(
             status=status.HTTP_403_FORBIDDEN,
diff --git a/openedx/core/djangoapps/embargo/middleware.py b/openedx/core/djangoapps/embargo/middleware.py
index 94051c518e0709d234917982adaef4ad0e061762..feb476fc9c30cbe6b7ecac6ba5dc5564c27b5c42 100644
--- a/openedx/core/djangoapps/embargo/middleware.py
+++ b/openedx/core/djangoapps/embargo/middleware.py
@@ -34,7 +34,7 @@ from django.core.exceptions import MiddlewareNotUsed
 from django.urls import reverse
 from django.utils.deprecation import MiddlewareMixin
 from django.shortcuts import redirect
-from ipware.ip import get_ip
+from ipware.ip import get_client_ip
 
 from openedx.core.lib.request_utils import course_id_from_url
 
@@ -83,7 +83,7 @@ class EmbargoMiddleware(MiddlewareMixin):
             if pattern.match(request.path) is not None:
                 return None
 
-        ip_address = get_ip(request)
+        ip_address = get_client_ip(request)[0]
         ip_filter = IPFilter.current()
 
         if ip_filter.enabled and ip_address in ip_filter.blacklist_ips:
diff --git a/openedx/core/djangoapps/geoinfo/middleware.py b/openedx/core/djangoapps/geoinfo/middleware.py
index dbc01ec95aa8feb94fc5a0f6aa7d1b9cea962bf8..f465dd1654fb157274cfd2974eb0bbd3ac34cb18 100644
--- a/openedx/core/djangoapps/geoinfo/middleware.py
+++ b/openedx/core/djangoapps/geoinfo/middleware.py
@@ -9,14 +9,13 @@ Usage:
 decorator `django.utils.decorators.decorator_from_middleware(middleware_class)`
 
 """
-
-
 import logging
 import geoip2.database
 
 from django.conf import settings
 from django.utils.deprecation import MiddlewareMixin
-from ipware.ip import get_real_ip
+from ipware.ip import get_client_ip
+from ipware.utils import is_public_ip
 
 log = logging.getLogger(__name__)
 
@@ -31,13 +30,13 @@ class CountryMiddleware(MiddlewareMixin):
 
         Store country code in session.
         """
-        new_ip_address = get_real_ip(request)
+        new_ip_address = get_client_ip(request)[0]
         old_ip_address = request.session.get('ip_address', None)
 
         if not new_ip_address and old_ip_address:
             del request.session['ip_address']
             del request.session['country_code']
-        elif new_ip_address != old_ip_address:
+        elif new_ip_address != old_ip_address and is_public_ip(new_ip_address):
             reader = geoip2.database.Reader(settings.GEOIP_PATH)
             try:
                 response = reader.country(new_ip_address)
diff --git a/openedx/core/djangoapps/geoinfo/tests/test_middleware.py b/openedx/core/djangoapps/geoinfo/tests/test_middleware.py
index 4e3baa3f3e05b8808bb4325a3c7dcd8f00d216ca..6a5e82ae8b0d342dff62bb840f0b285d6ce33d6c 100644
--- a/openedx/core/djangoapps/geoinfo/tests/test_middleware.py
+++ b/openedx/core/djangoapps/geoinfo/tests/test_middleware.py
@@ -107,20 +107,6 @@ class CountryMiddlewareTests(TestCase):
         assert 'CN' == request.session.get('country_code')
         assert '117.79.83.100' == request.session.get('ip_address')
 
-    def test_ip_address_is_none(self):
-        # IP address is not defined in request.
-        request = self.request_factory.get('/somewhere')
-        request.user = self.anonymous_user
-        # Run process_request to set up the session in the request
-        # to be able to override it.
-        self.session_middleware.process_request(request)
-        request.session['country_code'] = 'CN'
-        request.session['ip_address'] = '117.79.83.1'
-        self.country_middleware.process_request(request)
-        # No country code exists after request processing.
-        assert 'country_code' not in request.session
-        assert 'ip_address' not in request.session
-
     def test_ip_address_is_ipv6(self):
         request = self.request_factory.get(
             '/somewhere',
diff --git a/openedx/core/djangoapps/util/ratelimit.py b/openedx/core/djangoapps/util/ratelimit.py
index 9dc1ea858c1d4935bcf55462810b93b6e86159f3..6fd7266f559838672293d9c3656c23dd55fc23f6 100644
--- a/openedx/core/djangoapps/util/ratelimit.py
+++ b/openedx/core/djangoapps/util/ratelimit.py
@@ -1,15 +1,13 @@
 """
 Code to get ip from request.
 """
-
-
 from uuid import uuid4
 
-from ipware.ip import get_ip
+from ipware.ip import get_client_ip
 
 
 def real_ip(group, request):  # pylint: disable=unused-argument
-    return get_ip(request)
+    return get_client_ip(request)[0]
 
 
 def request_post_email(group, request) -> str:  # pylint: disable=unused-argument
diff --git a/requirements/constraints.txt b/requirements/constraints.txt
index 2deab70c368fc5b050ca9c38adf8c82dcf762686..667c146d000429681c50fc90e70508eb0bcbb957 100644
--- a/requirements/constraints.txt
+++ b/requirements/constraints.txt
@@ -24,9 +24,6 @@ django-cors-headers<3.0.0
 # It seems like django-countries > 5.5 may cause performance issues for us.
 django-countries==5.5
 
-# Removes deprecated get_ip function, which we still use (ARCHBOM-1329 for unpinning)
-django-ipware<3.0.0
-
 # django-storages version 1.9 drops support for boto storage backend.
 django-storages<1.9
 
@@ -34,7 +31,7 @@ django-storages<1.9
 # The team that owns this package will manually bump this package rather than having it pulled in automatically.
 # This is to allow them to better control its deployment and to do it in a process that works better
 # for them.
-edx-enterprise==3.17.40
+edx-enterprise==3.17.41
 
 # Upgrading to 2.12.0 breaks several test classes due to API changes, need to update our code accordingly
 factory-boy==2.8.1
diff --git a/requirements/edx/base.txt b/requirements/edx/base.txt
index 1f7c091740e7a3584e1928070fc0c9da919bc484..8124ca532a97dd047019d2a078918bf4808fae3e 100644
--- a/requirements/edx/base.txt
+++ b/requirements/edx/base.txt
@@ -58,7 +58,7 @@ django-countries==5.5     # via -c requirements/edx/../constraints.txt, -r requi
 django-crum==0.7.9        # via -r requirements/edx/base.in, edx-django-utils, edx-enterprise, edx-proctoring, edx-rbac, edx-toggles, super-csv
 django-fernet-fields==0.6  # via -r requirements/edx/base.in, edx-enterprise, edx-event-routing-backends, edxval
 django-filter==2.4.0      # via -r requirements/edx/base.in, edx-enterprise, lti-consumer-xblock
-django-ipware==2.1.0      # via -c requirements/edx/../constraints.txt, -r requirements/edx/base.in, edx-enterprise, edx-proctoring
+django-ipware==3.0.2      # via -c requirements/edx/../constraints.txt, -r requirements/edx/base.in, edx-enterprise, edx-proctoring
 django-js-asset==1.2.2    # via django-mptt
 django-method-override==1.0.4  # via -r requirements/edx/base.in
 django-model-utils==4.1.1  # via -r requirements/edx/base.in, django-user-tasks, edx-bulk-grades, edx-celeryutils, edx-completion, edx-enterprise, edx-milestones, edx-organizations, edx-proctoring, edx-rbac, edx-submissions, edx-when, edxval, ora2, super-csv
@@ -99,7 +99,7 @@ edx-django-release-util==1.0.0  # via -r requirements/edx/base.in
 edx-django-sites-extensions==3.0.0  # via -r requirements/edx/base.in
 edx-django-utils==3.13.0  # via -r requirements/edx/base.in, django-config-models, edx-drf-extensions, edx-enterprise, edx-rest-api-client, edx-toggles, edx-when, ora2, super-csv
 edx-drf-extensions==6.5.0  # via -r requirements/edx/base.in, edx-completion, edx-enterprise, edx-organizations, edx-proctoring, edx-rbac, edx-when, edxval
-edx-enterprise==3.17.40   # via -c requirements/edx/../constraints.txt, -r requirements/edx/base.in
+edx-enterprise==3.17.41   # via -c requirements/edx/../constraints.txt, -r requirements/edx/base.in
 edx-event-routing-backends==4.0.1  # via -r requirements/edx/base.in
 edx-i18n-tools==0.5.3     # via ora2
 edx-milestones==0.3.0     # via -r requirements/edx/base.in
diff --git a/requirements/edx/development.txt b/requirements/edx/development.txt
index 692df620382fcd5b20efb8cfd3234797202a5bfe..4f4e6be2d154b7fcad7c5b5617c6613feedf5607 100644
--- a/requirements/edx/development.txt
+++ b/requirements/edx/development.txt
@@ -69,7 +69,7 @@ django-crum==0.7.9        # via -r requirements/edx/testing.txt, edx-django-util
 django-debug-toolbar==3.2  # via -r requirements/edx/development.in
 django-fernet-fields==0.6  # via -r requirements/edx/testing.txt, edx-enterprise, edx-event-routing-backends, edxval
 django-filter==2.4.0      # via -r requirements/edx/testing.txt, edx-enterprise, lti-consumer-xblock
-django-ipware==2.1.0      # via -c requirements/edx/../constraints.txt, -r requirements/edx/testing.txt, edx-enterprise, edx-proctoring
+django-ipware==3.0.2      # via -c requirements/edx/../constraints.txt, -r requirements/edx/testing.txt, edx-enterprise, edx-proctoring
 django-js-asset==1.2.2    # via -r requirements/edx/testing.txt, django-mptt
 django-method-override==1.0.4  # via -r requirements/edx/testing.txt
 django-model-utils==4.1.1  # via -r requirements/edx/testing.txt, django-user-tasks, edx-bulk-grades, edx-celeryutils, edx-completion, edx-enterprise, edx-milestones, edx-organizations, edx-proctoring, edx-rbac, edx-submissions, edx-when, edxval, ora2, super-csv
@@ -110,7 +110,7 @@ edx-django-release-util==1.0.0  # via -r requirements/edx/testing.txt
 edx-django-sites-extensions==3.0.0  # via -r requirements/edx/testing.txt
 edx-django-utils==3.13.0  # via -r requirements/edx/testing.txt, django-config-models, edx-drf-extensions, edx-enterprise, edx-rest-api-client, edx-toggles, edx-when, ora2, super-csv
 edx-drf-extensions==6.5.0  # via -r requirements/edx/testing.txt, edx-completion, edx-enterprise, edx-organizations, edx-proctoring, edx-rbac, edx-when, edxval
-edx-enterprise==3.17.40   # via -c requirements/edx/../constraints.txt, -r requirements/edx/testing.txt
+edx-enterprise==3.17.41   # via -c requirements/edx/../constraints.txt, -r requirements/edx/testing.txt
 edx-event-routing-backends==4.0.1  # via -r requirements/edx/testing.txt
 edx-i18n-tools==0.5.3     # via -r requirements/edx/testing.txt, ora2
 edx-lint==4.0.1           # via -r requirements/edx/testing.txt
diff --git a/requirements/edx/testing.txt b/requirements/edx/testing.txt
index 992efa764e40b9f897eb74e825ca036a1257b385..cdb2c27c5653b9dafabe809ec0a6697de243d9a4 100644
--- a/requirements/edx/testing.txt
+++ b/requirements/edx/testing.txt
@@ -67,7 +67,7 @@ django-countries==5.5     # via -c requirements/edx/../constraints.txt, -r requi
 django-crum==0.7.9        # via -r requirements/edx/base.txt, edx-django-utils, edx-enterprise, edx-proctoring, edx-rbac, edx-toggles, super-csv
 django-fernet-fields==0.6  # via -r requirements/edx/base.txt, edx-enterprise, edx-event-routing-backends, edxval
 django-filter==2.4.0      # via -r requirements/edx/base.txt, edx-enterprise, lti-consumer-xblock
-django-ipware==2.1.0      # via -c requirements/edx/../constraints.txt, -r requirements/edx/base.txt, edx-enterprise, edx-proctoring
+django-ipware==3.0.2      # via -c requirements/edx/../constraints.txt, -r requirements/edx/base.txt, edx-enterprise, edx-proctoring
 django-js-asset==1.2.2    # via -r requirements/edx/base.txt, django-mptt
 django-method-override==1.0.4  # via -r requirements/edx/base.txt
 django-model-utils==4.1.1  # via -r requirements/edx/base.txt, django-user-tasks, edx-bulk-grades, edx-celeryutils, edx-completion, edx-enterprise, edx-milestones, edx-organizations, edx-proctoring, edx-rbac, edx-submissions, edx-when, edxval, ora2, super-csv
@@ -107,7 +107,7 @@ edx-django-release-util==1.0.0  # via -r requirements/edx/base.txt
 edx-django-sites-extensions==3.0.0  # via -r requirements/edx/base.txt
 edx-django-utils==3.13.0  # via -r requirements/edx/base.txt, django-config-models, edx-drf-extensions, edx-enterprise, edx-rest-api-client, edx-toggles, edx-when, ora2, super-csv
 edx-drf-extensions==6.5.0  # via -r requirements/edx/base.txt, edx-completion, edx-enterprise, edx-organizations, edx-proctoring, edx-rbac, edx-when, edxval
-edx-enterprise==3.17.40   # via -c requirements/edx/../constraints.txt, -r requirements/edx/base.txt
+edx-enterprise==3.17.41   # via -c requirements/edx/../constraints.txt, -r requirements/edx/base.txt
 edx-event-routing-backends==4.0.1  # via -r requirements/edx/base.txt
 edx-i18n-tools==0.5.3     # via -r requirements/edx/base.txt, -r requirements/edx/testing.in, ora2
 edx-lint==4.0.1           # via -r requirements/edx/testing.in