diff --git a/Kconfig b/Kconfig
index 54f91b8cd329169206f82f544ee1277c415d8e82..fce814d4857de870987debcf24ffc8e0fefb5e06 100644
--- a/Kconfig
+++ b/Kconfig
@@ -1,6 +1,20 @@
 
 mainmenu "White Rabbit Switch  configuration"
 
+config DOTCONF_URL
+
+	string "URL for a run-time replacement of dot-config"
+	help
+	  The White Rabbit Switch is configured at run-time,
+	  according to a dot-config .config file. The file
+	  is the same .config you are defining now.  If you
+	  select an empty string, dot-config is not replaced
+	  at run time.  Otherwise, tftp://, ftp:// or http://
+	  URLs are allowed. Names are allowed if you configured
+	  a DNS server.  The special strings IPADDR and MACADDR
+	   are substituted before retrieving the file.
+	  Example:  "tftp://morgana/wrs-config-IPADDR"
+
 config BR2_CONFIGFILE
 	string "Configuration file for Buildroot"
 	default "wrs_release_br2_config"
diff --git a/build/scripts/wrs_build_wraprootfs b/build/scripts/wrs_build_wraprootfs
index 68f9a02cfa9b742bf228fdbcb7ac44789bb437cd..f60ac3afea313f2e94d25ef4177fd0e9a84d1629 100755
--- a/build/scripts/wrs_build_wraprootfs
+++ b/build/scripts/wrs_build_wraprootfs
@@ -32,7 +32,8 @@ ROOTFS_INITRAMFS="$WRS_OUTPUT_DIR/images/wrs-initramfs.gz"
 
 cat > $TMPSCRIPT << EOF
 . $WRS_BASE_DIR/../.config
