Linode StackScript for basic Ubuntu configuration
Linode StackScript for basic Ubuntu configuration
Overview
This is an example of a Linode StackScript that does basic configuration of a new Ubuntu instance:
- locks root user
- creates a non-root user
- copies SSH keys from root to the non-root user
- inserts a password for the non-root user
- enables
sudo
(with password) for the non-root user - configures
ufw
to block everything except SSH
Using this Stack Script
- login to Linode portal
- create new stackscript
- paste code below
- save, note Id number
- adjust Terraform model to reference the corr ect Id
Script
#!/bin/bash
# UDF variables
# <UDF name="USER" label="Create a non-root user" example="Using root user directly is not recommended" default=""/>
# <UDF name="USER_PASSWORD" label="Create a non-root user password" example="Example: mo7adL*^*3MD$QJcQYLcKLPrLx" default=""/>
# <UDF name="UPGRADE" label="Upgrade the system automatically ?" oneof="yes,no" default="yes" />
# <UDF name="SSH_PORT" label="Set SSH server port" example="This won't be reflected in your Linode Dashboard" default="22" />
# <UDF name="ROOT_LOCK" label="Lock the root account ?" oneof="yes,no" default="yes" />
# <UDF name="HOSTNAME" label="Host name" default="localhost" />
logfile="/var/log/stackscript.log"
error(){
for x in "$@"; do
test -n "$x" && \
printf "[ERROR] ($(date '+%y-%m-%d %H:%M:%S')) %s\n" "$x" >> $logfile
done
}
info(){
for x in "$@"; do
test -n "$x" && \
printf "[INFO] ($(date '+%y-%m-%d %H:%M:%S')) %s\n" "$x" >> $logfile
done
}
log(){
# log command error info
local msg
msg="$(2>&1 eval $1)"
[ $? -ne 0 ] && \
error "$msg" "$2" || \
info "$msg" "$3"
}
## User creation ##
user_create() {
# user_create user [password]
local ret=0
[ -z "$USER_PASSWORD" ] && \
USER_PASSWORD=$(awk -F: '$1 ~ /^root$/ { print $2 }' /etc/shadow) \
|| USER_PASSWORD=$(openssl passwd -6 $USER_PASSWORD)
ret=$?
useradd -mG sudo \
-s /bin/bash \
-p $USER_PASSWORD \
$USER
ret=$((ret+$?))
return $ret
}
ssh_config(){
# ssh_config ...
local ret=0
local sedopts="-i -E /etc/ssh/sshd_config -e 's/.*Port 22/Port $SSH_PORT/' \
-e 's/.*(PermitEmptyPasswords) .+/\1 no/' \
-e 's/.*(X11Forwarding) .+/\1 no/' \
-e 's/.*(ClientAliveInterval) .+/\1 300/' \
-e 's/.*(ClientAliveCountMax) .+/\1 2/' \
-e 's/.*(PubkeyAuthentication) .+/\1 yes/'"
if [ -d /root/.ssh ]; then
if [ "$USER" ]; then
sedopts="$sedopts -e 's/.*(PermitRootLogin) .+/\1 no/'"
cp -r /root/.ssh /home/$USER && \
chown -R $USER:$USER /home/$USER/.ssh && \
chmod 700 /home/$USER/.ssh
ret=$?
else
sedopts="$sedopts -e 's/.*(PermitRootLogin) .+/\1 yes/'"
fi
sedopts="$sedopts -e 's/.*(PasswordAuthentication) .+/\1 no/'"
else
sedopts="$sedopts -e 's/.*(PasswordAuthentication) .+/\1 yes/'"
fi
eval sed $sedopts
ret=$((ret+$?))
systemctl restart ssh
ret=$((ret+$?))
return $ret
}
debian_upgrade(){
export DEBIAN_FRONTEND="noninteractive"
>/dev/null 2>&1 apt update -qq && \
>/dev/null 2>&1 apt upgrade -qqy
}
log "user_create" \
"$USER creation failed." "$USER creation successful."
log "ssh_config" \
"SSH configuration failed." "SSH configuration successful."
[ "$ROOT_LOCK" = "yes" ] && {
log "passwd -l root" \
"root lock failed." "root locked successfully."
}
[ "$UPGRADE" = "yes" ] && {
log "debian_upgrade" \
"System upgrade failed." "System upgrade completed successfully."
}
hostnamectl set-hostname $HOSTNAME
ufw default deny incoming
ufw default allow outgoing
ufw allow $SSH_PORT/tcp
ufw enable
Script copyright
Adapted from this script (c) Debdut Chakraborty for Linux Handbook 2021, licensed under GNU General Public License v3