diff --git a/c/opendht.cpp b/c/opendht.cpp
index 99759edaacca9c584e6c3627b9e86d34441ab275..6f9770c57ed91ed6715f0ff1df584296f9bbcfc3 100644
--- a/c/opendht.cpp
+++ b/c/opendht.cpp
@@ -2,6 +2,8 @@
 #include "opendht.h"
 
 using ValueSp = std::shared_ptr<dht::Value>;
+using PrivkeySp = std::shared_ptr<dht::crypto::PrivateKey>;
+using CertSp = std::shared_ptr<dht::crypto::Certificate>;
 
 #ifdef __cplusplus
 extern "C" {
@@ -119,23 +121,30 @@ dht_blob* dht_publickey_encrypt(const dht_publickey* pk, const char* data, size_
 dht_privatekey* dht_privatekey_generate(unsigned key_length_bits) {
     if (key_length_bits == 0)
         key_length_bits = 4096;
-    return reinterpret_cast<dht_privatekey*>(new dht::crypto::PrivateKey(dht::crypto::PrivateKey::generate(key_length_bits)));
+    return reinterpret_cast<dht_privatekey*>(new PrivkeySp(std::make_shared<dht::crypto::PrivateKey>(dht::crypto::PrivateKey::generate(key_length_bits))));
 }
 
 dht_privatekey* dht_privatekey_import(const uint8_t* dat, size_t dat_size, const char* password) {
     try {
-        return reinterpret_cast<dht_privatekey*>(new dht::crypto::PrivateKey(dat, dat_size, password));
+        return reinterpret_cast<dht_privatekey*>(new PrivkeySp(std::make_shared<dht::crypto::PrivateKey>(dat, dat_size, password)));
     } catch (const dht::crypto::CryptoException& e) {
         return nullptr;
     }
 }
 
-dht_publickey* dht_privatekey_get_publickey(const dht_privatekey* key) {
-    return reinterpret_cast<dht_publickey*>(new dht::crypto::PublicKey(reinterpret_cast<const dht::crypto::PrivateKey*>(key)->getPublicKey()));
+dht_publickey* dht_privatekey_get_publickey(const dht_privatekey* k) {
+    const auto& key = *reinterpret_cast<const PrivkeySp*>(k);
+    return reinterpret_cast<dht_publickey*>(new dht::crypto::PublicKey(key->getPublicKey()));
 }
 
 void dht_privatekey_delete(dht_privatekey* pk) {
-    delete reinterpret_cast<dht::crypto::PrivateKey*>(pk);
+    delete reinterpret_cast<PrivkeySp*>(pk);
+}
+
+// config
+void dht_runner_config_default(dht_runner_config* config) {
+    bzero(config, sizeof(dht_runner_config));
+    config->threaded = true;
 }
 
 // dht::DhtRunner
@@ -152,6 +161,30 @@ void dht_runner_run(dht_runner* r, in_port_t port) {
     runner->run(port, {}, true);
 }
 
+void dht_runner_run_config(dht_runner* r, in_port_t port, const dht_runner_config* conf) {
+    auto runner = reinterpret_cast<dht::DhtRunner*>(r);
+    dht::DhtRunner::Config config;
+    config.dht_config.node_config.is_bootstrap = conf->dht_config.node_config.is_bootstrap;
+    config.dht_config.node_config.maintain_storage = conf->dht_config.node_config.maintain_storage;
+    config.dht_config.node_config.node_id = *reinterpret_cast<const dht::InfoHash*>(&conf->dht_config.node_config.node_id);
+    config.dht_config.node_config.network = conf->dht_config.node_config.network;
+    config.dht_config.node_config.persist_path = conf->dht_config.node_config.persist_path;
+
+    if (conf->dht_config.id.privkey)
+        config.dht_config.id.first = *reinterpret_cast<const PrivkeySp*>(conf->dht_config.id.privkey);
+
+    if (conf->dht_config.id.certificate)
+        config.dht_config.id.second = *reinterpret_cast<const CertSp*>(conf->dht_config.id.certificate);
+
+    config.threaded = conf->threaded;
+    config.proxy_server = conf->proxy_server;
+    config.push_node_id = conf->push_node_id;
+    config.push_token = conf->push_token;
+    config.peer_discovery = conf->peer_discovery;
+    config.peer_publish = conf->peer_publish;
+    runner->run(port, config);
+}
+
 void dht_runner_ping(dht_runner* r, struct sockaddr* addr, socklen_t addr_len) {
     auto runner = reinterpret_cast<dht::DhtRunner*>(r);
     runner->bootstrap(dht::SockAddr(addr, addr_len));
diff --git a/c/opendht_c.h b/c/opendht_c.h
index e4b0180c480f35d0793996f50f7e45f70cdc61bd..ee3290fcd690527b342a96c1bba266f147635605 100644
--- a/c/opendht_c.h
+++ b/c/opendht_c.h
@@ -70,6 +70,12 @@ OPENDHT_C_PUBLIC void dht_privatekey_delete(dht_privatekey*);
 struct OPENDHT_C_PUBLIC dht_certificate;
 typedef struct dht_certificate dht_certificate;
 
+struct OPENDHT_PUBLIC dht_identity {
+    dht_privatekey* privkey;
+    dht_certificate* certificate;
+};
+typedef struct dht_identity dht_identity;
+
 // callbacks
 typedef bool (*dht_get_cb)(const dht_value* value, void* user_data);
 typedef bool (*dht_value_cb)(const dht_value* value, bool expired, void* user_data);
@@ -80,12 +86,44 @@ struct OPENDHT_C_PUBLIC dht_op_token;
 typedef struct dht_op_token dht_op_token;
 OPENDHT_C_PUBLIC void dht_op_token_delete(dht_op_token* token);
 
+// config
+struct OPENDHT_PUBLIC dht_node_config {
+    dht_infohash node_id;
+    uint32_t network;
+    bool is_bootstrap;
+    bool maintain_storage;
+    const char* persist_path;
+};
+typedef struct dht_node_config dht_node_config;
+
+struct OPENDHT_PUBLIC dht_secure_config
+{
+    dht_node_config node_config;
+    dht_identity id;
+};
+typedef struct dht_secure_config dht_secure_config;
+
+struct OPENDHT_PUBLIC dht_runner_config {
+    dht_secure_config dht_config;
+    bool threaded;
+    const char* proxy_server;
+    const char* push_node_id;
+    const char* push_token;
+    bool peer_discovery;
+    bool peer_publish;
+    dht_certificate* server_ca;
+    dht_identity client_identity;
+};
+typedef struct dht_runner_config dht_runner_config;
+OPENDHT_C_PUBLIC void dht_runner_config_default(dht_runner_config* config);
+
 // dht::DhtRunner
 struct OPENDHT_C_PUBLIC dht_runner;
 typedef struct dht_runner dht_runner;
 OPENDHT_C_PUBLIC dht_runner* dht_runner_new();
 OPENDHT_C_PUBLIC void dht_runner_delete(dht_runner* runner);
 OPENDHT_C_PUBLIC void dht_runner_run(dht_runner* runner, in_port_t port);
+OPENDHT_C_PUBLIC void dht_runner_run_config(dht_runner* runner, in_port_t port, const dht_runner_config* config);
 OPENDHT_C_PUBLIC void dht_runner_ping(dht_runner* runner, struct sockaddr* addr, socklen_t addr_len);
 OPENDHT_C_PUBLIC void dht_runner_bootstrap(dht_runner* runner, const char* host, const char* service);
 OPENDHT_C_PUBLIC void dht_runner_get(dht_runner* runner, const dht_infohash* hash, dht_get_cb cb, dht_done_cb done_cb, void* cb_user_data);