Stage 6: server image with a console installer (0.4.0)

- server/ profile and build-iso.sh [desktop|server]; make iso-server,
  make qemu-server, run-qemu.sh --serial; login on tty and ttyS0
- das-server: SSH, chrony, NetworkManager/dhcpcd, Docker with Compose,
  nftables (closed except SSH, own table), fail2ban reading socklog,
  sshd without root passwords, Docker log rotation, tools
- das-server-install: dialog installer in Ukrainian and English, or
  unattended with --config; GPT + Btrfs subvolumes, GRUB for UEFI and BIOS,
  serial console, SSH key with optional keys-only logins
- das-install-common: mount-source and postinstall shared with Calamares
- dsv: runit service manager (list, enable, disable, start, stop,
  restart, status, logs) with bash completion, also on the desktop
- das-update split into a subpackage without GTK; the window and tray
  icon move to /usr/libexec/das/das-update-gui
- das-snapper-setup enables dbus, which snapper needs
- TODO: ISO size review with measured numbers and options

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
das
2026-10-19 21:28:26 +03:00
co-authored by Claude Opus 5.5
parent 5349a028c8
commit eba4516998
42 changed files with 1454 additions and 114 deletions
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 Das
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+582
View File
@@ -0,0 +1,582 @@
#!/bin/bash
# das-server-install - console installer for Das OS Server.
#
# Usage: das-server-install [--config FILE]
#
# Asks its questions with dialog and installs the live image on a disk:
# GPT with an EFI or BIOS boot partition and Btrfs with the same subvolumes
# as the desktop installer, so snapshots and rollback work the same way.
# With --config it asks nothing and takes the answers from FILE (see
# /usr/share/examples/das-server-installer/install.conf).
set -Eeuo pipefail
log=/tmp/das-server-install.log
target=/mnt/das-target
source_root=/run/das-installer/root
libexec=/usr/libexec/das/installer
# Answers; a config file sets the same variables
DISK=""
HOST_NAME=dasos-server
USER_NAME=""
USER_PASSWORD=""
SSH_KEY=""
SSH_PASSWORDS=yes
TIMEZONE=Europe/Kyiv
KEYMAP=us
LOCALE=en_US.UTF-8
NETWORK=dhcpcd
ERASE_DISK=no
lang=en
[[ ${LANG:-} == uk* ]] && lang=uk
# t KEY: the message in the installer's language
t() {
local key=$1
if [[ $lang == uk ]]; then
case $key in
title) echo "Встановлення Das OS Server" ;;
lang) echo "Мова встановлення:" ;;
disk) echo "Диск для встановлення. Усі дані на ньому буде знищено." ;;
nodisk) echo "Не знайдено дисків для встановлення." ;;
host) echo "Ім'я сервера (латинські літери, цифри, дефіс):" ;;
badhost) echo "Неправильне ім'я сервера." ;;
user) echo "Ім'я користувача-адміністратора (вхід через sudo, root вимкнено):" ;;
baduser) echo "Неправильне ім'я: малі латинські літери, цифри, _ та -, не root." ;;
pass) echo "Пароль користувача:" ;;
pass2) echo "Ще раз той самий пароль:" ;;
badpass) echo "Паролі порожні або не збігаються." ;;
key) echo "Публічний ключ SSH для входу (вставте рядок ssh-ed25519 ... або залиште порожнім):" ;;
badkey) echo "Це не схоже на публічний ключ SSH." ;;
nopass) echo "Заборонити вхід по SSH за паролем (лише за ключем)?" ;;
tz) echo "Часовий пояс (наприклад, Europe/Kyiv, UTC):" ;;
badtz) echo "Немає такого часового поясу." ;;
keymap) echo "Розкладка клавіатури в консолі:" ;;
locale) echo "Мова системи:" ;;
net) echo "Мережа:" ;;
net_dhcpcd) echo "dhcpcd: DHCP на всіх інтерфейсах (просто)" ;;
net_nm) echo "NetworkManager: налаштування через nmtui (Wi-Fi, статичні адреси)" ;;
summary) echo "Перевірте налаштування:" ;;
erase) echo "УСІ ДАНІ НА ДИСКУ %s БУДЕ ЗНИЩЕНО. Продовжити?" ;;
cancel) echo "Встановлення скасовано." ;;
s_source) echo "Підготовка образу системи..." ;;
s_disk) echo "Розмітка диска %s..." ;;
s_copy) echo "Копіювання системи (кілька хвилин)..." ;;
s_config) echo "Налаштування системи..." ;;
s_post) echo "Локалі, знімки, initramfs (кілька хвилин)..." ;;
s_boot) echo "Встановлення завантажувача..." ;;
finished) echo "Das OS Server встановлено. Вийміть інсталяційний носій і перезавантажте сервер.\n\nВхід: %s, далі sudo. Служби: dsv list. Оновлення: das-update." ;;
reboot) echo "Перезавантажити зараз?" ;;
failed) echo "Помилка встановлення. Журнал: %s" ;;
root) echo "Інсталятор треба запускати від root (sudo das-server-install)." ;;
yes) echo "так" ;;
no) echo "ні" ;;
esac
else
case $key in
title) echo "Das OS Server installation" ;;
lang) echo "Installation language:" ;;
disk) echo "Disk to install to. All data on it will be erased." ;;
nodisk) echo "No disks to install to were found." ;;
host) echo "Server name (Latin letters, digits, hyphen):" ;;
badhost) echo "Invalid server name." ;;
user) echo "Administrator user name (uses sudo, root login is disabled):" ;;
baduser) echo "Invalid name: lowercase Latin letters, digits, _ and -, not root." ;;
pass) echo "User password:" ;;
pass2) echo "The same password again:" ;;
badpass) echo "The passwords are empty or do not match." ;;
key) echo "SSH public key to log in with (paste the ssh-ed25519 ... line, or leave empty):" ;;
badkey) echo "This does not look like an SSH public key." ;;
nopass) echo "Disable SSH password login (keys only)?" ;;
tz) echo "Time zone (for example Europe/Kyiv, UTC):" ;;
badtz) echo "No such time zone." ;;
keymap) echo "Console keyboard layout:" ;;
locale) echo "System language:" ;;
net) echo "Network:" ;;
net_dhcpcd) echo "dhcpcd: DHCP on all interfaces (simple)" ;;
net_nm) echo "NetworkManager: set up with nmtui (Wi-Fi, static addresses)" ;;
summary) echo "Check the settings:" ;;
erase) echo "ALL DATA ON %s WILL BE ERASED. Continue?" ;;
cancel) echo "Installation cancelled." ;;
s_source) echo "Preparing the system image..." ;;
s_disk) echo "Partitioning %s..." ;;
s_copy) echo "Copying the system (a few minutes)..." ;;
s_config) echo "Configuring the system..." ;;
s_post) echo "Locales, snapshots, initramfs (a few minutes)..." ;;
s_boot) echo "Installing the boot loader..." ;;
finished) echo "Das OS Server is installed. Remove the installation medium and reboot.\n\nLog in as %s, then use sudo. Services: dsv list. Updates: das-update." ;;
reboot) echo "Reboot now?" ;;
failed) echo "Installation failed. Log: %s" ;;
root) echo "The installer must run as root (sudo das-server-install)." ;;
yes) echo "yes" ;;
no) echo "no" ;;
esac
fi
}
interactive=1
dialog_ui() {
local labels=()
if [[ $lang == uk ]]; then
labels=(--ok-label "Гаразд" --cancel-label "Скасувати" --yes-label "Так" --no-label "Ні")
fi
dialog --backtitle "Das OS Server" --title "$(t title)" "${labels[@]}" "$@" 3>&1 1>&2 2>&3
}
# Shows a step in the dialog, or prints it when installing from a config file
step() {
if [[ -n $interactive ]]; then
dialog --backtitle "Das OS Server" --title "$(t title)" --infobox "$1" 5 70
echo "==> $1" >>"$log"
else
echo "==> $1" | tee -a "$log"
fi
}
fail() {
trap - ERR
local msg
# shellcheck disable=SC2059
msg=$(printf "$(t failed)" "$log")
if [[ -n $interactive ]]; then
dialog --backtitle "Das OS Server" --title "$(t title)" --msgbox "$msg\n\n$(tail -n 12 "$log" | sed 's/\\/\\\\/g')" 22 76 || true
clear
fi
echo "das-server-install: $msg" >&2
exit 1
}
cancelled() {
[[ -n $interactive ]] && clear
t cancel
exit 1
}
# --- Questions -------------------------------------------------------------
# Disks that can be installed to: not read-only, not the live medium
list_disks() {
local live="" dev
if dev=$(blkid -L VOID_LIVE 2>/dev/null); then
live=$(lsblk -no PKNAME "$dev" 2>/dev/null | head -n 1)
[[ -n $live ]] && live=/dev/$live || live=$dev
fi
lsblk -dpno NAME,TYPE,RO,SIZE,MODEL | while read -r name type ro size model; do
[[ $type == disk && $ro == 0 && $name != "$live" ]] || continue
[[ $name == /dev/zram* || $name == /dev/loop* ]] && continue
printf '%s\t%s %s\n' "$name" "$size" "${model:-}"
done
}
ask_language() {
local choice
choice=$(dialog --backtitle "Das OS Server" --title "Das OS Server" \
--default-item "$lang" --menu "Language / Мова:" 10 50 2 \
en "English" uk "Українська" 3>&1 1>&2 2>&3) || cancelled
lang=$choice
if [[ $lang == uk ]]; then
LOCALE=uk_UA.UTF-8
# The default console font has no Cyrillic (a font needs a Unicode table,
# .psfu); there is no font to set on serial or ssh
case $(tty) in /dev/tty[0-9]*) setfont cyr-sun16 2>/dev/null || true ;; esac
fi
}
ask_disk() {
local items=() name desc
while IFS=$'\t' read -r name desc; do
items+=("$name" "$desc")
done < <(list_disks)
if [[ ${#items[@]} -eq 0 ]]; then
dialog_ui --msgbox "$(t nodisk)" 7 60 || true
cancelled
fi
DISK=$(dialog_ui --menu "$(t disk)" 15 70 6 "${items[@]}") || cancelled
}
valid_host() {
[[ $1 =~ ^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$ ]]
}
valid_user() {
[[ $1 =~ ^[a-z_][a-z0-9_-]{0,31}$ ]] || return 1
case $1 in root | live | nobody | daemon | bin | sys) return 1 ;; esac
}
valid_key() {
[[ -z $1 || $1 =~ ^(ssh-(ed25519|rsa|dss)|ecdsa-sha2-[a-z0-9]+|sk-[a-z0-9@.-]+)\ [A-Za-z0-9+/=]+ ]]
}
ask_host() {
while :; do
HOST_NAME=$(dialog_ui --inputbox "$(t host)" 8 60 "$HOST_NAME") || cancelled
valid_host "$HOST_NAME" && return
dialog_ui --msgbox "$(t badhost)" 6 50 || true
done
}
ask_user() {
local p1 p2
while :; do
USER_NAME=$(dialog_ui --inputbox "$(t user)" 9 60 "$USER_NAME") || cancelled
valid_user "$USER_NAME" && break
dialog_ui --msgbox "$(t baduser)" 7 60 || true
done
while :; do
p1=$(dialog_ui --insecure --passwordbox "$(t pass)" 8 60) || cancelled
p2=$(dialog_ui --insecure --passwordbox "$(t pass2)" 8 60) || cancelled
if [[ -n $p1 && $p1 == "$p2" ]]; then
USER_PASSWORD=$p1
return
fi
dialog_ui --msgbox "$(t badpass)" 6 50 || true
done
}
ask_ssh() {
while :; do
SSH_KEY=$(dialog_ui --inputbox "$(t key)" 10 76 "$SSH_KEY") || cancelled
valid_key "$SSH_KEY" && break
dialog_ui --msgbox "$(t badkey)" 6 50 || true
done
SSH_PASSWORDS=yes
if [[ -n $SSH_KEY ]] && dialog_ui --yesno "$(t nopass)" 7 60; then
SSH_PASSWORDS=no
fi
}
ask_system() {
while :; do
TIMEZONE=$(dialog_ui --inputbox "$(t tz)" 8 60 "$TIMEZONE") || cancelled
[[ -f /usr/share/zoneinfo/$TIMEZONE ]] && break
dialog_ui --msgbox "$(t badtz)" 6 50 || true
done
KEYMAP=$(dialog_ui --default-item "$KEYMAP" --menu "$(t keymap)" 15 50 7 \
us "English (US)" ua-utf "Українська" uk "English (UK)" de-latin1 "Deutsch" \
fr-latin1 "Français" pl2 "Polski") || cancelled
LOCALE=$(dialog_ui --default-item "$LOCALE" --menu "$(t locale)" 10 50 2 \
en_US.UTF-8 "English" uk_UA.UTF-8 "Українська") || cancelled
NETWORK=$(dialog_ui --default-item "$NETWORK" --menu "$(t net)" 10 76 2 \
dhcpcd "$(t net_dhcpcd)" NetworkManager "$(t net_nm)") || cancelled
}
confirm() {
local key pw msg
key=$(t no)
pw=$(t yes)
[[ -n $SSH_KEY ]] && key=$(t yes)
[[ $SSH_PASSWORDS == no ]] && pw=$(t no)
dialog_ui --no-collapse --msgbox "$(t summary)
Disk: $DISK
Host: $HOST_NAME
User: $USER_NAME
SSH key: $key
SSH passwords: $pw
Time zone: $TIMEZONE
Keyboard: $KEYMAP
Language: $LOCALE
Network: $NETWORK" 18 60 || cancelled
# shellcheck disable=SC2059
msg=$(printf "$(t erase)" "$DISK")
dialog_ui --defaultno --yesno "$msg" 7 60 || cancelled
ERASE_DISK=yes
}
# --- Installation ----------------------------------------------------------
# part N: the device of partition N on $DISK
part() {
lsblk -lnpo NAME,TYPE "$DISK" | awk '$2 == "part" { print $1 }' | sed -n "${1}p"
}
in_target() {
chroot "$target" "$@"
}
# Undo mounts from an earlier attempt or a failure
unmount_target() {
if mountpoint -q "$target"; then
umount -R "$target" || umount -Rl "$target"
fi
}
uefi() {
[[ -d /sys/firmware/efi ]]
}
serial_console() {
grep -q 'console=ttyS0' /proc/cmdline
}
partition() {
local efi root
unmount_target
wipefs -a "$DISK"
sgdisk --zap-all "$DISK"
if uefi; then
sgdisk -n 1:0:+512M -t 1:ef00 -c 1:EFI -n 2:0:0 -t 2:8300 -c 2:dasos "$DISK"
else
# GRUB on BIOS keeps its core image in a small partition on GPT
sgdisk -n 1:0:+1M -t 1:ef02 -c 1:bios -n 2:0:0 -t 2:8300 -c 2:dasos "$DISK"
fi
partprobe "$DISK" 2>/dev/null || true
udevadm settle
efi=$(part 1)
root=$(part 2)
[[ -b $root ]] || return 1
uefi && mkfs.vfat -F 32 -n EFI "$efi"
mkfs.btrfs -f -L dasos "$root"
# The same subvolumes as the Calamares configuration (mount.conf)
mkdir -p "$target"
mount "$root" "$target"
for sv in @ @home @snapshots @var_log @var_cache_xbps; do
btrfs subvolume create "$target/$sv"
done
umount "$target"
local opts=noatime,compress=zstd:1
mount -o "$opts,subvol=@" "$root" "$target"
mkdir -p "$target"/{home,.snapshots,var/log,var/cache/xbps}
mount -o "$opts,subvol=@home" "$root" "$target/home"
mount -o "$opts,subvol=@snapshots" "$root" "$target/.snapshots"
mount -o "$opts,subvol=@var_log" "$root" "$target/var/log"
mount -o "$opts,subvol=@var_cache_xbps" "$root" "$target/var/cache/xbps"
if uefi; then
mkdir -p "$target/boot/efi"
mount -o umask=0077 "$efi" "$target/boot/efi"
fi
}
copy_system() {
# No --sparse: GRUB can't read kernels with Btrfs holes (see postinstall)
rsync -aHAX --numeric-ids "$source_root/" "$target/"
}
write_fstab() {
local root_uuid efi_uuid opts=noatime,compress=zstd:1
root_uuid=$(blkid -s UUID -o value "$(part 2)")
{
echo "# <file system> <dir> <type> <options> <dump> <pass>"
echo "UUID=$root_uuid / btrfs $opts,subvol=@ 0 0"
echo "UUID=$root_uuid /home btrfs $opts,subvol=@home 0 0"
echo "UUID=$root_uuid /.snapshots btrfs $opts,subvol=@snapshots 0 0"
echo "UUID=$root_uuid /var/log btrfs $opts,subvol=@var_log 0 0"
echo "UUID=$root_uuid /var/cache/xbps btrfs $opts,subvol=@var_cache_xbps 0 0"
if uefi; then
efi_uuid=$(blkid -s UUID -o value "$(part 1)")
echo "UUID=$efi_uuid /boot/efi vfat defaults,umask=0077 0 2"
fi
} >"$target/etc/fstab"
}
mount_chroot() {
mount -t proc proc "$target/proc"
mount -t sysfs sys "$target/sys"
mount --rbind /dev "$target/dev"
mount -t tmpfs tmpfs "$target/run"
if uefi; then
mount -t efivarfs efivarfs "$target/sys/firmware/efi/efivars" 2>/dev/null || true
fi
}
# set_rc VAR VALUE: sets VAR in /etc/rc.conf, uncommenting Void's example line
set_rc() {
local rc=$target/etc/rc.conf
if grep -q "^#\?$1=" "$rc"; then
sed -i "s|^#\?$1=.*|$1=\"$2\"|" "$rc"
else
echo "$1=\"$2\"" >>"$rc"
fi
}
enable_service() {
ln -sfn "/etc/sv/$1" "$target/etc/runit/runsvdir/default/$1"
}
disable_service() {
rm -f "$target/etc/runit/runsvdir/default/$1"
}
configure() {
local home
# The live image's /etc/issue tells how to log in to the live system
printf 'Das OS Server \\r (\\l)\n\n' >"$target/etc/issue"
echo "$HOST_NAME" >"$target/etc/hostname"
if ! grep -q "[[:space:]]$HOST_NAME\$" "$target/etc/hosts"; then
printf '127.0.1.1\t%s\n' "$HOST_NAME" >>"$target/etc/hosts"
fi
echo "LANG=$LOCALE" >"$target/etc/locale.conf"
ln -sfn "/usr/share/zoneinfo/$TIMEZONE" "$target/etc/localtime"
set_rc KEYMAP "$KEYMAP"
set_rc HARDWARECLOCK UTC
[[ $LOCALE == uk* || $KEYMAP == ua* ]] && set_rc FONT cyr-sun16
# The administrator: sudo through wheel, root has no password
in_target useradd -m -s /bin/bash -G wheel,docker,socklog "$USER_NAME"
# -c: Void's PAM stack for chpasswd only has pam_permit for passwords, so
# without it nothing is written (Void's own installer does the same)
printf '%s:%s\n' "$USER_NAME" "$USER_PASSWORD" | in_target chpasswd -c SHA512
in_target passwd -l root >/dev/null
echo "%wheel ALL=(ALL:ALL) ALL" >"$target/etc/sudoers.d/10-wheel"
chmod 440 "$target/etc/sudoers.d/10-wheel"
if [[ -n $SSH_KEY ]]; then
home=$target/home/$USER_NAME
install -d -m 700 "$home/.ssh"
echo "$SSH_KEY" >"$home/.ssh/authorized_keys"
chmod 600 "$home/.ssh/authorized_keys"
in_target chown -R "$USER_NAME:$USER_NAME" "/home/$USER_NAME/.ssh"
fi
if [[ $SSH_PASSWORDS == no ]]; then
printf '%s\n' "# Written by das-server-install: SSH keys only" \
"PasswordAuthentication no" "KbdInteractiveAuthentication no" \
>"$target/etc/ssh/sshd_config.d/40-das-keys-only.conf"
fi
for sv in sshd chronyd nftables fail2ban docker socklog-unix nanoklogd; do
enable_service "$sv"
done
if [[ $NETWORK == NetworkManager ]]; then
disable_service dhcpcd
enable_service dbus
enable_service NetworkManager
else
enable_service dhcpcd
fi
serial_console && enable_service agetty-ttyS0
return 0
}
install_bootloader() {
local grub=$target/etc/default/grub cmdline="loglevel=4"
serial_console && cmdline+=" console=tty0 console=ttyS0,115200"
sed -i -e '/^GRUB_DISTRIBUTOR=/d' -e '/^GRUB_CMDLINE_LINUX_DEFAULT=/d' -e '/^GRUB_TIMEOUT=/d' \
-e '/^GRUB_TERMINAL/d' -e '/^GRUB_SERIAL_COMMAND=/d' -e '/^GRUB_DISABLE_OS_PROBER=/d' "$grub"
{
echo 'GRUB_DISTRIBUTOR="Das OS"'
echo "GRUB_CMDLINE_LINUX_DEFAULT=\"$cmdline\""
echo 'GRUB_TIMEOUT=5'
echo 'GRUB_DISABLE_OS_PROBER=true'
if serial_console; then
echo 'GRUB_TERMINAL="console serial"'
echo 'GRUB_SERIAL_COMMAND="serial --unit=0 --speed=115200"'
fi
} >>"$grub"
if uefi; then
in_target grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=dasos
# Also at the fallback path, for firmware that forgets boot entries
in_target grub-install --target=x86_64-efi --efi-directory=/boot/efi --removable --no-nvram
else
in_target grub-install --target=i386-pc "$DISK"
fi
}
finish() {
# The first snapshot, also shown in the boot menu (like Calamares' shellprocess@snapshot)
in_target snapper --no-dbus -c root create -d "Fresh install" -c number --userdata important=yes || true
in_target grub-mkconfig -o /boot/grub/grub.cfg
# The installer is not needed on the installed system
in_target xbps-remove -y das-server-installer das-install-common || true
sync
}
# Any failing command stops the installation with the log (set -E: also
# inside functions; "f || fail" would switch set -e off within f).
install_system() {
: >"$log"
trap fail ERR
step "$(t s_source)"
"$libexec/mount-source" >>"$log" 2>&1
# shellcheck disable=SC2059
step "$(printf "$(t s_disk)" "$DISK")"
partition >>"$log" 2>&1
step "$(t s_copy)"
copy_system >>"$log" 2>&1
step "$(t s_config)"
write_fstab >>"$log" 2>&1
mount_chroot >>"$log" 2>&1
configure >>"$log" 2>&1
step "$(t s_post)"
in_target "$libexec/postinstall" >>"$log" 2>&1
step "$(t s_boot)"
install_bootloader >>"$log" 2>&1
finish >>"$log" 2>&1
unmount_target >>"$log" 2>&1
trap - ERR
}
load_config() {
local file=$1
[[ -r $file ]] || {
echo "das-server-install: cannot read $file" >&2
exit 1
}
# shellcheck source=/dev/null
. "$file"
interactive=""
local bad=""
[[ -b $DISK ]] || bad+=" DISK"
valid_host "$HOST_NAME" || bad+=" HOST_NAME"
valid_user "$USER_NAME" || bad+=" USER_NAME"
[[ -n $USER_PASSWORD ]] || bad+=" USER_PASSWORD"
valid_key "$SSH_KEY" || bad+=" SSH_KEY"
[[ $SSH_PASSWORDS == yes || ( $SSH_PASSWORDS == no && -n $SSH_KEY ) ]] || bad+=" SSH_PASSWORDS"
[[ -f /usr/share/zoneinfo/$TIMEZONE ]] || bad+=" TIMEZONE"
[[ $NETWORK == dhcpcd || $NETWORK == NetworkManager ]] || bad+=" NETWORK"
[[ $ERASE_DISK == yes ]] || bad+=" ERASE_DISK"
if [[ -n $bad ]]; then
echo "das-server-install: invalid or missing in $file:$bad" >&2
exit 1
fi
}
main() {
if [[ $EUID -ne 0 ]]; then
exec sudo --preserve-env=LANG "$0" "$@"
fi
case ${1:-} in
--config)
load_config "${2:?--config needs a file}"
;;
-h | --help)
sed -n '2,11s/^# \{0,1\}//p' "$0"
exit 0
;;
"") ;;
*)
echo "das-server-install: unknown option $1" >&2
exit 1
;;
esac
if [[ -n $interactive ]]; then
ask_language
ask_disk
ask_host
ask_user
ask_ssh
ask_system
confirm
fi
install_system
if [[ -n $interactive ]]; then
local msg
# shellcheck disable=SC2059
msg=$(printf "$(t finished)" "$USER_NAME")
if dialog_ui --yesno "$msg\n\n$(t reboot)" 12 70; then
reboot
fi
clear
else
echo "==> done, log: $log"
fi
}
main "$@"
@@ -0,0 +1,20 @@
# Answers for an unattended Das OS Server installation:
# sudo das-server-install --config install.conf
# The file is read by bash. Every value is checked before anything is done.
# The disk to install to; it is erased completely
DISK=/dev/vda
ERASE_DISK=no # must be "yes" to install
HOST_NAME=dasos-server
USER_NAME=admin # gets sudo; root login stays disabled
USER_PASSWORD=change-me
# A public key for SSH logins (optional), and whether passwords stay allowed
SSH_KEY=""
SSH_PASSWORDS=yes # "no" requires SSH_KEY
TIMEZONE=Europe/Kyiv
KEYMAP=us # console layout: us, ua-utf, uk, de-latin1, ...
LOCALE=en_US.UTF-8 # or uk_UA.UTF-8
NETWORK=dhcpcd # or NetworkManager