diff --git a/src/ringdht/namedirectory.cpp b/src/ringdht/namedirectory.cpp
index c5f2033dc9a1a3144b2b1a49ad21b5981fc13b3a..f89e060fbb5c28a9a1638a3d6695972c81bdfad1 100644
--- a/src/ringdht/namedirectory.cpp
+++ b/src/ringdht/namedirectory.cpp
@@ -37,6 +37,7 @@ namespace ring {
 constexpr const char* const QUERY_NAME {"/name/"};
 constexpr const char* const QUERY_ADDR {"/addr/"};
 constexpr const char* const HTTPS_PROTO {"https://"};
+constexpr const char* const CACHE_DIRECTORY {"namecache"};
 
 /** Parser for Ring URIs.         ( protocol        )    ( username         ) ( hostname                            ) */
 const std::regex URI_VALIDATOR {"^([a-zA-Z]+:(?://)?)?(?:([a-z0-9-_]{1,64})@)?([a-zA-Z0-9\\-._~%!$&'()*+,;=:\\[\\]]+)"};
@@ -68,7 +69,7 @@ NameDirectory::lookupUri(const std::string& uri, const std::string& default_serv
 
 NameDirectory::NameDirectory(const std::string& s)
    : serverHost_(s),
-     cachePath_(fileutils::get_cache_dir()+DIR_SEPARATOR_STR+"namecache"+DIR_SEPARATOR_STR+serverHost_)
+     cachePath_(fileutils::get_cache_dir()+DIR_SEPARATOR_STR+CACHE_DIRECTORY+DIR_SEPARATOR_STR+serverHost_)
 {}
 
 void
@@ -81,7 +82,9 @@ NameDirectory& NameDirectory::instance(const std::string& server)
 {
     const std::string& s = server.empty() ? DEFAULT_SERVER_HOST : server;
     static std::map<std::string, NameDirectory> instances {};
-    auto r = instances.emplace(s, NameDirectory{s});
+    auto r = instances.emplace(std::piecewise_construct,
+                      std::forward_as_tuple(s),
+                      std::forward_as_tuple(s));
     if (r.second)
         r.first->second.load();
     return r.first->second;
@@ -137,8 +140,11 @@ void NameDirectory::lookupAddress(const std::string& addr, LookupCallback cb)
                 auto name = json["name"].asString();
                 if (not name.empty()) {
                     RING_DBG("Found name for %s: %s", addr.c_str(), name.c_str());
-                    addrCache_.emplace(name, addr);
-                    nameCache_.emplace(addr, name);
+                    {
+                        std::lock_guard<std::mutex> l(lock_);
+                        addrCache_.emplace(name, addr);
+                        nameCache_.emplace(addr, name);
+                    }
                     cb(name, Response::found);
                     saveCache();
                 } else {
@@ -212,8 +218,11 @@ void NameDirectory::lookupName(const std::string& n, LookupCallback cb)
                     addr = addr.substr(HEX_PREFIX.size());
                 if (not addr.empty()) {
                     RING_DBG("Found address for %s: %s", name.c_str(), addr.c_str());
-                    addrCache_.emplace(name, addr);
-                    nameCache_.emplace(addr, name);
+                    {
+                        std::lock_guard<std::mutex> l(lock_);
+                        addrCache_.emplace(name, addr);
+                        nameCache_.emplace(addr, name);
+                    }
                     cb(addr, Response::found);
                     saveCache();
                 } else {
@@ -302,6 +311,7 @@ void NameDirectory::registerName(const std::string& addr, const std::string& n,
                 auto success = json["success"].asBool();
                 RING_DBG("Got reply for registration of %s -> %s: %s", name.c_str(), addr.c_str(), success ? "success" : "failure");
                 if (success) {
+                    std::lock_guard<std::mutex> l(lock_);
                     addrCache_.emplace(name, addr);
                     nameCache_.emplace(addr, name);
                 }
@@ -324,9 +334,13 @@ void NameDirectory::registerName(const std::string& addr, const std::string& n,
 void
 NameDirectory::saveCache()
 {
-    fileutils::recursive_mkdir(fileutils::get_cache_dir()+DIR_SEPARATOR_STR+"namecache");
+    fileutils::recursive_mkdir(fileutils::get_cache_dir()+DIR_SEPARATOR_STR+CACHE_DIRECTORY);
+    std::lock_guard<std::mutex> lock(fileutils::getFileLock(cachePath_));
     std::ofstream file(cachePath_, std::ios::trunc | std::ios::binary);
-    msgpack::pack(file, nameCache_);
+    {
+        std::lock_guard<std::mutex> l(lock_);
+        msgpack::pack(file, nameCache_);
+    }
     RING_DBG("Saved %lu name-address mappings", (long unsigned)nameCache_.size());
 }
 
@@ -337,6 +351,7 @@ NameDirectory::loadCache()
 
     // read file
     {
+        std::lock_guard<std::mutex> lock(fileutils::getFileLock(cachePath_));
         std::ifstream file(cachePath_);
         if (!file.is_open()) {
             RING_DBG("Could not load %s", cachePath_.c_str());
@@ -351,6 +366,7 @@ NameDirectory::loadCache()
     }
 
     // load values
+    std::lock_guard<std::mutex> l(lock_);
     msgpack::object_handle oh;
     if (pac.next(oh))
         oh.get().convert(nameCache_);
diff --git a/src/ringdht/namedirectory.h b/src/ringdht/namedirectory.h
index f6b8984377e25a64b3ad17ac7e4c3b57ca0f7a6a..dcceb87ca4c6b165a0ebc6f1a75434430ab1e889 100644
--- a/src/ringdht/namedirectory.h
+++ b/src/ringdht/namedirectory.h
@@ -17,9 +17,12 @@
  */
 #pragma once
 
+#include "noncopyable.h"
+
 #include <functional>
 #include <map>
 #include <string>
+#include <mutex>
 
 namespace ring {
 
@@ -51,14 +54,16 @@ public:
     }
 
 private:
+    NON_COPYABLE(NameDirectory);
+    NameDirectory(NameDirectory&&) = delete;
     constexpr static const char* const DEFAULT_SERVER_HOST = "ns.ring.cx";
 
     const std::string serverHost_ {DEFAULT_SERVER_HOST};
     const std::string cachePath_;
 
-    std::map<std::string, std::string> nameCache_;
-    std::map<std::string, std::string> addrCache_;
-
+    std::map<std::string, std::string> nameCache_ {};
+    std::map<std::string, std::string> addrCache_ {};
+    std::mutex lock_ {};
 
     bool validateName(const std::string& name) const;