diff --git a/.gitignore b/.gitignore
index 07b1e7f7bde0d5a7e99dce877578ef81f4716b95..f3c24f632ce4408361bc9c8aa69e85e9902e783f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,3 +8,4 @@ Djblets.egg-info
 *.rej
 *.orig
 .*.sw*
+*.pyc
\ No newline at end of file
diff --git a/djblets/extensionbrowser/forms.py b/djblets/extensionbrowser/forms.py
new file mode 100644
index 0000000000000000000000000000000000000000..6ec8b46c17bfd4477bac2c26ce2a5c6f45fe64f9
--- /dev/null
+++ b/djblets/extensionbrowser/forms.py
@@ -0,0 +1,12 @@
+from django import forms
+from django.utils.translation import ugettext as _
+
+
+class AddExtensionForm(forms.Form):
+    """Form for adding extensions.
+
+    This form handles installing new extensions from a remote URL,
+    through the extension browser interface.
+    """
+    extension_url = forms.URLField(label=_("Extension URL"), required=True)
+    package_name = forms.CharField(label=_("Package Name"), required=True)
diff --git a/djblets/extensionbrowser/templates/extensionbrowser/extension_manager.html b/djblets/extensionbrowser/templates/extensionbrowser/extension_manager.html
new file mode 100644
index 0000000000000000000000000000000000000000..d77cbeddde5831fb287e3bd052aa2ec4cdde7b1f
--- /dev/null
+++ b/djblets/extensionbrowser/templates/extensionbrowser/extension_manager.html
@@ -0,0 +1,33 @@
+{% extends "admin/base_site.html" %}
+{% load adminmedia admin_list djblets_extensions i18n staticfiles %}
+
+{% block title %}{% trans "Add Extensions" %} {{block.super}}{% endblock %}
+
+{% block extrahead %}
+<link rel="stylesheet" type="text/css" href="{% admin_media_prefix %}css/forms.css" />
+<link rel="stylesheet" type="text/css" href="{% static "djblets/css/admin.css" %}" />
+<link rel="stylesheet" type="text/css" href="{% static "djblets/css/extensions.css" %}" />
+
+{{block.super}}
+{% endblock %}
+
+{% block content %}
+
+<h1 class="title">{% trans "Add Extensions" %}</h1>
+<div id="content-main">
+ <form action="browser" method="post">
+  {% csrf_token %}
+  {{form.as_p}}
+  <input type="submit" value="Submit" />
+ </form>
+</div>
+{% if distribution_error %}
+{%  trans "An error occurred: package name does not match the resource downloaded." %}
+{% endif %}
+{% if install_error %}
+{%  trans "An error occurred: " %} {{error}}
+{% endif %}
+{% if install_success %}
+{%  trans "Extension installed. You may now activate it." %}
+{% endif %}
+{% endblock %}
diff --git a/djblets/extensionbrowser/urls.py b/djblets/extensionbrowser/urls.py
new file mode 100644
index 0000000000000000000000000000000000000000..a276d45683e82f93e335616b62856674455e6df8
--- /dev/null
+++ b/djblets/extensionbrowser/urls.py
@@ -0,0 +1,6 @@
+from django.conf.urls.defaults import patterns, url
+
+
+urlpatterns = patterns('djblets.extensionbrowser.views',
+    url(r'^$', 'add_extension'),
+)
diff --git a/djblets/extensionbrowser/views.py b/djblets/extensionbrowser/views.py
new file mode 100644
index 0000000000000000000000000000000000000000..6b3ad2a59bf812de0bbcd7bc64d9fbe74ee1073a
--- /dev/null
+++ b/djblets/extensionbrowser/views.py
@@ -0,0 +1,58 @@
+from django.contrib.admin.views.decorators import staff_member_required
+from django.shortcuts import render_to_response
+from django.template.context import RequestContext
+from djblets.extensionbrowser.forms import AddExtensionForm
+import pkg_resources
+from setuptools.command import easy_install
+
+
+@staff_member_required
+def add_extension(request, extension_manager,
+                  template_name='extensionbrowser/extension_manager.html'):
+    """View for adding extensions.
+
+    Presents a view for inputing remote extension URLs and then
+    the extension at the given resource is installed.
+    """
+    distribution_error = False
+    install_error = False
+    install_success = False
+    error = None
+    if request.method == 'POST':
+        form = AddExtensionForm(request.POST)
+
+        if form.is_valid():
+            try:
+                easy_install.main(["-U", request.POST['extension_url']])
+
+                dist = pkg_resources.get_distribution(
+                    request.POST['package_name'])
+                dist.activate()
+                pkg_resources.working_set.add(dist)
+
+                extension_manager.load(True)
+
+            except pkg_resources.DistributionNotFound:
+            # Raised by pkg_resources, user likely entered the wrong name at
+            # package_name.
+                distribution_error = True
+
+            except Exception, e:
+            # Problem with install.
+                install_error = True
+                error = e
+
+            if not distribution_error and not install_error:
+                # At this point, everything went okay with the installation.
+                install_success = True
+
+    else:
+        form = AddExtensionForm()
+
+    return render_to_response(template_name, RequestContext(request, {
+        'distribution_error': distribution_error,
+        'error': error,
+        'form': form,
+        'install_error': install_error,
+        'install_success': install_success,
+    }))
diff --git a/djblets/extensions/base.py b/djblets/extensions/base.py
index 09a95ec0f970764958ea6f23841e625c5d0fbb6f..632bc6b09612e281362bf65227401ba9ef2ce693 100644
--- a/djblets/extensions/base.py
+++ b/djblets/extensions/base.py
@@ -459,13 +459,6 @@ class ExtensionManager(object):
 
         found_extensions = {}
 
-        # Reload pkg_resources
-        import pkg_resources
-        if pkg_resources:
-            del pkg_resources
-            del sys.modules['pkg_resources']
-            import pkg_resources
-
         for entrypoint in self._entrypoint_iterator():
             registered_ext = None
 
diff --git a/djblets/extensions/templates/extensions/extension_list.html b/djblets/extensions/templates/extensions/extension_list.html
index 3e756f939b7c624e7098b0b6afb96262567370bd..558d6e35a1e89536c0b5a016658712c9652779e6 100644
--- a/djblets/extensions/templates/extensions/extension_list.html
+++ b/djblets/extensions/templates/extensions/extension_list.html
@@ -62,5 +62,11 @@
 {% else %}
  <p>{% trans "There are no extensions installed." %}</p>
 {% endif %}
+<ul class="actions">
+ <li>
+  <a href="browser">Add Extension</a>
+ </li>
+</ul>
+</ul>
 </div>
 {% endblock %}
diff --git a/djblets/settings.py b/djblets/settings.py
index 81f0a99e2939bb4dbc929683486d2af68a8c0e8f..3c64e26cfd05431215a942c33c9428b7a33a2bd8 100644
--- a/djblets/settings.py
+++ b/djblets/settings.py
@@ -29,6 +29,7 @@ INSTALLED_APPS = [
     'django.contrib.staticfiles',
     'djblets.auth',
     'djblets.datagrid',
+    'djblets.extensionbrowser',
     'djblets.extensions',
     'djblets.feedview',
     'djblets.gravatars',
