diff --git a/Ladybird/Android/src/main/AndroidManifest.xml b/Ladybird/Android/src/main/AndroidManifest.xml
index c48a1e683a6..7fe1232bdd7 100644
--- a/Ladybird/Android/src/main/AndroidManifest.xml
+++ b/Ladybird/Android/src/main/AndroidManifest.xml
@@ -12,6 +12,8 @@
         android:smallScreens="true" />
 
     <uses-permission android:name="com.android.browser.permission.READ_HISTORY_BOOKMARKS" />
+    <uses-permission android:name="android.permission.INTERNET"/>
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
 
     <application
         android:allowBackup="true"
@@ -28,27 +30,32 @@
         android:supportsRtl="true"
         android:theme="@style/Theme.Ladybird"
         tools:targetApi="33">
-
         <activity
             android:name=".LadybirdActivity"
             android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density"
             android:exported="true"
-            android:label="@string/app_name"
             android:launchMode="singleTop"
             android:screenOrientation="unspecified">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
+
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
+
             <meta-data
                 android:name="android.app.extract_android_style"
                 android:value="minimal" />
         </activity>
-
         <service
             android:name=".WebContentService"
+            android:enabled="true"
             android:exported="false"
-            android:process=":WebContent"/>
+            android:process=":WebContent" />
+        <service
+            android:name=".RequestServerService"
+            android:enabled="true"
+            android:exported="false"
+            android:process=":RequestServer" />
     </application>
 
 </manifest>
diff --git a/Ladybird/Android/src/main/cpp/LadybirdServiceBase.h b/Ladybird/Android/src/main/cpp/LadybirdServiceBase.h
index 1879f9a201d..a30ab0f09e2 100644
--- a/Ladybird/Android/src/main/cpp/LadybirdServiceBase.h
+++ b/Ladybird/Android/src/main/cpp/LadybirdServiceBase.h
@@ -7,5 +7,8 @@
 #pragma once
 
 #include <AK/Error.h>
+#include <jni.h>
 
 ErrorOr<int> service_main(int ipc_socket, int fd_passing_socket);
+
+extern JavaVM* global_vm;
diff --git a/Ladybird/Android/src/main/cpp/LadybirdServiceBaseJNI.cpp b/Ladybird/Android/src/main/cpp/LadybirdServiceBaseJNI.cpp
index 3a7c12bc73f..cbd1d7d4a05 100644
--- a/Ladybird/Android/src/main/cpp/LadybirdServiceBaseJNI.cpp
+++ b/Ladybird/Android/src/main/cpp/LadybirdServiceBaseJNI.cpp
@@ -10,6 +10,8 @@
 #include <Ladybird/Utilities.h>
 #include <jni.h>
 
