Compare commits
3 Commits
6718b1c311
...
09a95860f9
Author | SHA1 | Date |
---|---|---|
macmpi | 09a95860f9 | |
macmpi | 51e426e9bf | |
macmpi | 1eca862849 |
20
README.md
20
README.md
|
@ -1,16 +1,16 @@
|
||||||
# Deploy Alpine Linux on a headless system
|
# Install (or rescue) Alpine Linux on a headless system
|
||||||
|
|
||||||
[Alpine Linux documentation](https://docs.alpinelinux.org/user-handbook/0.1a/Installing/setup_alpine.html) assumes **initial setup** is carried-out on a system with a keyboard & display to interract with.\
|
[Alpine Linux documentation](https://docs.alpinelinux.org/user-handbook/0.1a/Installing/setup_alpine.html) assumes **initial setup** is carried-out on a system with a keyboard & display to interract with.\
|
||||||
However, in many cases one might want to deploy a headless system that is only available through a network connection (ethernet, wifi or as USB ethernet gadget).
|
However, in many cases one might want to deploy a headless system that is only available through a network connection (ethernet, wifi or as USB ethernet gadget).
|
||||||
|
|
||||||
This repo provides an **overlay file** to initially boot such headless system (leveraging Alpine distro's `initramfs` feature): it starts a basic ssh server to log-into from another Computer, in order to then perform actual system setup.
|
This repo provides an **overlay file** to initially bootstrap[^1] a headless system (leveraging Alpine distro's `initramfs` feature): it starts a basic ssh server to log-into from another Computer, so that actual install on fresh system (or rescue on existing disk-based system) can then be performed remotely.
|
||||||
|
|
||||||
|
|
||||||
## Install procedure:
|
## Install procedure:
|
||||||
Please follow [Alpine Linux Wiki](https://wiki.alpinelinux.org/wiki/Installation#Installation_Overview) to download & create installation media for the target platform.\
|
Please follow [Alpine Linux Wiki](https://wiki.alpinelinux.org/wiki/Installation#Installation_Overview) to download & create installation media for the target platform.\
|
||||||
Tools provided here can be used on any plaform for any install modes (diskless, data disk, system disk).
|
Tools provided here can be used on any plaform for any install modes (diskless, data disk, system disk).
|
||||||
|
|
||||||
Just add [**headless.apkovl.tar.gz**](https://github.com/macmpi/alpine-linux-headless-bootstrap/raw/main/headless.apkovl.tar.gz)[^1] overlay file at the root of Alpine Linux boot media (or onto any custom side-media) and boot-up the system.\
|
Just add [**headless.apkovl.tar.gz**](https://github.com/macmpi/alpine-linux-headless-bootstrap/raw/main/headless.apkovl.tar.gz)[^2] overlay file at the root of Alpine Linux boot media (or onto any custom side-media) and boot-up the system.\
|
||||||
With default network interface definitions (and SSID/pass file if using wifi), system can then be remotely accessed with: `ssh root@<IP>`\
|
With default network interface definitions (and SSID/pass file if using wifi), system can then be remotely accessed with: `ssh root@<IP>`\
|
||||||
(system IP address may be determined with any IP scanning tools such as `nmap`).
|
(system IP address may be determined with any IP scanning tools such as `nmap`).
|
||||||
|
|
||||||
|
@ -19,10 +19,10 @@ From there, actual system install can be performed as usual with `setup-alpine`
|
||||||
|
|
||||||
|
|
||||||
Extra files may be added next to `headless.apkovl.tar.gz` to customise boostrapping configuration (check sample files):
|
Extra files may be added next to `headless.apkovl.tar.gz` to customise boostrapping configuration (check sample files):
|
||||||
- `wpa_supplicant.conf`[^2] (*mandatory for wifi usecase*): define wifi SSID & password.
|
- `wpa_supplicant.conf`[^3] (*mandatory for wifi usecase*): define wifi SSID & password.
|
||||||
- `interfaces`[^2] (*optional*): define network interfaces at will, if defaults DCHP-based are not suitable.
|
- `interfaces`[^3] (*optional*): define network interfaces at will, if defaults DCHP-based are not suitable.
|
||||||
- `ssh_host_*_key*` (*optional*): provide custom ssh keys to be injected (may be stored), instead of using bundled ones[^1] (not stored). Providing an empty key file will trigger new keys generation (ssh server may take longer to start).
|
- `ssh_host_*_key*` (*optional*): provide custom ssh keys to be injected (may be stored), instead of using bundled ones[^2] (not stored). Providing an empty key file will trigger new keys generation (ssh server may take longer to start).
|
||||||
- `unattended.sh`[^2] (*optional*): create custom automated deployment script to further tune & extend actual setup (backgrounded).
|
- `unattended.sh`[^3] (*optional*): create custom automated deployment script to further tune & extend actual setup (backgrounded).
|
||||||
|
|
||||||
|
|
||||||
**Goody:** seamless USB bootstrapping for PiZero devices (or similar supporting USB ethernet gadget networking):\
|
**Goody:** seamless USB bootstrapping for PiZero devices (or similar supporting USB ethernet gadget networking):\
|
||||||
|
@ -31,9 +31,11 @@ With Computer set-up to share networking with USB interface as 10.42.0.1 gateway
|
||||||
|
|
||||||
Main execution steps are logged in `/var/log/messages`.
|
Main execution steps are logged in `/var/log/messages`.
|
||||||
|
|
||||||
[^1]: About bundled ssh keys: as this package is essentially intended to **quickly bootstrap** system in order to configure it, it purposely embeds [some ssh keys](https://github.com/macmpi/alpine-linux-headless-bootstrap/tree/main/overlay/etc/ssh) so that bootstrapping is as fast as possible. Those (temporary) keys are moved in RAM /tmp, so they will **not be saved/reused** once permanent configuration is set (with or without ssh server voluntarily installed in permanent setup).
|
[^1]: Initial boot fully preserves system's original state (config files & installed packages): a fresh system will therefore come-up as unconfigured.
|
||||||
|
|
||||||
[^2]: These files are linux text files: Windows/macOS users need to use text editors supporting linux text line-ending (such as [notepad++](https://notepad-plus-plus.org/), BBEdit or any similar).
|
[^2]: About bundled ssh keys: as this package is essentially intended to **quickly bootstrap** system in order to configure it, it purposely embeds [some ssh keys](https://github.com/macmpi/alpine-linux-headless-bootstrap/tree/main/overlay/etc/ssh) so that bootstrapping is as fast as possible. Those (temporary) keys are moved in RAM /tmp, so they will **not be saved/reused** once permanent configuration is set (with or without ssh server voluntarily installed in permanent setup).
|
||||||
|
|
||||||
|
[^3]: These files are linux text files: Windows/macOS users need to use text editors supporting linux text line-ending (such as [notepad++](https://notepad-plus-plus.org/), BBEdit or any similar).
|
||||||
|
|
||||||
|
|
||||||
## How to customize ?
|
## How to customize ?
|
||||||
|
|
Binary file not shown.
|
@ -5,26 +5,68 @@
|
||||||
|
|
||||||
VERSION="0.7"
|
VERSION="0.7"
|
||||||
|
|
||||||
|
|
||||||
|
_apk() {
|
||||||
|
local cmd="$1"
|
||||||
|
local pkg="$2"
|
||||||
|
|
||||||
|
case $cmd in
|
||||||
|
add) # install only if not already present
|
||||||
|
if ! apk info | grep -wq "${pkg}"; then
|
||||||
|
apk add "$pkg" && printf "${pkg} " >> /tmp/.trash/installed
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
del) # delete only if previously installed
|
||||||
|
if grep -wq "$pkg" /tmp/.trash/installed; then
|
||||||
|
apk del "$pkg" && sed -i 's/\b'"${pkg}"'\b//' /tmp/.trash/installed
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "only add/del: wrong usage"; exit
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
_preserve() {
|
||||||
|
[ -f "$1" ] && cp "$1" "${1}.orig"
|
||||||
|
}
|
||||||
|
|
||||||
|
_restore() {
|
||||||
|
if [ -f "${1}.orig" ]; then
|
||||||
|
mv -- "${1}.orig" "${1}"
|
||||||
|
else
|
||||||
|
rm -rf "${1}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
##### End of part to be dupplicated into post-cleanup (do not alter!)
|
||||||
|
|
||||||
|
|
||||||
# Redirect stdout and errors to console as rc.local does not log anything
|
# Redirect stdout and errors to console as rc.local does not log anything
|
||||||
exec 1>/dev/console 2>&1
|
exec 1>/dev/console 2>&1
|
||||||
|
|
||||||
logger -st ${0##*/} "Alpine Linux headless bootstrap v$VERSION by macmpi"
|
logger -st ${0##*/} "Alpine Linux headless bootstrap v$VERSION by macmpi"
|
||||||
|
|
||||||
mkdir /tmp/.trash
|
mkdir /tmp/.trash
|
||||||
ovlpath=$( find /media -maxdepth 2 -type d -path '*/.*' -prune -o -type f -name *.apkovl.tar.gz -exec dirname {} \; | head -1 )
|
|
||||||
|
|
||||||
# Help randomess for wpa_supplicant and ssh server
|
# grab used ovl filename from dmesg
|
||||||
|
ovl="$( dmesg | grep -o 'Loading user settings from .*:' | awk '{print $5}' | sed 's/:.*$//' )"
|
||||||
|
ovlpath="$( dirname "$ovl" )"
|
||||||
|
|
||||||
|
# Help randomness for wpa_supplicant and ssh server
|
||||||
rc-service seedrng start
|
rc-service seedrng start
|
||||||
|
|
||||||
## Setup Network interfaces
|
## Setup Network interfaces
|
||||||
if [ -f "${ovlpath}/wpa_supplicant.conf" ]; then
|
if [ -f "${ovlpath}/wpa_supplicant.conf" ]; then
|
||||||
logger -st ${0##*/} "Wifi setup found !"
|
logger -st ${0##*/} "Wifi setup found !"
|
||||||
apk add wpa_supplicant
|
_apk add wpa_supplicant
|
||||||
|
_preserve "/etc/wpa_supplicant/wpa_supplicant.conf"
|
||||||
install -m600 "${ovlpath}/wpa_supplicant.conf" /etc/wpa_supplicant/wpa_supplicant.conf
|
install -m600 "${ovlpath}/wpa_supplicant.conf" /etc/wpa_supplicant/wpa_supplicant.conf
|
||||||
else
|
else
|
||||||
logger -st ${0##*/} "Wifi setup not found !"
|
logger -st ${0##*/} "Wifi setup not found !"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
_preserve "/etc/network/interfaces"
|
||||||
if ! install -m644 "${ovlpath}/interfaces" /etc/network/interfaces; then
|
if ! install -m644 "${ovlpath}/interfaces" /etc/network/interfaces; then
|
||||||
# set default interfaces if not specified by interface file on boot storage
|
# set default interfaces if not specified by interface file on boot storage
|
||||||
logger -st ${0##*/} "No interfaces file supplied, building default interfaces..."
|
logger -st ${0##*/} "No interfaces file supplied, building default interfaces..."
|
||||||
|
@ -74,18 +116,21 @@ fi
|
||||||
echo "Using following network interfaces:"
|
echo "Using following network interfaces:"
|
||||||
cat /etc/network/interfaces
|
cat /etc/network/interfaces
|
||||||
|
|
||||||
|
_preserve "/etc/hostname"
|
||||||
echo "alpine-headless" > /etc/hostname
|
echo "alpine-headless" > /etc/hostname
|
||||||
hostname -F /etc/hostname
|
hostname -F /etc/hostname
|
||||||
|
|
||||||
grep -q "wlan" /etc/network/interfaces && [ -f /etc/wpa_supplicant/wpa_supplicant.conf ] && rc-service wpa_supplicant start
|
grep -q "wlan" /etc/network/interfaces && \
|
||||||
|
[ -f /etc/wpa_supplicant/wpa_supplicant.conf ] && \
|
||||||
|
rc-service wpa_supplicant start
|
||||||
rc-service networking start
|
rc-service networking start
|
||||||
|
|
||||||
|
|
||||||
## Setup temporary SSH server (root login, no password)
|
## Setup temporary SSH server (root login, no password)
|
||||||
## we use some bundled or optionaly provided keys to avoid generation at startup and save time
|
## We use some bundled (or optionaly provided) keys to avoid generation at startup and save time
|
||||||
apk add openssh
|
_apk add openssh
|
||||||
cp /etc/ssh/sshd_config /etc/ssh/sshd_config.orig
|
_preserve "/etc/ssh/sshd_config"
|
||||||
cp /etc/conf.d/sshd /etc/conf.d/sshd.orig
|
_preserve "/etc/conf.d/sshd"
|
||||||
|
|
||||||
cat <<-EOF >> /etc/ssh/sshd_config
|
cat <<-EOF >> /etc/ssh/sshd_config
|
||||||
AuthenticationMethods none
|
AuthenticationMethods none
|
||||||
|
@ -95,20 +140,29 @@ cat <<-EOF >> /etc/ssh/sshd_config
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
# Banner file
|
# Banner file
|
||||||
|
warn=""
|
||||||
|
grep -q "${ovlpath}.*[[:space:]]ro[[:space:],]" /proc/mounts; RO=$?
|
||||||
|
[ "$RO" -eq "0" ] && warn="(remount partition rw!)"
|
||||||
|
|
||||||
cat <<-EOF > /tmp/.trash/banner
|
cat <<-EOF > /tmp/.trash/banner
|
||||||
|
|
||||||
Alpine Linux headless bootstrap v$VERSION by macmpi
|
Alpine Linux headless bootstrap v$VERSION by macmpi
|
||||||
|
|
||||||
|
You may want to delete/rename .apkovl file before reboot ${warn}:
|
||||||
|
$ovl
|
||||||
|
(can be done automatically with unattended script - see sample snippet)
|
||||||
|
|
||||||
|
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
# Bundled temporary keys are moved in RAM /tmp so they won't be stored
|
# Bundled temporary keys are moved in RAM /tmp so they won't be stored
|
||||||
# within permanent config later (new ones will then be generated)
|
# within permanent config later (new ones will then be generated at reboot)
|
||||||
KEYGEN_STANCE="sshd_disable_keygen=yes"
|
KEYGEN_STANCE="sshd_disable_keygen=yes"
|
||||||
mv /etc/ssh/ssh_host_*_key* /tmp/.trash/.
|
mv /etc/ssh/ssh_host_*_key* /tmp/.trash/.
|
||||||
|
|
||||||
# Inject optional custom keys (those might be stored)
|
# Inject optional custom keys (those might be stored)
|
||||||
if install -m600 "${ovlpath}"/ssh_host_*_key* /etc/ssh/; then
|
if install -m600 "${ovlpath}"/ssh_host_*_key* /etc/ssh/; then
|
||||||
# check for empty key within injected ones: generate new keys if found
|
# check for empty key within injected ones: if found, generate new keys
|
||||||
if find /etc/ssh/ -maxdepth 1 -type f -name 'ssh_host_*_key*' -empty | grep -q .; then
|
if find /etc/ssh/ -maxdepth 1 -type f -name 'ssh_host_*_key*' -empty | grep -q .; then
|
||||||
rm /etc/ssh/ssh_host_*_key*
|
rm /etc/ssh/ssh_host_*_key*
|
||||||
KEYGEN_STANCE=""
|
KEYGEN_STANCE=""
|
||||||
|
@ -130,16 +184,19 @@ rc-service sshd start
|
||||||
|
|
||||||
## Prep for final post-cleanup
|
## Prep for final post-cleanup
|
||||||
## clears any installed packages and settings
|
## clears any installed packages and settings
|
||||||
cat <<-EOF > /tmp/.trash/post-cleanup
|
# copy begininng of this file to keep functions
|
||||||
#!/bin/sh
|
sed -n '/^#* End .*alter!)$/q;p' /etc/local.d/headless.start > /tmp/.trash/post-cleanup
|
||||||
|
|
||||||
|
cat <<-EOF >> /tmp/.trash/post-cleanup
|
||||||
|
|
||||||
logger -st ${0##*/} "Cleaning-up..."
|
logger -st ${0##*/} "Cleaning-up..."
|
||||||
mv /etc/ssh/sshd_config.orig /etc/ssh/sshd_config
|
_restore "/etc/ssh/sshd_config"
|
||||||
mv /etc/conf.d/sshd.orig /etc/conf.d/sshd
|
_restore "/etc/conf.d/sshd"
|
||||||
apk del openssh
|
_apk del openssh
|
||||||
apk del wpa_supplicant
|
_restore "/etc/wpa_supplicant/wpa_supplicant.conf"
|
||||||
rm -rf /etc/wpa_supplicant
|
_apk del wpa_supplicant
|
||||||
rm /etc/network/interfaces
|
_restore "/etc/network/interfaces"
|
||||||
rm /etc/hostname
|
_restore "/etc/hostname"
|
||||||
rm /etc/modules-load.d/g_ether.conf
|
rm /etc/modules-load.d/g_ether.conf
|
||||||
rm /etc/modprobe.d/g_ether.conf
|
rm /etc/modprobe.d/g_ether.conf
|
||||||
rc-update del local default
|
rc-update del local default
|
||||||
|
|
|
@ -14,12 +14,13 @@ sleep 60
|
||||||
|
|
||||||
|
|
||||||
## This snippet removes apkovl file on volume after initial boot
|
## This snippet removes apkovl file on volume after initial boot
|
||||||
ovlpath=$( find /media -maxdepth 2 -type d -path '*/.*' -prune -o -type f -name *.apkovl.tar.gz -exec dirname {} \; | head -1 )
|
ovl="$( dmesg | grep -o 'Loading user settings from .*:' | awk '{print $5}' | sed 's/:.*$//' )"
|
||||||
|
ovlpath="$( dirname "$ovl" )"
|
||||||
|
|
||||||
# also works in case volume is mounted read-only
|
# also works in case volume is mounted read-only
|
||||||
grep -q "${ovlpath}.*[[:space:]]ro[[:space:],]" /proc/mounts; RO=$?
|
grep -q "${ovlpath}.*[[:space:]]ro[[:space:],]" /proc/mounts; RO=$?
|
||||||
[ "$RO" -eq "0" ] && mount -o remount,rw "${ovlpath}"
|
[ "$RO" -eq "0" ] && mount -o remount,rw "${ovlpath}"
|
||||||
rm "${ovlpath}"/*.apkovl.tar.gz
|
rm -f "${ovl}"
|
||||||
[ "$RO" -eq "0" ] && mount -o remount,ro "${ovlpath}"
|
[ "$RO" -eq "0" ] && mount -o remount,ro "${ovlpath}"
|
||||||
|
|
||||||
########################################################
|
########################################################
|
||||||
|
|
Loading…
Reference in New Issue