diff --git a/Knot.files b/Knot.files
index b48a5a247ca7cb127672f4999e2a0fdd7ccd4877..bf9e7b8f8191a7fc9916500b35dda6a5cb24b376 100644
--- a/Knot.files
+++ b/Knot.files
@@ -4,18 +4,15 @@ Makefile.am
 README
 configure.ac
 doc/Makefile.am
-doc/configuration.texi
-doc/indices.texi
-doc/installation.texi
-doc/introduction.texi
-doc/knot.texi
-doc/migration.texi
-doc/reference.texi
-doc/requirements.texi
-doc/running.texi
-doc/security.texi
-doc/synth_record.texi
-doc/troubleshooting.texi
+doc/configuration.rst
+doc/index.rst
+doc/installation.rst
+doc/introduction.rst
+doc/migration.rst
+doc/reference.rst
+doc/requirements.rst
+doc/running.rst
+doc/troubleshooting.rst
 libtap/Makefile.am
 libtap/runtests.c
 libtap/tap/basic.c
@@ -114,6 +111,8 @@ src/knot/dnssec/zone-sign.c
 src/knot/dnssec/zone-sign.h
 src/knot/knot.h
 src/knot/main.c
+src/knot/modules/dnstap.c
+src/knot/modules/dnstap.h
 src/knot/modules/synth_record.c
 src/knot/modules/synth_record.h
 src/knot/nameserver/axfr.c
