diff --git a/repro.in b/repro.in
index 982d446..e5c1d30 100755
--- a/repro.in
+++ b/repro.in
@@ -16,78 +16,148 @@ trap "{ rm -r $IMGDIRECTORY; }" EXIT
 
 DIFFOSCOPE="diffoscope"
 
+function get_subguids() {
+	local user=$(id -u)
+	local subuids
+	local subgids
+	while IFS=: read uid start count ; do
+		if [[ $user == $(id -u $uid) ]] ; then
+			subuids="1:$start:$count"
+			break
+		fi
+	done </etc/subuid
+	while IFS=: read uid start count ; do
+		if [[ $user == $(id -u $uid) ]] ; then
+			subgids="1:$start:$count"
+			break
+		fi
+	done </etc/subgid
+	[[ $subuids && $subgids ]] || return 1
+	printf " --uid_mapping %s --gid_mapping %s " "$subuids" "$subgids"
+}
+
+# Desc: Enter a user namespace with virtual privileges
+function become_rootless() {
+	((rootless_userns)) || return
+	((__REPRO_NSJAIL == 1)) && return
+	local subguids=$(get_subguids)
+	if (($?)) ; then
+		error "Your user has no subuids or subgids"
+		exit 1
+	fi
+	exec nsjail -Mo --quiet --skip_setsid \
+	            --disable_clone_newnet --disable_clone_newpid \
+	            --disable_rlimit --disable_proc --keep_caps \
+	            --chroot / --cwd "$(pwd)" --rw \
+	            --uid 0 --gid 0 $subguids \
+	            --keep_env  -E '__REPRO_NSJAIL=1' -- "${orig_argv[@]}"
+	#exec become-root unshare --mount "${orig_argv[@]}"
+}
 # Desc: Escalates privileges
 orig_argv=("$0" "$@")
 src_owner=${SUDO_USER:-$USER}
 function check_root() {
-    (( EUID == 0 )) && return
-    if type -P sudo >/dev/null; then
-        exec sudo -- "${orig_argv[@]}"
-    else
-        exec su root -c "$(printf ' %q' "${orig_argv[@]}")"
-    fi
+	(( EUID == 0 )) && return
+	if ((rootless_userns)); then
+		exec become-root unshare --mount "${orig_argv[@]}"
+	elif type -P sudo >/dev/null; then
+		exec sudo -- "${orig_argv[@]}"
+	else
+		exec su root -c "$(printf ' %q' "${orig_argv[@]}")"
+	fi
+}
+
+function require_userns_tools() {
+	#if command -v become-root >/dev/null \
+	if command -v unshare >/dev/null \
+		&& command -v nsjail >/dev/null \
+		&& command -v fuse-overlayfs >/dev/null
+	then
+		return 0
+	fi
+	warning "nsjail, fuse-overlayfs and unshare (util-linux) are necessary for rootless operation"
+	#warning "nsjail, fuse-overlayfs and become-root are necessary for rootless operation"
+	#warning "https://github.com/giuseppe/become-root"
+	warning "https://github.com/containers/fuse-overlayfs"
+	warning "https://github.com/google/nsjail"
+	return 1
+}
+
+function mountoverlay() {
+	if ((rootless_userns)); then
+		fuse-overlayfs "$@"
+	else
+		mount -t overlayfs overlayfs "$@"
+	fi
+}
+function umountoverlay() {
+	if ((rootless_userns)); then
+	  fusermount -u "$@"
+	else
+		umount "$@"
+	fi
 }
 
 # Use a private gpg keyring
 function gpg() {
-  command gpg --homedir="$BUILDDIRECTORY/_gnupg" "$@"
+  command gpg --homedir="$BUILDDIRECTORY/gnupg" "$@"
 }
 
 function init_gnupg() {
-    [ ! -d "$BUILDDIRECTORY/_gnupg" ] && mkdir -p "$BUILDDIRECTORY/_gnupg"
+	[ ! -d "$BUILDDIRECTORY/gnupg" ] && mkdir -p "$BUILDDIRECTORY/gnupg"
 
-    # ensure signing key is available
-    gpg --auto-key-locate nodefault,wkd --locate-keys pierre@archlinux.de
+	# ensure signing key is available
+	gpg --auto-key-locate nodefault,wkd --locate-keys pierre@archlinux.de
 }
 
 # Desc: Sets the appropriate colors for output
 function colorize() {
-    # prefer terminal safe colored and bold text when tput is supported
-    if tput setaf 0 &>/dev/null; then
-        ALL_OFF="$(tput sgr0)"
-        BOLD="$(tput bold)"
-        BLUE="${BOLD}$(tput setaf 4)"
-        GREEN="${BOLD}$(tput setaf 2)"
-        RED="${BOLD}$(tput setaf 1)"
-        YELLOW="${BOLD}$(tput setaf 3)"
-    else
-        ALL_OFF="\e[0m"
-        BOLD="\e[1m"
-        BLUE="${BOLD}\e[34m"
-        GREEN="${BOLD}\e[32m"
-        RED="${BOLD}\e[31m"
-        YELLOW="${BOLD}\e[33m"
-    fi
-    readonly ALL_OFF BOLD BLUE GREEN RED YELLOW
+	# prefer terminal safe colored and bold text when tput is supported
+	if tput setaf 0 &>/dev/null; then
+		ALL_OFF="$(tput sgr0)"
+		BOLD="$(tput bold)"
+		BLUE="${BOLD}$(tput setaf 4)"
+		GREEN="${BOLD}$(tput setaf 2)"
+		RED="${BOLD}$(tput setaf 1)"
+		YELLOW="${BOLD}$(tput setaf 3)"
+	else
+		ALL_OFF="\e[0m"
+		BOLD="\e[1m"
+		BLUE="${BOLD}\e[34m"
+		GREEN="${BOLD}\e[32m"
+		RED="${BOLD}\e[31m"
+		YELLOW="${BOLD}\e[33m"
+	fi
+	readonly ALL_OFF BOLD BLUE GREEN RED YELLOW
 }
 colorize
 
 # Desc: Message format
 function msg() {
-    local mesg=$1; shift
+	local mesg=$1; shift
     # shellcheck disable=SC2059
-    printf "${GREEN}==>${ALL_OFF}${BOLD} ${mesg}${ALL_OFF}\n" "$@" >&2
+	printf "${GREEN}==>${ALL_OFF}${BOLD} ${mesg}${ALL_OFF}\n" "$@" >&2
 }
 
 # Desc: Sub-message format
 function msg2() {
-    local mesg=$1; shift
+	local mesg=$1; shift
     # shellcheck disable=SC2059
-    printf "${BLUE}  ->${ALL_OFF}${BOLD} ${mesg}${ALL_OFF}\n" "$@" >&2
+	printf "${BLUE}  ->${ALL_OFF}${BOLD} ${mesg}${ALL_OFF}\n" "$@" >&2
 }
 
 # Desc: Warning format
 function warning() {
-    local mesg=$1; shift
+	local mesg=$1; shift
     # shellcheck disable=SC2059
-    printf "${YELLOW}==> $(gettext "WARNING:")${ALL_OFF}${BOLD} ${mesg}${ALL_OFF}\n" "$@" >&2
+	printf "${YELLOW}==> $(gettext "WARNING:")${ALL_OFF}${BOLD} ${mesg}${ALL_OFF}\n" "$@" >&2
 }
 
 # Desc: Error format
 function error() {
-    local mesg=$1; shift
+	local mesg=$1; shift
     # shellcheck disable=SC2059
-    printf "${RED}==> $(gettext "ERROR:")${ALL_OFF}${BOLD} ${mesg}${ALL_OFF}\n" "$@" >&2
+	printf "${RED}==> $(gettext "ERROR:")${ALL_OFF}${BOLD} ${mesg}${ALL_OFF}\n" "$@" >&2
 }
 
 ##
