diff --git a/extras/packaging/gnu-linux/debian/postinst b/extras/packaging/gnu-linux/debian/postinst
index 39ad146ec20fa8eca45a8232e9d49edf1dceb9ee..d716e78168e986fd59d41ed1dc69f785233e4283 100644
--- a/extras/packaging/gnu-linux/debian/postinst
+++ b/extras/packaging/gnu-linux/debian/postinst
@@ -60,6 +60,9 @@ configure_yaml() {
             echo "# When verbose is set to true, the server logs all incoming connections"
             echo "verbose: false"
             echo ""
+            echo "# If true, will send request to use UPNP if available"
+            echo "enable_upnp: true"
+            echo ""
             echo "# On server, identities are saved in /etc/dhtnet/id/"
             echo "certificate: \"/etc/dhtnet/id/id-server.crt\""
             echo "privateKey: \"/etc/dhtnet/id/id-server.pem\""
diff --git a/tools/common.cpp b/tools/common.cpp
index 7b10bfd817cb77cc31e6fd9341fda3e7674d94bb..06b92080254251457559b7fbe4981d5f6d057439 100644
--- a/tools/common.cpp
+++ b/tools/common.cpp
@@ -53,7 +53,8 @@ connectionManagerConfig(dht::crypto::Identity identity,
                         const std::string& turn_host,
                         const std::string& turn_user,
                         const std::string& turn_pass,
-                        const std::string& turn_realm)
+                        const std::string& turn_realm,
+                        const bool enable_upnp)
 {
     // DHT node creation: To make a connection manager at first a DHT node should be created
     dht::DhtRunner::Config dhtConfig;
@@ -93,6 +94,15 @@ connectionManagerConfig(dht::crypto::Identity identity,
         config->turnServerPwd = turn_pass;
         config->turnServerRealm = turn_realm;
     }
+
+    if (enable_upnp) {
+        // UPnP configuration
+        auto upnpContext = std::make_shared<dhtnet::upnp::UPnPContext>(ioContext, logger);
+        auto controller = std::make_shared<dhtnet::upnp::Controller>(upnpContext);
+        config->upnpEnabled = true;
+        config->upnpCtrl = controller;
+    }
+
     return std::move(config);
 }
 template<typename T>
diff --git a/tools/common.h b/tools/common.h
index 97c44c9ace3e396a3429ab58e76f6b369a16cff6..dbd72c3cffe1d1430fda6942d31fa3b9cdcaeb73 100644
--- a/tools/common.h
+++ b/tools/common.h
@@ -21,6 +21,9 @@
 #include "ice_transport_factory.h"
 #include "certstore.h"
 
+#include "upnp/upnp_control.h"
+#include "upnp/upnp_context.h"
+
 namespace dhtnet {
 
 #define Log(...) do { fmt::print(__VA_ARGS__); std::fflush(stdout); } while (0)
@@ -40,7 +43,8 @@ std::unique_ptr<ConnectionManager::Config> connectionManagerConfig(
     const std::string& turn_host ="",
     const std::string& turn_user="",
     const std::string& turn_pass="",
-    const std::string& turn_realm="");
+    const std::string& turn_realm="",
+    const bool enable_upnp=true);
 // add ioContext to readFromStdin
 
 template<typename T>
diff --git a/tools/dhtnet_crtmgr/main.cpp b/tools/dhtnet_crtmgr/main.cpp
index 70e551e811f27c22780e7a66a2f75b9d130e121a..4705e94492be65111a9ea51adf6effcfb14ec6ad 100644
--- a/tools/dhtnet_crtmgr/main.cpp
+++ b/tools/dhtnet_crtmgr/main.cpp
@@ -122,6 +122,9 @@ int create_yaml_config(std::filesystem::path file, std::filesystem::path certifi
         yaml_file << "\n# When verbose is set to true, the server logs all incoming connections\n";
         yaml_file << "verbose: false\n";
 
+        yaml_file << "\n# If true, will send request to use UPNP if available\n";
+        yaml_file << "enable_upnp: true\n";
+
         yaml_file << "\n# On server, identities are saved in /etc/dhtnet/id/\n";
         yaml_file << "# On client, they are generaly saved in ~/.dnc/\n";
         yaml_file << "certificate: " << certificate << "\n";
diff --git a/tools/dnc/dnc.cpp b/tools/dnc/dnc.cpp
index 18860ae783f64ef456358cd2772de6bea4522342..27cf3b4afee0ea099a6ba85fe3e531abd0b93f6f 100644
--- a/tools/dnc/dnc.cpp
+++ b/tools/dnc/dnc.cpp
@@ -61,7 +61,8 @@ Dnc::Dnc(dht::crypto::Identity identity,
          const std::string& turn_realm,
          const bool anonymous,
          const bool verbose,
-         const std::map<std::string, std::vector<int>> authorized_services)
+         const std::map<std::string, std::vector<int>> authorized_services,
+         const bool enable_upnp)
     :logger(verbose ? dht::log::getStdLogger() : nullptr),
     ioContext(std::make_shared<asio::io_context>()),
     iceFactory(std::make_shared<IceTransportFactory>(logger))
