diff --git a/.gitignore b/.gitignore
index 1a24eb4b398e4443ab20d5e3c21911eae10f4d35..1ed41e96489a96260def9defd0cf23f645e81a27 100644
--- a/.gitignore
+++ b/.gitignore
@@ -55,6 +55,7 @@
 /src/dnssec/libdnssec.pc
 /src/libknot.pc
 /src/libknot/version.h
+/src/knot/modules/static_modules.h
 
 # dnstap
 /src/contrib/dnstap/Makefile
diff --git a/configure.ac b/configure.ac
index 0b475f815269eb87777bac912b53da00fe3c4689..d8016290110a9dbd25faac43dbf9152a71299bd5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -196,6 +196,14 @@ AC_ARG_WITH([configdir],
         [config_dir=$withval])
 AC_SUBST(config_dir)
 
+module_dir=
+module_instdir="${libdir}/knot/modules-${KNOT_VERSION_MAJOR}.${KNOT_VERSION_MINOR}"
+AC_ARG_WITH([moduledir],
+        AC_HELP_STRING([--with-moduledir=path], [Path to auto-loaded dynamic modules. [default not set]]),
+        [module_dir=$withval module_instdir=$module_dir])
+AC_SUBST(module_instdir)
+AC_SUBST(module_dir)
+
 #########################################
 # Dependencies needed for Knot DNS daemon
 #########################################
@@ -275,6 +283,31 @@ AS_IF([test "$with_urcu" != "no"], [
 AC_SEARCH_LIBS([urcu_init], [urcu], [AC_MSG_ERROR([liburcu is too old (< 0.4.0), urcu_init symbol found])])
 ])
 
+static_modules=""
+shared_modules=""
+AS_IF([test "$enable_daemon" = "yes"],[
+  static_modules_declars=""
+  static_modules_init=""
+  doc_modules=""
+
+  KNOT_MODULE([dnsproxy],    "yes", "non-shareable")
+  KNOT_MODULE([dnstap],      "no")
+  KNOT_MODULE([noudp],       "yes")
+  KNOT_MODULE([onlinesign],  "yes", "non-shareable")
+  KNOT_MODULE([rosedb],      "no")
+  KNOT_MODULE([rrl],         "yes")
+  KNOT_MODULE([stats],       "yes")
+  KNOT_MODULE([synthrecord], "yes")
+  KNOT_MODULE([whoami],      "yes")
+
+  AC_SUBST([STATIC_MODULES_DECLARS], [$(printf "$static_modules_declars")])
+  AM_SUBST_NOTMAKE([STATIC_MODULES_DECLARS])
+  AC_SUBST([STATIC_MODULES_INIT], [$(printf "$static_modules_init")])
+  AM_SUBST_NOTMAKE([STATIC_MODULES_INIT])
+  AC_SUBST([DOC_MODULES], [$(printf "$doc_modules")])
+  AM_SUBST_NOTMAKE([DOC_MODULES])
+])
+
 opt_dnstap=no
 AS_IF([test "$enable_daemon" = "yes" -o "$enable_utilities" = "yes"],[
 dnl Check for dnstap.
@@ -385,17 +418,6 @@ AS_CASE([$timer_mapsize],
                  [AC_ERROR([timer_mapsize must be an integer number])])])
 AC_DEFINE_UNQUOTED([TIMER_MAPSIZE], [$timer_mapsize], [Timer DB mapsize.])
 
