diff --git a/client/HTTPServer.cpp b/client/HTTPServer.cpp
index fc045760..cff6256c 100644
--- a/client/HTTPServer.cpp
+++ b/client/HTTPServer.cpp
@@ -94,26 +94,41 @@ void HTTPConnection::HandleWriteReply(const boost::system::error_code& e)
     }
 }
 
-void HTTPConnection::HandleRequest()
+void HTTPConnection::Send404Reply()
+{
+    try {
+        const std::string error_page = "404.html";
+        m_Reply = i2p::util::http::Response(404, GetFileContents(error_page, true));
+        m_Reply.setHeader("Content-Type", i2p::util::http::getMimeType(error_page));
+    } catch(const std::runtime_error&) {
+        // Failed to load 404.html, assume the webui is incorrectly installed
+        m_Reply = i2p::util::http::Response(404,
+            "<!DOCTYPE HTML><html>"
+            "<head><title>Error: 404 - webui not installed</title></head><body>"
+                "<p>It looks like your webui installation is broken.</p>"
+                "<p>Run the following command to (re)install it:</p>"
+                "<pre>./i2pd --install /path/to/webui</pre>"
+                "<p>The webui folder should come with the binaries.</p>"
+            "</body></html>"
+        );
+    }
+    SendReply();
+}
+
+std::string HTTPConnection::GetFileContents(const std::string& filename, bool preprocess) const
 {
     boost::system::error_code e;
 
-    std::string uri = m_Request.getUri();
-    if(uri == "/")
-        uri = "index.html";
-
-    // Use canonical to avoid .. or . in path
+     // Use canonical to avoid .. or . in path
     const boost::filesystem::path address = boost::filesystem::canonical(
-        i2p::util::filesystem::GetWebuiDataDir() / uri, e
+        i2p::util::filesystem::GetWebuiDataDir() / filename, e
     );
 
     const std::string address_str = address.string();
     
     std::ifstream ifs(address_str);
-    if(e || !ifs || !isAllowed(address_str)) {
-        m_Reply = i2p::util::http::Response(404, "");
-        return SendReply();
-    }
+    if(e || !ifs || !isAllowed(address_str))
+        throw std::runtime_error("Cannot load " + address_str + ".");
 
     std::string str;
     ifs.seekg(0, ifs.end);
@@ -122,11 +137,27 @@ void HTTPConnection::HandleRequest()
     ifs.read(&str[0], str.size());
     ifs.close();
     
-    str = i2p::util::http::preprocessContent(str, address.parent_path().string());
-    m_Reply = i2p::util::http::Response(200, str);
+    if(preprocess)
+        return i2p::util::http::preprocessContent(str, address.parent_path().string());
+    else
+        return str;
+}
 
-    m_Reply.setHeader("Content-Type", i2p::util::http::getMimeType(address_str));
-    SendReply();
+void HTTPConnection::HandleRequest()
+{
+
+    std::string uri = m_Request.getUri();
+    if(uri == "/")
+        uri = "index.html";
+
+    try {
+        m_Reply = i2p::util::http::Response(200, GetFileContents(uri, true));
+        m_Reply.setHeader("Content-Type", i2p::util::http::getMimeType(uri));
+        SendReply();
+    } catch(const std::runtime_error&) {
+        // Cannot open the file for some reason, send 404
+        Send404Reply();
+    }
 }
 
 void HTTPConnection::HandleI2PControlRequest()
@@ -138,7 +169,7 @@ void HTTPConnection::HandleI2PControlRequest()
     SendReply();
 }
 
-bool HTTPConnection::isAllowed(const std::string& address)
+bool HTTPConnection::isAllowed(const std::string& address) const
 {
     const std::size_t pos_dot = address.find_last_of('.');
     const std::size_t pos_slash = address.find_last_of('/');
diff --git a/client/HTTPServer.h b/client/HTTPServer.h
index d47cd700..a4209e2d 100644
--- a/client/HTTPServer.h
+++ b/client/HTTPServer.h
@@ -32,11 +32,18 @@ private:
     void HandleWriteReply(const boost::system::error_code& ecode);
     void SendReply();
 
+    void Send404Reply();
+
+    /*
+     * @throw std::runtime_error when the file is not accessible
+     */
+    std::string GetFileContents(const std::string& filename, bool preprocess) const;
+
     void HandleRequest();
     void HandleI2PControlRequest();
     void ExtractParams(const std::string& str, std::map<std::string, std::string>& params);
     
-    bool isAllowed(const std::string& address);
+    bool isAllowed(const std::string& address) const;
 private:
     boost::asio::ip::tcp::socket* m_Socket;
     char m_Buffer[HTTP_CONNECTION_BUFFER_SIZE + 1];
diff --git a/webui/404.html b/webui/404.html
new file mode 100644
index 00000000..41174fe6
--- /dev/null
+++ b/webui/404.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<title>404 - Page not found</title>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<link rel="stylesheet" href="css/main.css">
+</head>
+
+
+<body>
+<div class="header">
+    <h1>404 - Page not found</h1>
+</div>
+
+<div class="content">
+    <h2 class="content-subhead">The page you were looking for could not be found.</h2>
+</div>
+
+<!--#include virtual="menu.html" -->
+<!--#include virtual="footer.html" -->
+
+</body>
+</html>
diff --git a/webui/help.html b/webui/help.html
index d626ec16..09f519b2 100644
--- a/webui/help.html
+++ b/webui/help.html
@@ -5,7 +5,6 @@
 <meta charset="utf-8">
 <meta name="viewport" content="width=device-width, initial-scale=1">
 <link rel="stylesheet" href="css/main.css">
-<script type="text/javascript" src="javascript/I2PControl.js"></script>
 </head>
 
 <body>
diff --git a/webui/menu.html b/webui/menu.html
index 47c7e8b0..d73089e3 100644
--- a/webui/menu.html
+++ b/webui/menu.html
@@ -8,7 +8,7 @@
             <a href="netdb.html" class="menu-link">Network Database</a>
         </li>
         <li class="menu-item">
-            <a href="#/config" class="menu-link">Configure</a>
+            <a href="config.html" class="menu-link">Configure</a>
         </li>
         <li class="menu-item">
             <a href="help.html" class="menu-link">Help</a>
diff --git a/webui/netdb.html b/webui/netdb.html
index 2ac2147a..321c3751 100644
--- a/webui/netdb.html
+++ b/webui/netdb.html
@@ -19,7 +19,7 @@ function updateNetDbInfo(result, session) {
         "leasesets" : result["i2p.router.netdb.leasesets"],
     });
     
-    window.setTimeout(function() { requestNetDbInfo(session); }, 5000);
+    window.setTimeout(function() { requestNetDbInfo(session); }, 10000);
 }
 
 function requestNetDbInfo(session) {