diff --git a/scripts/update-project-files.py b/scripts/update-project-files.py
index 6dcb7153a2c120849f4995f65880181803bef6c7..bc49167300632b5f0dda1b90a2dd269f51a3022a 100755
--- a/scripts/update-project-files.py
+++ b/scripts/update-project-files.py
@@ -7,7 +7,7 @@
 SOURCES = [
     # documentation
     "README", "KNOWN_ISSUES", 
-    "Doxyfile*", "Doxy.file.h", "doc/*.texi",
+    "Doxyfile*", "Doxy.file.h", "doc/*.rst",
 
     # build-system
     "*.ac", "*.am",
diff --git a/src/Makefile.am b/src/Makefile.am
index e383ed79869ee35e9f37fd7e32bd6bdfd0c8e76d..dd31888e4f33047aa0bb79713bc2ed891d1f3bf9 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -172,19 +172,19 @@ libknot_la_SOURCES =				\
 	libknot/rdata/nsec.h			\
 	libknot/rdata/nsec3.c			\
 	libknot/rdata/nsec3.h			\
-	libknot/rdata/nsec3param.h			\
-	libknot/rdata/nsec3param.c			\
+	libknot/rdata/nsec3param.h		\
+	libknot/rdata/nsec3param.c		\
 	libknot/rdata/nsec.h			\
 	libknot/rdata/rrsig.h			\
 	libknot/rdata/soa.h			\
-	libknot/rdata/tsig.c				\
-	libknot/rdata/tsig.h				\
+	libknot/rdata/tsig.c			\
+	libknot/rdata/tsig.h			\
 	libknot/rrset-dump.c			\
 	libknot/rrset-dump.h			\
 	libknot/rdata.c				\
 	libknot/rdata.h				\
-	libknot/rdataset.c				\
-	libknot/rdataset.h				\
+	libknot/rdataset.c			\
+	libknot/rdataset.h			\
 	libknot/rrset.c				\
 	libknot/rrset.h				\
 	libknot/tsig-op.c			\
@@ -242,8 +242,6 @@ libknotd_la_SOURCES =				\
 	knot/nameserver/update.h		\
 	knot/modules/synth_record.c		\
 	knot/modules/synth_record.h		\
-	knot/modules/dnstap.c		\
-	knot/modules/dnstap.h		\
 	knot/other/debug.h			\
 	knot/server/dthreads.c			\
 	knot/server/dthreads.h			\
@@ -255,8 +253,8 @@ libknotd_la_SOURCES =				\
 	knot/server/rrl.h			\
 	knot/server/server.c			\
 	knot/server/server.h			\
-	knot/server/net.c				\
-	knot/server/net.h				\
+	knot/server/net.c			\
+	knot/server/net.h			\
 	knot/server/tcp-handler.c		\
 	knot/server/tcp-handler.h		\
 	knot/server/udp-handler.c		\
@@ -316,6 +314,10 @@ knsupdate_LDADD  = libknotus.la libknots.la libknot.la zscanner/libzscanner.la
 knsec3hash_LDADD = libknotus.la libknots.la libknot.la
 
 if HAVE_DNSTAP
+libknotd_la_SOURCES +=				\
+	knot/modules/dnstap.c			\
+	knot/modules/dnstap.h
+
 kdig_LDADD	+= dnstap/libdnstap.la
 khost_LDADD	+= dnstap/libdnstap.la
 libknotd_la_LIBADD += dnstap/libdnstap.la
diff --git a/src/knot/nameserver/query_module.c b/src/knot/nameserver/query_module.c
index 1110b80e9deb0471a7f74a46751fe962659b04e6..5e9d9fcb1181a85ddbce49a324ccfa22fd39bbd5 100644
--- a/src/knot/nameserver/query_module.c
+++ b/src/knot/nameserver/query_module.c
@@ -4,7 +4,9 @@
 
 /* Compiled-in module headers. */
 #include "knot/modules/synth_record.h"
+#if USE_DNSTAP
 #include "knot/modules/dnstap.h"
+#endif
 
 /* Compiled-in module table. */
 struct compiled_module {
@@ -12,13 +14,17 @@ struct compiled_module {
 	qmodule_load_t load;
 	qmodule_unload_t unload;
 };
+
 /*! \note All modules should be dynamically loaded later on. */
-#define MODULE_COUNT 2
-struct compiled_module MODULES[MODULE_COUNT] = {
+struct compiled_module MODULES[] = {
         { "synth_record", &synth_record_load, &synth_record_unload },
+#if USE_DNSTAP
         { "dnstap",       &dnstap_load,       &dnstap_unload }
+#endif
 };
 
+#define MODULE_COUNT sizeof(MODULES) / sizeof(MODULES[0])
+
 struct query_plan *query_plan_create(mm_ctx_t *mm)
 {
 	struct query_plan *plan = mm_alloc(mm, sizeof(struct query_plan));
diff --git a/src/utils/dig/dig_exec.c b/src/utils/dig/dig_exec.c
index 27f914330c33665470eb9eba4f636368ea227d89..48ca4835aa7ea4b35ee6e3f49719b4246a1ca0b2 100644
--- a/src/utils/dig/dig_exec.c
+++ b/src/utils/dig/dig_exec.c
@@ -26,7 +26,7 @@
 #include "common/print.h"		// time_diff
 #include "common/errcode.h"		// KNOT_EOK
 #include "common/descriptor.h"		// KNOT_RRTYPE_
-#include "common/sockaddr.h"
+#include "common/sockaddr.h"		// sockaddr_set_raw
 #include "utils/common/msg.h"		// WARN
 #include "utils/common/netio.h"		// get_socktype
 #include "utils/common/exec.h"		// print_packet
@@ -34,7 +34,182 @@
 #if USE_DNSTAP
 # include "dnstap/message.h"
 # include "dnstap/writer.h"
-#endif
+
+static int dump_dnstap(dt_writer_t                 *writer,
+                       const Dnstap__Message__Type msg_type,
+                       const uint8_t               *wire,
+                       const size_t                wire_len,
+                       net_t                       *net,
+                       const struct timeval        *qtime,
+                       const struct timeval        *rtime)
+{
+	const struct sockaddr *qa = NULL;
+	const struct sockaddr *ra = NULL;
+	Dnstap__Message       msg;
+	int                   ret;
+
+	if (writer == NULL) {
+		return KNOT_EOK;
+	}
+
+	net_set_local_info(net);
+
+	if (msg_type == DNSTAP__MESSAGE__TYPE__TOOL_QUERY) {
+		qa = net->srv->ai_addr;
+		ra = net->local_info->ai_addr;
+	} else if (msg_type == DNSTAP__MESSAGE__TYPE__TOOL_RESPONSE) {
+		qa = net->local_info->ai_addr;
+		ra = net->srv->ai_addr;
+	}
+
+	ret = dt_message_fill(&msg, msg_type, qa, ra,
+	                      net->srv->ai_protocol, wire, wire_len,
+	                      qtime, rtime);
+	if (ret != KNOT_EOK) {
+		return ret;
+	}
+
+	return dt_writer_write(writer, (const ProtobufCMessage *) &msg);
+}
+
+static float get_query_time(const Dnstap__Dnstap *frame)
+{
+	struct timeval from = {
+		.tv_sec = frame->message->query_time_sec,
+		.tv_usec = frame->message->query_time_nsec / 1000
+	};
+
+	struct timeval to = {
+		.tv_sec = frame->message->response_time_sec,
+		.tv_usec = frame->message->response_time_nsec / 1000
+	};
+
+	return time_diff(&from, &to);
+}
+
+static void process_dnstap(const query_t *query)
+{
+	dt_reader_t *reader = query->dt_reader;
+	int         ret;
+
+	if (query->dt_reader == NULL) {
+		return;
+	}
+
+	for (;;) {
+		Dnstap__Dnstap      *frame = NULL;
+		ProtobufCBinaryData *msg = NULL;
+		bool                is_response;
+
+		// Read next message.
+		ret = dt_reader_read(reader, &frame);
+		if (ret == KNOT_EOF) {
+			break;
+		} else if (ret != KNOT_EOK) {
+			ERR("can't read dnstap message\n");
+			break;
+		}
+
+		// Check for dnstap message.
+		if (frame->type != DNSTAP__DNSTAP__TYPE__MESSAGE) {
+			WARN("ignoring non-dnstap message\n");
+			dt_reader_free_frame(reader, &frame);
+			continue;
+		}
+
+		// Check for the type of dnstap message.
+		if (frame->message->has_response_message) {
+			msg = &frame->message->response_message;
+			is_response = true;
+		} else if (frame->message->has_query_message) {
+			if (!query->style.show_query) {
+				dt_reader_free_frame(reader, &frame);
+				continue;
+			}
+			msg = &frame->message->query_message;
+			is_response = false;
+		} else {
+			WARN("unsupported dnstap message\n");
+			dt_reader_free_frame(reader, &frame);
+			continue;
+		}
+
+		// Create dns packet based on dnstap wire data.
+		knot_pkt_t *pkt = knot_pkt_new(msg->data, msg->len, NULL);
+		if (pkt == NULL) {
+			ERR("can't allocate packet\n");
+			dt_reader_free_frame(reader, &frame);
+			break;
+		}
+
+		// Parse packet and reconstruct required data.
+		if (knot_pkt_parse(pkt, 0) == KNOT_EOK) {
+			ProtobufCBinaryData *addr = NULL;
+			uint32_t            port = 0;
+			time_t              timestamp = 0;
+			float               query_time = 0.0;
+			net_t               net_ctx = { 0 };
+
+			if (is_response) {
+				addr = &frame->message->response_address;
+				port = frame->message->response_port;
+
+				timestamp = frame->message->response_time_sec;
+				query_time = get_query_time(frame);
+			} else {
+				addr = &frame->message->query_address;
+				port = frame->message->query_port;
+
+				timestamp = frame->message->query_time_sec;
+			}
+
+			// Prepare connection information string.
+			if (addr->data != NULL &&
+			    frame->message->has_socket_family &&
+			    frame->message->has_socket_protocol) {
+				struct sockaddr_storage ss;
+				int    family = AF_UNSPEC, proto = 0;
+
+				switch (frame->message->socket_family) {
+				case DNSTAP__SOCKET_FAMILY__INET:
+					family = AF_INET;
+					break;
+				case DNSTAP__SOCKET_FAMILY__INET6:
+					family = AF_INET6;
+					break;
+				default:
+					break;
+				}
+
+				switch (frame->message->socket_protocol) {
+				case DNSTAP__SOCKET_PROTOCOL__UDP:
+					proto = SOCK_DGRAM;
+					break;
+				case DNSTAP__SOCKET_PROTOCOL__TCP:
+					proto = SOCK_STREAM;
+					break;
+				default:
+					break;
+				}
+
+				sockaddr_set_raw(&ss, family, addr->data);
+				sockaddr_port_set(&ss, port);
+				get_addr_str(&ss, proto, &net_ctx.remote_str);
+			}
+
+			print_packet(pkt, &net_ctx, pkt->size, query_time,
+			             timestamp, is_response, &query->style);
+
+			net_clean(&net_ctx);
+		} else {
+			ERR("can't print dnstap message\n");
+		}
+
+		knot_pkt_free(&pkt);
+		dt_reader_free_frame(reader, &frame);
+	}
+}
+#endif // USE_DNSTAP
 
 static knot_pkt_t* create_query_packet(const query_t *query)
 {
@@ -268,46 +443,6 @@ static bool last_serial_check(const uint32_t serial, const knot_pkt_t *reply)
 	}
 }
 
-static int dump_dnstap(dt_writer_t                 *writer,
-                       const Dnstap__Message__Type msg_type,
-                       const uint8_t               *wire,
-                       const size_t                wire_len,
-                       net_t                       *net,
-                       const struct timeval        *qtime,
-                       const struct timeval        *rtime)
-{
-#if USE_DNSTAP
-	const struct sockaddr *qa = NULL;
-	const struct sockaddr *ra = NULL;
-	Dnstap__Message       msg;
-	int                   ret;
-
-	if (writer == NULL) {
-		return KNOT_EOK;
-	}
-
-	net_set_local_info(net);
-
-	if (msg_type == DNSTAP__MESSAGE__TYPE__TOOL_QUERY) {
-		qa = net->srv->ai_addr;
-		ra = net->local_info->ai_addr;
-	} else if (msg_type == DNSTAP__MESSAGE__TYPE__TOOL_RESPONSE) {
-		qa = net->local_info->ai_addr;
-		ra = net->srv->ai_addr;
-	}
-
-	ret = dt_message_fill(&msg, msg_type, qa, ra,
-	                      net->srv->ai_protocol, wire, wire_len,
-	                      qtime, rtime);
-	if (ret != KNOT_EOK) {
-		return ret;
-	}
-
-	return dt_writer_write(writer, (const ProtobufCMessage *) &msg);
-#endif
-	return KNOT_EOK;
-}
-
 static int process_query_packet(const knot_pkt_t        *query,
                                 net_t                   *net,
                                 const query_t           *query_ctx,
@@ -341,10 +476,12 @@ static int process_query_packet(const knot_pkt_t        *query,
 	// Get stop query time and start reply time.
 	gettimeofday(&t_query, NULL);
 
+#if USE_DNSTAP
 	// Make the dnstap copy of the query.
 	dump_dnstap(query_ctx->dt_writer,
 	            DNSTAP__MESSAGE__TYPE__TOOL_QUERY,
 	            query->wire, query->size, net, &t_query, NULL);
+#endif // USE_DNSTAP
 
 	// Print query packet if required.
 	if (style->show_query) {
@@ -378,10 +515,12 @@ static int process_query_packet(const knot_pkt_t        *query,
 		// Get stop reply time.
 		gettimeofday(&t_end, NULL);
 
+#if USE_DNSTAP
 		// Make the dnstap copy of the response.
 		dump_dnstap(query_ctx->dt_writer,
 		            DNSTAP__MESSAGE__TYPE__TOOL_RESPONSE,
 		            in, in_len, net, &t_query, &t_end);
+#endif // USE_DNSTAP
 
 		// Create reply packet structure to fill up.
 		reply = knot_pkt_new(in, in_len, NULL);
@@ -590,10 +729,12 @@ static int process_xfr_packet(const knot_pkt_t        *query,
 	// Get stop query time and start reply time.
 	gettimeofday(&t_query, NULL);
 
+#if USE_DNSTAP
 	// Make the dnstap copy of the query.
 	dump_dnstap(query_ctx->dt_writer,
 	            DNSTAP__MESSAGE__TYPE__TOOL_QUERY,
 	            query->wire, query->size, net, &t_query, NULL);
+#endif // USE_DNSTAP
 
 	// Print query packet if required.
 	if (style->show_query) {
@@ -618,10 +759,12 @@ static int process_xfr_packet(const knot_pkt_t        *query,
 		// Get stop message time.
 		gettimeofday(&t_end, NULL);
 
+#if USE_DNSTAP
 		// Make the dnstap copy of the response.
 		dump_dnstap(query_ctx->dt_writer,
 		            DNSTAP__MESSAGE__TYPE__TOOL_RESPONSE,
 		            in, in_len, net, &t_query, &t_end);
+#endif // USE_DNSTAP
 
 		// Create reply packet structure to fill up.
 		reply = knot_pkt_new(in, in_len, NULL);
@@ -782,148 +925,6 @@ static void process_xfr(const query_t *query)
 	knot_pkt_free(&out_packet);
 }
 
-#if USE_DNSTAP
-static float get_query_time(const Dnstap__Dnstap *frame)
-{
-	struct timeval from = {
-		.tv_sec = frame->message->query_time_sec,
-		.tv_usec = frame->message->query_time_nsec / 1000
-	};
-
-	struct timeval to = {
-		.tv_sec = frame->message->response_time_sec,
-		.tv_usec = frame->message->response_time_nsec / 1000
-	};
-
-	return time_diff(&from, &to);
-}
-#endif
-
-static void process_dnstap(const query_t *query)
-{
-#if USE_DNSTAP
-	dt_reader_t *reader = query->dt_reader;
-	int         ret;
-
-	if (query->dt_reader == NULL) {
-		return;
-	}
-
-	for (;;) {
-		Dnstap__Dnstap      *frame = NULL;
-		ProtobufCBinaryData *msg = NULL;
-		bool                is_response;
-
-		// Read next message.
-		ret = dt_reader_read(reader, &frame);
-		if (ret == KNOT_EOF) {
-			break;
-		} else if (ret != KNOT_EOK) {
-			ERR("can't read dnstap message\n");
-			break;
-		}
-
-		// Check for dnstap message.
-		if (frame->type != DNSTAP__DNSTAP__TYPE__MESSAGE) {
-			WARN("ignoring non-dnstap message\n");
-			dt_reader_free_frame(reader, &frame);
-			continue;
-		}
-
-		// Check for the type of dnstap message.
-		if (frame->message->has_response_message) {
-			msg = &frame->message->response_message;
-			is_response = true;
-		} else if (frame->message->has_query_message) {
-			if (!query->style.show_query) {
-				dt_reader_free_frame(reader, &frame);
-				continue;
-			}
-			msg = &frame->message->query_message;
-			is_response = false;
-		} else {
-			WARN("unsupported dnstap message\n");
-			dt_reader_free_frame(reader, &frame);
-			continue;
-		}
-
-		// Create dns packet based on dnstap wire data.
-		knot_pkt_t *pkt = knot_pkt_new(msg->data, msg->len, NULL);
-		if (pkt == NULL) {
-			ERR("can't allocate packet\n");
-			dt_reader_free_frame(reader, &frame);
-			break;
-		}
-
-		// Parse packet and reconstruct required data.
-		if (knot_pkt_parse(pkt, 0) == KNOT_EOK) {
-			ProtobufCBinaryData *addr = NULL;
-			uint32_t            port = 0;
-			time_t              timestamp = 0;
-			float               query_time = 0.0;
-			net_t               net_ctx = { 0 };
-
-			if (is_response) {
-				addr = &frame->message->response_address;
-				port = frame->message->response_port;
-
-				timestamp = frame->message->response_time_sec;
-				query_time = get_query_time(frame);
-			} else {
-				addr = &frame->message->query_address;
-				port = frame->message->query_port;
-
-				timestamp = frame->message->query_time_sec;
-			}
-
-			// Prepare connection information string.
-			if (addr->data != NULL &&
-			    frame->message->has_socket_family &&
-			    frame->message->has_socket_protocol) {
-				struct sockaddr_storage ss;
-				int    family = AF_UNSPEC, proto = 0;
-
-				switch (frame->message->socket_family) {
-				case DNSTAP__SOCKET_FAMILY__INET:
-					family = AF_INET;
-					break;
-				case DNSTAP__SOCKET_FAMILY__INET6:
-					family = AF_INET6;
-					break;
-				default:
-					break;
-				}
-
-				switch (frame->message->socket_protocol) {
-				case DNSTAP__SOCKET_PROTOCOL__UDP:
-					proto = SOCK_DGRAM;
-					break;
-				case DNSTAP__SOCKET_PROTOCOL__TCP:
-					proto = SOCK_STREAM;
-					break;
-				default:
-					break;
-				}
-
-				sockaddr_set_raw(&ss, family, addr->data);
-				sockaddr_port_set(&ss, port);
-				get_addr_str(&ss, proto, &net_ctx.remote_str);
-			}
-
-			print_packet(pkt, &net_ctx, pkt->size, query_time,
-			             timestamp, is_response, &query->style);
-
-			net_clean(&net_ctx);
-		} else {
-			ERR("can't print dnstap message\n");
-		}
-
-		knot_pkt_free(&pkt);
-		dt_reader_free_frame(reader, &frame);
-	}
-#endif
-}
-
 int dig_exec(const dig_params_t *params)
 {
 	node_t *n = NULL;
@@ -944,9 +945,11 @@ int dig_exec(const dig_params_t *params)
 		case OPERATION_XFR:
 			process_xfr(query);
 			break;
+#if USE_DNSTAP
 		case OPERATION_LIST_DNSTAP:
 			process_dnstap(query);
 			break;
+#endif // USE_DNSTAP
 		case OPERATION_LIST_SOA:
 			break;
 		default:
diff --git a/src/utils/dig/dig_params.c b/src/utils/dig/dig_params.c
index b714dd715d882c5f07f8547b04d2741ac76f5f3e..34b2c8afc5401687cb7b7ea926f4d38d2af256ce 100644
--- a/src/utils/dig/dig_params.c
+++ b/src/utils/dig/dig_params.c
@@ -797,7 +797,7 @@ query_t* query_create(const char *owner, const query_t *conf)
 #if USE_DNSTAP
 		query->dt_reader = NULL;
 		query->dt_writer = NULL;
-#endif
+#endif // USE_DNSTAP
 	} else {
 		query->conf = conf;
 		if (conf->local != NULL) {
@@ -831,7 +831,7 @@ query_t* query_create(const char *owner, const query_t *conf)
 #if USE_DNSTAP
 		query->dt_reader = conf->dt_reader;
 		query->dt_writer = conf->dt_writer;
-#endif
+#endif // USE_DNSTAP
 
 		if (knot_copy_key_params(&conf->key_params, &query->key_params)
 		    != KNOT_EOK) {
@@ -883,7 +883,7 @@ void query_free(query_t *query)
 			dt_writer_free(query->dt_writer);
 		}
 	}
-#endif
+#endif // USE_DNSTAP
 
 	free(query->owner);
 	free(query->port);
@@ -1141,7 +1141,7 @@ static int parse_dnstap_input(const char *value, query_t *query)
 
 	return KNOT_EOK;
 }
-#endif
+#endif // USE_DNSTAP
 
 static void complete_servers(query_t *query, const query_t *conf)
 {
@@ -1472,7 +1472,7 @@ static int parse_opt1(const char *opt, const char *value, dig_params_t *params,
 #else
 		ERR("no dnstap support but -E specified\n");
 		return KNOT_EINVAL;
-#endif
+#endif // USE_DNSTAP
 		break;
 	case 'G':
 #if USE_DNSTAP
@@ -1498,7 +1498,7 @@ static int parse_opt1(const char *opt, const char *value, dig_params_t *params,
 #else
 		ERR("no dnstap support but -G specified\n");
 		return KNOT_EINVAL;
-#endif
+#endif // USE_DNSTAP
 		break;
 	case '-':
 		if (strcmp(opt, "-help") == 0) {
diff --git a/src/utils/dig/dig_params.h b/src/utils/dig/dig_params.h
index c1d6a446785820637b82c34e8693d26b8261a438..0a953779e56a32ac9dd407b839bec29b39267ff2 100644
--- a/src/utils/dig/dig_params.h
+++ b/src/utils/dig/dig_params.h
@@ -35,7 +35,7 @@
 #if USE_DNSTAP
 # include "dnstap/reader.h"
 # include "dnstap/writer.h"
-#endif
+#endif // USE_DNSTAP
 
 #define KDIG_VERSION "kdig, version " PACKAGE_VERSION "\n"
 
@@ -129,7 +129,7 @@ struct query {
 	dt_reader_t	*dt_reader;
 	/*!< Context for dnstap writer output. */
 	dt_writer_t	*dt_writer;
-#endif
+#endif // USE_DNSTAP
 };
 
 /*! \brief Settings for dig. */