-
Notifications
You must be signed in to change notification settings - Fork 0
/
bsdeb
executable file
·496 lines (425 loc) · 11.7 KB
/
bsdeb
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
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
#!/bin/bash
# exit script immediately on non-zero status
set -e
PROGRAM_NAME="Debian Bootstrapper"
PROGRAM_VERSION="1.0.0-SNAPSHOT"
DEBIAN_VERSION=12.7
REPO_SOURCE_URL="https://github.com/genebarker/debian/raw/master"
SCRIPT_FILENAME="$(basename ${BASH_SOURCE})"
BASE_DIR="$(dirname ${BASH_SOURCE})"
CONFIG_FILENAME="server.conf"
CONFIG_FILEPATH="${BASE_DIR}/${CONFIG_FILENAME}"
BOOTSTRAP=OFF
AUTO_YES=OFF
HELP=$(cat << EOF
NAME
${SCRIPT_FILENAME} - a Debian server bootstrapper
SYNOPSIS
${SCRIPT_FILENAME} [-bhy] [-f configfile]
DESCRIPTION
Bootstrap a new Debian server using a configuration file.
Given a freshly installed headless Debian ${DEBIAN_VERSION}
server, this script configures it using the settings found in
the configuration file.
OPTIONS
-b Bootstrap server
-f configfile Configuration file, default: ${CONFIG_FILENAME}
-h Display this help
-y Answer yes to confirmation messages
EOF
)
run_main()
{
display_script_header
parse_script_options $@
verify_bootstrap_selected
verify_and_load_config_file
verify_debian_version
upgrade_debian_image_to_latest
install_vim_and_set_as_default
install_remote_access_utils
install_diagnostic_utils
install_windows_integration_utils
install_core_dev_utils
install_help_utils
setup_unattended_upgrades
configure_ssh_server
setup_networking
load_and_install_dotfiles
gen_ssh_keys_and_set_auth_user
run_config_file_script
}
display_script_header()
{
echo "${PROGRAM_NAME} for Debian ${DEBIAN_VERSION}"
echo "Version ${PROGRAM_VERSION} - MIT License"
echo
}
parse_script_options()
{
echo ".. parsing script options"
while getopts ':bf:yh' opt
do
case "$opt" in
b)
BOOTSTRAP=ON
;;
f)
override_config_file "$OPTARG"
;;
y)
AUTO_YES=ON
;;
h)
show_help
exit 0
;;
:)
show_error "Option requires an argument."
exit 1
;;
?)
show_error "Invalid command option."
exit 1
;;
esac
done
# remove getopts parms from parameter list
shift $((OPTIND-1))
}
override_config_file()
{
CONFIG_FILEPATH=$1
CONFIG_FILENAME=$(basename "$CONFIG_FILEPATH")
if [ ! -f $1 ]
then
echo "Config file (${CONFIG_FILENAME}) not found, will try to download from repo."
fi
}
show_help()
{
echo
echo "${HELP}"
}
show_error()
{
local message=$1
echo
echo "ERROR: $1"
}
verify_bootstrap_selected()
{
if [ $BOOTSTRAP = OFF ]
then
echo
echo "Exiting since bootstrap option not used."
exit 0
fi
}
verify_and_load_config_file()
{
if [ ! -f "$CONFIG_FILEPATH" ]
then
get_config_file_from_repo_and_exit $CONFIG_FILENAME
fi
echo ".. config file set ($CONFIG_FILEPATH)"
echo ".. displaying config"
echo
cat $CONFIG_FILEPATH
question="Is this the correct config to apply (y/n)?"
ask_continue_question "$question"
source $CONFIG_FILEPATH
echo ".. config file loaded"
}
get_config_file_from_repo_and_exit()
{
local filename=$1
download_config_file $filename
echo -n "Update config file ${filename} with your settings, "
echo "then rerun this script."
exit 1
}
download_config_file()
{
echo ".. downloading config file from repo"
wget ${REPO_SOURCE_URL}/$1
echo ".. config file download successful"
}
ask_continue_question()
{
local question=$1
echo
echo -n "$question "
if [ $AUTO_YES = ON ]
then
echo Yes
return
fi
old_stty_cfg=$(stty -g)
stty raw -echo ; answer=$(head -c 1) ; stty $old_stty_cfg
if echo "$answer" | grep -iq "^y"
then
echo Yes
return
else
echo No
exit 1
fi
}
verify_debian_version()
{
if [ -f /etc/debian_version ]
then
version=$(cat /etc/debian_version)
echo ".. identified version of Debian image ($version)"
else
version="UNKNOWN"
fi
if [ "$version" != "$DEBIAN_VERSION" ]
then
question=$(cat << EOF
WARNING: The version of this Debian image ($version) does NOT match
the script target ($DEBIAN_VERSION).
Do you still want to bootstrap this image (y/n)?
EOF
)
ask_continue_question "$question"
echo
fi
}
upgrade_debian_image_to_latest()
{
echo ".. upgrading Debian image to latest available"
apt-get update && apt-get -y dist-upgrade
}
install_vim_and_set_as_default()
{
echo ".. installing vim and setting as default editor"
apt-get -y install vim
update-alternatives --set editor /usr/bin/vim.basic
echo ".. installing curl (needed by vim-plug)"
apt-get -y install curl
}
install_remote_access_utils()
{
echo ".. installing remote access utilities"
apt-get -y install tmux rsync
}
install_diagnostic_utils()
{
echo ".. installing diagnostic utilities"
apt-get -y install htop ncdu
}
install_windows_integration_utils()
{
echo ".. installing windows integration utilitities"
apt-get -y install zip unzip dos2unix
}
install_core_dev_utils()
{
echo ".. installing core development utilities"
apt-get -y install git ack bat
}
install_help_utils()
{
echo ".. installing help utilities"
apt-get -y install tldr ddgr w3m
echo ".. configure tldr"
local root_tldr_dir="/root/.local/share/tldr"
mkdir -p $root_tldr_dir
tldr --update
echo ".. copying tldr data for non admin user ($NON_ADMIN_USERNAME)"
local reg_tldr_dir="/home/$NON_ADMIN_USERNAME/.local/share/tldr"
if [ -d $reg_tldr_dir ]
then
rm -rf $reg_tldr_dir
fi
su -c "mkdir -p $reg_tldr_dir" $NON_ADMIN_USERNAME
cp -r $root_tldr_dir/* $reg_tldr_dir
chown -R $NON_ADMIN_USERNAME:$NON_ADMIN_USERNAME $reg_tldr_dir
echo ".. set default browser to w3m"
local env_file="/etc/environment"
backup_or_recover_original_file $env_file
echo "export BROWSER=w3m" > $env_file
}
setup_unattended_upgrades()
{
if [ "${AUTO_PATCH}" != "ON" ]
then
return # nothing to configure
fi
echo ".. installing unattended-upgrades"
apt-get -y install unattended-upgrades
systemctl enable unattended-upgrades
systemctl start unattended-upgrades
sleep 2
}
configure_ssh_server()
{
if [ -z "$SSH_PORT" ] && [ -z "$SSH_PERMIT_ROOT_LOGIN" ] && [ -z "$SSH_PASSWORD_AUTH" ]
then
return # nothing to configure
fi
echo ".. configuring ssh"
local config_file="/etc/ssh/sshd_config"
backup_or_recover_original_file $config_file
if [ -n "$SSH_PORT" ]
then
echo ".. setting SSH_PORT to ${SSH_PORT}"
sed -i "s/#Port 22/Port $SSH_PORT/" $config_file
fi
if [ -n "$SSH_PERMIT_ROOT_LOGIN" ]
then
echo ".. setting PermitRootLogin to ${SSH_PERMIT_ROOT_LOGIN}"
sed -i "s/^#\?PermitRootLogin.*/PermitRootLogin $SSH_PERMIT_ROOT_LOGIN/" $config_file
fi
if [ -n "$SSH_PASSWORD_AUTH" ]
then
echo ".. setting PasswordAuthentication to ${SSH_PASSWORD_AUTH}"
sed -i "s/^#\?PasswordAuthentication.*/PasswordAuthentication $SSH_PASSWORD_AUTH/" $config_file
fi
service sshd restart
service sshd status
}
backup_or_recover_original_file()
{
local file_path=$1
if [ -f "${file_path}.orig" ]
then
# restore the original
cp "${file_path}.orig" $file_path
else
# backup the original
cp $file_path "${file_path}.orig"
fi
}
setup_networking () {
setup_network_interface
setup_hostname
}
setup_network_interface () {
if [ "${IFACE}" != "static" ]
then
echo ".. skipping network interface setup since done by DNS"
return
fi
local interfaces_path="/etc/network/interfaces"
backup_or_recover_original_file $interfaces_path
local resolv_path="/etc/resolv.conf"
backup_or_recover_original_file $resolv_path
# get line num primary network interface
local line_to_replace=$(grep -En '\Wdhcp$' $interfaces_path | cut -d: -f1)
# build its replacement
head -${line_to_replace} $interfaces_path > interfaces.temp
sed -i 's/dhcp/static/' interfaces.temp
echo " address ${IFACE_ADDRESS}" >> interfaces.temp
echo " netmask ${IFACE_NETMASK}" >> interfaces.temp
echo " gateway ${IFACE_GATEWAY}" >> interfaces.temp
# update name servers
if [ ! -z "${NAMESERVER_1}" ]
then
echo "nameserver ${NAMESERVER_1}" > $resolv_path
if [ ! -z "${NAMESERVER_2}" ]
then
echo "nameserver ${NAMESERVER_2}" >> $resolv_path
fi
fi
# change the primary interface
mv interfaces.temp $interfaces_path
echo ".. changed network interfaces"
cat $interfaces_path
echo ".. restarting network"
systemctl restart networking
sleep 2
}
setup_hostname () {
if [ -z "$HOSTNAME" ]
then
return # nothing to configure
fi
echo ".. setting hostname with system"
hostnamectl set-hostname $HOSTNAME
echo ".. updating hosts file"
local hosts_path="/etc/hosts"
local ip_address="${IFACE_ADDRESS}"
if [ -z "${ip_address}" ]
then
ip_address=$(get_ip_address)
fi
backup_or_recover_original_file $hosts_path
echo "127.0.0.1 localhost" > $hosts_path
echo "${ip_address} ${FQDN} ${HOSTNAME}" >> $hosts_path
cat $hosts_path
echo ".. hostname changed"
hostnamectl
}
get_ip_address () {
local iface_name=$(ip route get 1.1.1.1 | grep -o "dev [^ ]*" | awk '{print $2}')
ip -4 addr show $iface_name | grep -oP '(?<=inet\s)\d+(\.\d+){3}'
}
load_and_install_dotfiles()
{
if [ -z "$DOTFILES_REPO_URL" ]
then
return # no dotfile repo defined
fi
echo ".. cloning dotfiles repo for root user"
if [ -d dotfiles ]
then
cd ~/dotfiles
git pull origin
else
cd
git clone $DOTFILES_REPO_URL
fi
if [ -n "$DOTFILES_REPO_INSTALL_SCRIPT" ]
then
echo ".. installing root user dotfiles"
cd
./dotfiles/$DOTFILES_REPO_INSTALL_SCRIPT
fi
if [ -z "$NON_ADMIN_USERNAME" ]
then
return # no non admin user
fi
echo ".. copying dotfiles repo for non admin user ($NON_ADMIN_USERNAME)"
if [ -d /home/$NON_ADMIN_USERNAME/dotfiles ]
then
rm -rf /home/$NON_ADMIN_USERNAME/dotfiles
fi
cp -r ~/dotfiles /home/$NON_ADMIN_USERNAME
chown -R $NON_ADMIN_USERNAME:$NON_ADMIN_USERNAME /home/$NON_ADMIN_USERNAME/dotfiles
if [ -n "$DOTFILES_REPO_INSTALL_SCRIPT" ]
then
echo ".. installing non admin user dotfiles"
su $NON_ADMIN_USERNAME -c "/home/$NON_ADMIN_USERNAME/dotfiles/$DOTFILES_REPO_INSTALL_SCRIPT"
fi
}
gen_ssh_keys_and_set_auth_user()
{
if [ -z "$NON_ADMIN_USERNAME" ]
then
return # no non admin user
fi
echo ".. generating SSH keys for non admin user ($NON_ADMIN_USERNAME)"
KEY_HOME=/home/$NON_ADMIN_USERNAME/.ssh
rm -f $KEY_HOME/id_rsa
su $NON_ADMIN_USERNAME -c "ssh-keygen -q -t rsa -N '' -f $KEY_HOME/id_rsa"
if [ -z "$NON_ADMIN_AUTH_KEY" ]
then
if [ -z "$NON_ADMIN_AUTH_KEY_DOTFILES_PATH" ]
then
return # no authorized key
fi
# use authorized keys in dotfiles
NON_ADMIN_AUTH_KEY=$(cat "/home/$NON_ADMIN_USERNAME/dotfiles/$NON_ADMIN_AUTH_KEY_DOTFILES_PATH")
fi
echo ".. adding authorized key"
su $NON_ADMIN_USERNAME -c "echo $NON_ADMIN_AUTH_KEY > $KEY_HOME/authorized_keys"
}
run_config_file_script()
{
echo ".. running config file script"
configure_box
}
run_main $@