summaryrefslogtreecommitdiff
path: root/posts/unattended-installation-of-alpine-linux.md
blob: a77e55c8c70f7503647b49e0b920e4d09ce01e8d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
---
title: "Unattended installation of Alpine Linux"
description: "How to customize Alpine Linux installation images for unattended installation."
published: 2023-11-03
---

Today I would like to share a quick and dirty way to perform unattended installations of [Alpine Linux][].
I use it to spin up offline and diskless local virtual machines on OpenBSD's built-in virtual machine monitor [`vmm(4)`][vmm] for one-off tasks such as testing or cross-compiling a piece of software.
However, the method I describe is also suitable for headless installations on your favorite single board computer, and remote installations in the cloud.

The idea is to modify one of Alpine's official ISO 9660 images to run a custom script on boot.
The script feeds prepared answers to Alpine's main installation script, [`setup-alpine`][setup-alpine], and performs some optional adjustments.

To begin with, download one of Alpine's installation images from the official [downloads page][downloads].
I chose the *virtual* image because of it's small size, but you can also use the *extended* image if you like.

    $ curl --location --remote-name-all \
        https://dl-cdn.alpinelinux.org/alpine/v3.18/releases/x86_64/alpine-virt-3.18.4-x86_64{.iso,.iso.sha256,.iso.asc}
    $ sha256 -c alpine-*.iso.sha256

If you wish to verify the PGP signature, you need to import Alpine's PGP key first.

    $ curl --location https://alpinelinux.org/keys/ncopa.asc |
        gpg --import -
    $ gpg --verify alpine*.iso.asc

Next, we create a so-called *overlay file*.
This is essentially a tarball to be extracted in the file system root.
See the [wiki page][lbu] on Alpine's local backup utility.

Create a directory for the overlay:

    $ mkdir ovl

Enable the default boot services as described [here][custom_iso]:

    $ mkdir -p ovl/etc
    $ touch ovl/etc/.default_boot_services

Enable the `local` service.
This service will run our custom installation script on boot.

    $ mkdir -p ovl/etc/runlevels/default
    $ ln -sf /etc/init.d/local ovl/etc/runlevels/default

Configure the APK repositories in `ovl/etc/apk/repositories`:

    /media/cdrom/apks
    https://dl-cdn.alpinelinux.org/alpine/v3.18/main
    https://dl-cdn.alpinelinux.org/alpine/v3.18/community

Add our custom installation script `ovl/etc/local.d/auto-setup-alpine.start`.
Feel free to adapt the script to your personal needs.
Take care though.
You cannot see the script's output on the console.

```
#! /bin/sh

set -o errexit
set -o nounset

# Uncomment to shutdown on completion.
#trap 'poweroff' EXIT INT

# Close standard input.
exec 0<&-

# Run only once.
rm -f /etc/local.d/auto-setup-alpine.start
rm -f /etc/runlevels/default/local

timeout 300 setup-alpine -ef /etc/auto-setup-alpine/answers
rm -rf /etc/auto-setup-alpine

# Disable password authentication
sed -i -e 's/^root:x:/root:*:/' -e 's/^stefan:x:/stefan:*:/' /etc/passwd
sed -i -e 's/^root:[^:]*/root:*/' -e 's/^stefan:[^:]*/stefan:*/' /etc/shadow

apk update
apk upgrade

apk add man-pages mandoc mandoc-apropos docs

cat >/etc/doas.d/site.conf <<EOF
permit nopass :wheel
permit nopass keepenv root
EOF

# Uncomment for sys install.
#sed -i -e 's/relatime/noatime/' /etc/fstab
```

Ensure that the script is executable:

    $ chmod 755 ovl/etc/local.d/auto-setup-alpine.start

Put the answers for the [`setup-alpine`][setup-alpine] script into `ovl/etc/auto-setup-alpine/answers`.
Feel free to adapt the answers to your personal needs.
You can run `setup-alpine -c answers` to create a new answer file with the defaults.
Or you can [read the source][default_answers].

```
KEYMAPOPTS=none
HOSTNAMEOPTS=alpine
DEVDOPTS=mdev
TIMEZONEOPTS="-z UTC"
PROXYOPTS=none
APKREPOSOPTS="-1"
SSHDOPTS=openssh
NTPOPTS="openntpd"

# Diskless
DISKOPTS=none
LBUOPTS=none
APKCACHEOPTS=none

# Admin user name and ssh key.
USEROPTS="-a -u -g audio,video,netdev stefan"
USERSSHKEY="ssh-rsa AAA... stefan@localhost"

# Contents of /etc/network/interfaces
INTERFACESOPTS="auto lo
iface lo inet loopback

auto eth0
iface eth0 inet dhcp
"
```

Create the actual overlay file using GNU tar:

    $ tar --owner=0 --group=0 -czf localhost.apkovl.tar.gz -C ovl .

Add the overlay file to the ISO 9660 image using [GNU xorriso][].
Note that the prefix of the overlay file name must be the hostname of the target machine, in this case `localhost`.

    $ xorriso \
      -indev alpine-virt-3.18.4-x86_64.iso \
      -outdev my-alpine.iso \
      -map localhost.apkovl.tar.gz /localhost.apkovl.tar.gz \
      -boot_image any replay

That's it.
You can boot off this image and await a completely unattended installation of Alpine Linux.

[Alpine Linux]: https://www.alpinelinux.org/
[setup-alpine]: https://wiki.alpinelinux.org/w/index.php?title=Alpine_setup_scripts&oldid=25337#setup-alpine
[downloads]: https://www.alpinelinux.org/downloads/
[lbu]: https://wiki.alpinelinux.org/w/index.php?title=Alpine_local_backup&oldid=25418
[custom_iso]: https://wiki.alpinelinux.org/w/index.php?title=How_to_make_a_custom_ISO_image_with_mkimage&oldid=25379#Create_the_ISO
[GNU xorriso]: https://www.gnu.org/software/xorriso/
[vmm]: https://man.openbsd.org/OpenBSD-7.4/vmm
[default_answers]: https://gitlab.alpinelinux.org/alpine/alpine-conf/-/blob/80370671291376ee040e5e25c0ea38a9c0780f2a/setup-alpine.in#L81
Generated by cgit. See skreutz.com for my tech blog and contact information.