@@ -127,20 +197,55 @@ lock_close() {
     # shellcheck disable=2034
     exec {fd}>&-
 }
-
 # Desc: Executes an command inside a given nspawn container
 # 1: Container name
 # 2: Command to execute
 function exec_nspawn(){
     local container=$1
     systemd-nspawn -q \
-      --as-pid2 \
-      --register=no \
-      --pipe \
-      -E "PATH=/usr/local/sbin:/usr/local/bin:/usr/bin" \
-      -D "$BUILDDIRECTORY/$container" "${@:2}"
+		--as-pid2 \
+		--register=no \
+		--pipe \
+		-E "PATH=/usr/local/sbin:/usr/local/bin:/usr/bin" \
+		-D "$BUILDDIRECTORY/$container" "${@:2}"
 }
 
+
+# Desc: Executes an command inside a given nsjail container
+# 1: Container name
+# 2: Optional: one --bind=... bindmount option
+# 2/3: Command to execute
+function exec_nsjail(){
+    local container=$1
+    local args=( -Mo --quiet
+            --disable_clone_newuser
+            --disable_clone_newnet
+            --disable_rlimits
+            --keep_caps
+            --tmpfsmount /tmp
+            --bindmount_ro /dev
+            -E "PATH=/usr/local/sbin:/usr/local/bin:/usr/bin"
+            --chroot "$BUILDDIRECTORY/$container" --rw
+          )
+    ## use a no-op forking unshare as pid1
+    if [[ $2 == --bind=* ]] ; then
+        nsjail "${args[@]}" --bindmount "${2#--bind=}" -- /usr/bin/unshare -f "${@:3}"
+    else
+        nsjail "${args[@]}" -- /usr/bin/unshare -f "${@:2}"
+    fi
+}
+
+function exec_container(){
+	if ((rootless_userns)); then
+		exec_nsjail "$@"
+	else
+		exec_nspawn "$@"
+	fi
+}
+
+
+
+
 # Desc: Removes the root container
 function cleanup_root_volume(){
     warning "Removing root container..."
@@ -152,7 +257,7 @@ function cleanup_root_volume(){
 function remove_snapshot (){
     local build=$1
     msg2 "Delete snapshot for $build..."
-    umount "$BUILDDIRECTORY/$build" || true
+    umountoverlay "$BUILDDIRECTORY/$build" || true
     rm -rf "${BUILDDIRECTORY:?}/${build}"
     rm -rf "${BUILDDIRECTORY:?}/${build}_upperdir"
     rm -rf "${BUILDDIRECTORY:?}/${build}_workdir"
@@ -169,7 +274,7 @@ function create_snapshot (){
     msg2 "Create snapshot for $build..."
     mkdir -p "$BUILDDIRECTORY/"{"${build}","${build}_upperdir","${build}_workdir"}
     # shellcheck disable=SC2140
-    mount -t overlay overlay \
+    mountoverlay \
         -o lowerdir="$BUILDDIRECTORY/root",upperdir="$BUILDDIRECTORY/${build}_upperdir",workdir="$BUILDDIRECTORY/${build}_workdir" \
         "$BUILDDIRECTORY/${build}"
     touch "$BUILDDIRECTORY/$build"
@@ -181,7 +286,7 @@ function create_snapshot (){
 function build_package(){
     local build=$1
     local builddir=${2:-"/startdir"}
-    exec_nspawn "$build" \
+    exec_container "$build" \
         --bind="$PWD:/srcdest" \
 bash <<-__END__
 set -e
@@ -205,6 +310,7 @@ function init_chroot(){
 
     # Prepare root chroot
     if [ ! -d "$BUILDDIRECTORY"/root ]; then
+
         lock 9 "$BUILDDIRECTORY"/root.lock
         msg "Preparing chroot"
         trap '{ cleanup_root_volume; exit 1; }' ERR
@@ -218,30 +324,32 @@ function init_chroot(){
         printf '%s.UTF-8 UTF-8\n' en_US de_DE > "$BUILDDIRECTORY"/root/etc/locale.gen
         printf 'LANG=en_US.UTF-8\n' > "$BUILDDIRECTORY"/root/etc/locale.conf
 
-        systemd-machine-id-setup --root="$BUILDDIRECTORY"/root
+        exec_container root systemd-machine-id-setup
         msg2 "Setting up keyring, this might take a while..."
-        exec_nspawn root pacman-key --init &> /dev/null
-        exec_nspawn root pacman-key --populate archlinux &> /dev/null
+        exec_container root pacman-key --init &> /dev/null
+        exec_container root pacman-key --populate archlinux &> /dev/null
 
         msg2 "Updating and installing base & base-devel"
-        exec_nspawn root pacman -Syu base-devel --noconfirm
-        exec_nspawn root pacman -R arch-install-scripts --noconfirm
-        exec_nspawn root locale-gen
-
-        printf 'builduser ALL = NOPASSWD: /usr/bin/pacman\n' > "$BUILDDIRECTORY"/root/etc/sudoers.d/builduser-pacman
-        exec_nspawn root useradd -m -G wheel -s /bin/bash -d /build builduser
+        exec_container root pacman -Syu base-devel --noconfirm
+        exec_container root pacman -R arch-install-scripts --noconfirm
+        exec_container root locale-gen
+
+        printf '%s\n\n' 'Defaults preserve_groups' \
+				              'builduser ALL = NOPASSWD: /usr/bin/pacman' \
+				        > "$BUILDDIRECTORY"/root/etc/sudoers.d/builduser-pacman
+        exec_container root useradd -m -G wheel -s /bin/bash -d /build builduser
         echo "keyserver-options auto-key-retrieve" | install -Dm644 /dev/stdin "$BUILDDIRECTORY/root"/build/.gnupg/gpg.conf
-        exec_nspawn root chown -R builduser /build/.gnupg
+        exec_container root chown -R builduser /build/.gnupg
         lock_close 9
     else
-
       if lock 9 "$BUILDDIRECTORY"/root.lock; then
-          printf 'Server = %s\n' "$HOSTMIRROR" > "$BUILDDIRECTORY"/root/etc/pacman.d/mirrorlist
-          exec_nspawn root pacman -Syu --noconfirm
+        printf 'Server = %s\n' "$HOSTMIRROR" > "$BUILDDIRECTORY"/root/etc/pacman.d/mirrorlist
+        exec_container root pacman -Syu --noconfirm
           lock_close 9
       else
           msg "Couldn't acquire lock on root chroot, didn't update."
-      fi
+    fi
+
     fi
     trap - ERR INT
 }
@@ -276,7 +384,6 @@ function cmd_check(){
     pkgbuild_sha256sum="${buildinfo[pkgbuild_sha256sum]}"
     SOURCE_DATE_EPOCH="${buildinfo[builddate]}"
 
-
     local build="${pkgbase}_$$"
 
     msg2 "Preparing packages"
@@ -304,7 +411,7 @@ function cmd_check(){
     sed -i "s/LocalFileSigLevel.*//g" "$BUILDDIRECTORY/$build/etc/pacman.conf"
 
     # Father I have sinned
-    exec_nspawn "$build" \
+    exec_container "$build" \
     bash <<-__END__
 shopt -s globstar
 install -d -o builduser -g builduser /startdir
@@ -326,16 +433,16 @@ __END__
 
     msg "Installing packages"
     # shellcheck disable=SC2086
-    exec_nspawn "$build" --bind="$(readlink -e ${cachedir}):/cache" bash -c \
+    exec_container "$build" --bind="$(readlink -e ${cachedir}):/cache" bash -c \
         'yes y | pacman -Udd --overwrite "*" -- "$@"' -bash "${packages[@]}"
 
     read -r -a buildinfo_packages <<< "$(buildinfo -f installed "${pkg}")"
     uninstall=$(comm -13 \
         <(printf '%s\n' "${buildinfo_packages[@]}" | rev | cut -d- -f4- | rev | sort) \
-        <(exec_nspawn "$build" --bind="$(readlink -e ${cachedir}):/cache" pacman -Qq | sort))
+        <(exec_container "$build" --bind="$(readlink -e ${cachedir}):/cache" pacman -Qq | sort))
 
     if [ -n "$uninstall" ]; then
-        exec_nspawn "$build" pacman -Rdd --noconfirm -- $uninstall
+        exec_container "$build" pacman -Rdd --noconfirm -- $uninstall
     fi
 
     build_package "$build" "$builddir"
@@ -376,6 +483,7 @@ Usage:
 General Options:
  -h                           Print this help message
  -d                           Run diffoscope if packages are not reproducible
+ -r                           Run without root privileges in nsjail containers
 __END__
 }
 
@@ -392,18 +500,24 @@ fi
 
 xdg_repro_dir="${XDG_CONFIG_HOME:-$HOME/.config}/archlinux-repro"
 if [[ -r "$xdg_repro_dir/repro.conf" ]]; then
-    # shellcheck source=/dev/null
-    source "$xdg_repro_dir/repro.conf"
+	# shellcheck source=/dev/null
+	source "$xdg_repro_dir/repro.conf"
 elif [[ -r "$HOME/.repro.conf" ]]; then
-    # shellcheck source=/dev/null
-    source "$HOME/.repro.conf"
+	# shellcheck source=/dev/null
+	source "$HOME/.repro.conf"
 fi
 
 
-while getopts :hdoC:P:M: arg; do
+while getopts :hdorC:P:M: arg; do
     case $arg in
         h) print_help; exit 0;;
         d) run_diffoscope=1;;
+        r) rootless_userns=1;
+           require_userns_tools || exit 1
+           become_rootless
+           # TODO: better detection for valid writable build directory
+           [[ $BUILDDIRECTORY == /var/lib/repro ]] && BUILDDIRECTORY="${XDG_CACHE_HOME:-$HOME/.cache}/archlinux-repro"
+           ;;
         *) ;;
     esac
 done