summaryrefslogtreecommitdiff
path: root/README.md
blob: 1cb82b3b1745c02c77e7485f0a35d5451a1bc5d8 (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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
# v-i---a Debian installer using vmdb2

**WARNING: Running v-i is like waking up after an alien invasion, in a
post-apocalyptic world, with everything you knew or owned gone
forever. When you run v-i, it *will* wipe away everything on that
computer. All volume groups will be deleted, all storage drives
emptied. Any existing partitions will be lost. Forget any data you
used to have, and operating systems you used to have installed. If you
don't know what you're doing, leave.**

**v-i** installs enough of Debian installed so that the system can be
configured with a configuration management system once it's up an
running. **v-i** isn't meant to install a full desktop stack or
service suite: it's meant to provide a base on which such can be
installed. However, **v-i** can probably do that, but the [author][]
thinks such setup and configuration is better done post-install.

**v-i** installs a very basic system that is only really suitable as a
target for provisioning using your configuration management system of
choice (the author uses Ansible). The basic system allows you to log
in as root with SSH using the key you provide to **v-i**. The
installer removes all partitions on all drives on the system, and sets
up LUKS and LVM2 on all the drives you specify. It sets up the time
zone and console keyboard layout you specify. The installed system is
fairly basic, but functional. Anything else you'll have to install and
configure yourself.

**v-i** installs a very basic Debian onto a PC. It's entirely
non-interactive and unhelpful. The author wrote it so that repeated
installations would be less of a chore than using the official Debian
installer. (Actually, the author thought it'd be a quick, easy hack,
and was too stubborn to give up, when it turned out to be a bit
tricky. What was meant to be a weekend hack turned into a multi-year
project, on and off.)

 **v-i** uses **vmdb2** to install onto bare metal hardware.
[**vmdb2**][] is a program to create a disk image virtual machines
with Debian, by the same author. It "installs Debian" to a file
representing a hard drive. It's basically [debootstrap][], except the
target is a disk image instead of a directory. It's used to create
[Debian images for Raspberry Pis][].

To use **v-i** to install Debian on a PC:

* Boot the target machine off a live system that has **v-i**
  installed.
  - the author uses a USB stick with an image built with the
    [`build-installer.sh`][] script
  - the author logs into the installer system via SSH
* Create a v-i target specification file. See below for an example.
* Run the command: `v-i --verbose exolobe5.yaml`
* See `installer.log` for what happened during the installation, if
  anything failed.

Example target specification file:

```yaml
hostname: exolobe5
drive: /dev/nvme0n1
```

See [spec.md][] for a full description of the target specification
file.

With all this configuration in a file, which you can keep in git, you
can install a base system repeatedly to a specific computer, and do it
the same way every time. If that's not something you do, then you may
want to use the official Debian installer instead.

(Caveat: **v-i** does nothing to configure your BIOS/UEFI. It can't.
You have to manually configure it the way you want it to be. For
example, one of the author's machines needs to have its boot order
adjusted after every operating system installation. It's quite
tedious.)

[**vmdb2**]: https://vmdb2.liw.fi/
[debootstrap]: https://wiki.debian.org/Debootstrap
[Debian images for Raspberry Pis]: https://raspi.debian.net/
[`build-installer.sh`]: build-installer.sh
[`v-i`]: v-i
[`std.yml`]: std.yml
[spec.md]: spec.md
[tutorial]: tutorial.md
[author]: https://liw.fi/
[Debian installer]: https://www.debian.org/devel/debian-installer/
[preseed files]: https://wiki.debian.org/DebianInstaller/Preseed
[udeb]: https://en.wikipedia.org/wiki/Deb_(file_format)

## Motivation

The official [Debian installer][] is often referred to as _d-i_. It
works quite well, for almost any hardware Debian can run on, and
supports a lot of languages, and it's flexible enough to be acceptable
for nearly every use case. Millions upon millions of people are
satisfied users of it. It is a great achievement of Debian, and the
people of the `debian-boot` team.

However, the **v-i** author felt it was lacking for their needs:

* d-i is not entirely easy to understand and modify. It requires
  building special [udeb][] packages for any software that's to be
  part of the installer environment, which makes it harder to make
  changes to the installer without co-operation from maintainers of
  those packages. The architecture of d-i is also a little non-linear.
  d-i also needs to support a very wide variety of hardware and use
  cases, which has made it large and complex.

  **v-i** is happy with normal deb packages, and is a thin Python
  wrapper script around **vmdb2**, making it reasonably easy to
  understand and change. Well, easy for its author. The price for this
  is less flexibility and less ease of use.

* d-i is primarily meant to be used interactively, but it does support
  [preseed files][] for automating an installation. Preseeding means
  providing answers, in a file, to questions a package being installed
  may ask during its installation. This is fine, if a little
  cumbersome, but only helps to answer questions the packages ask when
  installed.

  **v-i** lets you have the full power of Ansible during initial
  installation.

If **v-i** isn't suitable for your uses, that's OK. The author is
happy with his toy.


## Architecture

**vmdb2** is given a sequence of _steps_ to execute: create this
partition, make that file system, install those packages, etc.
**vmdb2** runs the steps against a disk image or physical hard drive,
with a chroot of the file systems, to do things like installing a
package in the system being installed.

**v-i** defines a fairly minimal _standard install_, whose goal is to
get the target system into a state where it boots from its own,
internal storage, and where the rest of the system configuration can
be finished using your configuration management system of choice. The
standard system looks like this:

* UEFI boot, with an EFI partition (500 MiB)
* a cleartext `/boot` partition (500 MiB)
* LVM2 for the rest of the target drive, and all extra drives
  - one VG
  - no RAID at this time
* optional LUKS for all physical volumes, using the same passphrase
* a `root` LV (20 GiB)
* the rest of the VG not allocated
* a basic Debian installation
  - network setup on `eth0` using `systemd-networkd`
  - optionally wifi using `systemd-networkd` and `iwd`
  - SSH host key and host certificate installed if defined
  - `root` password is locked, no login on console
  - log in as `root` allowed over SSH using a key or user certificate

While **vmdb2** can, and does, run Ansible to configure the system
being installed, in practice some things work better if most
configuration is done to a running system; if nothing else, some
Ansible modules don't work well in a chroot. The goal of **v-i** is to
get a system into that state as quickly and easily as possible. For
example, the Ansible module to set a hostname on a system with systemd
requires systemd to be running. That's awkward while the system is
still being installed in a chroot.

Thus, **v-i** does the following:

* delete any trace of LVM2 from all drives, erase all SSDs (securely,
  if possble), and generally reset the system to as close to a blank
  state as possible
  - __there is no question "are you sure?" to give the user a chance to
    repent: as soon as you run **v-i**, you've lost all your data__
* create a partition table ("label") on the target drive
* create cleartext EFI and boot partitions, needed to boot with UEFI
  and LUKS
* create a physical volume for LVM2, and a logical volume for the root
  file system
  - add any additional drives as physical volumes to the volume group
  - optionally use LUKS2 for full disk encryption for each physical
    volume (LUKS2 for `argon2id` support)
* install the Debian base system
  - run `debootstrap`, install a boot loader, and create fstab and
    `crypttab` files
* run the standard Ansible playbook (see [`std.yml`][])
  - set hostname
  - set keyboard layout
  - configure networking (using systemd-networkd)
  - install an SSH server
  - add a chosen SSH public key to the root user's authorized keys
    file
  - other configuration
* run any additional playbooks provided by the user

**v-i** uses the **vmdb2** caching feature, where the results of
`debootstrap` and some other steps get stored in a compressed tar
archive. On subsequent runs, if the cache file exists, it's unpacked,
instead of running the commands. This speeds things up a bit: running
**v-i** without the cache file takes the author about 5 minutes; with
the cache file it takes about 1.5 minutes. This matters if there is a
need to do many installations. It also matters if you're developing
an installer and need to run it tens of times a day.


## Hacking

The main files of **v-i** are:

* [`v-i`][]---the actual installer, a Python script
* [`std.yml`][]---the Ansible playbook to configure a standard install

Also, to build an image to boot off for running the installer:

* `build-installer.sh`---build a disk image where **v-i** can be run
  - put image on a USB drive, boot off that drive, run installer
  - note that you can use any live image with **vmdb2** installed; the
    image built with this is just the easiest for the author
* `installer.vmdb`---the **vmdb2** specification file for creating the
  installer image
* `installer.yml`---the Ansible playbook for creating the installer
  image

See the [tutorial][] about ways to add your SSH public key to the image so
that you can log into the installer via SSH.

You probably mostly only need to modify `v-i` and `std.yml`. The rest
is to get you and your target machine into a state where you can run
the installer. If you have a working installer image, you can update
those two files by copying new versions into place: this is much
faster than building a whole new installer image.

## Building the installer image

To build the installer image, run the following on a Debian system
with the required dependencies installed and access to the Internet:

~~~sh
sudo ./build-installer.sh ~/installer.tar.gz
~~~

The file name argument, `~/installer.tar.gz`, specifies what file to
use to cache the output of `debootstrap` between runs of the script.
The cache is created if it doesn't exist, and is used to speed up
repeated builds significantly. You need to use different cache if you
change the `deboottrap` or `apt` steps in the `installer.vmdb` file.

## FAQ

This section is prescient: the author hasn't been asked any questions
yet, but expects the following to be asked.

### What version of Debian does v-i install?

**v-i** installs the Debian stable release, by default. That's version
12 (bookworm) at the time of writing this. You can install other
versions by setting the `debian_release` field in the target
specification file. Any version from Debian 11 onward should work.

### What about other releases of Debian?

The Debian 11 (bullseye) release is the earliest release the author
has gotten to work with **v-i**.

### Is only UEFI supported?

Yes.

### Why is BIOS (without UEFI) not supported?

All of the author's PCs have UEFI, and the author doesn't care to do
the work to add support for BIOS.

### What about multi-boot?

**v-i** doesn't support installing more than one operating system on
one computer. The author has no need for this.

### What about installing something else than Debian?

The author only cares about Debian, but in principle, fairly little of
**vmdb2** and **v-i** are specific to Debian. It should be possible to
add support for other operating systems to be installed, at least ones
based on Linux. If you're interested, you need to change or replace at
least the following steps in **vmdb2** code, and then change the
[`v-i`][] script to generate a specification using those steps:

* `debootstrap`---install base operating system into a directory
  - after this step, all the files in a base installation should be in
    the specified directory tree, except the boot loader and kernel
  - could probably be replaced with providing **v-i** with a pre-built
    cache tar archive
* `apt`---install packages
  - whatever package manager the system has probably works
  - you can probably run the package manager from a **vmdb2** `chroot` step
* `grub`---install boot loader
  - this chooses the appropriate Debian package automatically
  - might possibly be doable as a `shell` step
  - this is likely the trickiest bit: booting is _intricate_
* `cryptsetup`---format a drive for full disk encryption
  - this just runs the `cryptsetup` program and tells the fstab step
    to create a crypttab file
  - might just work
* `vgcreate` and `lvcreate`---create LVM2
  - these just run the relevant LVM2 commands
  - might just work

### What about other kinds of computers than PCs?

The author only uses 64-bit PC computers (`amd64` arhitecture in
Debian; also known as x86-64). **v-i** may well work for other
kinds of computers, as long as they can boot off an installer image
("live image"), and use GRUB for booting. The author would be
interested to hear if that is the case.

### Why is the LUKS password in cleartext?

It would be ideal if **v-i** (or **vmdb2**) got the LUKS password for
full disk encryption in a secure way from a secure source, but that
turned out to be tricky to do. The author felt it was too tricky to do
well in the installer environment, while it's pretty easy to do in a
running system. Thus, the cleartext password _in the installer_ is a
compromise. You're expected to change the password after the
installation is done.

It would be possible to ask the person doing the installation to enter
the password manually, but this would mean the installation would not
be fully automated. The author didn't want that.

### Do I have to use Ansible?

No. Use whatever you like once you've installed a system with **v-i**
and booted it. **v-i** itself uses Ansible, because that was easy for
the author to use.

## Can I use wifi?

The installer image has all the wifi firmware packages in Debian and
`iwd` installed, but does not automatically connect to a wifi network.
To connect:

~~~sh
iwctl station wlan0 get-networks
iwctl stations wlan0 connect Valkama
~~~

The first command lists available networks. The second one connects to
a specific one. WPA2 with pre-shared keys (passwords) is supported.

`iwctl` and `iwd` remember the network you've connected to, and will
connect to one automatically in the future after booting.

To avoid having to connect manually even once, you can add the
following lines to the `configure-installer` (or `write-config.sh`)
configuration file:

~~~yaml
wifi_name: Valkama
wifi_password: notopen
~~~

The installed system is plain Debian, and you can configure it to
support wifi as you would any other Debian system. The `v-i` installer
**does** copy over the wifi credentials to the installed system.

### I'd like to use v-i, but I need changes

If you can make the changes yourself, go ahead: this is free and open
source software, have at it. If you don't have the skill or time to
make changes yourself, you'll need to find someone else to make them.
This might require paying them.

The author is, unfortunately, probably not willing to spend their free
time to make changes that don't benefit them directly, for free.
Sorry. They _are_ willing to review and merge changes that would make
the software better. (Also, the author is willing to be paid for such
work, for corporate customers. Unfortunately, invoicing private people
is too complicated.)

### Why write v-i, when X, Y, and Z already exist?

The author likes writing software, and dislikes evaluating software.


# Legalese

Copyright 2018-2022  Lars Wirzenius

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.