summaryrefslogtreecommitdiff
path: root/assets/zfssetup
blob: 6bc95ca6c766a634f7331968a4cd7a9b6804708c (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
398
399
400
401
402
403
404
405
406
#!/usr/bin/env bash
# install arch linux on zfs root, stage one
# Craig Jennings <c@cjennings.net>
#
# https://openzfs.github.io/openzfs-docs/Getting%20Started/Arch%20Linux/Root%20on%20ZFS.html

# set -e # halt on any error

#  -------------------------- Prerequisites --------------------------

sed -i "s/^#ParallelDownloads = 5$/ParallelDownloads = 15/" /etc/pacman.conf
loadkeys us
timedatectl set-ntp true

###  --------------------------- Choose Disk ---------------------------

all_disk_ids=( $(ls /dev/disk/by-id/) )
echo ""; echo "Select the disk id to use. All data will be erased."
select disk_id in "${all_disk_ids[@]}"; do
    # ensure valid selection
    if [[ -n $disk_id ]]; then
        selection=$disk_id
        break
    else
        echo "Invalid. Try again."
    fi
done

# Confirm the selected disk
read -p "Confirm: '$selection' [y/n]? " choice
if [[ "$choice" != "y" ]]; then
    echo "Exiting..."
    exit 1
fi

DISK="/dev/disk/by-id/$selection"
MNT=/mnt   # Set a mount point
SWAPSIZE=4 # Set swap size in GB
RESERVE=1  # Set how much space to leave at the end of disk, minimum 1GB

###  --------------------------- Erase Disk -------------------------

echo ""; echo "### Erasing Disk"
blkdiscard -f "${DISK}" || true    # discard all sectors on flash-based storage
sgdisk --zap-all "${DISK}"         # clear the disk

###  ------------------------- Partition Disk ------------------------

echo ""; echo "### Partitioning Disk"
parted --script --align=optimal  "${DISK}" -- \
 mklabel gpt \
 mkpart EFI 2MiB 1GiB \
 mkpart bpool 1GiB 5GiB \
 mkpart rpool 5GiB -$((SWAPSIZE + RESERVE))GiB \
 mkpart swap  -$((SWAPSIZE + RESERVE))GiB -"${RESERVE}"GiB \
 mkpart BIOS 1MiB 2MiB \
 set 1 esp on \
 set 5 bios_grub on \
 set 5 legacy_boot on

###  ---------------------- Setup Encrypted Swap ---------------------

echo ""; echo "### Encrypted Swap"
for i in ${DISK}; do
   cryptsetup open --type plain --key-file /dev/random "${i}"-part4 "${i##*/}"-part4
   mkswap /dev/mapper/"${i##*/}"-part4
   swapon /dev/mapper/"${i##*/}"-part4
done

#  ------------------- Create Boot And Root Pools ------------------

# This step creates a separate boot pool for /boot with the features limited to
# only those that GRUB supports, allowing the root pool to use any/all features.

echo ""; echo "### Checking ZFS Module"
modprobe zfs # ensure zfs module is loaded

echo ""; echo "### Creating Boot Pool"
# shellcheck disable=SC2046
zpool create -d \
    -o feature@async_destroy=enabled \
    -o feature@bookmarks=enabled \
    -o feature@embedded_data=enabled \
    -o feature@empty_bpobj=enabled \
    -o feature@enabled_txg=enabled \
    -o feature@extensible_dataset=enabled \
    -o feature@filesystem_limits=enabled \
    -o feature@hole_birth=enabled \
    -o feature@large_blocks=enabled \
    -o feature@lz4_compress=enabled \
    -o feature@spacemap_histogram=enabled \
    -o ashift=12 \
    -o autotrim=on \
    -O acltype=posixacl \
    -O canmount=off \
    -O compression=lz4 \
    -O devices=off \
    -O normalization=formD \
    -O relatime=on \
    -O xattr=sa \
    -O mountpoint=/boot \
    -R "${MNT}" \
    bpool \
    $(for i in ${DISK}; do
       printf '%s ' "${i}-part2";
      done)

echo ""; echo "### Creating Root Pool"
# shellcheck disable=SC2046
zpool create \
    -o ashift=12 \
    -o autotrim=on \
    -R "${MNT}" \
    -O acltype=posixacl \
    -O canmount=off \
    -O compression=zstd \
    -O dnodesize=auto \
    -O normalization=formD \
    -O relatime=on \
    -O xattr=sa \
    -O mountpoint=/ \
    rpool \
   $(for i in ${DISK}; do
      printf '%s ' "${i}-part3";
     done)

echo ""; echo "### Creating Unencrypted Root System Container"
# create UNENCRYPTED root system container
zfs create \
 -o canmount=off \
 -o mountpoint=none \
rpool/archlinux

#  --------------------- Create System Datasets --------------------

echo ""; echo "### Creating System Datasets"
zfs create -o canmount=noauto -o mountpoint=/  rpool/archlinux/root
zfs mount rpool/archlinux/root
zfs create -o mountpoint=legacy rpool/archlinux/home
mkdir "${MNT}"/home
mount -t zfs rpool/archlinux/home "${MNT}"/home
zfs create -o mountpoint=legacy  rpool/archlinux/var
zfs create -o mountpoint=legacy rpool/archlinux/var/lib
zfs create -o mountpoint=legacy rpool/archlinux/var/log
zfs create -o mountpoint=none bpool/archlinux
zfs create -o mountpoint=legacy bpool/archlinux/root
mkdir "${MNT}"/boot
mount -t zfs bpool/archlinux/root "${MNT}"/boot
mkdir -p "${MNT}"/var/log
mkdir -p "${MNT}"/var/lib
mount -t zfs rpool/archlinux/var/lib "${MNT}"/var/lib
mount -t zfs rpool/archlinux/var/log "${MNT}"/var/log

#  ---------------------- Format And Mount ESP ---------------------

echo ""; echo "### Format And Mount ESP"
for i in ${DISK}; do
 mkfs.vfat -n EFI "${i}"-part1
 mkdir -p "${MNT}"/boot/efis/"${i##*/}"-part1
 mount -t vfat -o iocharset=iso8859-1 "${i}"-part1 "${MNT}"/boot/efis/"${i##*/}"-part1
done

mkdir -p "${MNT}"/boot/efi
mount -t vfat -o iocharset=iso8859-1 "$(echo "${DISK}" | sed "s|^ *||"  | cut -f1 -d' '|| true)"-part1 "${MNT}"/boot/efi

###  -------------------------- Install Base -------------------------

echo ""; echo "### Installing Base"
# install packages with pacstrap
pacstrap "${MNT}" \
         base \
         base-devel \
         dkms \
         efibootmgr \
         git \
         grub \
         intel-ucode \
         linux-firmware \
         linux-lts \
         linux-lts-headers \
         man-db \
         man-pages \
         vi

# create fstab and remove all zroot entries
echo ""; echo "### Creating fstab"
genfstab -U -p "${MNT}" >> "${MNT}"/etc/fstab
sed -i '/^# zroot/d' "${MNT}"/etc/fstab
sed -i '/^zroot/d' "${MNT}"/etc/fstab
sed -i '/^$/d' "${MNT}"/etc/fstab
echo "" >> "${MNT}"/etc/fstab # one blank line at the end

# copy over dns settings to the new system
echo ""; echo "### Copying DNS Settings"
cp -v /etc/resolv.conf "${MNT}"/etc

#  ----------------------------- Chroot ----------------------------
# copy second part of this script to the new system

echo ""; echo "### Copying script then chrooting"
sed '1,/^#part2$/d' `basename $0` >  "${MNT}"/root
chroot "${MNT}" /usr/bin/env DISK="${DISK}" /root/stage2.sh

#  -------------------------- After Chroot -------------------------

umount -Rl "${MNT}"
zfs snapshot -r rpool@initial-installation
zfs snapshot -r bpool@initial-installation

zpool export -a

echo ""; echo "### Done with Stage Two"

#part2
#!/usr/bin/env bash
# install arch linux on zfs root, stage two
# Craig Jennings <c@cjennings.net>

printf '\033c'

password="welcome" # root password; will force change after login
hostname="velox"
disk=/dev/nvme0n1

yay_repo="https://aur.archlinux.org/yay.git"
source_dir="/usr/src"
logfile=/root/zfsarch_stage2.log

cd # go home

#  --------------------- Add ArchZFS Repository --------------------

pacman-key --init
pacman-key --refresh-keys
pacman-key --populate

curl --fail-early --fail -L https://archzfs.com/archzfs.gpg \
|  pacman-key -a - --gpgdir /etc/pacman.d/gnupg

pacman-key \
--lsign-key \
--gpgdir /etc/pacman.d/gnupg \
DDF7DB817396A49B2A2723F7403BD972F75D9D76

tee -a /etc/pacman.d/mirrorlist-archzfs <<- 'EOF'
## See https://github.com/archzfs/archzfs/wiki
## France
#,Server = https://archzfs.com/$repo/$arch

## Germany
#,Server = https://mirror.sum7.eu/archlinux/archzfs/$repo/$arch
#,Server = https://mirror.biocrafting.net/archlinux/archzfs/$repo/$arch

## India
#,Server = https://mirror.in.themindsmaze.com/archzfs/$repo/$arch

## United States
#,Server = https://zxcvfdsa.com/archzfs/$repo/$arch
EOF

tee -a /etc/pacman.conf <<- 'EOF'

#[archzfs-testing]
#Include = /etc/pacman.d/mirrorlist-archzfs

#,[archzfs]
#,Include = /etc/pacman.d/mirrorlist-archzfs
EOF

# this #, prefix is a workaround for ci/cd tests
# remove them
sed -i 's|#,||' /etc/pacman.d/mirrorlist-archzfs
sed -i 's|#,||' /etc/pacman.conf
sed -i 's|^#||' /etc/pacman.d/mirrorlist

#  ---------- Install Packages And Linux Compatible Kernel ---------
pacman -Sy

kernel_compatible_with_zfs="$(pacman -Si zfs-linux \
| grep 'Depends On' \
| sed "s|.*linux=||" \
| awk '{ print $1 }')"
pacman -U --noconfirm https://america.archive.pkgbuild.com/packages/l/linux/linux-"${kernel_compatible_with_zfs}"-x86_64.pkg.tar.zst

pacman -S --noconfirm zfs-linux zfs-utils

#  ---------------------- Configure Mkinitcpio ---------------------

sed -i 's|filesystems|zfs filesystems|' /etc/mkinitcpio.conf
mkinitcpio -P

#  ------------------------- General Hostid ------------------------

zgenhostid -f -o /etc/hostid

#  ---------------------- Apply Grub Workaround ----------------------
# Note: This workaround needs to be applied for every GRUB update, as the update will overwrite the changes.

echo 'export ZPOOL_VDEV_NAME_PATH=YES' >> /etc/profile.d/zpool_vdev_name_path.sh
# shellcheck disable=SC1091
. /etc/profile.d/zpool_vdev_name_path.sh

# GRUB fails to detect rpool name, hard code as "rpool"
sed -i "s|rpool=.*|rpool=rpool|"  /etc/grub.d/10_linux

#  -------------------------- Install Grub -------------------------

mkdir -p /boot/efi/archlinux/grub-bootdir/i386-pc/
mkdir -p /boot/efi/archlinux/grub-bootdir/x86_64-efi/
for i in ${DISK}; do
 grub-install --target=i386-pc --boot-directory \
     /boot/efi/archlinux/grub-bootdir/i386-pc/  "${i}"
done
grub-install --target x86_64-efi --boot-directory \
 /boot/efi/archlinux/grub-bootdir/x86_64-efi/ --efi-directory \
 /boot/efi --bootloader-id archlinux --removable
if test -d /sys/firmware/efi/efivars/; then
   grub-install --target x86_64-efi --boot-directory \
    /boot/efi/archlinux/grub-bootdir/x86_64-efi/ --efi-directory \
    /boot/efi --bootloader-id archlinux
fi

# Import both bpool and rpool at boot:
echo 'GRUB_CMDLINE_LINUX="zfs_import_dir=/dev/"' >> /etc/default/grub

# Generate GRUB menu:
mkdir -p /boot/grub
grub-mkconfig -o /boot/grub/grub.cfg
cp /boot/grub/grub.cfg \
 /boot/efi/archlinux/grub-bootdir/x86_64-efi/grub/grub.cfg
cp /boot/grub/grub.cfg \
 /boot/efi/archlinux/grub-bootdir/i386-pc/grub/grub.cfg

# For both legacy and EFI booting: mirror ESP content:
espdir=$(mktemp -d)
find /boot/efi/ -maxdepth 1 -mindepth 1 -type d -print0 \
| xargs -t -0I '{}' cp -r '{}' "${espdir}"
find "${espdir}" -maxdepth 1 -mindepth 1 -type d -print0 \
    | xargs -t -0I '{}' sh -vxc "find /boot/efis/ -maxdepth 1 -mindepth 1 -type d -print0 | xargs -t -0I '[]' cp -r '{}' '[]'"

###  ----------------------- Config Environment ---------------------

# required software
pacman -S --noconfirm sed networkmanager reflector
systemctl enable NetworkManager
systemctl enable reflector.timer

# parallel downloads
sed -i "s/^#ParallelDownloads = 5$/ParallelDownloads = 15/" /etc/pacman.conf

# aur config
sed -i '/^CFLAGS=/s/-march=x86-64 -mtune=generic/-march=native/' /etc/makepkg.conf
sed -i 's/^#RUSTFLAGS="-C opt-level=2"/RUSTFLAGS="-C opt-level=2 -C target-cpu=native"/g'  /etc/makepkg.conf
sed -i 's/^#MAKEFLAGS="-j2"/MAKEFLAGS="-j$(nproc)"/g' /etc/makepkg.conf
sed -i 's/^COMPRESSXZ=(xz -c -z -)/COMPRESSXZ=(xz -c -z --threads=0 -)/g' /etc/makepkg.conf
sed -i 's/^COMPRESSZST=(zstd -c -z -q -)/COMPRESSZST=(zstd -c -z -q --threads=0 -)/g' /etc/makepkg.conf

# set up local time
sudo ln -sf /usr/share/zoneinfo/US/Central /etc/localtime
hwclock --systohc

# set up locale
echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen
locale-gen
echo "LANG=en_US.UTF-8" > /etc/locale.conf

# set up hostname
echo "$hostname" > /etc/hostname
echo "127.0.0.1       localhost" >> /etc/hosts
echo "::1             localhost" >> /etc/hosts
echo "127.0.1.1       $hostname.localdomain $hostname" >> /etc/hosts

# console settings
echo "KEYMAP=us" > /etc/vconsole.conf

#  ------------------------ Enable AUR Helper ------------------------

pacman -Syy
pacman -S --needed --noconfirm base-devel git openssh wget
build_dir="$source_dir/yay"
mkdir -p "$build_dir"
chown "$username:$username" -R "/home/$username"
sudo -u "$username" git clone --depth 1 "$yay_repo" "$build_dir"
cd "$build_dir" && sudo -u "$username" makepkg --noconfirm -si

###  ------------------------- Enable ZFS Services ----------------------
# add kernel modules

pacman -S --noconfirm zfs-dkms

# enable zfs services
systemctl enable zfs-import-cache
systemctl enable zfs-import.target
systemctl enable zfs-mount.service
systemctl enable zfs-share
systemctl enable zfs-zed
systemctl enable zfs.target

###  ----------------------------- Wrap Up --------------------------

# set root password; must change first login
echo "root:$password" | chpasswd
chage -d 0 root

#  --------------------------- Exit Chroot ---------------------------
exit