@@ -91,7 +92,8 @@ Dnc::Dnc(dht::crypto::Identity identity,
                                           turn_host,
                                           turn_user,
                                           turn_pass,
-                                          turn_realm);
+                                          turn_realm,
+                                          enable_upnp);
     // create a connection manager
     connectionManager = std::make_unique<ConnectionManager>(std::move(config));
 
@@ -206,8 +208,9 @@ Dnc::Dnc(dht::crypto::Identity identity,
          const std::string& turn_user,
          const std::string& turn_pass,
          const std::string& turn_realm,
-         const bool verbose)
-    : Dnc(identity, bootstrap,turn_host,turn_user,turn_pass, turn_realm, true, verbose, {})
+         const bool verbose,
+         const bool enable_upnp)
+    : Dnc(identity, bootstrap,turn_host,turn_user,turn_pass, turn_realm, true, verbose, {}, enable_upnp)
 {
     std::condition_variable cv;
     auto name = fmt::format("nc://{:s}:{:d}", remote_host, remote_port);
diff --git a/tools/dnc/dnc.h b/tools/dnc/dnc.h
index 6e5537dfa63c602423c0e4c4606845284842332d..7d03cc97ca224b621354aa59d772a19a27fe3f9b 100644
--- a/tools/dnc/dnc.h
+++ b/tools/dnc/dnc.h
@@ -41,7 +41,8 @@ public:
         const std::string& turn_realm,
         const bool anonymous,
         const bool verbose,
-        const std::map<std::string, std::vector<int>> authorized_services);
+        const std::map<std::string, std::vector<int>> authorized_services,
+        const bool enable_upnp);
     // Build a client
     Dnc(
         dht::crypto::Identity identity,
@@ -53,7 +54,8 @@ public:
         const std::string& turn_user,
         const std::string& turn_pass,
         const std::string& turn_realm,
-        const bool verbose);
+        const bool verbose,
+        const bool enable_upnp);
     ~Dnc();
     void run();
 
diff --git a/tools/dnc/dnc.yaml b/tools/dnc/dnc.yaml
index f1b06ea28ea825d090bce3092509864c6e7ae5c5..649a9be511b9f4aa2b82d41568046443b85d1cd5 100644
--- a/tools/dnc/dnc.yaml
+++ b/tools/dnc/dnc.yaml
@@ -16,6 +16,9 @@ turn_realm: "ring"
 # When verbose is set to true, the server logs all incoming connections
 verbose: false
 
+# If true, will send request to use UPNP if available
+enable_upnp: true
+
 # On server, identities are saved in /etc/dhtnet/id/
 # On client, identities are saved in ~/.dnc/
 #certificate: "to/your/certificate.crt"
diff --git a/tools/dnc/main.cpp b/tools/dnc/main.cpp
index 2e4d1bf1a622cf32e304fb4ff2780c128cf6f4ff..f759ff5087c369c6b688d4e04f505b6b572070dc 100644
--- a/tools/dnc/main.cpp
+++ b/tools/dnc/main.cpp
@@ -51,6 +51,7 @@ struct dhtnc_params
     bool anonymous_cnx {false};
     bool verbose {false};
     std::map<std::string, std::vector<int>> authorizedServices {};
+    bool enable_upnp {true};
 };
 
 static const constexpr struct option long_options[]
@@ -201,6 +202,9 @@ parse_args(int argc, char** argv)
                     params.authorizedServices[ip].push_back(port);
                 }
             }
+            if (config["enable_upnp"]) {
+                params.enable_upnp = config["enable_upnp"].as<bool>();
+            }
         }
     }
     return params;
@@ -272,7 +276,8 @@ main(int argc, char** argv)
                                               params.turn_realm,
                                               params.anonymous_cnx,
                                               params.verbose,
-                                              params.authorizedServices);
+                                              params.authorizedServices,
+                                              params.enable_upnp);
     } else {
         dhtnc = std::make_unique<dhtnet::Dnc>(identity,
                                               params.bootstrap,
@@ -283,7 +288,8 @@ main(int argc, char** argv)
                                               params.turn_user,
                                               params.turn_pass,
                                               params.turn_realm,
-                                              params.verbose);
+                                              params.verbose,
+                                              params.enable_upnp);
     }
     dhtnc->run();
     return EXIT_SUCCESS;