diff --git a/include/opendht/dht.h b/include/opendht/dht.h
index 9a21b308b2589041837b486048f03457da164df6..ecb85d878d03456358ceba4c842d50b6e20b667c 100644
--- a/include/opendht/dht.h
+++ b/include/opendht/dht.h
@@ -169,7 +169,7 @@ public:
      * Initialise the Dht with two open sockets (for IPv4 and IP6)
      * and an ID for the node.
      */
-    Dht(int s, int s6, const InfoHash& id);
+    Dht(int s, int s6, const InfoHash& id, bool bootstrap = false);
     virtual ~Dht();
 
     /**
@@ -413,6 +413,8 @@ private:
          */
         InfoHash randomId(const RoutingTable::const_iterator& bucket) const;
 
+        unsigned depth(const RoutingTable::const_iterator& bucket) const;
+
         /**
          * Split a bucket in two equal parts.
          */
@@ -699,6 +701,12 @@ private:
     // cache of nodes not in the main routing table but used for searches
     NodeCache cache;
 
+    // are we a bootstrap node ?
+    // note: Any running node can be used as a bootstrap node.
+    //       Only nodes running only as bootstrap nodes should
+    //       be put in bootstrap mode.
+    const bool is_bootstrap {false};
+
     // the stuff
     RoutingTable buckets {};
     RoutingTable buckets6 {};
diff --git a/include/opendht/infohash.h b/include/opendht/infohash.h
index e3d735e3b3224b10702115432fd063d7f1360a18..4a98a23138936745262301b61a319be9c8e96b86 100644
--- a/include/opendht/infohash.h
+++ b/include/opendht/infohash.h
@@ -152,7 +152,7 @@ public:
     void
     setBit(unsigned nbit, bool b)
     {
-        auto& num = *(begin()+(nbit/8));
+        auto& num = (*this)[nbit/8];
         unsigned bit = 7 - (nbit % 8);
         num ^= (-b ^ num) & (1 << bit);
     }
diff --git a/src/dht.cpp b/src/dht.cpp
index 1279386d52682e7136c7e16543d86f47fae27a26..f6ea0fef972a85c06535117baf73a0bd809425dc 100644
--- a/src/dht.cpp
+++ b/src/dht.cpp
@@ -261,18 +261,23 @@ Dht::RoutingTable::randomId(const Dht::RoutingTable::const_iterator& it) const
 InfoHash
 Dht::RoutingTable::middle(const RoutingTable::const_iterator& it) const
 {
-    int bit1 = it->first.lowbit();
-    int bit2 = std::next(it) != end() ? std::next(it)->first.lowbit() : -1;
-    int bit = std::max(bit1, bit2) + 1;
-
-    if (bit >= 8*(int)HASH_LEN)
+    unsigned bit = depth(it);
+    if (bit >= 8*HASH_LEN)
         throw std::out_of_range("End of table");
 
     InfoHash id = it->first;
-    id[bit / 8] |= (0x80 >> (bit % 8));
+    id.setBit(bit, 1);
     return id;
 }
 
+unsigned
+Dht::RoutingTable::depth(const RoutingTable::const_iterator& it) const
+{
+    int bit1 = it->first.lowbit();
+    int bit2 = std::next(it) != end() ? std::next(it)->first.lowbit() : -1;
+    return std::max(bit1, bit2)+1;
+}
+
 Dht::RoutingTable::iterator
 Dht::RoutingTable::findBucket(const InfoHash& id)
 {
@@ -609,11 +614,10 @@ Dht::newNode(const InfoHash& id, const sockaddr *sa, socklen_t salen, int confir
             }
         }
 
-        if (mybucket && (!dubious || list.size() == 1)) {
-            DHT_DEBUG("Splitting.");
+        if ((mybucket || (is_bootstrap and list.depth(b) < 6)) && (!dubious || list.size() == 1)) {
+            DHT_DEBUG("Splitting from depth %u", list.depth(b));
             sendCachedPing(*b);
             list.split(b);
-            //dumpTables();
             return newNode(id, sa, salen, confirm);
         }
 
@@ -1967,8 +1971,9 @@ Dht::getSearchesLog(sa_family_t af) const
     return out.str();
 }
 
-Dht::Dht(int s, int s6, const InfoHash& id)
- : dht_socket(s), dht_socket6(s6), myid(id), now(clock::now()), mybucket_grow_time(now), mybucket6_grow_time(now)
+Dht::Dht(int s, int s6, const InfoHash& id, bool bootstrap)
+ : dht_socket(s), dht_socket6(s6), myid(id), is_bootstrap(bootstrap),
+   now(clock::now()), mybucket_grow_time(now), mybucket6_grow_time(now)
 {
     if (s < 0 && s6 < 0)
         return;