Skip to content

Instantly share code, notes, and snippets.

@isac322
Last active April 17, 2020 05:21
Show Gist options
  • Save isac322/13cb288b23201162167152f8c49ecf2a to your computer and use it in GitHub Desktop.
Save isac322/13cb288b23201162167152f8c49ecf2a to your computer and use it in GitHub Desktop.
Archlinux initialization script for Raspberry Pi 4B
#!/usr/bin/env bash
set -ex
USER_NAME='bhyoo'
HOST_NAME='bhyoo.com'
VPN_NAME='YooVPN'
systemctl start systemd-resolved.service
pacman-key --init
pacman-key --populate archlinuxarm
pacman -Syu base base-devel git zsh vim --noconfirm
userdel -r alarm
useradd -m -G wheel,storage -s "$(command -v zsh)" -u 1000 ${USER_NAME}
echo "password for ${USER_NAME}"
passwd ${USER_NAME}
echo "password for root"
passwd root
sed /etc/sudoers -i -Ee 's/^\s*#\s*%wheel\s*ALL=\(ALL\)\s*ALL$/%wheel\tALL=(ALL)\tALL/'
echo "$HOST_NAME" >/etc/hostname
ln -sf /usr/share/zoneinfo/Asia/Seoul /etc/localtime
# Select appropriate locale
locales=('en_US.UTF-8' 'ko_KR.UTF-8')
for locale in "${locales[@]}"; do
sed -Ei "s/#(${locale}.*)/\1/" /etc/locale.gen
done
echo 'LANG=ko_KR.UTF-8' >/etc/locale.conf
locale-gen
timedatectl set-ntp true
# setup shell & install yay
packages=(
'oh-my-zsh-git'
'zsh-history-search-multi-word-git'
'zsh-fast-syntax-highlighting-git'
'zsh-autosuggestions'
'zsh-completions'
'zsh-theme-powerlevel10k-git'
'alias-tips-git'
'ssh-audit'
'pkgfile'
'pygmentize' # for colorize plugin of oh-my-zsh
'openvpn'
'openvpn3-git'
'easy-rsa'
'pi-hole-whitelist-git'
)
su "${USER_NAME}" -c "mkdir /home/${USER_NAME}/yay"
cd /home/"${USER_NAME}"/yay
su "${USER_NAME}" -c 'git clone https://aur.archlinux.org/yay.git .'
su -P "${USER_NAME}" -c 'makepkg -cirs --noconfirm && yay -S '"${packages[*]}"' --noconfirm --removemake && cp /usr/share/oh-my-zsh/zshrc ~/.zshrc'
rm -rf /home/"${USER_NAME}"/yay
{
echo ''
echo 'source /usr/share/zsh/plugins/zsh-autosuggestions/zsh-autosuggestions.zsh'
echo 'source /usr/share/zsh/plugins/fast-syntax-highlighting/fast-syntax-highlighting.plugin.zsh'
echo 'source /usr/share/zsh/plugins/history-search-multi-word/history-search-multi-word.plugin.zsh'
echo 'source /usr/share/zsh/plugins/alias-tips/alias-tips.plugin.zsh'
echo 'source /usr/share/zsh-theme-powerlevel10k/powerlevel10k.zsh-theme'
} >>/home/"${USER_NAME}"/.zshrc
plugins=(
'colored-man-pages'
'colorize'
'command-not-found'
'extract'
'sudo'
'tmux'
'vundle'
'docker'
'git'
'pip'
'python'
'virtualenv'
'archlinux'
'systemd'
)
perl -0777 -i -pe 's/^\s*plugins\s*=\s*\([^)]*\)$/plugins=('"${plugins[*]}"')/gm' /home/"${USER_NAME}"/.zshrc
# setup udisks2
pacman -Syu udisks2 ntfs-3g --noconfirm
systemctl enable udisks2.service pkgfile-update.timer --now
# setup OpenVPN
# If system has a single IPv4, it is selected automatically. Else, ask the user
if [[ $(ip addr | grep inet | grep -v inet6 | grep -vEc '127\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}') -eq 1 ]]; then
ip=$(ip addr | grep inet | grep -v inet6 | grep -vE '127\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | cut -d '/' -f 1 | grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}')
else
number_of_ips=$(ip addr | grep inet | grep -v inet6 | grep -vEc '127\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}')
echo
echo "What IPv4 address should the OpenVPN server bind to?"
ip addr | grep inet | grep -v inet6 | grep -vE '127\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | cut -d '/' -f 1 | grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | nl -s ') '
read -p "IPv4 address [1]: " ip_number
until [[ -z "$ip_number" || "$ip_number" =~ ^[0-9]+$ && "$ip_number" -le "$number_of_ips" ]]; do
echo "$ip_number: invalid selection."
read -p "IPv4 address [1]: " ip_number
done
[[ -z "$ip_number" ]] && ip_number="1"
ip=$(ip addr | grep inet | grep -v inet6 | grep -vE '127\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | cut -d '/' -f 1 | grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | sed -n "$ip_number"p)
fi
protocol=udp
port=1194
echo '############ WAITING FOR /tmp/ca.crt ############'
while read i; do
if [ "$i" = ca.crt ]; then
mv /tmp/ca.crt /etc/openvpn/server/
chown root:root /etc/openvpn/server/ca.crt
break;
fi;
done < <(inotifywait -e create --format '%f' --quiet /tmp --monitor)
cd /etc/easy-rsa
easyrsa init-pki
easyrsa gen-req ${VPN_NAME} nopass
cp "/etc/easy-rsa/pki/private/${VPN_NAME}.key" /etc/openvpn/server/
openvpn --genkey --secret /etc/openvpn/server/ta.key
cp "/etc/easy-rsa/pki/reqs/${VPN_NAME}.req" /tmp
chown "${USER_NAME}" "/tmp/${VPN_NAME}.req"
echo "############ WAITING FOR /tmp/${VPN_NAME}.crt ############"
while read i; do
if [ "$i" = "${VPN_NAME}.crt" ]; then
mv "/tmp/${VPN_NAME}.crt" /etc/openvpn/server/
chown root:root "/etc/openvpn/server/${VPN_NAME}.crt"
break;
fi;
done < <(inotifywait -e create --format '%f' --quiet /tmp --monitor)
cp /usr/share/openvpn/examples/server.conf "/etc/openvpn/server/${VPN_NAME}.conf"
sed -i -E -e "s/^cert\s+.+\$/cert ${VPN_NAME}.crt/" "/etc/openvpn/server/${VPN_NAME}.conf"
sed -i -E -e "s/^key\s+.+\$/key ${VPN_NAME}.key/" "/etc/openvpn/server/${VPN_NAME}.conf"
sed -i -E -e 's/^dh\s+.+$/dh none\necdh-curve secp521r1/' "/etc/openvpn/server/${VPN_NAME}.conf"
sed -i -E -e 's/^tls-auth\s+.+$/tls-crypt ta.key/' "/etc/openvpn/server/${VPN_NAME}.conf"
sed -i -E -e 's/^;(user|group)\s+nobody$/\1 nobody/' "/etc/openvpn/server/${VPN_NAME}.conf"
sed -i -E -e "s/^;?local\s+.+\$/local ${ip}/" "/etc/openvpn/server/${VPN_NAME}.conf"
tee -a "/etc/openvpn/server/${VPN_NAME}.conf" > /dev/null << END
push "dhcp-option DNS 10.8.0.1"
cipher AES-256-GCM
auth SHA512
tls-version-min 1.2
tls-cipher TLS-DHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-AES-128-GCM-SHA256:TLS-DHE-RSA-WITH-AES-256-CBC-SHA:TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA:TLS-DHE-RSA-WITH-AES-128-CBC-SHA:TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA
END
systemctl enable --now "openvpn-server@${VPN_NAME}"
# setup iptables
iptables -t nat -A POSTROUTING -s 10.8.0.0/24 ! -d 10.8.0.0/24 -j SNAT --to $ip
iptables -I INPUT -p $protocol --dport $port -j ACCEPT
iptables -I FORWARD -s 10.8.0.0/24 -j ACCEPT
iptables -I FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -N LOG_AND_DROP
iptables -A INPUT -p tcp -m tcp --dport 22 -m state --state NEW -m recent --set --name DEFAULT --rsource
iptables -A INPUT -p tcp -m tcp --dport 22 -m state --state NEW -m recent --update --seconds 90 --hitcount 4 --name DEFAULT --rsource -j LOG_AND_DROP
iptables -A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
iptables -A LOG_AND_DROP -j LOG --log-prefix "iptables deny: " --log-level 7
iptables -A LOG_AND_DROP -j DROP
iptables -I INPUT -i tun0 -j ACCEPT
iptables -A INPUT -i tun0 -p tcp --destination-port 53 -j ACCEPT
iptables -A INPUT -i tun0 -p udp --destination-port 53 -j ACCEPT
iptables -A INPUT -i tun0 -p tcp --destination-port 80 -j ACCEPT
iptables -A INPUT -p tcp --destination-port 1194 -j ACCEPT
iptables -A INPUT -p udp --destination-port 1194 -j ACCEPT
iptables -I INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -I INPUT -i lo -j ACCEPT
iptables -P INPUT DROP
iptables -A INPUT -p udp --dport 80 -j REJECT --reject-with icmp-port-unreachable
iptables -A INPUT -p tcp --dport 443 -j REJECT --reject-with tcp-reset
iptables -A INPUT -p udp --dport 443 -j REJECT --reject-with icmp-port-unreachable
iptables-save -f /etc/iptables/iptables.rules
systemctl enable iptables.service
# setup sshd
function modify_sshd_config() {
local val="$1"
shift
local cfg_path='/etc/ssh/sshd_config'
local exprs=()
for key in "$@"; do
if grep -qE "^\s*#\s*${key}\s+${val}\s*$" "$cfg_path"; then
exprs+=(-e "s/^\s*#\s*${key}\s+.+$/${key} ${val}/")
else
exprs+=(-e "s/^\s*#\s*${key}\s+(.+)$/${key} ${val}\t# \1/")
fi
done
sed -i -E "${exprs[@]}" "$cfg_path"
}
modify_sshd_config 'no' 'PermitEmptyPasswords' 'PermitRootLogin' 'PasswordAuthentication' 'Compression'
modify_sshd_config 'yes' 'PubkeyAuthentication' 'StrictModes'
modify_sshd_config '5' 'MaxAuthTries'
# install pacakges for maintainence
pacman -Syu htop tmux powertop lshw --noconfirm
# setup vim
# setup pi-hole
su "${USER_NAME}" -P -c "yay -S pi-hole-server php-sqlite nginx-mainline php-fpm --noconfirm --removemake"
systemctl disable systemd-resolved.service --now
sed -i -E -e 's/^\s*#\s*DBINTERVAL\s*=\s*.+$/DBINTERVAL=60.0/' /etc/pihole/pihole-FTL.conf
sed -i -E -e 's/^PIHOLE_INTERFACE=.*$/PIHOLE_INTERFACE=tun0/' /etc/pihole/setupVars.conf
sed -i -E -e 's/^IPV4_ADDRESS=.*$/IPV4_ADDRESS=10.8.0.1\/24/' /etc/pihole/setupVars.conf
systemctl enable pihole-FTL.service pi-hole-whitelist.timer --now
tee -a /etc/hosts > /dev/null << END
127.0.0.1 localhost
$ip pi.hole $HOST_NAME
END
function join_by() {
local IFS="$1"
shift
echo "$*"
}
exceptions=(
'/srv/http/pihole'
'/run/pihole-ftl/pihole-FTL.port'
'/run/log/pihole/pihole.log'
'/run/log/pihole-ftl/pihole-FTL.log'
'/etc/pihole'
'/etc/hosts'
'/etc/hostname'
'/etc/dnsmasq.d/02-pihole-dhcp.conf'
'/etc/dnsmasq.d/03-pihole-wildcard.conf'
'/etc/dnsmasq.d/04-pihole-static-dhcp.conf'
'/proc/meminfo'
'/proc/cpuinfo'
'/sys/class/thermal/thermal_zone0/temp'
'/tmp'
)
sed -i -E -e 's/^\s*;\s*extension=(pdo_sqlite|sockets|sqlite3)\s*$/extension=\1/' /etc/php/php.ini
exceptions_str=$(join_by : "${exceptions[@]}")
sed -i -E -e "s/^\s*;\s*open_basedir\s*=\s*.*$/open_basedir = ${exceptions_str//\//\\/}/" /etc/php/php.ini
sed -i -E -e 's/^;?listen\s*=\s*.+$/listen = \/run\/php-fpm\/php-fpm.sock/' /etc/php/php-fpm.d/www.conf
mkdir /etc/systemd/system/php-fpm.service.d -p
tee /etc/systemd/system/php-fpm.service.d/override.conf > /dev/null << END
[Service]
ReadWritePaths = /srv/http/pihole
ReadWritePaths = /run/pihole-ftl/pihole-FTL.port
ReadWritePaths = /run/log/pihole/pihole.log
ReadWritePaths = /run/log/pihole-ftl/pihole-FTL.log
ReadWritePaths = /etc/pihole
ReadWritePaths = /etc/hosts
ReadWritePaths = /etc/hostname
ReadWritePaths = /etc/dnsmasq.d/
ReadWritePaths = /proc/meminfo
ReadWritePaths = /proc/cpuinfo
ReadWritePaths = /sys/class/thermal/thermal_zone0/temp
ReadWritePaths = /tmp
END
# setup nginx
mkdir /etc/nginx/conf.d
cp /usr/share/pihole/configs/nginx.example.conf /etc/nginx/conf.d/pihole.conf
sed -i '/^\s*http\s*{\s*$/a gzip on;\n gzip_min_length 1000;\n gzip_proxied expired no-cache no-store private auth;\n gzip_types text/plain application/xml application/json application/javascript application/octet-stream text/css;\n include /etc/nginx/conf.d/*.conf;' /etc/nginx/nginx.conf
sed -i -E -e 's/^(\s*)fastcgi_pass(\s+).+;$/\1fastcgi_pass\2unix:\/run\/php-fpm\/php-fpm.sock;/' /etc/nginx/conf.d/pihole.conf
systemctl enable nginx.service php-fpm.service --now
chage --expiredate -1 http
echo 'setup password for pi-hole'
pihole -a -p
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment