Compare commits
12 Commits
6d0a8021cb
...
bafc443817
Author | SHA1 | Date |
---|---|---|
macmpi | bafc443817 | |
macmpi | 6718b1c311 | |
macmpi | 7e91859180 | |
macmpi | c8de3f87c2 | |
macmpi | 5193a9296b | |
macmpi | a518b2d421 | |
macmpi | fa08356540 | |
macmpi | c41be0072c | |
macmpi | 124f39d1c8 | |
macmpi | 84da591fda | |
macmpi | aa371a2e0c | |
macmpi | 6b903b2670 |
|
@ -0,0 +1,7 @@
|
||||||
|
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
|
||||||
|
|
35
README.md
35
README.md
|
@ -1,41 +1,42 @@
|
||||||
# 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, 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).
|
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 enables a basic ssh server to log-into from another Computer, in order to finalize system setup.
|
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.
|
||||||
|
|
||||||
|
|
||||||
## 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 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-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), 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 after setup!).\
|
As with Alpine Linux initial bring-up, `root` account has no password initially (change that during setup!).\
|
||||||
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).
|
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).
|
||||||
|
|
||||||
|
|
||||||
Add-on files may be added next to `headless.apkovl.tar.gz` to customise setup (sample files are provided):
|
Extra files may be added next to `headless.apkovl.tar.gz` to customise boostrapping configuration (check sample files):
|
||||||
- `wpa_supplicant.conf` (*mandatory for wifi usecase*): define wifi SSID & password.
|
- `wpa_supplicant.conf`[^2] (*mandatory for wifi usecase*): define wifi SSID & password.
|
||||||
- `interfaces` (*optional*): define network interfaces at will, if defaults DCHP-based are not suitable.
|
- `interfaces`[^2] (*optional*): define network interfaces at will, if defaults DCHP-based are not suitable.
|
||||||
- `unattended.sh` (*optional*): make custom automated deployment script to further tune & extend setup (backgrounded).
|
- `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`[^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 which can support USB ethernet gadget networking):\
|
**Goody:** seamless USB bootstrapping for PiZero devices (or similar supporting USB ethernet gadget networking):\
|
||||||
Just add `dtoverlay=dwc2` in `usercfg.txt` (or `config.txt`), and plug-in USB to Computer port.\
|
Just add `dtoverlay=dwc2` in `usercfg.txt` (or `config.txt`), and plug USB cable into 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 /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 RAM /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 further ?
|
## How to customize ?
|
||||||
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.
3
make.sh
3
make.sh
|
@ -1,5 +1,8 @@
|
||||||
#!/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
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
VERSION="0.6"
|
# Copyright 2022 - 2023, macmpi
|
||||||
|
# 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
|
||||||
|
@ -8,19 +11,21 @@ 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 -type d -path '*/.*' -prune -o -type f -name *.apkovl.tar.gz -exec dirname {} \; | head -1 )
|
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
|
||||||
|
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
|
||||||
cp "${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
|
||||||
|
|
||||||
if ! cp "${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..."
|
||||||
for dev in $(ls /sys/class/net)
|
for dev in $(ls /sys/class/net)
|
||||||
|
@ -77,27 +82,50 @@ rc-service networking start
|
||||||
|
|
||||||
|
|
||||||
## Setup temporary SSH server (root login, no password)
|
## Setup temporary SSH server (root login, no password)
|
||||||
## we use some bundled keys to avoid generation at boot and save time
|
## we use some bundled or optionaly provided keys to avoid generation at startup 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
|
||||||
|
|
||||||
mv /etc/ssh/ssh_host_* /tmp/.trash/.
|
|
||||||
|
|
||||||
cp /etc/ssh/sshd_config /etc/ssh/sshd_config.orig
|
cp /etc/ssh/sshd_config /etc/ssh/sshd_config.orig
|
||||||
|
cp /etc/conf.d/sshd /etc/conf.d/sshd.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
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Banner file
|
||||||
|
cat <<-EOF > /tmp/.trash/banner
|
||||||
|
|
||||||
|
Alpine Linux headless bootstrap v$VERSION by macmpi
|
||||||
|
|
||||||
|
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_ed25519_key
|
||||||
HostKey /tmp/.trash/ssh_host_rsa_key
|
HostKey /tmp/.trash/ssh_host_rsa_key
|
||||||
EOF
|
EOF
|
||||||
|
fi
|
||||||
|
|
||||||
cp /etc/conf.d/sshd /etc/conf.d/sshd.orig
|
echo "$KEYGEN_STANCE" >> /etc/conf.d/sshd
|
||||||
cat <<-EOF >> /etc/conf.d/sshd
|
|
||||||
sshd_disable_keygen=yes
|
|
||||||
EOF
|
|
||||||
|
|
||||||
rc-service sshd start
|
rc-service sshd start
|
||||||
|
|
||||||
## Prep for final post-cleanup
|
## Prep for final post-cleanup
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
# 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
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
# 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
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
# Copyright 2022 - 2023, macmpi
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
# Sample network interfaces file
|
# Sample network interfaces file
|
||||||
|
|
||||||
auto lo
|
auto lo
|
||||||
|
|
|
@ -1,6 +1,88 @@
|
||||||
#/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"
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
# Copyright 2022 - 2023, macmpi
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
# Sample wpa_supplicant.conf
|
# Sample wpa_supplicant.conf
|
||||||
country=FR
|
country=FR
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue