diff --git a/files/bootlocal.sh b/files/bootlocal.sh
index 548918c4eee98b3525e98bd52f26dce933eb84a2..9e449423f181643843662864d83184f6491becc9 100644
--- a/files/bootlocal.sh
+++ b/files/bootlocal.sh
@@ -1,5 +1,3 @@
 #!/bin/sh
 
-useradd -m -s /bin/sh user
-echo -n "\n123456\n123456" /tmp/pw
-passwd user </tmp/pw
+installer.sh
diff --git a/files/functions.sh b/files/functions.sh
new file mode 100755
index 0000000000000000000000000000000000000000..bfbc2577fe95a67117863cb2ceab8e9e82eb1dcf
--- /dev/null
+++ b/files/functions.sh
@@ -0,0 +1,305 @@
+INSTALLER_BIND_MOUNTS="/dev /sys /proc"
+INSTALLER_BIND_UMOUNTS="/proc /sys /dev"
+
+# -------------------------------------------------------------------
+# Logging
+
+log() {
+    echo "$@" >> $INSTALLER_LOGFILE
+}
+
+exec_log() {
+    echo "> $@" >> $INSTALLER_LOGFILE
+    "$@" &>> $INSTALLER_LOGFILE
+}
+
+exec_log_err() {
+    echo "> $@" >> $INSTALLER_LOGFILE
+    "$@" 2>> $INSTALLER_LOGFILE
+}
+
+upload_logfile() {
+    curl -s --capath ./certs -H "Content-Type: text/plain" -T "$INSTALLER_LOGFILE" -m 20 "$INSTALLER_LOGFILE_URL" > /dev/null
+}
+
+# -------------------------------------------------------------------
+# UI
+
+# Nachricht ohne OK-Button
+dialog_info() {
+    log ">>> $1"
+    dialog --title "SDM-Installation" --infobox "$1" 15 70 || exit 1
+}
+
+# Nachricht mit OK-Button
+dialog_msg() {
+    log ">>> $1"
+    dialog --title "SDM-Installation" --msgbox "$1" 15 70 || exit 1
+}
+
+dialog_ask_password() {
+    dialog --title "SDM-Installation" --insecure --nocancel --passwordbox "Passwort:" 15 70
+}
+
+fatal_error() {
+    upload_logfile
+    
+    log "!!! Installation abgebrochen: "
+    dialog_msg "$@ Bestätigen, um Rechner neuzustarten."
+    
+    exit 1
+}
+
+# -------------------------------------------------------------------
+# Bind mounts
+
+bind_mount() {
+    for DISKS_PARTITIONS_FS in $INSTALLER_BIND_MOUNTS
+    do
+        mount --bind $DISKS_PARTITIONS_FS "$target$DISKS_PARTITIONS_FS"
+    done
+}
+
+bind_umount() {
+    for DISKS_PARTITIONS_FS in $INSTALLER_BIND_UMOUNTS
+    do
+        umount "$target$DISKS_PARTITIONS_FS"
+    done
+}
+
+
+# -------------------------------------------------------------------
+# Paritionierung
+# neue Partitionstabelle anlegen
+
+part_clean() {
+    # Anfang der Festplatte überschreiben, um GPT Tabelle wegzubekommen
+    exec_log dd if=/dev/zero of="$1" bs=1M count=16
+    sleep 2
+    part_rescan
+    sleep 1
+    
+    if [ "$part" == "msdos" ]
+    then
+        exec_log /usr/local/sbin/fdisk "$1" <<EOF
+o
+w
+EOF
+    elif [ "$part" == "gpt" ]
+    then
+        # EFI-Systempartition anlegen ...
+        exec_log /usr/local/sbin/fdisk "$1" <<EOF
+g
+w
+EOF
+    fi
+}
+
+# neue Partition anlegen
+# $2 = Partitionsnummer
+# $3 = Start der Partition
+# $4 = Ende der Partition (mit + am Anfang: Größe der Partition)
+part_new() {
+    exec_log /usr/local/sbin/fdisk -u "$1" <<EOF
+n
+p
+$2
+$3
+$4
+w
+EOF
+}
+
+part_rescan() {
+    sleep 2
+    exec_log partprobe
+    sleep 2
+}
+
+# -------------------------------------------------------------------
+# Partitionierung
+# Partitionen anlegen
+
+frz_partition() {
+    # Partionstabelle erstellen und Partitionen anlegen ohne Fehlerkontrolle.
+    # manchmal kommt ein Fehler, dass die Partitionstabelle nicht neu
+    # eingelesen werden konnte. Das ist aber so ziemlich egal, kann aber
+    # nicht von anderen Fehlern unterschieden werden.
+    
+    if [ "$partclean" == "yes" ]
+    then
+        dialog_info "Erstelle neue Partitionstabelle auf $disk ..."
+        sleep 2
+        part_clean "$disk"
+        part_rescan
+    fi
+    
+    if [ -n "$rootpart" ]
+    then
+        dialog_info "Erstelle Root-Partition als Partition $rootpart auf $disk"
+        sleep 1
+    
+        if [ -n "$rootsize" ]
+            then part_new "$disk" "$rootpart" "$rootstart" "$rootsize"
+            else part_new "$disk" "$rootpart" "$rootstart" "$rootend"
+        fi
+    fi
+    
+    if [ -n "$swappart" ]
+    then
+        dialog_info "Erstelle Swap-Partition als Partition $swappart auf $disk"
+        sleep 1
+        if [ -n "$swapsize" ]
+            then part_new "$disk" "$swappart" "$swapstart" "$swapsize"
+            else part_new "$disk" "$swappart" "$swapstart" "$swapend"
+        fi
+    fi
+    
+    part_rescan
+}
+
+
+# -------------------------------------------------------------------
+# Formatierung
+
+frz_format() {
+    if [ -n "$rootpart" ]
+    then
+        dialog_info "Formatiere Root-Partition ${disk}${rootpart} mit ext4"
+        sleep 1
+    
+        exec_log mkfs.ext4 -q "${disk}${rootpart}" || fatal_error "Formatierung der Root-Partition fehlgeschlagen!"
+    fi
+    
+    if [ -n "$swappart" ]
+    then
+        dialog_info "Formatiere Swap-Partition ${disk}${swappart}"
+        sleep 1
+        exec_log mkswap "${disk}${swappart}" || fatal_error "Formatierung der Swap-Partition fehlgeschlagen!"
+    fi
+}
+
+
+# -------------------------------------------------------------------
+# Mount
+
+frz_mount() {
+    dialog_info "Mounte Root-Partition ${disk}${rootpart} auf $target"
+    if [ -n "$rootpart" ]
+    then
+        if [ -z "$roottype" ]
+        then
+            roottype="ext4"
+        fi
+        mkdir -p $target
+        mount -t "$roottype" "${disk}${rootpart}" "$target" || fatal_error "Das Ziel-Dateisystem konnte nicht eingehangen werden!"
+    fi
+}
+
+
+# -------------------------------------------------------------------
+# Installation
+
+sdm_install() {
+    frz_log_vars
+    frz_pre
+    frz_partition
+    frz_format
+    frz_mount
+    frz_sync
+    frz_hostname
+    frz_bootmgr
+    frz_provision
+    frz_post
+    frz_cleanup
+}
+
+
+# -------------------------------------------------------------------
+# 
+
+frz_log_vars() {
+    log hostname=$hostname
+    log force_hostname=$force_hostname
+    log target=$target
+    log source=$source
+    log config=$config
+    log disk=$disk
+    log part=$part
+    log efidisk=$efidisk
+    log efipart=$efipart
+    log partclean=$partclean
+    log rootpart=$rootpart
+    log rootsize=$rootsize
+    log rootstart=$rootstart
+    log rootend=$rootend
+    log swappart=$swappart
+    log swapsize=$swapsize
+    log swapstart=$swapstart
+    log swapend=$swapend
+    log subdir=$subdir
+}
+
+
+# -------------------------------------------------------------------
+# 
+
+frz_pre() {
+    :
+}
+
+
+# -------------------------------------------------------------------
+# 
+
+frz_post() {
+    :
+}
+
+
+
+# -------------------------------------------------------------------
+# 
+
+frz_hostname() {
+    if [ -n "$force_hostname" ]
+    then
+        hostname="$force_hostname"
+    fi
+    
+    if [ -n "$target" ] && [ -n "$hostname" ]
+    then
+        dialog_info "Setze Hostname auf $hostname"
+        sleep 1
+        
+        echo $hostname > "$target/etc/hostname"
+    fi
+}
+
+
+# -------------------------------------------------------------------
+# 
+
+provision() {
+    if [ -n "$provision" ]
+    then
+        dialog_info "Provisioniere System mit '$provision' ..."
+        bind_mount
+        exec_log chroot "$target" /bin/bash -c "cd /etc/ansible; ansible-playbook ${provision}.yml -i hosts --limit local"
+        bind_umount
+    fi
+}
+
+
+# -------------------------------------------------------------------
+# 
+
+frz_cleanup() {
+    dialog_info "Führe ldconfig aus ..."
+    exec_log chroot $target ldconfig
+    
+    umount $target
+    rmdir $target
+    
+    return 0
+}
diff --git a/files/installer.sh b/files/installer.sh
new file mode 100755
index 0000000000000000000000000000000000000000..8d242deab8f2687906b512d90ca386ff73204410
--- /dev/null
+++ b/files/installer.sh
@@ -0,0 +1,176 @@
+#!/bin/bash
+# Variablen:
+export INSTALLER_DNS="tu-dresden.de"
+export INSTALLER_CONFIG=''
+export INSTALLER_CONFIG_FILE="/tmp/installer-tmpfile.sh"
+export INSTALLER_CONFIG_URL=''
+export INSTALLER_DEBUGGING=''
+export INSTALLER_ERROR_ACTION=reboot
+export INSTALLER_LOGFILE="/tmp/installer.log"
+export INSTALLER_MODE='sdm_install'
+export INSTALLER_NOTIFY_URL=''
+
+# VERWENDETE VARIABLEN
+# OS_DISTRIBUTION
+
+# ----------------------------------------------------------------------------------------------------------------------
+# Vorbereitung
+update-ca-certificates
+uname -r
+[ -d /sys/firmware/efi ] && echo UEFI || echo BIOS
+sleep 5
+export PATH=/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin/
+
+
+
+# damit das Skript von überall aus gestartet werden kann:
+# in eigenen Ordner wechseln
+# dirname: gibt Pfad aus ohne Dateiname
+# readlink: kompletter Pfad aus $0
+cd "$(dirname "$(readlink -f "$0")")"
+
+. ./functions.sh
+
+# prüfe, wenn uid ungliche Null
+if ! [ $EUID -eq 0 ]
+then
+    echo "Der SDM-Installer muss als Benutzer »root« gestartet werden!"
+    exit 1
+fi
+
+clear
+# dmesg -n: gibt auf Konsole Nr x aus
+dmesg -n 1
+# swap auschalten
+swapoff -a
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# Auf Netzwerk warten
+
+# hier wird mit Status-Anzeige 10x probiert INSTALLER_DNS (tu-dresden.de) aufzulösen (um die DNS-Konfiguration durch DHCP abzuwarten)
+(
+
+counter=0
+while ! nslookup $INSTALLER_DNS 2> /dev/null > /dev/null
+do
+    [ "$counter" -ge 100 ] && exit 1
+    
+    counter=$(expr $counter + 1)
+    echo $counter
+    
+    sleep 1
+done
+
+echo XXX
+echo 100
+echo "Netzwerkverbindung erfolgreich."
+echo XXX
+
+sleep 5
+# Lampda Funktion, die Klammern "fangen" die Ausgabe ab
+# --gauge Infobox mit Höhe Breite %Anzeige, XXX ist für dialog erforderlich
+) | dialog --title "SDM-Installation" --gauge "Warte auf Netzwerk-Verbindung ..." 15 70 0
+
+if [ ${PIPESTATUS[0]} -eq 1 ]
+then
+    dialog_info "Netzwerkverbindung gescheitert! Der Rechner wird neugestartet." && sleep 3
+    $INSTALLER_ERROR_ACTION; exit 1
+fi
+
+
+export hostname="$(hostname)"
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# Parameter
+
+# Kernel-Parameter in Umgebung übernehmen
+export $(cat /proc/cmdline)
+
+# Debug-Modus -> Installation überspringen und in eine Shell droppen
+# verlassen durch? vielleicht reboot oder poweroff
+if [ -n "$INSTALLER_DEBUGGING" ]
+then
+    while true
+    do
+        bash
+    done
+fi
+
+# Parameter prüfen
+if [ -z "$OS_DISTRIBUTION" ] && [ -n "$INSTALLER_MODE" ]
+then
+    dialog_info "Fehlende Parameter! Der Rechner wird neugestartet." && sleep 3
+    $INSTALLER_ERROR_ACTION; exit 1
+fi
+
+# ----------------------------------------------------------------------------------------------------------------------
+# Konfiguration laden
+if [ -n "$INSTALLER_CONFIG_URL" ]
+then
+    if [[ "$INSTALLER_CONFIG_URL" == http* ]]
+    then
+        INSTALLER_CONFIG_URL="$INSTALLER_CONFIG_URL?hostname=$hostname"
+        dialog_info "Hole Installationskonfiguration von Server ..." && sleep 1
+        
+        if ! curl -s --capath ./certs/ -o "$INSTALLER_CONFIG_FILE" "$INSTALLER_CONFIG_URL?hostname=$hostname" > /dev/null
+        then
+            dialog_info "Installations-Skript konnten nicht geholt werden!\n\nDer Rechner wird neugestartet." && sleep 3
+            $INSTALLER_ERROR_ACTION; exit 1
+        fi
+        chmod +x "$INSTALLER_CONFIG_FILE"
+        export $INSTALLER_CONFIG="$INSTALLER_CONFIG_FILE"
+    fi
+fi
+
+
+# Konfiguration entweder über URL oder fest in das Tinycore einbauen unter $INSTALLER_CONFIG_FILE
+# das . VAR lädt den Inhalt der Datei in die Shell Umgebung
+. "$INSTALLER_CONFIG"
+
+
+# nochmal aus cmdline überschreiben
+export $(cat /proc/cmdline)
+
+if [ $(type -t $INSTALLER_MODE) != "function" ]
+then
+    dialog_info "Unbekannte Methode: $INSTALLER_MODE. Der Rechner wird neugestartet." && sleep 3
+    $INSTALLER_ERROR_ACTION; exit 1
+fi
+
+[ -n "$INSTALLER_LOGFILE_URL" ] && INSTALLER_LOGFILE_URL="$INSTALLER_LOGFILE_URL?hostname=$hostname"
+[ -n "$INSTALLER_NOTIFY_URL" ] && INSTALLER_NOTIFY_URL="$INSTALLER_NOTIFY_URL?hostname=$hostname"
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+
+
+dialog_info "Starte Installation ... \n\nHostname: $hostname \nDistribution: $OS_DISTRIBUTION\nModus: $INSTALLER_MODE\nKonfiguration: $INSTALLER_CONFIG"
+sleep 5
+
+# Installation aufrufen
+($INSTALLER_MODE)
+
+if [ $? -eq 0 ]
+then
+    dialog_info "Installationsprotokolle werden hochgeladen ..."
+    upload_logfile
+    
+    if [ -n "$INSTALLER_NOTIFY_URL" ]
+    then
+        dialog_info "Installation erfolgreich.\n\nMelde an Server ..."
+        
+        if curl -s --capath ./certs/ "$INSTALLER_NOTIFY_URL" > /dev/null
+        then
+            dialog_info "Installation erfolgreich.\n\nDer Rechner wird neugestartet." && sleep 3
+        else
+            dialog_msg "Installation erfolgreich.\n\nServer nicht erreichbar.\n\nBestätigen, um Rechner neuzustarten."
+        fi
+    else
+        dialog_msg "Installation erfolgreich.\n\nBestätigen, um Rechner neuzustarten."
+    fi
+fi
+
+#reboot
+exit 0
diff --git a/tasks/buildinstaller.yml b/tasks/buildinstaller.yml
index 432f37ff7b4770a27d90fc81952fc65b35463d25..1f4560e564fa4ad85f16272e100c71973d84bc7f 100644
--- a/tasks/buildinstaller.yml
+++ b/tasks/buildinstaller.yml
@@ -30,6 +30,8 @@
     mode: "{{ _linux_install_file.mode }}"
   loop:
     - {"name": "bootlocal.sh", "mode": "0775" }
+    - {"name": "installer.sh", "mode": "0775" }
+    - {"name": "function.sh", "mode": "0775" }
   loop_control:
     loop_var: _linux_install_file