-
Notifications
You must be signed in to change notification settings - Fork 1
/
install.sh
executable file
·401 lines (318 loc) · 10.7 KB
/
install.sh
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
#!/usr/bin/env bash
# For installing NixOS having booted from the minimal USB image.
# To run:
# bash -c "$(curl https://raw.githubusercontent.com/Red-Flake/red-flake-nix/main/install.sh)"
# e: Exit script immediately if any command returns a non-zero exit status.
# u: Exit script immediately if an undefined variable is used.
# o pipefail: Ensure Bash pipelines return a non-zero status if any command fails.
set -eou pipefail
# make sure this script is run as root (sudo does not work)
if [ "$(id -u)" -ne 0 ]; then
printf "This script has to run as root (do not use sudo)\n" >&2
exit 1
elif [ -n "${SUDO_USER:-}" ]; then
printf "This script has to run as root (not sudo)\n" >&2
exit 1
fi
# define variables
LOGFILE="/mnt/nixos_install.log"
FLAKE="github:Red-Flake/red-flake-nix"
GIT_REV="main"
# define colors
RED="\e[31m"
GREEN="\e[32m"
YELLOW="\e[33m"
BLUE="\e[34m"
MAGENTA="\e[35m"
CYAN="\e[36m"
WHITE="\e[37m"
ENDCOLOR="\e[0m"
function colorprint() {
local color="$1"
local text="$2"
local endcolor="\e[0m"
echo -e "${color}${text}${endcolor}"
}
function log() {
local level="$1"
local message="$2"
case "$level" in
"ERROR")
colorprint "$RED" "[$level] $message"
;;
"INFO")
colorprint "$BLUE" "[$level] $message"
;;
"WARN")
colorprint "$YELLOW" "[$level] $message"
;;
*)
echo "[$level] $message"
;;
esac
}
function check_command() {
local cmd="$1"
if ! command -v "$cmd" &> /dev/null; then
log "ERROR" "Command not found: $cmd. Please install it and re-run the script."
exit 1
fi
}
function yesno() {
local prompt="$1"
while true; do
read -rp "$prompt [y/n] " yn
case $yn in
[Yy]* ) echo "y"; return;;
[Nn]* ) echo "n"; return;;
* ) log "INFO" "Please answer yes or no.";;
esac
done
}
log "INFO" "Welcome to the Red Flake installer!"
log "INFO" "The installer will log the installation process to $LOGFILE."
log "WARN" "This script will format the *entire* disk with a 1GB boot partition
(labelled NIXBOOT), 16GB of swap, then allocating the rest to ZFS.
The following ZFS datasets will be created:
- zroot/root (mounted at / with blank snapshot)
- zroot/nix (mounted at /nix)
- zroot/tmp (mounted at /tmp)
- zroot/persist (mounted at /persist)
- zroot/cache (mounted at /cache)"
# Check for required commands
for cmd in blkdiscard sgdisk zpool zfs mkfs.fat mkswap swapon; do
check_command "$cmd"
done
# Network connectivity check
if ! ping -c 1 github.com &> /dev/null; then
log "ERROR" "Network connectivity check failed. Please ensure you have an active internet connection."
exit 1
fi
# Check if in a VM
if [[ -b "/dev/vda" ]]; then
log "INFO" "VM was detected!"
DISK="/dev/vda"
do_format=$(yesno "Will now install Red-Flake to ${DISK}. This irreversibly formats the entire disk. Are you sure?")
if [[ $do_format == "n" ]]; then
exit
fi
BOOTDISK="${DISK}3"
SWAPDISK="${DISK}2"
ZFSDISK="${DISK}1"
else
log "INFO" "Your attached storage devices will now be listed."
read -p "Press enter to continue." NULL
printf "\n"
log "INFO" "Detected the following devices:"
lsblk
printf "\n"
read -p "Which device do you wish to install on? " DISKINPUT
DISK="/dev/${DISKINPUT}"
if [ ! -b "$DISK" ]; then
log "ERROR" "Device $DISK does not exist."
exit 1
fi
BOOTDISK="${DISK}p3"
SWAPDISK="${DISK}p2"
ZFSDISK="${DISK}p1"
log "INFO" "Boot Partition: $BOOTDISK"
log "INFO" "SWAP Partition: $SWAPDISK"
log "INFO" "ZFS Partition: $ZFSDISK"
do_format=$(yesno "Will now install Red-Flake to ${DISK}. This irreversibly formats the entire disk. Are you sure?")
if [[ $do_format == "n" ]]; then
exit
fi
fi
sgdisk -p "$DISK" > /dev/null
log "INFO" "Erasing disk ${DISK} ..."
blkdiscard -f "$DISK"
log "INFO" "Clear partition table on disk ${DISK} ..."
sgdisk --zap-all "$DISK"
log "INFO" "Creating new GPT partition table on disk ${DISK} ..."
sgdisk -o "$DISK"
sgdisk -p "$DISK" > /dev/null
log "INFO" "Creating partitions on disk ${DISK} ..."
sgdisk -n3:1M:+1G -t3:EF00 "$DISK"
sgdisk -n2:0:+16G -t2:8200 "$DISK"
sgdisk -n1:0:0 -t1:BF01 "$DISK"
log "INFO" "Notifying kernel of partition changes..."
sgdisk -p "$DISK" > /dev/null
sleep 5
log "INFO" "Creating Swap"
mkswap "$SWAPDISK" --label "SWAP"
swapon "$SWAPDISK"
log "INFO" "Creating Boot Disk"
mkfs.vfat "$BOOTDISK" -n NIXBOOT
use_encryption=$(yesno "Use encryption? (Encryption must also be enabled within host config.)")
if [[ $use_encryption == "y" ]]; then
encryption_options=(-O encryption=aes-256-gcm -O keyformat=passphrase -O keylocation=prompt)
else
encryption_options=()
fi
log "INFO" "Creating base ZFS pool zroot on disk ${ZFSDISK} ..."
zpool create -f \
-o ashift=12 \
-o autotrim=on \
-O compression=zstd \
-O acltype=posixacl \
-O atime=off \
-O xattr=sa \
-O normalization=formD \
-O mountpoint=none \
-R /mnt \
"${encryption_options[@]}" \
zroot "$ZFSDISK"
log "INFO" "Creating /"
zfs create -o mountpoint=none zroot/root
zfs create -o mountpoint=legacy zroot/root/nixos
zfs snapshot zroot/root/nixos@blank
log "INFO" "Enabling automatic snapshots for ZFS pool zroot"
zfs set com.sun:auto-snapshot=true zroot
mount -t zfs zroot/root/nixos /mnt
log "INFO" "Mounting /boot (efi)"
mount --mkdir "$BOOTDISK" /mnt/boot
log "INFO" "Creating /nix"
zfs create -o mountpoint=legacy zroot/nix
mount --mkdir -t zfs zroot/nix /mnt/nix
log "INFO" "Creating /tmp"
zfs create -o mountpoint=legacy zroot/tmp
mount --mkdir -t zfs zroot/tmp /mnt/tmp
log "INFO" "Creating /cache"
zfs create -o mountpoint=legacy zroot/cache
mount --mkdir -t zfs zroot/cache /mnt/cache
log "INFO" "Creating /home"
zfs create -o mountpoint=legacy zroot/home
mount --mkdir -t zfs zroot/home /mnt/home
restore_snapshot=$(yesno "Do you want to restore from a persist snapshot?")
if [[ $restore_snapshot == "y" ]]; then
read -p "Enter full path to snapshot: " snapshot_file_path
log "INFO" "Creating /persist"
zfs receive -o mountpoint=legacy zroot/persist < "$snapshot_file_path"
else
log "INFO" "Creating /persist"
zfs create -o mountpoint=legacy zroot/persist
fi
mount --mkdir -t zfs zroot/persist /mnt/persist
while true; do
read -rp "Which host to install? (kvm / vmware / t580) " HOST
case $HOST in
kvm|vmware|t580 ) break;;
* ) echo "Invalid host. Please select a valid host.";;
esac
done
## user setup logic based on host
# create /persist/etc/shadow.d
mkdir -p /mnt/persist/etc/shadow.d
# setup users with persistent passwords
# https://reddit.com/r/NixOS/comments/o1er2p/tmpfs_as_root_but_without_hardcoding_your/h22f1b9/
# create a password with for root and $user with:
# mkpasswd -m sha-512 'PASSWORD' | sudo tee -a /persist/etc/shadow.d/root
# set root password
while true; do
# Prompt for the password
echo -n "Enter password for user root: "
stty -echo # Disable echoing
read root_password
stty echo # Re-enable echoing
echo # Move to a new line
# Prompt for the password confirmation
echo -n "Confirm password: "
stty -echo
read root_password_confirm
stty echo
echo # Move to a new line
# Check if passwords match
if [ "$root_password" = "$root_password_confirm" ]; then
echo "$root_password" | mkpasswd -m sha-512 --stdin | tee -a /mnt/persist/etc/shadow.d/root > /dev/null
unset root_password root_password_confirm
echo "Password set successfully."
break
else
echo "Passwords do not match. Please try again."
fi
done
# Set username based on chosen host
case $HOST in
kvm | vmware )
USER="redflake"
;;
t580 )
USER="pascal"
;;
* )
echo "Invalid host. Please select a valid host."
;;
esac
log "INFO" "You chose to install host $HOST. Automatically setting user to $USER."
# setup users with persistent passwords
# https://reddit.com/r/NixOS/comments/o1er2p/tmpfs_as_root_but_without_hardcoding_your/h22f1b9/
# create a password with for root and $user with:
# mkpasswd -m sha-512 'PASSWORD' | sudo tee -a /persist/etc/shadow.d/root
# set user password
while true; do
# Prompt for the password
echo -n "Enter password for user $USER: "
stty -echo # Disable echoing
read user_password
stty echo # Re-enable echoing
echo # Move to a new line
# Prompt for the password confirmation
echo -n "Confirm password: "
stty -echo
read user_password_confirm
stty echo
echo # Move to a new line
# Check if passwords match
if [ "$user_password" = "$user_password_confirm" ]; then
echo "$user_password" | mkpasswd -m sha-512 --stdin | tee -a /mnt/persist/etc/shadow.d/$USER > /dev/null
unset user_password user_password_confirm
echo "Password set successfully."
break
else
echo "Passwords do not match. Please try again."
fi
done
# Set correct permissions for /persist/etc/shadow.d
chown -R root:shadow /mnt/persist/etc/shadow.d/
chmod -R 640 /mnt/persist/etc/shadow.d/
log "INFO" "Installing Red-Flake with host profile ${HOST} for user ${USER} on disk ${DISK}..."
nixos-install --no-root-password --flake "${FLAKE}/${GIT_REV:-main}#$HOST" --option tarball-ttl 0
log "INFO" "Syncing disk writes..."
sync
log "INFO" "Setting up persistence..."
mkdir -p /mnt/persist/var/lib/
# setup NetworkManager persistence
mkdir -p /mnt/persist/etc/NetworkManager
if [ -d /etc/NetworkManager/system-connections ]; then
cp -r /etc/NetworkManager/system-connections /mnt/persist/etc/NetworkManager/
fi
mkdir -p /mnt/persist/var/lib/NetworkManager
if [ -d /var/lib/NetworkManager ]; then
cp /var/lib/NetworkManager/{secret_key,seen-bssids,timestamps} /mnt/persist/var/lib/NetworkManager/
fi
# setup Docker persistence
if [ -d /mnt/var/lib/docker ]; then
cp -r /mnt/var/lib/docker /mnt/persist/var/lib/docker
fi
# setup LXC / LXD persistence
if [ -d /mnt/var/lib/lxd ]; then
cp -r /mnt/var/lib/lxd /mnt/persist/var/lib/lxd
fi
# setup ssl certs persistence
mkdir -p /mnt/persist/etc/ssl/
if [ -d /mnt/etc/ssl/certs ]; then
cp -r /mnt/etc/ssl/certs/ /mnt/persist/etc/ssl/
fi
log "INFO" "Taking initial ZFS snapshot of freshly installed system"
zfs snapshot -r zroot@install
log "INFO" "Unmouting /mnt/boot"
umount -f /mnt/boot
log "INFO" "Unmouting ZFS pools"
zfs umount -a
log "INFO" "Exporting ZFS pools"
zpool export -a
log "INFO" "Installation finished. It is now safe to reboot."
do_reboot=$(yesno "Do you want to reboot now?")
if [[ $do_reboot == "y" ]]; then
reboot
fi