-mkdir -p $TMPFS/wr
+mkdir -p $TMPFS/wr/etc
+cp $WRS_BASE_DIR/../.config $TMPFS/wr/etc/dot-config
 
 cp -r $rootfs_vanilla/* $TMPFS
 cp -r $WRS_OUTPUT_DIR/images/wr/* $TMPFS/wr
@@ -46,42 +47,6 @@ rm -rf $TMPFS/dev
 (cd $TMPFS && tar xzf $DEVTAR)
 (cd $TMPFS && ln -fs sbin/init .)
 
-if [ ! -z "$CONFIG_NTP_SERVER" ]; then
-    echo "ntpserver $CONFIG_NTP_SERVER" > $TMPFS/wr/etc/wr_date.conf
-fi
-
-if [ ! -z "$CONFIG_DNS_SERVER" ]; then
-    rm -f $TMPFS/etc/resolv.conf
-    echo "nameserver $CONFIG_DNS_SERVER" > $TMPFS/etc/resolv.conf
-    if [ ! -z "$CONFIG_DNS_DOMAIN" ]; then
-        echo "domain $CONFIG_DNS_DOMAIN" >> $TMPFS/etc/resolv.conf
-    fi
-fi
-
-if [ "$CONFIG_REMOTE_SYSLOG_UDP" = "y" ]; then
-    sed -i 's/@@remote-host/@remote-host/' $TMPFS/etc/rsyslog.conf
-fi
-if [ ! -z "$CONFIG_REMOTE_SYSLOG_SERVER" ]; then
-    sed -i '/remote-host/ s/^##//' $TMPFS/etc/rsyslog.conf
-    sed -i 's/remote-host/$CONFIG_REMOTE_SYSLOG_SERVER/' $TMPFS/etc/rsyslog.conf
-fi
-
-# Fix SNMP values: for all not-empty configs remove commend and replace value
-cfgfile="$TMPFS/wr/etc/snmpd.conf"
-set | grep CONFIG_SNMP | sed 's/=/ /' | while read varname value; do
-    if [ -z "\$value" ]; then continue; fi
-    sed -i "/\$varname/ s/^#//" \$cfgfile
-    sed -i "/\$varname/ s/\$varname/\$value/" \$cfgfile
-done
-
-# Fix log values
-cfgfile="$TMPFS/wr/sbin/start-daemons.sh"
-set | grep CONFIG_WRS_LOG | sed 's/=/ /' | while read varname value; do
-    if [ -z "\$value" ]; then continue; fi
-    sed -i "/\$varname/ s,\$varname,\$value," \$cfgfile
-done
-
-
 mkdir -p $TMPFS/root/.ssh
 #cat $HOME/.ssh/id_?sa.pub >> $TMPFS/root/.ssh/authorized_keys
 if [ -f $WRS_BASE_DIR/authorized_keys ]; then
diff --git a/doc/wrs-developer-manual.in b/doc/wrs-developer-manual.in
index 6ca9947ffc6da5a49c1d430af5033cf73a31d901..958959fae93dbdea86c257ddba96b20cdae16395 100644
--- a/doc/wrs-developer-manual.in
+++ b/doc/wrs-developer-manual.in
@@ -177,12 +177,11 @@ After release 3.3, we decided to add @i{Kconfig} support. This means
 that the first build step is expected to be ``@t{make menuconfig}'',
 like it happens for the kernel.  The default configuration is selected
 by default when one of the build scripts is run, so the procedure for
-the final user is the same as for v3.3 and earlier.  A build with a
-non-default configuration, however, is not considered as
-``supported'', and @i{Kconfig} is there mainly to help developers try
-new packages and setups without changing the repository or
-introducing problems for other users.  For some more information about
-@i{Kconfig} in this package, see the @i{@sc{wrs} User's Manual}.
+the final user is the same as for v3.3 and earlier.
+
+After release 4.1 we support dynamic reconfiguration. As opposed
+to build-time configuration, run-time configuration is expected to
+be frequent, and it's thus documented in the @i{@sc{wrs} Users' Manual}.
 
 The build system is set up as a mix of scripts and makefiles. Every
 sub-package is built by its own script and/or Makefile, and configuration is
@@ -451,14 +450,9 @@ to be used at installation time. See @ref{Flashing Procedure} for details.
 
 Some details of the complete firmware archive depend on the values of
 active @t{Kconfig} variables. If no manual configuration is performed,
-what applies is @t{configs/wrs_release_defconfig}.
-
-If you want to customize your configuration to install several
-switches pre-configured for your network, we suggest you rebuild
-the @i{firmware} archive after running @t{make menuconfig} to select
-your own values
-
-@c FIXME FIXME FIXME: Store kconfig and build info in the archive itself
+what applies is @t{configs/wrs_release_defconfig}. Please note that
+we now support dynamic reconfiguration at run-time. See the @i{@sc{wrs}
+Users' Manual}.
 
 @c --------------------------------------------------------------------------
 @node Rebuilding Parts
@@ -811,7 +805,11 @@ The main components are:
 
 @end table
 
-The most important tools in @file{userspace/tools} are the following:
+@sc{wrs} user space includes also some tools and scripts. Tools
+are build from source files in @file{userspace/tools} while the
+scripts are copied directly from @file{userspace/rootfs_override/wr/bin}.
+
+The following tools and scripts are provided:
 
 @table @file
 
@@ -838,7 +836,7 @@ The most important tools in @file{userspace/tools} are the following:
 	The program is a simple program for talking with serial ports.
 
 @item wr_phytool
-	A tool to read and write PHY registers in the switch
+	A tool to read and write PHY registers in the switch.
 
 @item wr_mon
 	A simple monitor of White Rabbit status. It prints to @i{stdout}
@@ -880,6 +878,20 @@ The most important tools in @file{userspace/tools} are the following:
         for each port and for the RTU daemon. The @t{--help} option
         lists all configuration items of the tool.
 
+@item apply_dot-config
+	The script is used to apply @t{dot-config} settings to the
+        current configuration files.  It is run at boot time before
+        any service is started. The @t{dot-config} mechanism is
+        documented in the @i{@sc{wrs} Users' Manual}.
+
+@item change_dot-config
+	This script changes the current @t{dot-config} file. It is
+        designed to be the back-end of the web interface, when changing
+        configuration items.  The script does nothing to @i{apply}
+        the changes, and it only performs editing.
+        It is the responsibility of the caller to ensure the proper
+        service is restarted with the new configuration.
+
 @item sdb-read
 	The tool, copied from the @t{fpga-config-space} project,
 	is documented in the next section,
diff --git a/doc/wrs-user-manual.in b/doc/wrs-user-manual.in
index f1edcca47fae7ced46480269facc7ea04937fc58..39e55d505cfd882bb860b656c6642d4dcc49d201 100644
--- a/doc/wrs-user-manual.in
+++ b/doc/wrs-user-manual.in
@@ -281,28 +281,121 @@ only be performed by the manufacturer, not the final user.
 
 
 @c ##########################################################################
-@node Kconfig Support
-@chapter Kconfig Support
+@node Configuration of the Device
+@chapter Configuration of the Device
 
 After release 3.3 of this software package, we added Kconfig support
-to wr-switch-sw.  The user can ignore this step: building as usual
-from a fresh checkout of @t{wr-switch-sw} silently selects
-the default configuration.
+to wr-switch-sw.  If you build your software image (as documented
+in the @i{@sc{wrs} Developer's Manual}),  you can make some
+configuration choices for your customized firmware image.  But most
+users are not expected to rebuild.
+
+After release 4.1, we moved most of the configuration to run-time
+(rather than build-time): the @t{.config} file that you create
+with a ``@t{make menuconfig}'' or equivalent command, is now copied
+to the @sc{wrs} filesystem and used during boot.  Moreover, the
+switch can download a new configuration at boot time, if so
+configured. This allows customization of each installed switch
+through a central server, without modifying the filesystem image in
+each specimen.
 
-You may exploit this @t{Kconfig} option to build firmware images
-preconfigured for your own network.
+@c ==========================================================================
+@node Dynamic WRS Configuration
+@section Dynamic WRS Configuration
+
+The switch can boot using its internal @sc{nand} memory or as an NFS-Root
+host. In the latter case configuration can be changed on the server,
+and if a unit is replaced, a change in the @sc{dhcp} database is all
+that's needed to recover network operation.  But this option implies
+some network traffic on your management network, as well as an NFS
+server able to host all of your switches.
+
+When a switch is booted from internal storage, we used to rely on
+internal configuration (either selected at build time or modified
+using @i{ssh} or the web interface).  This approach doesn't scale
+well to large installation, because if a device needs to be replaced,
+its own configuration is lost.
+
+With @i{dynamic configuration}, each @sc{wrs} device loads its own
+configuration file each time it is booted, and applies the choices
+before starting any service.  The name of the configuration file can
+include the @sc{mac} or @sc{ip} address of the device, to allow
+running several switches with different configurations in the same
+network.
+
+@c ==========================================================================
+@node The Configuration File
+@section The Configuration File
+
+The main configuration file for the @sc{wrs} is
+@t{/wr/etc/dot-config}.  You create this file by running ``@t{make
+menuconfig}'' within @t{wr-switch-sw}, and making your choices.
+You can also edit the text file, or run other configurators: @t{make xconfig},
+@t{make gconfig}, @t{make config}.
+
+The configuration step creates @t{.config}, that you can copy to your
+@sc{wrs} as @t{/wr/etc/dot-config}. After reboot, you'll see your
+choices in effect.
+
+The first configuration choice is @t{CONFIG_DOTCONF_URL}.  If the
+selected string is not empty, the Switch will download a new @t{dot-config}
+file, and replace the copy in local storage if it is different. If
+the string is empty, no network access is performed.
+
+@t{CONFIG_DOTCONF_URL} is of the form
+``@i{protocol}@t{://}@i{host}@t{/}@i{pathname}''.  The special upper-case
+strings @t{IPADDR} and @t{MACADDR} are substituted with the current
+addresses of the management port of the switch.
+
+The three parts of the URL are as follows:
+
+@table @i
+
+@item protocol
+
+	We support @t{http}, @t{ftp} and @t{tftp}.  Any other protocols
+        result in an error, and the @t{dot-config} file is not replaced.
+
+@item host
+
+	The host can be an IP address, or a name. In order to use
+        a name you must specify a valid @t{CONFIG_DNS_SERVER} and
+        optionally @t{CONFIG_DNS_DOMAIN}.  The values
+        in the current @t{dot-config} are used to load the new file.
+
+@item path
+
+	The pathname can include directory components and @t{IPADDR}
+        or @t{MACADDR} (or both).
+
+@end table
+
+For example this is a valid configuration for run-time update:
+
+@smallexample
+   CONFIG_DOTCONF_URL="tftp://morgana/wrs-config-IPADDR"
+   CONFIG_DNS_SERVER="192.168.16.1"
+   CONFIG_DNS_DOMAIN="i.gnudd.com"
+@end smallexample
+
+And it results, in my case, in @t{wrs-config-192.168.16.9} being
+served to the @sc{wrs}.
 
-To change configuration, you are expected to run ``@t{make
-menuconfig}'' (or @i{gconfig} or @i{kconfig} or the old text-mode
-@i{config}) from the top-level directory of @i{wr-switch-sw}.  To
-silently enact the default configuration, run ``@t{make defconfig}''
-(this is done by the normal build if no configuration is present).
+Please remember that the new @t{dot-config} should include a valid
+@t{DOTCONF_URL} setting, or you won't be able to update the configuration
+at the next boot.   In any case, you can always copy a configuration
+file using @i{ssh}, or use the web interface to change the configuration.
+Changes performed using the web interface are immediately active, because
+the web server takes proper action; the new file copied over with @i{ssh},
+or any hand-edits, are only effective at next boot, unless overwritten by
+a remote configuration file.
 
-The released firmware image uses the default configuration, but we'll
-soon offer the option to change most of these values at boot-time
-(by downloading configuration from a network server) or run-time.
+@c ==========================================================================
+@node Configuration Items that Apply at Build Time
+@section Configuration Items that Apply at Build Time
 
-The following configuration options are available
+The following items in @t{dot-config} are used at build time; changing
+them in the installed version has no effect:
 
 @table @code
 
@@ -313,6 +406,31 @@ The following configuration options are available
         @t{configs/buildroot} directory; an absolute pathname is used
         unchanged.
 
+@item CONFIG_KEEP_ROOTFS
+
+	A boolean option for developers: if set the build script does
+        not delete the temporary copy of the generated filesystem and
+        reports its pathname in the build messages.
+
+@end table
+
+@c ==========================================================================
+@node Configuration Items that Apply at Run Time
+@section Configuration Items that Apply at Run Time
+
+The following items in @t{dot-config} are used at run time: at every
+boot the value (the old one or the just-downloaded one) is used in the
+appropriate way, before the respective service is started.  When the
+value is changed by the web interface, proper action is taken.
+
+@table @code
+
+@item CONFIG_DOTCONF_URL
+
+	The location of a config file to be used at a replacement
+        the next time the system boots. See @ref{Dynamic WRS Configuration}
+        and @ref{The Configuration File} for details.
+
 @item CONFIG_NTP_SERVER
 
 	The NTP server used to prime White Rabbit time, at system boot.
@@ -358,12 +476,6 @@ The following configuration options are available
         unknown facility names will generate a runtime error on the switch.
         All three strings default to ``@t{daemon.info}''.
 
-@item CONFIG_KEEP_ROOTFS
-
-	A boolean option for developers: if set the build script does
-        not delete the temporary copy of the generated filesystem and
-        reports its pathname in the build messages.
-
 @end table
 
 @c ############################################################################
diff --git a/userspace/rootfs_override/etc/init.d/S20dot-config b/userspace/rootfs_override/etc/init.d/S20dot-config
new file mode 100755
index 0000000000000000000000000000000000000000..6a31d3dc4f89887d3884ceef51721ca7ac69b511
--- /dev/null
+++ b/userspace/rootfs_override/etc/init.d/S20dot-config
@@ -0,0 +1,56 @@
+#!/bin/sh
+
+# This script applies the dot-config. It is a boot script, but actual
+# functionality is moved to a separate binary, so the web interface
+# could edit dot-config and run /wr/bin/apply_dot-config like we do here,
+# without the need to rember wheter this is S20 or S10 during boot.
+
+# First, read dot-config to get the new location, if any.
+dotconfig=/wr/etc/dot-config
+tmpconfig=/tmp/dot-config
+
+if [ -f $dotconfig ]; then
+    . $dotconfig
+fi
+
+# Create /etc/resolv.conf, so we can use it. /etc is ramdisk anyways
+if [ ! -z "$CONFIG_DNS_SERVER" ]; then
+    echo "nameserver $CONFIG_DNS_SERVER" > /etc/resolv.conf
+    if [ ! -z "$CONFIG_DNS_DOMAIN" ]; then
+        echo "domain $CONFIG_DNS_DOMAIN" >> /etc/resolv.conf
+    fi
+fi
+
+# If we are expected to get a new dot-conf, do it
+if [ -n "$CONFIG_DOTCONF_URL" ]; then
+    # replace IPADDR and MACADDR, to have a device-specific name
+    macaddr=$(cat /sys/class/net/eth0/address)
+    ipaddr=$(ifconfig eth0 | grep inet | cut -d: -f 2 | cut '-d '  -f 1)
+    URL=$(echo $CONFIG_DOTCONF_URL | \
+	sed -e s/MACADDR/$macaddr/ -e s/IPADDR/$ipaddr/)
+    # split the parts, as we need to handle tftp by hand
+    proto=$(echo $URL | cut -d: -f 1)
+    host=$(echo $URL | cut -d/ -f 3)
+    filename=$(echo $URL | cut -d/ -f 4-)
+
+    rm -f $tmpconfig
+    case $proto in
+	http|ftp)
+	    wget $URL -O $tmpconfig
+	    ;;
+	tftp)
+	    tftp -g -r "$filename" -l $tmpconfig $host
+	    ;;
+	*)
+	    echo "Invalid URL for dot-config: \"$URL\"" >& 2
+	    ;;
+    esac
+    # If it exists and it is not empty or awfully small, trust it
+    if [ -f $tmpconfig ] &&
+	[ $(cat $tmpconfig | wc -c) -gt 200 ]; then
+	cmp -s $tmpconfig $dotconfig || cp $tmpconfig $dotconfig
+    fi
+fi
+
+# Finally, apply what we have, be it old or new
+. /wr/bin/apply_dot-config
diff --git a/userspace/rootfs_override/etc/rsyslog.conf b/userspace/rootfs_override/etc/rsyslog.conf.in
similarity index 100%
rename from userspace/rootfs_override/etc/rsyslog.conf
rename to userspace/rootfs_override/etc/rsyslog.conf.in
diff --git a/userspace/rootfs_override/wr/bin/apply_dot-config b/userspace/rootfs_override/wr/bin/apply_dot-config
new file mode 100755
index 0000000000000000000000000000000000000000..8194a2dfbb9c34c61e97be4a0d580d76086d6e2a
--- /dev/null
+++ b/userspace/rootfs_override/wr/bin/apply_dot-config
@@ -0,0 +1,77 @@
+#!/bin/sh
+
+# This script applies the current dot-config to make
+# the choices users wanted.  You can change the dot-config on flash,
+# and call this script to apply changes (please note that some changes
+# require restarting running processes).  The script is called at
+# every boot by /etc/init.d/S20dot-config
+
+# We create a temporary file in /tmp, to avoid wearing flash if not
+# needed. Then we replace the real file if different.
+
+T=$(mktemp /tmp/config-XXXXXX)
+
+copy_conf() {
+    # busybox cmp exits 1 or 2 according to GNU man page
+    for dest in $*; do
+	cmp -s $T $1 || cp $T $1
+    done
+}
+
+# Check and complain, but we need to edit some files even if unconfigured.
+if [ -f /wr/etc/dot-config ]; then
+    . /wr/etc/dot-config
+    configured=true
+else
+    echo "No /wr/etc/dot-config to use" >& 2
+    configured=false
+fi
+
+##### Actual configuration actions start here.
+
+# A non-existent wr_date.conf means no NTP. So "rm" if unconfigured
+if [ ! -z "$CONFIG_NTP_SERVER" ]; then
+    echo "ntpserver $CONFIG_NTP_SERVER" > $T
+    copy_conf /wr/etc/wr_date.conf
+else
+    rm -f /wr/etc/wr_date.conf
+fi
+
+# /etc/resolv.conf can be empty, so start empty
+> $T
+if [ ! -z "$CONFIG_DNS_SERVER" ]; then
+    echo "nameserver $CONFIG_DNS_SERVER" >> $T
+    if [ ! -z "$CONFIG_DNS_DOMAIN" ]; then
+        echo "domain $CONFIG_DNS_DOMAIN" >> $T
+    fi
+fi
+copy_conf /etc/resolv.conf /usr/etc/resolv.conf
+
+# rsyslog.conf is created from a template file, and busybox sed has -i
+cp /usr/etc/rsyslog.conf.in $T
+if [ "$CONFIG_REMOTE_SYSLOG_UDP" = "y" ]; then
+    sed -i 's/@@remote-host/@remote-host/' $T
+fi
+if [ ! -z "$CONFIG_REMOTE_SYSLOG_SERVER" ]; then
+    sed -i '/remote-host/ s/^##//' $T
+    sed -i "s/remote-host/$CONFIG_REMOTE_SYSLOG_SERVER/" $T
+fi
+copy_conf /etc/rsyslog.conf /usr/etc/rsyslog.conf
+
+# Fix SNMP values: for all not-empty configs remove comment and replace value
+cp /wr/etc/snmpd.conf.in $T
+set | grep CONFIG_SNMP | sed 's/=/ /' | while read varname value; do
+    if [ -z "$value" ]; then continue; fi
+    sed -i "/$varname/ s/^#//" $T
+    sed -i "/$varname/ s/$varname/$value/" $T
+done
+copy_conf /wr/etc/snmpd.conf
+
+# Fix log values
+cp /wr/sbin/start-daemons.sh.in $T
+set | grep CONFIG_WRS_LOG | sed 's/=/ /' | while read varname value; do
+    if [ -z "$value" ]; then continue; fi
+    sed -i "/$varname/ s,$varname,$value," $T
+done
+copy_conf /wr/sbin/start-daemons.sh
+
diff --git a/userspace/rootfs_override/wr/bin/change_dot-config b/userspace/rootfs_override/wr/bin/change_dot-config
new file mode 100755
index 0000000000000000000000000000000000000000..5d80a5898bf50569b2e4fd6f09e9d9d256aa0908
--- /dev/null
+++ b/userspace/rootfs_override/wr/bin/change_dot-config
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+# Change a configuration item in dot-config. "=n" is special and it means
+# the option is being unset. "=y" remains unquoted, all the rest is quoted.
+# We still lack support for integers, not used in wrs' .config so far.
+
+dotconfig="/wr/etc/dot-config"
+
+for action in "$*"; do
+    # We accept both CONFIG_THIS= and THIS=
+    item="CONFIG_$(echo $action | cut -d= -f 1 | sed 's/^CONFIG_//')"
+    value=$(echo $action | cut -d= -f 2)
+    if [ "$value" = "n" ]; then
+	line="# $item is not set"
+
+    else
+	if [ "$value" = "y" ]; then
+	    line="${item}=y"
+	else
+	    line="${item}=\"$value\""
+	fi
+    fi
+    # now, a config item may be a substring of another one: careful
+    sed -i -e "/^${item}=/d" -e "/# ${item} is/d" $dotconfig
+    echo $line >> $dotconfig
+done
diff --git a/userspace/rootfs_override/wr/etc/snmpd.conf b/userspace/rootfs_override/wr/etc/snmpd.conf.in
similarity index 100%
rename from userspace/rootfs_override/wr/etc/snmpd.conf
rename to userspace/rootfs_override/wr/etc/snmpd.conf.in
diff --git a/userspace/rootfs_override/wr/sbin/start-daemons.sh b/userspace/rootfs_override/wr/sbin/start-daemons.sh.in
similarity index 100%
rename from userspace/rootfs_override/wr/sbin/start-daemons.sh
rename to userspace/rootfs_override/wr/sbin/start-daemons.sh.in