+JavaVM* global_vm;
+
 extern "C" JNIEXPORT void JNICALL
 Java_org_serenityos_ladybird_LadybirdServiceBase_nativeThreadLoop(JNIEnv*, jobject /* thiz */, jint ipc_socket, jint fd_passing_socket)
 {
@@ -31,6 +33,8 @@ Java_org_serenityos_ladybird_LadybirdServiceBase_initNativeCode(JNIEnv* env, job
         return;
     }
 
+    env->GetJavaVM(&global_vm);
+
     char const* raw_resource_dir = env->GetStringUTFChars(resource_dir, nullptr);
     s_serenity_resource_root = raw_resource_dir;
     env->ReleaseStringUTFChars(resource_dir, raw_resource_dir);
diff --git a/Ladybird/Android/src/main/cpp/RequestServerService.cpp b/Ladybird/Android/src/main/cpp/RequestServerService.cpp
new file mode 100644
index 00000000000..3856e2670e9
--- /dev/null
+++ b/Ladybird/Android/src/main/cpp/RequestServerService.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * Copyright (c) 2023, Andrew Kaster <akaster@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <AK/LexicalPath.h>
+#include <AK/OwnPtr.h>
+#include <Ladybird/Utilities.h>
+#include <LibCore/ArgsParser.h>
+#include <LibCore/EventLoop.h>
+#include <LibCore/LocalServer.h>
+#include <LibCore/System.h>
+#include <LibFileSystem/FileSystem.h>
+#include <LibIPC/SingleServer.h>
+#include <LibTLS/Certificate.h>
+#include <RequestServer/ConnectionFromClient.h>
+#include <RequestServer/GeminiProtocol.h>
+#include <RequestServer/HttpProtocol.h>
+#include <RequestServer/HttpsProtocol.h>
+
+// FIXME: Share b/w RequestServer and WebSocket
+ErrorOr<String> find_certificates(StringView serenity_resource_root)
+{
+    auto cert_path = TRY(String::formatted("{}/res/ladybird/cacert.pem", serenity_resource_root));
+    if (!FileSystem::exists(cert_path)) {
+        auto app_dir = LexicalPath::dirname(TRY(Core::System::current_executable_path()).to_deprecated_string());
+
+        cert_path = TRY(String::formatted("{}/cacert.pem", LexicalPath(app_dir).parent()));
+        if (!FileSystem::exists(cert_path))
+            return Error::from_string_view("Don't know how to load certs!"sv);
+    }
+    return cert_path;
+}
+
+ErrorOr<int> service_main(int ipc_socket, int fd_passing_socket)
+{
+    // Ensure the certificates are read out here.
+    DefaultRootCACertificates::set_default_certificate_path(TRY(find_certificates(s_serenity_resource_root)));
+    [[maybe_unused]] auto& certs = DefaultRootCACertificates::the();
+
+    Core::EventLoop event_loop;
+
+    // FIXME: Don't leak these :V
+    [[maybe_unused]] auto* gemini = new RequestServer::GeminiProtocol;
+    [[maybe_unused]] auto* http = new RequestServer::HttpProtocol;
+    [[maybe_unused]] auto* https = new RequestServer::HttpsProtocol;
+
+    auto socket = TRY(Core::LocalSocket::adopt_fd(ipc_socket));
+    auto client = TRY(RequestServer::ConnectionFromClient::try_create(move(socket)));
+    client->set_fd_passing_socket(TRY(Core::LocalSocket::adopt_fd(fd_passing_socket)));
+
+    return event_loop.exec();
+}
diff --git a/Ladybird/Android/src/main/cpp/WebContentService.cpp b/Ladybird/Android/src/main/cpp/WebContentService.cpp
index 919c707f6af..4fd80d2c6c3 100644
--- a/Ladybird/Android/src/main/cpp/WebContentService.cpp
+++ b/Ladybird/Android/src/main/cpp/WebContentService.cpp
@@ -4,6 +4,7 @@
  * SPDX-License-Identifier: BSD-2-Clause
  */
 
+#include "WebContentService.h"
 #include "LadybirdServiceBase.h"
 #include <AK/LexicalPath.h>
 #include <Ladybird/FontPlugin.h>
@@ -28,15 +29,7 @@
 #include <WebContent/ConnectionFromClient.h>
 #include <WebContent/PageHost.h>
 
-class NullResourceConnector : public Web::ResourceLoaderConnector {
-    virtual void prefetch_dns(AK::URL const&) override { }
-    virtual void preconnect(AK::URL const&) override { }
-
-    virtual RefPtr<Web::ResourceLoaderConnectorRequest> start_request(DeprecatedString const&, AK::URL const&, HashMap<DeprecatedString, DeprecatedString> const&, ReadonlyBytes, Core::ProxyData const&) override
-    {
-        return nullptr;
-    }
-};
+static ErrorOr<NonnullRefPtr<Protocol::RequestClient>> bind_request_server_service();
 
 ErrorOr<int> service_main(int ipc_socket, int fd_passing_socket)
 {
@@ -52,7 +45,8 @@ ErrorOr<int> service_main(int ipc_socket, int fd_passing_socket)
 
     Web::FrameLoader::set_default_favicon_path(DeprecatedString::formatted("{}/res/icons/16x16/app-browser.png", s_serenity_resource_root));
 
-    Web::ResourceLoader::initialize(make_ref_counted<NullResourceConnector>());
+    auto request_server_client = TRY(bind_request_server_service());
+    Web::ResourceLoader::initialize(TRY(WebView::RequestServerAdapter::try_create(move(request_server_client))));
 
     bool is_layout_test_mode = false;
 
@@ -71,3 +65,29 @@ ErrorOr<int> service_main(int ipc_socket, int fd_passing_socket)
 
     return event_loop.exec();
 }
+
+ErrorOr<NonnullRefPtr<Protocol::RequestClient>> bind_request_server_service()
+{
+    int socket_fds[2] {};
+    TRY(Core::System::socketpair(AF_LOCAL, SOCK_STREAM, 0, socket_fds));
+
+    int ui_fd = socket_fds[0];
+    int server_fd = socket_fds[1];
+
+    int fd_passing_socket_fds[2] {};
+    TRY(Core::System::socketpair(AF_LOCAL, SOCK_STREAM, 0, fd_passing_socket_fds));
+
+    int ui_fd_passing_fd = fd_passing_socket_fds[0];
+    int server_fd_passing_fd = fd_passing_socket_fds[1];
+
+    // NOTE: The java object takes ownership of the socket fds
+    bind_request_server_java(server_fd, server_fd_passing_fd);
+
+    auto socket = TRY(Core::LocalSocket::adopt_fd(ui_fd));
+    TRY(socket->set_blocking(true));
+
+    auto new_client = TRY(try_make_ref_counted<Protocol::RequestClient>(move(socket)));
+    new_client->set_fd_passing_socket(TRY(Core::LocalSocket::adopt_fd(ui_fd_passing_fd)));
+
+    return new_client;
+}
diff --git a/Ladybird/Android/src/main/cpp/WebContentService.h b/Ladybird/Android/src/main/cpp/WebContentService.h
new file mode 100644
index 00000000000..2da6a1c0c93
--- /dev/null
+++ b/Ladybird/Android/src/main/cpp/WebContentService.h
@@ -0,0 +1,9 @@
+/*
+ * Copyright (c) 2023, Andrew Kaster <akaster@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+void bind_request_server_java(int ipc_socket, int fd_passing_socket);
diff --git a/Ladybird/Android/src/main/cpp/WebContentServiceJNI.cpp b/Ladybird/Android/src/main/cpp/WebContentServiceJNI.cpp
new file mode 100644
index 00000000000..111e3940f78
--- /dev/null
+++ b/Ladybird/Android/src/main/cpp/WebContentServiceJNI.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2023, Andrew Kaster <akaster@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include "JNIHelpers.h"
+#include "LadybirdServiceBase.h"
+#include <jni.h>
+
+jobject global_instance;
+jclass global_class_reference;
+jmethodID bind_request_server_method;
+
+extern "C" JNIEXPORT void JNICALL
+Java_org_serenityos_ladybird_WebContentService_nativeInit(JNIEnv* env, jobject thiz)
+{
+    global_instance = env->NewGlobalRef(thiz);
+
+    auto local_class = env->FindClass("org/serenityos/ladybird/WebContentService");
+    if (!local_class)
+        TODO();
+    global_class_reference = reinterpret_cast<jclass>(env->NewGlobalRef(local_class));
+    env->DeleteLocalRef(local_class);
+
+    auto method = env->GetMethodID(global_class_reference, "bindRequestServer", "(II)V");
+    if (!method)
+        TODO();
+    bind_request_server_method = method;
+}
+
+void bind_request_server_java(int ipc_socket, int fd_passing_socket)
+{
+    JavaEnvironment env(global_vm);
+    env.get()->CallVoidMethod(global_instance, bind_request_server_method, ipc_socket, fd_passing_socket);
+}
diff --git a/Ladybird/Android/src/main/java/org/serenityos/ladybird/LadybirdActivity.kt b/Ladybird/Android/src/main/java/org/serenityos/ladybird/LadybirdActivity.kt
index de5eeb5debf..84c57622640 100644
--- a/Ladybird/Android/src/main/java/org/serenityos/ladybird/LadybirdActivity.kt
+++ b/Ladybird/Android/src/main/java/org/serenityos/ladybird/LadybirdActivity.kt
@@ -9,6 +9,7 @@ package org.serenityos.ladybird
 import androidx.appcompat.app.AppCompatActivity
 import android.os.Bundle
 import org.serenityos.ladybird.databinding.ActivityMainBinding
+import java.net.URL
 import kotlin.io.path.Path
 
 class LadybirdActivity : AppCompatActivity() {
@@ -37,7 +38,7 @@ class LadybirdActivity : AppCompatActivity() {
         super.onStart()
 
         // FIXME: This is not the right place to load the homepage :^)
-        val initialURL = Path(resourceDir, "res/html/misc/welcome.html").toUri().toURL()
+        val initialURL = URL("https://ladybird.dev")
         view.loadURL(initialURL)
     }
 
diff --git a/Ladybird/Android/src/main/java/org/serenityos/ladybird/LadybirdServiceBase.kt b/Ladybird/Android/src/main/java/org/serenityos/ladybird/LadybirdServiceBase.kt
index 15d28c66392..f3f9d27a9d6 100644
--- a/Ladybird/Android/src/main/java/org/serenityos/ladybird/LadybirdServiceBase.kt
+++ b/Ladybird/Android/src/main/java/org/serenityos/ladybird/LadybirdServiceBase.kt
@@ -23,7 +23,7 @@ const val MSG_TRANSFER_SOCKETS = 2
 
 abstract class LadybirdServiceBase(protected val TAG: String) : Service() {
     private val threadPool = Executors.newCachedThreadPool()
-    private lateinit var resourceDir: String
+    protected lateinit var resourceDir: String
 
     override fun onCreate() {
         super.onCreate()
diff --git a/Ladybird/Android/src/main/java/org/serenityos/ladybird/RequestServerService.kt b/Ladybird/Android/src/main/java/org/serenityos/ladybird/RequestServerService.kt
new file mode 100644
index 00000000000..c1941a38b88
--- /dev/null
+++ b/Ladybird/Android/src/main/java/org/serenityos/ladybird/RequestServerService.kt
@@ -0,0 +1,21 @@
+/**
+ * Copyright (c) 2023, Andrew Kaster <akaster@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+package org.serenityos.ladybird
+
+import android.os.Message
+
+class RequestServerService : LadybirdServiceBase("RequestServerService") {
+    override fun handleServiceSpecificMessage(msg: Message): Boolean {
+        return false
+    }
+
+    companion object {
+        init {
+            System.loadLibrary("requestserver")
+        }
+    }
+}
diff --git a/Ladybird/Android/src/main/java/org/serenityos/ladybird/WebContentService.kt b/Ladybird/Android/src/main/java/org/serenityos/ladybird/WebContentService.kt
index 5b7c9fd670c..3c531baa35c 100644
--- a/Ladybird/Android/src/main/java/org/serenityos/ladybird/WebContentService.kt
+++ b/Ladybird/Android/src/main/java/org/serenityos/ladybird/WebContentService.kt
@@ -6,13 +6,37 @@
 
 package org.serenityos.ladybird
 
+import android.content.Context
+import android.content.Intent
 import android.os.Message
+import android.util.Log
 
 class WebContentService : LadybirdServiceBase("WebContentService") {
     override fun handleServiceSpecificMessage(msg: Message): Boolean {
         return false
     }
 
+    init {
+        nativeInit();
+    }
+
+    private fun bindRequestServer(ipcFd: Int, fdPassingFd: Int)
+    {
+        val connector = LadybirdServiceConnection(ipcFd, fdPassingFd, resourceDir)
+        connector.onDisconnect = {
+            // FIXME: Notify impl that service is dead and might need restarted
+            Log.e(TAG, "RequestServer Died! :(")
+        }
+        // FIXME: Unbind this at some point maybe
+        bindService(
+            Intent(this, RequestServerService::class.java),
+            connector,
+            Context.BIND_AUTO_CREATE
+        )
+    }
+
+    external fun nativeInit()
+
     companion object {
         init {
             System.loadLibrary("webcontent")
diff --git a/Ladybird/RequestServer/CMakeLists.txt b/Ladybird/RequestServer/CMakeLists.txt
index fab905c34c3..3b6f4e94e53 100644
--- a/Ladybird/RequestServer/CMakeLists.txt
+++ b/Ladybird/RequestServer/CMakeLists.txt
@@ -1,5 +1,9 @@
 set(REQUESTSERVER_SOURCE_DIR ${SERENITY_SOURCE_DIR}/Userland/Services/RequestServer)
 
+set(CMAKE_AUTOMOC OFF)
+set(CMAKE_AUTORCC OFF)
+set(CMAKE_AUTOUIC OFF)
+
 set(REQUESTSERVER_SOURCES
     ${REQUESTSERVER_SOURCE_DIR}/ConnectionFromClient.cpp
     ${REQUESTSERVER_SOURCE_DIR}/ConnectionCache.cpp
@@ -11,17 +15,28 @@ set(REQUESTSERVER_SOURCES
     ${REQUESTSERVER_SOURCE_DIR}/HttpsRequest.cpp
     ${REQUESTSERVER_SOURCE_DIR}/HttpsProtocol.cpp
     ${REQUESTSERVER_SOURCE_DIR}/Protocol.cpp
-    main.cpp
 )
 
-add_executable(RequestServer ${REQUESTSERVER_SOURCES})
+if (ANDROID)
+    add_library(requestserver SHARED
+        ${REQUESTSERVER_SOURCES}
+        ../Android/src/main/cpp/RequestServerService.cpp
+        ../Android/src/main/cpp/LadybirdServiceBaseJNI.cpp
+        ../Utilities.cpp
+    )
+else()
+    add_library(requestserver STATIC ${REQUESTSERVER_SOURCES})
+endif()
 
-target_include_directories(RequestServer PRIVATE ${SERENITY_SOURCE_DIR}/Userland/Services/)
-target_include_directories(RequestServer PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/..)
-target_link_libraries(RequestServer PRIVATE LibCore LibMain LibCrypto LibFileSystem LibGemini LibHTTP LibIPC LibMain LibTLS LibWebView)
+add_executable(RequestServer main.cpp)
+target_link_libraries(RequestServer PRIVATE requestserver)
+
+target_include_directories(requestserver PRIVATE ${SERENITY_SOURCE_DIR}/Userland/Services/)
+target_include_directories(requestserver PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/..)
+target_link_libraries(requestserver PUBLIC LibCore LibMain LibCrypto LibFileSystem LibGemini LibHTTP LibIPC LibMain LibTLS LibWebView)
 if (${CMAKE_SYSTEM_NAME} MATCHES "SunOS")
     # Solaris has socket and networking related functions in two extra libraries
-    target_link_libraries(RequestServer PRIVATE nsl socket)
+    target_link_libraries(requestserver PUBLIC nsl socket)
 endif()
 if (HAIKU)
     # Haiku has networking related functions in the network library
diff --git a/Ladybird/WebContent/CMakeLists.txt b/Ladybird/WebContent/CMakeLists.txt
index 20c131dd72e..bc12a8ee108 100644
--- a/Ladybird/WebContent/CMakeLists.txt
+++ b/Ladybird/WebContent/CMakeLists.txt
@@ -55,6 +55,7 @@ else()
     if (ANDROID)
         target_sources(webcontent PRIVATE
           ../Android/src/main/cpp/WebContentService.cpp
+          ../Android/src/main/cpp/WebContentServiceJNI.cpp
           ../Android/src/main/cpp/LadybirdServiceBaseJNI.cpp
         )
         target_link_libraries(webcontent PRIVATE android)
diff --git a/Ladybird/cmake/AndroidExtras.cmake b/Ladybird/cmake/AndroidExtras.cmake
index cc137bd6ea1..672ccc98ad7 100644
--- a/Ladybird/cmake/AndroidExtras.cmake
+++ b/Ladybird/cmake/AndroidExtras.cmake
@@ -33,7 +33,12 @@ add_custom_target(copy-content-filters
         "${SERENITY_SOURCE_DIR}/Base/home/anon/.config/BrowserContentFilters.txt"
         "asset-bundle/res/ladybird/BrowserContentFilters.txt"
 )
-add_dependencies(archive-assets copy-autoplay-allowlist copy-content-filters)
+add_custom_target(copy-certs
+    COMMAND ${CMAKE_COMMAND} -E copy_if_different
+        "${Lagom_BINARY_DIR}/cacert.pem"
+        "asset-bundle/res/ladybird/cacert.pem"
+)
+add_dependencies(archive-assets copy-autoplay-allowlist copy-content-filters copy-certs)
 add_custom_target(copy-assets COMMAND ${CMAKE_COMMAND} -E copy_if_different ladybird-assets.tar.gz "${CMAKE_SOURCE_DIR}/Android/src/main/assets/")
 add_dependencies(copy-assets archive-assets)
 add_dependencies(ladybird copy-assets)
diff --git a/Ladybird/cmake/InstallRules.cmake b/Ladybird/cmake/InstallRules.cmake
index c428b17fbca..9bb811bfb38 100644
--- a/Ladybird/cmake/InstallRules.cmake
+++ b/Ladybird/cmake/InstallRules.cmake
@@ -36,13 +36,18 @@ list(REMOVE_DUPLICATES all_required_lagom_libraries)
 # Remove ladybird shlib if it exists
 list(REMOVE_ITEM all_required_lagom_libraries ladybird)
 
-# Install webcontent impl library if it exists
-if (TARGET webcontent)
-  get_target_property(target_type webcontent TYPE)
-  if ("${target_type}" STREQUAL STATIC_LIBRARY)
-      list(APPEND all_required_lagom_libraries webcontent)
-  endif()
-endif()
+# Install service impl libraries if they exist
+macro(install_service_lib service)
+    if (TARGET ${service})
+      get_target_property(target_type ${service} TYPE)
+      if ("${target_type}" STREQUAL STATIC_LIBRARY)
+          list(APPEND all_required_lagom_libraries ${service})
+      endif()
+    endif()
+endmacro()
+foreach(service IN LISTS webcontent requestserver)
+    install_service_lib(${service})
+endforeach()
 
 install(TARGETS ${all_required_lagom_libraries}
   EXPORT ladybirdTargets