diff --git a/doc/tinc.texi b/doc/tinc.texi
index ac52e7b4..02265dc5 100644
--- a/doc/tinc.texi
+++ b/doc/tinc.texi
@@ -1511,6 +1511,23 @@ Write PID to @var{file} instead of @file{@value{localstatedir}/run/tinc.@var{net
 Disables encryption and authentication.
 Only useful for debugging.
 
+@item -R, --chroot
+Change process root directory to the directory where the config file is
+located (@file{@value{sysconfdir}/tinc/@var{netname}/} as determined by
+-n/--net option or as given by -c/--config option), for added security.
+The chroot is performed after all the initialization is done, after
+writing pid files and opening network sockets.
+
+Note that this option alone does not do any good without -U/--user, below.
+
+Note also that tinc can't run scripts anymore (such as tinc-down or host-up),
+unless it's setup to be runnable inside chroot environment.
+
+@item -U, --user=@var{user}
+Switch to the given @var{user} after initialization, at the same time as
+chroot is performed (see --chroot above).  With this option tinc drops
+privileges, for added security.
+
 @item --help
 Display a short reminder of these runtime options and terminate.
 
diff --git a/doc/tincd.8.in b/doc/tincd.8.in
index 97654f33..7e168fd0 100644
--- a/doc/tincd.8.in
+++ b/doc/tincd.8.in
@@ -8,7 +8,7 @@
 .Nd tinc VPN daemon
 .Sh SYNOPSIS
 .Nm
-.Op Fl cdDkKnL
+.Op Fl cdDkKnLRU
 .Op Fl -config Ns = Ns Ar DIR
 .Op Fl -no-detach
 .Op Fl -debug Ns Op = Ns Ar LEVEL
@@ -19,6 +19,8 @@
 .Op Fl -logfile Ns Op = Ns Ar FILE
 .Op Fl -pidfile Ns = Ns Ar FILE
 .Op Fl -bypass-security
+.Op Fl -chroot
+.Op Fl -user Ns = Ns Ar USER
 .Op Fl -help
 .Op Fl -version
 .Sh DESCRIPTION
@@ -87,6 +89,14 @@ Under Windows this option will be ignored.
 .It Fl -bypass-security
 Disables encryption and authentication of the meta protocol.
 Only useful for debugging.
+.It Fl -chroot
+With this option tinc chroots into the directory where network
+config is located (@sysconfdir@/tinc/NETNAME if -n option is used,
+or to the directory specified with -c option) after initialization.
+.It Fl -user Ns = Ns Ar USER
+setuid to the specified
+.Ar USER
+after initialization.
 .It Fl -help
 Display short list of options.
 .It Fl -version
diff --git a/src/tincd.c b/src/tincd.c
index 6fa87853..a8a0146d 100644
--- a/src/tincd.c
+++ b/src/tincd.c
@@ -39,6 +39,12 @@
 
 #include LZO1X_H
 
+#ifndef HAVE_MINGW
+#include <pwd.h>
+#include <grp.h>
+#include <time.h>
+#endif
+
 #include <getopt.h>
 #include "pidfile.h"
 
@@ -73,6 +79,12 @@ bool bypass_security = false;
 /* If nonzero, disable swapping for this process. */
 bool do_mlock = false;
 
+/* If nonzero, chroot to netdir after startup. */
+static bool do_chroot = false;
+
+/* If !NULL, do setuid to given user after startup */
+static const char *switchuser = NULL;
+
 /* If nonzero, write log entries to a separate file. */
 bool use_logfile = false;
 
@@ -94,6 +106,8 @@ static struct option const long_options[] = {
 	{"debug", optional_argument, NULL, 'd'},
 	{"bypass-security", no_argument, NULL, 3},
 	{"mlock", no_argument, NULL, 'L'},
+	{"chroot", no_argument, NULL, 'R'},
+	{"user", required_argument, NULL, 'U'},
 	{"logfile", optional_argument, NULL, 4},
 	{"pidfile", required_argument, NULL, 5},
 	{NULL, 0, NULL, 0}
@@ -119,6 +133,8 @@ static void usage(bool status)
 				"  -L, --mlock                Lock tinc into main memory.\n"
 				"      --logfile[=FILENAME]   Write log entries to a logfile.\n"
 				"      --pidfile=FILENAME     Write PID to FILENAME.\n"
+				"  -R, --chroot               chroot to NET dir at startup.\n"
+				"  -U, --user=USER            setuid to given USER at startup.\n"
 				"      --help                 Display this help and exit.\n"
 				"      --version              Output version information and exit.\n\n"));
 		printf(_("Report bugs to tinc@tinc-vpn.org.\n"));
@@ -130,7 +146,7 @@ static bool parse_options(int argc, char **argv)
 	int r;
 	int option_index = 0;
 
-	while((r = getopt_long(argc, argv, "c:DLd::k::n:K::", long_options, &option_index)) != EOF) {
+	while((r = getopt_long(argc, argv, "c:DLd::k::n:K::RU:", long_options, &option_index)) != EOF) {
 		switch (r) {
 			case 0:				/* long option */
 				break;
@@ -210,6 +226,14 @@ static bool parse_options(int argc, char **argv)
 					generate_keys = 1024;
 				break;
 
+			case 'R':				/* chroot to NETNAME dir */
+				do_chroot = true;
+				break;
+
+			case 'U':				/* setuid to USER */
+				switchuser = optarg;
+				break;
+
 			case 1:					/* show help */
 				show_help = true;
 				break;
@@ -407,6 +431,51 @@ static void free_names() {
 	if (confbase) free(confbase);
 }
 
+static bool drop_privs() {
+#ifdef HAVE_MINGW
+	if (switchuser) {
+		logger(LOG_ERR, _("%s not supported on this platform"), "-U");
+		return false;
+	}
+	if (do_chroot) {
+		logger(LOG_ERR, _("%s not supported on this platform"), "-R");
+		return false;
+	}
+#else
+	uid_t uid = 0;
+	if (switchuser) {
+		struct passwd *pw = getpwnam(switchuser);
+		if (!pw) {
+			logger(LOG_ERR, _("unknown user `%s'"), switchuser);
+			return false;
+		}
+		uid = pw->pw_uid;
+		if (initgroups(switchuser, pw->pw_gid) != 0 ||
+		    setgid(pw->pw_gid) != 0) {
+			logger(LOG_ERR, _("%s failed"), "initgroups()");
+			return false;
+		}
+		endgrent();
+		endpwent();
+	}
+	if (do_chroot) {
+		tzset();	/* for proper timestamps in logs */
+		if (chroot(confbase) != 0 || chdir(".") != 0) {
+			logger(LOG_ERR, _("%s failed"), "chroot()");
+			return false;
+		}
+		free(confbase);
+		confbase = xstrdup("");
+	}
+	if (switchuser)
+		if (setuid(uid) != 0) {
+			logger(LOG_ERR, _("%s failed"), "setuid()");
+			return false;
+		}
+#endif
+	return true;
+}
+
 int main(int argc, char **argv)
 {
 	program_name = argv[0];
@@ -506,6 +575,10 @@ int main2(int argc, char **argv)
 	if(!setup_network())
 		goto end;
 
+	/* drop privileges */
+	if (!drop_privs())
+		goto end;
+
 	/* Initiate all outgoing connections. */
 
 	try_outgoing_connections();
@@ -536,6 +609,6 @@ end:
 
 	exit_configuration(&config_tree);
 	free_names();
-	
+
 	return status;
 }