Compare commits

..

No commits in common. "bafc443817f2bb46fe3e9382e482200237c6de31" and "6d0a8021cb0a99a8645669ecc97d2d44e1e7f39c" have entirely different histories.

10 changed files with 32 additions and 165 deletions

View File

@ -1,7 +0,0 @@
SPDXVersion: SPDX-2.1
DataLicense: CC0-1.0
PackageName: alpine-linux-headless-bootstrap
PackageOriginator: macmpi
PackageHomePage: https://github.com/macmpi/alpine-linux-headless-bootstrap
PackageLicenseDeclared: MIT

View File

@ -1,42 +1,41 @@
# Deploy Alpine Linux on a headless system # Deploy 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, there are many cases where one might want to deploy a headless system, 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 boot such headless system (leveraging Alpine distro's `initramfs` feature): it enables a basic ssh server to log-into from another Computer, in order to finalize system setup.
## 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)[^1] overlay file at the root of Alpine Linux boot media (or onto any custom side-media) and boot 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), one may then access the system under `ssh` 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`).
As with Alpine Linux initial bring-up, `root` account has no password initially (change that during setup!).\ As with Alpine Linux initial bring-up, `root` account has no password initially (change that after setup!).\
From there, actual system install can be performed as usual with `setup-alpine` for instance (check [wiki](https://wiki.alpinelinux.org/wiki/Alpine_setup_scripts#setup-alpine) for details). From there, system install can be fine-tuned as usual with `setup-alpine` for instance (check [wiki](https://wiki.alpinelinux.org/wiki/Alpine_setup_scripts#setup-alpine) for details).
Extra files may be added next to `headless.apkovl.tar.gz` to customise boostrapping configuration (check sample files): Add-on files may be added next to `headless.apkovl.tar.gz` to customise setup (sample files are provided):
- `wpa_supplicant.conf`[^2] (*mandatory for wifi usecase*): define wifi SSID & password. - `wpa_supplicant.conf` (*mandatory for wifi usecase*): define wifi SSID & password.
- `interfaces`[^2] (*optional*): define network interfaces at will, if defaults DCHP-based are not suitable. - `interfaces` (*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). - `unattended.sh` (*optional*): make custom automated deployment script to further tune & extend setup (backgrounded).
- `unattended.sh`[^2] (*optional*): create custom automated deployment script to further tune & extend actual setup (backgrounded).
*Note:* 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 other).
**Goody:** seamless USB bootstrapping for PiZero devices (or similar supporting USB ethernet gadget networking):\ **Goody:** seamless USB bootstrapping for PiZero devices (or similar which can support USB ethernet gadget networking):\
Just add `dtoverlay=dwc2` in `usercfg.txt` (or `config.txt`), and plug USB cable into Computer port.\ Just add `dtoverlay=dwc2` in `usercfg.txt` (or `config.txt`), and plug-in USB to Computer port.\
With Computer set-up to share networking with USB interface as 10.42.0.1 gateway, one can log into device from Computer with: `ssh root@10.42.0.2` With Computer set-up to share networking with USB interface as 10.42.0.1 gateway, one can log into device from Computer with `ssh root@10.42.0.2` !...
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]: 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 /tmp, so they will **not be saved/reused** once permanent configuration is set (with or without ssh server voluntarily installed in permanent setup).
[^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).
## How to customize ? ## How to customize further ?
This repository may be forked/cloned/downloaded.\ This repository may be forked/cloned/downloaded.\
Main script file is [`headless.start`](https://github.com/macmpi/alpine-linux-headless-bootstrap/blob/main/overlay/etc/local.d/headless.start).\ Main script file is [`headless.start`](https://github.com/macmpi/alpine-linux-headless-bootstrap/blob/main/overlay/etc/local.d/headless.start).\
Execute `./make.sh` to rebuild `headless.apkovl.tar.gz` after changes. Execute `./make.sh` to rebuild `headless.apkovl.tar.gz` after changes.

Binary file not shown.

View File

@ -1,8 +1,5 @@
#!/bin/sh #!/bin/sh
# Copyright 2022 - 2023, macmpi
# SPDX-License-Identifier: MIT
chmod 600 overlay/etc/ssh/ssh_host_*_key chmod 600 overlay/etc/ssh/ssh_host_*_key
chmod +x overlay/etc/local.d/headless.start chmod +x overlay/etc/local.d/headless.start
tar czvf headless.apkovl.tar.gz -C overlay etc --owner=0 --group=0 tar czvf headless.apkovl.tar.gz -C overlay etc --owner=0 --group=0

View File

@ -1,9 +1,6 @@
#!/bin/sh #!/bin/sh
# Copyright 2022 - 2023, macmpi VERSION="0.6"
# SPDX-License-Identifier: MIT
VERSION="0.7"
# 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
@ -11,21 +8,19 @@ 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 ) ovlpath=$( find /media -type d -path '*/.*' -prune -o -type f -name *.apkovl.tar.gz -exec dirname {} \; | head -1 )
# Help randomess for wpa_supplicant and ssh server
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
install -m600 "${ovlpath}/wpa_supplicant.conf" /etc/wpa_supplicant/wpa_supplicant.conf cp "${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
if ! install -m644 "${ovlpath}/interfaces" /etc/network/interfaces; then if ! cp "${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..."
for dev in $(ls /sys/class/net) for dev in $(ls /sys/class/net)
@ -82,50 +77,27 @@ 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 keys to avoid generation at boot and save time
## bundled temporary keys are moved in /tmp so they won't be stored
## within permanent config later (new ones will then be generated)
apk add openssh apk add openssh
cp /etc/ssh/sshd_config /etc/ssh/sshd_config.orig
cp /etc/conf.d/sshd /etc/conf.d/sshd.orig
mv /etc/ssh/ssh_host_* /tmp/.trash/.
cp /etc/ssh/sshd_config /etc/ssh/sshd_config.orig
cat <<-EOF >> /etc/ssh/sshd_config cat <<-EOF >> /etc/ssh/sshd_config
AuthenticationMethods none AuthenticationMethods none
PermitEmptyPasswords yes PermitEmptyPasswords yes
PermitRootLogin yes PermitRootLogin yes
Banner /tmp/.trash/banner HostKey /tmp/.trash/ssh_host_ed25519_key
HostKey /tmp/.trash/ssh_host_rsa_key
EOF EOF
# Banner file cp /etc/conf.d/sshd /etc/conf.d/sshd.orig
cat <<-EOF > /tmp/.trash/banner cat <<-EOF >> /etc/conf.d/sshd
sshd_disable_keygen=yes
Alpine Linux headless bootstrap v$VERSION by macmpi
EOF EOF
# Bundled temporary keys are moved in RAM /tmp so they won't be stored
# within permanent config later (new ones will then be generated)
KEYGEN_STANCE="sshd_disable_keygen=yes"
mv /etc/ssh/ssh_host_*_key* /tmp/.trash/.
# Inject optional custom keys (those might be stored)
if install -m600 "${ovlpath}"/ssh_host_*_key* /etc/ssh/; then
# check for empty key within injected ones: generate new keys if found
if find /etc/ssh/ -maxdepth 1 -type f -name 'ssh_host_*_key*' -empty | grep -q .; then
rm /etc/ssh/ssh_host_*_key*
KEYGEN_STANCE=""
logger -st ${0##*/} "Will generate new SSH keys..."
else
chmod 644 /etc/ssh/ssh_host_*_key.pub
logger -st ${0##*/} "Using injected SSH keys..."
fi
else
logger -st ${0##*/} "Using bundled ssh keys from RAM..."
cat <<-EOF >> /etc/ssh/sshd_config
HostKey /tmp/.trash/ssh_host_ed25519_key
HostKey /tmp/.trash/ssh_host_rsa_key
EOF
fi
echo "$KEYGEN_STANCE" >> /etc/conf.d/sshd
rc-service sshd start rc-service sshd start
## Prep for final post-cleanup ## Prep for final post-cleanup

View File

@ -1,6 +1,3 @@
# Copyright 2022 - 2023, macmpi
# SPDX-License-Identifier: MIT
# added to support USB-Ethernet gadget mode at boot for Pi devices # added to support USB-Ethernet gadget mode at boot for Pi devices
options g_ether dev_addr=ea:64:2f:e8:19:94 host_addr=f6:67:ce:b3:c0:ea options g_ether dev_addr=ea:64:2f:e8:19:94 host_addr=f6:67:ce:b3:c0:ea

View File

@ -1,6 +1,3 @@
# Copyright 2022 - 2023, macmpi
# SPDX-License-Identifier: MIT
# added to support USB-Ethernet gadget mode at boot for Pi devices # added to support USB-Ethernet gadget mode at boot for Pi devices
# also requires dtoverlay=dwc2 is added to usercfg.txt or config.txt # also requires dtoverlay=dwc2 is added to usercfg.txt or config.txt

View File

@ -1,6 +1,3 @@
# Copyright 2022 - 2023, macmpi
# SPDX-License-Identifier: MIT
# Sample network interfaces file # Sample network interfaces file
auto lo auto lo

View File

@ -1,88 +1,6 @@
#/bin/sh #/bin/sh
# Copyright 2022 - 2023, macmpi
# SPDX-License-Identifier: MIT
## collection of few code snippets as sample unnatteded actions some may find usefull
## Obvious one; reminder: is run in the background
echo hello world !! echo hello world !!
sleep 60 sleep 60
########################################################
## 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 )
# also works in case volume is mounted read-only
grep -q "${ovlpath}.*[[:space:]]ro[[:space:],]" /proc/mounts; RO=$?
[ "$RO" -eq "0" ] && mount -o remount,rw "${ovlpath}"
rm "${ovlpath}"/*.apkovl.tar.gz
[ "$RO" -eq "0" ] && mount -o remount,ro "${ovlpath}"
########################################################
## This snippet configures Minimal diskless environment
# note: with INTERFACESOPTS=none, no networking will be setup so it won't work after reboot!
# Change it or run setup-interfaces in interractive mode afterwards (and lbu commit -d thenafter)
logger -st ${0##*/} "Setting-up minimal environment"
cat <<-EOF > /tmp/ANSWERFILE
# base answer file for setup-alpine script
# Do not set keyboard layout
KEYMAPOPTS=none
# Keep hostname
HOSTNAMEOPTS="$(hostname)"
# Set device manager to mdev
DEVDOPTS=mdev
# Contents of /etc/network/interfaces
INTERFACESOPTS=none
# Set Public nameserver
DNSOPTS="-n 208.67.222.222"
# Set timezone to UTC
TIMEZONEOPTS="UTC"
# set http/ftp proxy
PROXYOPTS=none
# Add first mirror (CDN)
APKREPOSOPTS="-1"
# Do not create any user
USEROPTS=none
# No Openssh
SSHDOPTS=none
# Use openntpd
NTPOPTS="chrony"
# No disk install (diskless)
DISKOPTS=none
# Setup storage for diskless (find boot directory in /media/xxxx/apk/.boot_repository)
LBUOPTS="$( find /media -maxdepth 3 -type d -path '*/.*' -prune -o -type f -name '.boot_repository' -exec dirname {} \; | head -1 | xargs dirname )"
APKCACHEOPTS="\$LBUOPTS/cache"
EOF
# trick setup-alpine to pretend existing SSH connection
# and therefore keep (do not reset) network interfaces while running in background
SSH_CONNECTION="FAKE" setup-alpine -ef /tmp/ANSWERFILE
lbu commit -d
########################################################
logger -st ${0##*/} "Finished unattended script" logger -st ${0##*/} "Finished unattended script"

View File

@ -1,6 +1,3 @@
# Copyright 2022 - 2023, macmpi
# SPDX-License-Identifier: MIT
# Sample wpa_supplicant.conf # Sample wpa_supplicant.conf
country=FR country=FR