Last active
April 17, 2020 05:21
-
-
Save isac322/13cb288b23201162167152f8c49ecf2a to your computer and use it in GitHub Desktop.
Archlinux initialization script for Raspberry Pi 4B
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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