-AS_IF([test "$enable_daemon" = "yes"],[
-
-dnl Check for rosedb module
-AC_ARG_ENABLE([rosedb],
-    AS_HELP_STRING([--enable-rosedb], [Enable static RR query module.]),
-    [], [enable_rosedb=no])
-]) # Knot DNS daemon dependencies
-
-AS_IF([test "$enable_rosedb" = yes], [AC_DEFINE([HAVE_ROSEDB], [1], [Define to 1 to enable static RR query module.])])
-AM_CONDITIONAL([HAVE_ROSEDB], [test "$enable_rosedb" = yes])
-
 # libedit
 AS_IF([test "$enable_daemon" = "yes" -o "$enable_utilities" = "yes"], [
   PKG_CHECK_MODULES([libedit], [libedit], [with_libedit=yes], [
@@ -534,6 +556,7 @@ result_msg_base="  $PACKAGE $VERSION
     Run dir:     ${run_dir}
     Storage dir: ${storage_dir}
     Config dir:  ${config_dir}
+    Module dir:  ${module_dir}
 
     Configuration DB mapsize: ${conf_mapsize} MiB
     Timers DB mapsize:        ${timer_mapsize} MiB
@@ -543,14 +566,17 @@ result_msg_base="  $PACKAGE $VERSION
     Knot DNS utils:         ${enable_utilities}
     Knot DNS documentation: ${enable_documentation}
 
-    Use recvmmsg:        ${enable_recvmmsg}
-    Use SO_REUSEPORT:    ${enable_reuseport}
-    Fast zone parser:    ${enable_fastparser}
-    Utilities with IDN:  ${with_libidn}
-    Systemd integration: ${enable_systemd}
-    Dnstap support:      ${opt_dnstap}
-    Code coverage:       ${enable_code_coverage}
-    PKCS #11 support:    ${enable_pkcs11}"
+    Static modules: ${static_modules}
+    Shared modules: ${shared_modules}
+
+    Use recvmmsg:          ${enable_recvmmsg}
+    Use SO_REUSEPORT:      ${enable_reuseport}
+    Fast zone parser:      ${enable_fastparser}
+    Utilities with IDN:    ${with_libidn}
+    Utilities with Dnstap: ${opt_dnstap}
+    Systemd integration:   ${enable_systemd}
+    Code coverage:         ${enable_code_coverage}
+    PKCS #11 support:      ${enable_pkcs11}"
 
 result_msg_esc=$(echo -n "$result_msg_base" | sed '$!s/$/\\n/' | tr -d '\n')
 result_msg_add="
@@ -563,6 +589,7 @@ AC_DEFINE_UNQUOTED([CONFIGURE_SUMMARY],["$result_msg_esc"],[Configure summary])
 
 AC_CONFIG_FILES([Makefile
                  doc/Makefile
+                 doc/modules.rst
                  libtap/Makefile
                  tests/Makefile
                  tests-fuzz/Makefile
@@ -572,6 +599,7 @@ AC_CONFIG_FILES([Makefile
                  src/contrib/dnstap/Makefile
                  src/dnssec/Makefile
                  src/dnssec/tests/Makefile
+                 src/knot/modules/static_modules.h
                  src/zscanner/Makefile
                  ])
 
diff --git a/doc/.gitignore b/doc/.gitignore
index 40206f4239d4f08a3aab140a782ffade08c922ef..40379ee7be4330d603ad5c79f610c64862a2c520 100644
--- a/doc/.gitignore
+++ b/doc/.gitignore
@@ -1,4 +1,5 @@
 /_build
+/modules.rst
 
 # sphinx-build manpages
 /man/knot.conf.5
diff --git a/doc/modules.rst.in b/doc/modules.rst.in
new file mode 100644
index 0000000000000000000000000000000000000000..727e9e0fc26e180212f30bb89ccf91226cb382a3
--- /dev/null
+++ b/doc/modules.rst.in
@@ -0,0 +1,8 @@
+.. highlight:: none
+.. _Modules:
+
+*******
+Modules
+*******
+
+@DOC_MODULES@
diff --git a/m4/dnstap.m4 b/m4/dnstap.m4
index c23ede901b422d625af0603daa3d17717bd34eeb..f530b55bf5d14597bcea118f02421991142bceef 100644
--- a/m4/dnstap.m4
+++ b/m4/dnstap.m4
@@ -7,9 +7,12 @@ AC_DEFUN([dt_DNSTAP],
 [
   AC_ARG_ENABLE([dnstap],
     AS_HELP_STRING([--enable-dnstap],
-                   [Enable dnstap support (requires fstrm, protobuf-c)]),
+                   [Enable dnstap support for kdig (requires fstrm, protobuf-c)]),
     [opt_dnstap=$enableval], [opt_dnstap=no])
 
+  AS_IF([test "$STATIC_MODULE_dnstap" != "no" -o "$SHARED_MODULE_dnstap" != "no"],
+        [opt_dnstap=yes])
+
   AS_IF([test "$opt_dnstap" != "no"],[
     AC_PATH_PROG([PROTOC_C], [protoc-c])
     AS_IF([test -z "$PROTOC_C"],[
diff --git a/m4/knot-module.m4 b/m4/knot-module.m4
new file mode 100644
index 0000000000000000000000000000000000000000..d8d5d47206dc43b83cb9758f186c1538c1ebad3f
--- /dev/null
+++ b/m4/knot-module.m4
@@ -0,0 +1,31 @@
+# KNOT_MODULE([module-name], [default], [non-shareable])
+# ------------------------------------------------------
+# Set Knot DNS module building
+
+AC_DEFUN([KNOT_MODULE],
+[
+  AC_ARG_WITH([module-$1],
+    AS_HELP_STRING([--with-module-$1=yes|shared|no], [Build '$1' module [default=$2]]),
+    [module=$withval],
+    [module=$2]
+  )
+
+  STATIC_MODULE_$1=no
+  SHARED_MODULE_$1=no
+  AS_CASE([$module],
+   [yes],    [STATIC_MODULE_$1=yes
+              static_modules="${static_modules}$1 "
+              static_modules_declars="${static_modules_declars}extern const knotd_mod_api_t knotd_mod_api_$1;\n"
+              static_modules_init="${static_modules_init}\\\\\n\t{ &knotd_mod_api_$1 },"
+              doc_modules="${doc_modules}.. include:: ../src/knot/modules/$1/$1.rst\n"],
+   [shared], [SHARED_MODULE_$1=yes
+              shared_modules="${shared_modules}$1 "
+              doc_modules="${doc_modules}.. include:: ../src/knot/modules/$1/$1.rst\n"
+              AS_IF([test "$3" = "non-shareable"],
+                    [AC_MSG_ERROR([Module $1 cannot be shared])])],
+   [no],     [],
+   [*],      [AC_MSG_ERROR([Invalid value '$module' for --with-module-$1])]
+  )
+  AM_CONDITIONAL([STATIC_MODULE_$1], [test "$STATIC_MODULE_$1" = "yes"])
+  AM_CONDITIONAL([SHARED_MODULE_$1], [test "$SHARED_MODULE_$1" = "yes"])
+])
diff --git a/src/Makefile.am b/src/Makefile.am
index c130d8ef2d969930993f74b9fd403d310acdd922..7111f1dd1830f6df7f19fb85692d70748bbf5446 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -17,6 +17,8 @@ AM_CPPFLAGS = \
 	-DCONFIG_DIR='"${config_dir}"'		\
 	-DSTORAGE_DIR='"${storage_dir}"'	\
 	-DRUN_DIR='"${run_dir}"'		\
+	-DMODULE_DIR='"${module_dir}"'		\
+	-DMODULE_INSTDIR='"${module_instdir}"'	\
 	-I$(srcdir)/dnssec/lib
 
 ######################
@@ -94,6 +96,9 @@ libcontrib_la_SOURCES +=			\
 	contrib/lmdb/midl.h
 endif !HAVE_LMDB
 
+libcontrib_la_CPPFLAGS = $(AM_CPPFLAGS) $(CFLAG_VISIBILITY)
+libcontrib_la_LDFLAGS = $(AM_LDFLAGS) $(LDFLAG_EXCLUDE_LIBS)
+
 # static: libknot-yparser sources
 libknot_yparser_la_SOURCES = 			\
 	libknot/yparser/yparser.c		\
@@ -190,7 +195,6 @@ libknot_la_SOURCES =				\
 	$(nobase_libknot_la_HEADERS)
 
 libknot_la_CPPFLAGS = $(AM_CPPFLAGS) $(CFLAG_VISIBILITY) $(lmdb_CFLAGS)
-libknot_la_CFLAGS = $(AM_CFLAGS)
 libknot_la_LDFLAGS = $(AM_LDFLAGS) $(libknot_VERSION_INFO) $(lmdb_LIBS) $(LDFLAG_EXCLUDE_LIBS)
 libknot_la_LIBADD = dnssec/libdnssec.la libcontrib.la
 
@@ -222,8 +226,8 @@ libknotus_la_SOURCES =				\
 	utils/common/token.c			\
 	utils/common/token.h
 
-libknotus_la_CPPFLAGS = $(AM_CPPFLAGS) $(libidn_CFLAGS) $(libedit_CFLAGS) $(gnutls_CFLAGS)
-libknotus_la_LDFLAGS = $(AM_LDFLAGS) $(libidn_LIBS)
+libknotus_la_CPPFLAGS = $(AM_CPPFLAGS) $(CFLAG_VISIBILITY) $(libidn_CFLAGS) $(libedit_CFLAGS) $(gnutls_CFLAGS)
+libknotus_la_LDFLAGS = $(AM_LDFLAGS) $(libidn_LIBS) $(LDFLAG_EXCLUDE_LIBS)
 libknotus_la_LIBADD = libcontrib.la libknot.la
 
 libknotd_la_SOURCES =				\
@@ -407,8 +411,8 @@ libknotd_la_SOURCES =				\
 	knot/zone/zonefile.c			\
 	knot/zone/zonefile.h
 
-libknotd_la_CPPFLAGS  = $(AM_CPPFLAGS) $(systemd_CFLAGS) $(liburcu_CFLAGS) $(lmdb_CFLAGS)
-libknotd_la_LDFLAGS = $(AM_LDFLAGS) $(systemd_LIBS) $(liburcu_LIBS)
+libknotd_la_CPPFLAGS  = $(AM_CPPFLAGS) $(CFLAG_VISIBILITY) $(systemd_CFLAGS) $(liburcu_CFLAGS) $(lmdb_CFLAGS) -DKNOTD_MOD_STATIC
+libknotd_la_LDFLAGS = $(AM_LDFLAGS) $(systemd_LIBS) $(liburcu_LIBS) -export-symbols-regex '^knotd_'
 libknotd_la_LIBADD = libknot.la libknot-yparser.la zscanner/libzscanner.la $(liburcu_LIBS)
 
 ###################
@@ -441,10 +445,12 @@ keymgr_SOURCES = 				\
 	utils/keymgr/functions.h		\
 	utils/keymgr/main.c
 
-knotd_CPPFLAGS  = $(AM_CPPFLAGS) $(liburcu_CFLAGS)
+knotd_CPPFLAGS  = $(AM_CPPFLAGS) $(CFLAG_VISIBILITY) $(liburcu_CFLAGS)
 knotd_LDADD     = libknotd.la libcontrib.la $(liburcu_LIBS)
-knotc_CPPFLAGS  = $(AM_CPPFLAGS) $(libedit_CFLAGS)
-knotc_LDADD     = libknotd.la libknotus.la $(libedit_LIBS)
+knotd_LDFLAGS   = $(AM_LDFLAGS) -rdynamic
+knotc_CPPFLAGS  = $(AM_CPPFLAGS) $(CFLAG_VISIBILITY) $(libedit_CFLAGS)
+knotc_LDADD     = libknotd.la libcontrib.la libknotus.la $(libedit_LIBS)
+knotc_LDFLAGS   = $(AM_LDFLAGS) -rdynamic
 keymgr_CPPFLAGS = $(AM_CPPFLAGS) $(liburcu_CFLAGS) -I$(srcdir)/dnssec/lib/dnssec \
                   -I$(srcdir)/dnssec $(gnutls_CFLAGS)
 keymgr_LDADD    = $(libidn_LIBS) $(liburcu_LIBS) libknotd.la libcontrib.la \
diff --git a/src/contrib/dnstap/Makefile.am b/src/contrib/dnstap/Makefile.am
index 84147de7798c89184e7d0b862579b3be37fe9ded..4ef03d02e5fac8726999401121fab53d996a957b 100644
--- a/src/contrib/dnstap/Makefile.am
+++ b/src/contrib/dnstap/Makefile.am
@@ -19,11 +19,16 @@ SUFFIXES = .proto .pb-c.c .pb-c.h
 
 noinst_LTLIBRARIES = libdnstap.la
 
+libdnstap_la_CPPFLAGS =			\
+	$(AM_CPPFLAGS)			\
+	$(CFLAG_VISIBILITY)
+
 libdnstap_la_CFLAGS =			\
 	$(DNSTAP_CFLAGS)
 
 libdnstap_la_LDFLAGS =			\
-	$(DNSTAP_LIBS)
+	$(DNSTAP_LIBS)			\
+	$(LDFLAG_EXCLUDE_LIBS)
 
 libdnstap_la_SOURCES =			\
 	convert.c			\
diff --git a/src/knot/modules/static_modules.h.in b/src/knot/modules/static_modules.h.in
new file mode 100644
index 0000000000000000000000000000000000000000..b2990fcfc872e356019bf0818d6cca7cb0db2336
--- /dev/null
+++ b/src/knot/modules/static_modules.h.in
@@ -0,0 +1,25 @@
+/*  Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "knot/include/module.h"
+
+// Forward declarations of static modules (generated by configure).
+@STATIC_MODULES_DECLARS@
+
+// STATIC_MODULES initializator (generated by configure).
+#define STATIC_MODULES_INIT @STATIC_MODULES_INIT@