diff --git a/scripts/build.sh b/scripts/build.sh
new file mode 100755
index 0000000..aa8822d
--- /dev/null
+++ b/scripts/build.sh
@@ -0,0 +1,278 @@
+#!/bin/bash
+
+set -e                  # exit on error
+set -o pipefail         # exit on pipeline error
+set -u                  # treat unset variable as error
+#set -x
+
+SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
+
+CMD=(setup_host debootstrap run_chroot build_iso)
+
+DATE=`TZ="UTC" date +"%y%m%d-%H%M%S"`
+
+function help() {
+    # if $1 is set, use $1 as headline message in help()
+    if [ -z ${1+x} ]; then
+        echo -e "This script builds bootable ubuntu ISO image"
+        echo -e
+    else
+        echo -e $1
+        echo
+    fi
+    echo -e "Supported commands : ${CMD[*]}"
+    echo -e
+    echo -e "Syntax: $0 [start_cmd] [-] [end_cmd]"
+    echo -e "\trun from start_cmd to end_end"
+    echo -e "\tif start_cmd is omitted, start from first command"
+    echo -e "\tif end_cmd is omitted, end with last command"
+    echo -e "\tenter single cmd to run the specific command"
+    echo -e "\tenter '-' as only argument to run all commands"
+    echo -e
+    exit 0
+}
+
+function find_index() {
+    local ret;
+    local i;
+    for ((i=0; i<${#CMD[*]}; i++)); do
+        if [ "${CMD[i]}" == "$1" ]; then
+            index=$i;
+            return;
+        fi
+    done
+    help "Command not found : $1"
+}
+
+function chroot_enter_setup() {
+    sudo mount --bind /dev chroot/dev
+    sudo mount --bind /run chroot/run
+    sudo chroot chroot mount none -t proc /proc
+    sudo chroot chroot mount none -t sysfs /sys
+    sudo chroot chroot mount none -t devpts /dev/pts
+}
+
+function chroot_exit_teardown() {
+    sudo chroot chroot umount /proc
+    sudo chroot chroot umount /sys
+    sudo chroot chroot umount /dev/pts
+    sudo umount chroot/dev
+    sudo umount chroot/run
+}
+
+function check_host() {
+    local os_ver;
+    os_ver=`lsb_release -d | grep "Ubuntu 20.04"`
+    if [[ $os_ver == "" ]]; then
+        echo "WARNING : OS is not Ubuntu 20.04 and is untested"
+    fi
+
+    if [ $(id -u) -eq 0 ]; then
+        echo "This script should not be run as 'root'"
+        exit 1
+    fi
+}
+
+function setup_host() {
+    echo "=====> running setup_host ..."
+    sudo apt update
+    sudo apt install -y binutils debootstrap squashfs-tools xorriso grub-pc-bin grub-efi-amd64-bin mtools
+    sudo mkdir -p chroot
+}
+
+function debootstrap() {
+    echo "=====> running debootstrap ... will take a couple of minutes ..."
+    sudo debootstrap  --arch=amd64 --variant=minbase focal chroot  http://us.archive.ubuntu.com/ubuntu/
+}
+
+function run_chroot() {
+    echo "=====> running run_chroot ..."
+
+    chroot_enter_setup
+
+    sudo ln -f $SCRIPT_DIR/chroot_build.sh chroot/root/chroot_build.sh
+    sudo cp -f /etc/apt/sources.list chroot/etc/apt/
+    sudo chroot chroot /root/chroot_build.sh -
+    sudo rm -f chroot/root/chroot_build.sh
+
+    chroot_exit_teardown
+}
+
+
+function build_iso() {
+    echo "=====> running build_iso ..."
+
+    rm -rf image
+    mkdir -p image/{casper,isolinux,install}
+
+    # copy kernel files
+    sudo cp chroot/boot/vmlinuz-**-**-generic image/casper/vmlinuz
+    sudo cp chroot/boot/initrd.img-**-**-generic image/casper/initrd
+
+    # memtest86
+    sudo cp chroot/boot/memtest86+.bin image/install/memtest86+
+
+    wget --progress=dot https://www.memtest86.com/downloads/memtest86-usb.zip -O image/install/memtest86-usb.zip
+    unzip -p image/install/memtest86-usb.zip memtest86-usb.img > image/install/memtest86
+    rm -f image/install/memtest86-usb.zip
+
+    # grub
+    touch image/ubuntu
+    cat <<EOF > image/isolinux/grub.cfg
+
+search --set=root --file /ubuntu
+
+insmod all_video
+
+set default="0"
+set timeout=30
+
+menuentry "Try Ubuntu FS without installing" {
+   linux /casper/vmlinuz boot=casper nopersistent toram quiet splash ---
+   initrd /casper/initrd
+}
+
+menuentry "Install Ubuntu FS" {
+   linux /casper/vmlinuz boot=casper only-ubiquity quiet splash ---
+   initrd /casper/initrd
+}
+
+menuentry "Check disc for defects" {
+   linux /casper/vmlinuz boot=casper integrity-check quiet splash ---
+   initrd /casper/initrd
+}
+
+menuentry "Test memory Memtest86+ (BIOS)" {
+   linux16 /install/memtest86+
+}
+
+menuentry "Test memory Memtest86 (UEFI, long load time)" {
+   insmod part_gpt
+   insmod search_fs_uuid
+   insmod chain
+   loopback loop /install/memtest86
+   chainloader (loop,gpt1)/efi/boot/BOOTX64.efi
+}
+EOF
+
+    # generate manifest
+    sudo chroot chroot dpkg-query -W --showformat='${Package} ${Version}\n' | sudo tee image/casper/filesystem.manifest
+    sudo cp -v image/casper/filesystem.manifest image/casper/filesystem.manifest-desktop
+    sudo sed -i '/ubiquity/d' image/casper/filesystem.manifest-desktop
+    sudo sed -i '/casper/d' image/casper/filesystem.manifest-desktop
+    sudo sed -i '/discover/d' image/casper/filesystem.manifest-desktop
+    sudo sed -i '/laptop-detect/d' image/casper/filesystem.manifest-desktop
+    sudo sed -i '/os-prober/d' image/casper/filesystem.manifest-desktop
+
+    # compress rootfs
+    sudo mksquashfs chroot image/casper/filesystem.squashfs
+    printf $(sudo du -sx --block-size=1 chroot | cut -f1) > image/casper/filesystem.size
+
+    # create diskdefines
+    cat <<EOF > image/README.diskdefines
+#define DISKNAME  Ubuntu from scratch
+#define TYPE  binary
+#define TYPEbinary  1
+#define ARCH  amd64
+#define ARCHamd64  1
+#define DISKNUM  1
+#define DISKNUM1  1
+#define TOTALNUM  0
+#define TOTALNUM0  1
+EOF
+
+    # create iso image
+    pushd $SCRIPT_DIR/image
+    grub-mkstandalone \
+        --format=x86_64-efi \
+        --output=isolinux/bootx64.efi \
+        --locales="" \
+        --fonts="" \
+        "boot/grub/grub.cfg=isolinux/grub.cfg"
+    
+    (
+        cd isolinux && \
+        dd if=/dev/zero of=efiboot.img bs=1M count=10 && \
+        sudo mkfs.vfat efiboot.img && \
+        LC_CTYPE=C mmd -i efiboot.img efi efi/boot && \
+        LC_CTYPE=C mcopy -i efiboot.img ./bootx64.efi ::efi/boot/
+    )
+
+    grub-mkstandalone \
+        --format=i386-pc \
+        --output=isolinux/core.img \
+        --install-modules="linux16 linux normal iso9660 biosdisk memdisk search tar ls" \
+        --modules="linux16 linux normal iso9660 biosdisk search" \
+        --locales="" \
+        --fonts="" \
+        "boot/grub/grub.cfg=isolinux/grub.cfg"
+
+    cat /usr/lib/grub/i386-pc/cdboot.img isolinux/core.img > isolinux/bios.img
+
+    sudo /bin/bash -c "(find . -type f -print0 | xargs -0 md5sum | grep -v -e 'md5sum.txt' -e 'bios.img' -e 'efiboot.img' > md5sum.txt)"
+
+    sudo xorriso \
+        -as mkisofs \
+        -iso-level 3 \
+        -full-iso9660-filenames \
+        -volid "Ubuntu from scratch" \
+        -eltorito-boot boot/grub/bios.img \
+        -no-emul-boot \
+        -boot-load-size 4 \
+        -boot-info-table \
+        --eltorito-catalog boot/grub/boot.cat \
+        --grub2-boot-info \
+        --grub2-mbr /usr/lib/grub/i386-pc/boot_hybrid.img \
+        -eltorito-alt-boot \
+        -e EFI/efiboot.img \
+        -no-emul-boot \
+        -append_partition 2 0xef isolinux/efiboot.img \
+        -output "../ubuntu-from-scratch.iso" \
+        -m "isolinux/efiboot.img" \
+        -m "isolinux/bios.img" \
+        -graft-points \
+           "/EFI/efiboot.img=isolinux/efiboot.img" \
+           "/boot/grub/bios.img=isolinux/bios.img" \
+           "."
+
+    popd
+}
+
+# =============   main  ================
+
+# we always stay in $SCRIPT_DIR
+cd $SCRIPT_DIR
+
+check_host
+
+# check number of args
+if [[ $# == 0 || $# > 3 ]]; then help; fi
+
+# loop through args
+dash_flag=false
+start_index=0
+end_index=${#CMD[*]}
+for ii in "$@";
+do
+    if [[ $ii == "-" ]]; then
+        dash_flag=true
+        continue
+    fi
+    find_index $ii
+    if [[ $dash_flag == false ]]; then
+        start_index=$index
+    else
+        end_index=$(($index+1))
+    fi
+done
+if [[ $dash_flag == false ]]; then
+    end_index=$(($start_index + 1))
+fi
+
+#loop through the commands
+for ((ii=$start_index; ii<$end_index; ii++)); do
+    ${CMD[ii]}
+done
+
+echo "$0 - Initial build is done!"
+
diff --git a/scripts/chroot_build.sh b/scripts/chroot_build.sh
new file mode 100755
index 0000000..1f8d684
--- /dev/null
+++ b/scripts/chroot_build.sh
@@ -0,0 +1,196 @@
+#!/bin/bash
+
+set -e                  # exit on error
+set -o pipefail         # exit on pipeline error
+set -u                  # treat unset variable as error
+#set -x
+
+SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
+
+CMD=(setup_host install_pkg finish_up)
+
+function help() {
+    # if $1 is set, use $1 as headline message in help()
+    if [ -z ${1+x} ]; then
+        echo -e "This script builds Ubuntu from scratch"
+        echo -e
+    else
+        echo -e $1
+        echo
+    fi
+    echo -e "Supported commands : ${CMD[*]}"
+    echo -e
+    echo -e "Syntax: $0 [start_cmd] [-] [end_cmd]"
+    echo -e "\trun from start_cmd to end_end"
+    echo -e "\tif start_cmd is omitted, start from first command"
+    echo -e "\tif end_cmd is omitted, end with last command"
+    echo -e "\tenter single cmd to run the specific command"
+    echo -e "\tenter '-' as only argument to run all commands"
+    echo -e
+    exit 0
+}
+
+function find_index() {
+    local ret;
+    local i;
+    for ((i=0; i<${#CMD[*]}; i++)); do
+        if [ "${CMD[i]}" == "$1" ]; then
+            index=$i;
+            return;
+        fi
+    done
+    help "Command not found : $1"
+}
+
+function check_host() {
+    if [ $(id -u) -ne 0 ]; then
+        echo "This script should be run as 'root'"
+        exit 1
+    fi
+
+    export HOME=/root
+    export LC_ALL=C
+}
+
+function setup_host() {
+    echo "=====> running setup_host ..."
+
+    echo "ubuntu-fs-live" > /etc/hostname
+
+    # we need to install systemd first, to configure machine id
+    apt-get update
+    apt-get install -y libterm-readline-gnu-perl systemd-sysv
+
+    #configure machine id
+    dbus-uuidgen > /etc/machine-id
+    ln -fs /etc/machine-id /var/lib/dbus/machine-id
+
+    # don't understand why, but multiple sources indicate this
+    dpkg-divert --local --rename --add /sbin/initctl
+    ln -s /bin/true /sbin/initctl
+}
+
+function install_pkg() {
+    echo "=====> running install_pkg ... will take a long time ..."
+    apt-get -y upgrade
+
+    # install live linux packages
+    apt-get install -y \
+    ubuntu-standard \
+    casper \
+    lupin-casper \
+    discover \
+    laptop-detect \
+    os-prober \
+    network-manager \
+    resolvconf \
+    net-tools \
+    wireless-tools \
+    wpagui \
+    locales \
+    linux-generic
+
+    # graphic installer - ubiquity
+    apt-get install -y \
+    ubiquity \
+    ubiquity-casper \
+    ubiquity-frontend-gtk \
+    ubiquity-slideshow-ubuntu \
+    ubiquity-ubuntu-artwork
+
+    # install graphics and desktop
+    apt-get install -y \
+    plymouth-theme-ubuntu-logo \
+    ubuntu-gnome-desktop \
+    ubuntu-gnome-wallpapers
+
+    # useful tools
+    apt-get install -y \
+    clamav-daemon \
+    terminator \
+    apt-transport-https \
+    curl \
+    vim \
+    nano \
+    less
+
+    # purge
+    apt-get purge -y \
+    transmission-gtk \
+    transmission-common \
+    gnome-mahjongg \
+    gnome-mines \
+    gnome-sudoku \
+    aisleriot \
+    hitori
+
+    # remove unused and clean up apt cache
+    apt-get autoremove -y
+
+    # final touch
+    dpkg-reconfigure locales
+    dpkg-reconfigure resolvconf
+
+    # network manager
+    cat <<EOF > /etc/NetworkManager/NetworkManager.conf
+[main]
+rc-manager=resolvconf
+plugins=ifupdown,keyfile
+dns=dnsmasq
+
+[ifupdown]
+managed=false
+EOF
+    dpkg-reconfigure network-manager
+
+    apt-get clean -y
+}
+
+function finish_up() { 
+    echo "=====> finish_up"
+
+    # truncate machine id (why??)
+    truncate -s 0 /etc/machine-id
+
+    # remove diversion (why??)
+    rm /sbin/initctl
+    dpkg-divert --rename --remove /sbin/initctl
+
+    rm -rf /tmp/* ~/.bash_history
+}
+
+# =============   main  ================
+
+check_host
+
+# check number of args
+if [[ $# == 0 || $# > 3 ]]; then help; fi
+
+# loop through args
+dash_flag=false
+start_index=0
+end_index=${#CMD[*]}
+for ii in "$@";
+do
+    if [[ $ii == "-" ]]; then
+        dash_flag=true
+        continue
+    fi
+    find_index $ii
+    if [[ $dash_flag == false ]]; then
+        start_index=$index
+    else
+        end_index=$(($index+1))
+    fi
+done
+if [[ $dash_flag == false ]]; then
+    end_index=$(($start_index + 1))
+fi
+
+# loop through the commands
+for ((ii=$start_index; ii<$end_index; ii++)); do
+    ${CMD[ii]}
+done
+
+echo "$0 - Initial build is done!"
+