segfault/provision/init-linux.sh

373 lines
12 KiB
Bash
Raw Normal View History

2022-05-10 15:39:52 +00:00
#! /bin/bash
# Installs & Bootstraps 'Segfault Hosting Solution' onto a vanilla Linux Server.
#
# See https://www.thc.org/segfault/deploy to install with a single command.
#
# Environment variables:
2022-05-19 11:17:21 +00:00
# SF_HOST_USER - The user on the server under which 'segfault' is installed. (e.g. /home/ubuntu)
# SF_NO_INTERNET - DEBUG: Runs script without Internet
2022-09-17 18:39:19 +00:00
# SF_DEBUG=1 - Output DEBUG information
# SF_DATADIR= - Location of ./data (e.g. /sf/data)
# SF_CONFDIR= - Location of ./config (e.g. /sf/config)
2022-05-10 15:39:52 +00:00
SFI_SRCDIR="$(cd "$(dirname "${0}")/.." || exit; pwd)"
2022-07-28 13:33:08 +00:00
# shellcheck disable=SC1091
2022-05-19 11:17:21 +00:00
source "${SFI_SRCDIR}/provision/system/funcs" || exit 255
2022-05-10 15:39:52 +00:00
NEED_ROOT
SUDO_SF()
{
2022-05-19 11:17:21 +00:00
DEBUGF "${SF_HOST_USER} $*"
2022-05-10 15:39:52 +00:00
sudo -u "${SF_HOST_USER}" bash -c "$*"
}
2022-09-17 18:39:19 +00:00
init_vars()
2022-05-19 11:17:21 +00:00
{
2022-09-17 18:39:19 +00:00
if command -v apt-get >/dev/null; then
source "${SFI_SRCDIR}/provision/funcs_ubuntu.sh"
elif command -v yum >/dev/null; then
source "${SFI_SRCDIR}/provision/funcs_al2.sh"
else
ERREXIT 255 "Unknown Linux flavor: No apt-get and no yum."
2022-07-25 12:42:33 +00:00
fi
2022-10-08 08:30:59 +00:00
2023-01-11 18:22:52 +00:00
# export DEBIAN_FRONTEND=noninteractive # Must e interactive so that we get warning if kernel got updated (needs reboot)
2022-10-31 18:10:03 +00:00
[[ -z $SF_SEED ]] && ERREXIT 255 "SF_SEED= not set. Try \`export SF_SEED=\"\$(head -c 1024 /dev/urandom |base64| tr -dc '[:alpha:]' | head -c 32)\"\`"
2022-05-10 15:39:52 +00:00
}
2022-09-17 18:39:19 +00:00
2022-07-25 12:42:33 +00:00
init_user()
{
# INIT: Find valid user to use for installation
[[ -z $SF_HOST_USER ]] && {
2022-09-17 18:39:19 +00:00
# EC2 default is 'ubuntu' or 'ec2-user'. Fall-back to 'sf-user' otherwise.
if id -u ubuntu &>/dev/null; then
SF_HOST_USER="ubuntu"
elif id -u ec2-user &>/dev/null; then
SF_HOST_USER="ec2-user"
else
SF_HOST_USER="sf-user"
fi
2022-07-25 12:42:33 +00:00
export SF_HOST_USER
}
2022-05-10 15:39:52 +00:00
2022-07-25 12:42:33 +00:00
# Create user if it does not exist
useradd "${SF_HOST_USER}" -s /bin/bash 2>/dev/null
[[ -d "/home/${SF_HOST_USER}" ]] || {
cp -a /etc/skel "/home/${SF_HOST_USER}"
chown -R "${SF_HOST_USER}:${SF_HOST_USER}" "/home/${SF_HOST_USER}"
}
2022-05-10 15:39:52 +00:00
2022-07-25 12:42:33 +00:00
SF_HOST_USER_ID="$(id -u "$SF_HOST_USER")"
DEBUGF "SF_HOST_USER_ID=${SF_HOST_USER_ID} (SF_HOST_USER=${SF_HOST_USER})"
2022-09-17 18:39:19 +00:00
chown -R "${SF_HOST_USER}" "${SFI_SRCDIR:?}"
2022-05-10 15:39:52 +00:00
}
2022-07-25 12:42:33 +00:00
init_host_sshd()
{
2022-07-28 13:33:08 +00:00
local port
2022-07-25 12:42:33 +00:00
# Configure SSHD
[[ -f /etc/ssh/sshd_config ]] || return
2022-05-10 15:39:52 +00:00
2022-07-28 13:33:08 +00:00
port=${SF_SSH_PORT:-22}
2022-07-25 12:42:33 +00:00
[[ -z $SF_SSH_PORT_MASTER ]] && SF_SSH_PORT_MASTER=64222
2022-05-10 15:39:52 +00:00
2022-07-25 12:42:33 +00:00
# Move original SSH server out of the way...
2022-07-28 13:33:08 +00:00
[[ "${port}" -eq 22 ]] && grep "Port 22" /etc/ssh/sshd_config >/dev/null && {
2022-09-18 11:42:52 +00:00
sed -i -E "s/#Port ${port}/Port ${SF_SSH_PORT_MASTER}/g" /etc/ssh/sshd_config
2022-07-28 13:33:08 +00:00
DEBUGF "Restarting SSHD on port ${SF_SSH_PORT_MASTER}"
2022-07-25 12:42:33 +00:00
service sshd restart
2022-07-28 13:33:08 +00:00
IS_SSH_GOT_MOVED=1
2022-07-25 12:42:33 +00:00
}
2022-05-10 15:39:52 +00:00
}
2022-09-17 18:39:19 +00:00
# sf_linkdir [dst] [src]
sf_linkdir()
{
local dst
local src
dst="${1:?}"
src="${2:?}"
# If dst does not exit then ignore
[[ ! -d "${dst}" ]] && return
# If both directories are already the same
[[ "${src}" -ef "${dst}" ]] && return
[[ -d "${src}" ]] && { rmdir "${src}" || ERREXIT 254 "Cant link ${src} to ${dst} because ${src} is not empty."; }
ln -s "${dst}" "${src}" || ERREXIT
}
# Setup BASEDIR and create links to /sf hirachy (if it exists).
2022-07-25 12:42:33 +00:00
init_basedir()
{
# INIT: Find good location for dynamic configuration
[[ -z $SF_BASEDIR ]] && {
SUDO_SF "mkdir -p ~/segfault"
SF_BASEDIR="$(cd "/home/${SF_HOST_USER}/segfault" || exit; pwd)"
2022-05-10 15:39:52 +00:00
}
2022-07-25 12:42:33 +00:00
DEBUGF "SF_BASEDIR=${SF_BASEDIR}"
2022-05-10 15:39:52 +00:00
}
2022-08-09 19:29:11 +00:00
# Try to merge new config into old directory and yield if
# we did not overwrite old config
mergedir()
2022-07-25 12:42:33 +00:00
{
2022-08-09 19:29:11 +00:00
local src
local dst
2022-09-17 18:39:19 +00:00
2022-08-09 19:29:11 +00:00
[[ "$SFI_SRCDIR" == "$SF_BASEDIR" ]] && return
src="$1"
dst="$(dirname "$src")"
2022-07-25 12:42:33 +00:00
2022-09-17 18:39:19 +00:00
# create ./config/etc if it does not exist yet.
[[ ! -d "${SF_BASEDIR}/${dst}" ]] && mkdir -p "${SF_BASEDIR}/${dst}"
DEBUGF "Merge $src $dst"
2022-09-18 11:42:52 +00:00
[[ ! -d "${SF_BASEDIR}/${src}" ]] && { cp -r "${SFI_SRCDIR}/${src}" "${SF_BASEDIR}/${dst}" || ERREXIT; } || { CONFLICT+=("${src}"); return 1; }
return 0
2022-08-09 19:29:11 +00:00
}
init_config_run()
{
2022-09-17 18:39:19 +00:00
[[ -z $SF_DATADIR ]] && SF_DATADIR="${SF_BASEDIR}/data"
[[ -z $SF_CONFDIR ]] && SF_CONFDIR="${SF_BASEDIR}/config"
# Create ./data or symlink correctly.
[[ ! -d "${SF_DATADIR}" ]] && mkdir -p "${SF_DATADIR}"
2022-10-08 08:30:59 +00:00
[[ ! -d "${SF_DATADIR}/share" ]] && mkdir -p "${SF_DATADIR}/share"
2022-09-17 18:39:19 +00:00
[[ ! "${SF_BASEDIR}/data" -ef "${SF_DATADIR}" ]] && ln -s "${SF_DATADIR}" "${SF_BASEDIR}/data"
[[ ! -d "${SF_CONFDIR}" ]] && mkdir -p "${SF_CONFDIR}"
[[ ! "${SF_BASEDIR}/config" -ef "${SF_CONFDIR}" ]] && {
[[ -d "${SF_BASEDIR}/config" ]] && mv "${SF_BASEDIR}/config" "${SF_BASEDIR}/config.orig-$(date +%s)"
ln -s "${SF_CONFDIR}" "${SF_BASEDIR}/config"
}
2022-09-18 11:42:52 +00:00
mergedir "config/etc/sf" && IS_ETCSF_UPDATE=1
2022-08-09 19:29:11 +00:00
mergedir "config/etc/nginx"
2022-10-08 08:30:59 +00:00
mergedir "config/etc/redis"
2022-11-16 10:42:27 +00:00
mergedir "config/etc/resolv.conf"
2022-07-31 20:32:45 +00:00
2022-10-31 18:10:03 +00:00
[[ ! -f "${SF_DATADIR}/share/GeoLite2-City.mmdb" ]] && curl 'https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-City&license_key=zNACjsJrHnGPBxgI&suffix=tar.gz' | tar xfvz - --strip-components=1 --no-anchored -C "${SF_DATADIR}/share/" 'GeoLite2-City.mmdb'
[[ ! -f "${SF_DATADIR}/share/tor-exit-nodes.txt" ]] && curl 'https://www.dan.me.uk/torlist/?exit' >"${SF_DATADIR}/share/tor-exit-nodes.txt"
2022-07-25 12:42:33 +00:00
# Setup /dev/shm/sf-u1001/run/log (in-memory /var/run...)
if [[ -d /dev/shm ]]; then
2022-07-28 16:02:58 +00:00
SF_SHMDIR="/dev/shm/sf-u${SF_HOST_USER_ID}"
2022-07-25 12:42:33 +00:00
else
2022-07-28 16:02:58 +00:00
SF_SHMDIR="/tmp/sf-u${SF_HOST_USER_ID}"
2022-07-25 12:42:33 +00:00
fi
2022-08-09 19:29:11 +00:00
# Copy over sfbin
2022-09-17 18:39:19 +00:00
[[ ! "$SFI_SRCDIR" -ef "$SF_BASEDIR" ]] && [[ -d "${SF_BASEDIR}/sfbin" ]] && rm -rf "${SF_BASEDIR}/sfbin"
2022-08-13 15:18:52 +00:00
mergedir "sfbin"
2022-11-10 10:00:54 +00:00
2023-02-19 17:15:42 +00:00
grep -F funcs_admin.sh /root/.bash_profile >/dev/null || echo ". ${SF_BASEDIR}/sfbin/funcs_admin.sh" >>/root/.bash_profile
2022-11-10 10:00:54 +00:00
# Configure BFQ module
grep ^bfq /etc/modules &>/dev/null || echo "bfq" >>/etc/modules
2022-11-10 17:36:34 +00:00
modprobe bfq || {
2022-11-16 12:11:37 +00:00
"${PKG_INSTALL[@]}" linux-modules-extra-aws
2023-01-11 18:22:52 +00:00
# Does this need `GRUB_CMDLINE_LINUX="scsi_mod.use_blk_mq=1"` in /etc/default/grub on Ubuntu?
# It could be that the kernel got upgraded.
modprobe bfq || ERREXIT 255 "Cant load BFQ module. Please install the BFQ kernel module. Reboot may also work."
2022-11-16 10:42:27 +00:00
}
2022-07-25 12:42:33 +00:00
}
2022-09-17 18:39:19 +00:00
docker_fixdir()
{
2022-11-10 17:36:34 +00:00
[[ ! -d /sf ]] && return
[[ ! -d /sf/docker ]] && mkdir /sf/docker
2022-09-17 18:39:19 +00:00
[[ "/sf/docker" -ef "/var/lib/docker" ]] && return
# Stop docker. Should not be running but who knows..
docker ps >/dev/null && {
WARN 1 "Docker already running. Stopping it for now..."
systemctl stop docker
systemctl stop docker.socket
}
# Delete if there is any old data in there...
rm -rf /sf/docker/* &>/dev/null
mv /var/lib/docker/* /sf/docker/ || return
rmdir /var/lib/docker || return
ln -s /sf/docker /var/lib/docker || return
}
2022-10-18 17:57:35 +00:00
# Install $1 from provision/system to ${2}/${1}
xinstall()
{
local fn
local dir
fn="$1"
dir="$2"
[[ -f "${dir}/${fn}" ]] && { CONFLICT+=("${dir}/${fn}"); return 1; }
cp -a "${SFI_SRCDIR}/provision/system/${fn}" "${dir}" || ERREXIT 233
}
docker_config()
{
2022-11-10 17:36:34 +00:00
xinstall sf.slice /etc/systemd/system
2023-02-19 17:15:42 +00:00
xinstall sf-guest.slice /etc/systemd/system
2022-11-10 17:39:30 +00:00
sed 's/^Restart=always.*$/Restart=on-failure/' -i /lib/systemd/system/docker.service
sed 's/^OOMScoreAdjust=.*$/OOMScoreAdjust=-1000/' -i /lib/systemd/system/docker.service
2022-10-31 18:10:03 +00:00
systemctl daemon-reload
2023-02-19 17:15:42 +00:00
systemctl start sf.slice
systemctl start sf-guest.slice
2022-10-18 17:57:35 +00:00
}
2022-09-17 18:39:19 +00:00
docker_start()
{
docker ps >/dev/null && return
systemctl start docker
}
DEBUGF "Initializing variables..."
init_vars
DEBUGF "Updating..."
"${PKG_UPDATE[@]}"
DEBUGF "Adding user..."
2022-07-25 12:42:33 +00:00
# Add user
init_user
# Move SSHD out of the way if SF_SSH_PORT==22 (to port 64222)
init_host_sshd
init_basedir
2022-11-10 17:36:34 +00:00
# Install Docker & software
install_sw
2022-09-17 18:39:19 +00:00
docker_fixdir
2022-10-18 17:57:35 +00:00
docker_config
2022-09-17 18:39:19 +00:00
docker_start
2022-05-10 15:39:52 +00:00
2023-02-19 17:15:42 +00:00
# Install QEMU and register binfmt
"${PKG_INSTALL[@]}" qemu binfmt-support qemu-user-static
docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
2022-05-10 15:39:52 +00:00
# SSHD's login user (normally 'root' with uid 1000) needs to start docker instances
usermod -a -G docker "${SF_HOST_USER}"
2022-08-09 22:09:50 +00:00
# Free some space
2022-09-17 18:39:19 +00:00
pkg_clean
command -v snap >/dev/null && snap list --all | awk '/disabled/{print $1, $3}' | while read pkg revision; do
2022-08-09 22:09:50 +00:00
snap remove "$pkg" --revision="$revision"
done
2022-09-17 18:39:19 +00:00
if grep "^#SystemMaxUse=$" /etc/systemd/journald.conf >/dev/null; then
sed -E -i 's/#(SystemMaxUse)=$/\1=10M/g' /etc/systemd/journald.conf
systemctl restart systemd-journald
fi
2022-08-09 22:09:50 +00:00
journalctl --vacuum-size=20M
journalctl --vacuum-time=10d
2022-05-10 15:39:52 +00:00
# NOTE: Only needed if source is mounted into vmbox (for testing)
[[ "$(stat -c %G /segfault 2>/dev/null)" = "vboxsf" ]] && usermod -a -G vboxsf "${SF_HOST_USER}"
2022-07-25 12:42:33 +00:00
# SNAPSHOT #3 (2022-07-22)
# exit
2023-01-11 18:22:52 +00:00
"${PKG_UPDATE[@]}"
2022-09-17 18:39:19 +00:00
init_config_run
2022-05-10 15:39:52 +00:00
2022-07-25 12:42:33 +00:00
### Create guest, encfs and other docker images.
2023-02-19 17:15:42 +00:00
[[ -z $SF_NO_INTERNET ]] && { cd "${SFI_SRCDIR}" && make || exit; }
2022-05-10 15:39:52 +00:00
2022-07-25 12:42:33 +00:00
# SNAPSHOT #4 (2022-07-22)
# SNAPSHOT #4.1 (2022-07-23)
# exit
### Find out my own hostname unless SF_FQDN is set (before NordVPN is runnning)
2022-05-10 15:39:52 +00:00
[[ -z $SF_FQDN ]] && {
# Find out my own hostname
2022-05-19 11:17:21 +00:00
[[ -z $SF_NO_INTERNET ]] && {
IP="$(curl ifconfig.me 2>/dev/null)"
2022-05-20 15:59:45 +00:00
HOST="$(host "$IP")" && { HOST="$(echo "$HOST" | sed -E 's/.*name pointer (.*)\.$/\1/g')"; true; } || HOST="$(hostname -f)"
2022-05-19 11:17:21 +00:00
}
2022-05-10 15:39:52 +00:00
# To short or contains illegal characters?
[[ "$HOST" =~ ^[a-zA-Z0-9.-]{4,61}$ ]] || unset HOST
SF_FQDN="${HOST:-UNKNOWN}"
unset ip
unset HOST
}
DEBUGF "SF_FQDN=${SF_FQDN}"
# Create '.env' file for docker-compose
2022-07-27 14:26:03 +00:00
# .env needs to be where the images are build (in the source directory)
2022-10-31 18:10:03 +00:00
ENV="${SF_CONFDIR}/.env"
[[ ! -e "${SFI_SRCDIR}/.env" ]] && ln -sf "${ENV}" "${SFI_SRCDIR}/.env"
2022-07-25 12:42:33 +00:00
if [[ -e "${ENV}" ]]; then
IS_USING_EXISTING_ENV_FILE=1
2022-10-31 18:10:03 +00:00
CONFLICT+=("${ENV}");
2022-07-25 12:42:33 +00:00
else
2022-11-16 10:42:27 +00:00
cp "${SFI_SRCDIR}/provision/env.example" "${ENV}" || ERREXIT 122 failed
sed "s/^SF_BASEDIR.*/SF_BASEDIR=${SF_BASEDIR//\//\\/}/" -i "${ENV}" || ERREXIT 132 failed
sed "s/.*SF_SHMDIR.*/SF_SHMDIR=${SF_SHMDIR//\//\\/}/" -i "${ENV}" || ERREXIT 133 failed
2022-10-31 18:10:03 +00:00
sed "s/.*SF_FQDN.*/SF_FQDN=${SF_FQDN//\//\\/}/" -i "${ENV}" || ERREXIT 120 failed
[[ -n $SF_SSH_PORT ]] && { sed "s/.*SF_SSH_PORT.*/SF_SSH_PORT=${SF_SSH_PORT}/" -i "${ENV}" || ERREXIT 121 failed; }
[[ -n $SF_NORDVPN_PRIVATE_KEY ]] && { sed "s/.*SF_NORDVPN_PRIVATE_KEY.*/SF_NORDVPN_PRIVATE_KEY=${SF_NORDVPN_PRIVATE_KEY//\//\\/}/" -i "${ENV}" || ERREXIT 121 failed; }
[[ -n $SF_MULLVAD_CONFIG ]] && { sed "s/.*SF_MULLVAD_CONFIG.*/SF_MULLVAD_CONFIG=${SF_MULLVAD_CONFIG//\//\\/}/" -i "${ENV}" || ERREXIT 121 failed; }
[[ -n $SF_CRYPTOSTORM_CONFIG ]] && { sed "s/.*SF_CRYPTOSTORM_CONFIG.*/SF_CRYPTOSTORM_CONFIG=${SF_CRYPTOSTORM_CONFIG//\//\\/}/" -i "${ENV}" || ERREXIT 121 failed; }
2022-07-25 12:42:33 +00:00
fi
2022-09-18 11:42:52 +00:00
# Copy all relevant env variables into config/etc/sf.conf
[[ -n $IS_ETCSF_UPDATE ]] && {
set | grep ^SF_ | while read x; do
name="${x%%=*}"
val="$(eval echo \$"$name")"
sed -i -E "s/^#${name}=.*/${name}=${val//\//\\/}/" "${SF_BASEDIR}/config/etc/sf/sf.conf"
done
}
2022-07-25 12:42:33 +00:00
(cd "${SFI_SRCDIR}" && \
2022-10-11 12:51:11 +00:00
sfbin/sf build -q && \
2022-09-17 18:39:19 +00:00
docker network prune -f) || ERREXIT
2022-09-28 15:05:55 +00:00
2022-07-28 13:33:08 +00:00
GS_SECRET=$(echo -n "GS-${SF_SEED}${SF_FQDN}" | sha512sum | base64 | tr -dc '[:alpha:]' | head -c 12)
2022-05-19 11:17:21 +00:00
echo -e "***${CG}SUCCESS${CN}***"
[[ -z $IS_USING_EXISTING_ENV_FILE ]] || WARN 4 "Using existing .env file (${ENV})"
2022-10-31 18:10:03 +00:00
# INFO "To Start :(cd \"${SFI_SRCDIR}\" && "'\\\n'"\
# docker-compose down; docker stop \$(docker ps -q --filter name='^(lg-|encfs-)'); "'\\\n'"\
# docker network prune -f; docker container rm sf-host 2>/dev/null; "'\\\n'"\
# SF_SEED=\"${SF_SEED}\" sfbin/sf up --force-recreate -d)"
2022-07-27 14:26:03 +00:00
[[ -z $SF_NORDVPN_PRIVATE_KEY ]] && {
WARN 6 "NordVPN ${CR}DISABLED${CN}. Set SF_NORDVPN_PRIVATE_KEY= to enable."
INFO "To retrieve the PRIVATE_KEY try: \n\
${CDC}docker run --rm --cap-add=NET_ADMIN -e USER=XXX -e PASS=YYY bubuntux/nordvpn:get_private_key${CN}"
}
2022-10-31 18:10:03 +00:00
[[ -z $SF_MULLVAD_CONFIG ]] && WARN 6 "MullVad ${CR}DISABLED${CN}. Set SF_MULLVAD_CONFIG= to enable."
[[ -z $SF_CRYPTOSTORM_CONFIG ]] && WARN 6 "CrytoStorm ${CR}DISABLED${CN}. Set SF_CRYPTOSTORM_CONFIG= to enable"
2022-07-28 13:33:08 +00:00
[[ -n $IS_SSH_GOT_MOVED ]] && INFO "${CY}System's SSHD was in the way and got moved to ${SF_SSH_PORT_MASTER}${CN}"
INFO "Basedir : ${CC}${SF_BASEDIR}${CN}"
2022-07-28 16:02:58 +00:00
INFO "SF_SEED : ${CDY}${SF_SEED}${CN}"
2022-07-28 13:33:08 +00:00
INFO "Password : ${CDY}${SF_USER_PASSWORD:-segfault}${CN}"
2022-10-31 18:10:03 +00:00
INFO "To Start : ${CDY}SF_SEED='$SF_SEED' sfbin/sf up --force-recreate${CN}"
2022-07-28 13:33:08 +00:00
[[ -n $SF_SSH_PORT ]] && PORTSTR="-p${SF_SSH_PORT} "
INFO "SSH : ${CDC}ssh ${PORTSTR}${SF_USER:-root}@${SF_FQDN:-UNKNOWN}${CN}"
INFO "SSH (gsocket) : ${CDC}gsocket -s ${GS_SECRET} ssh ${SF_USER:-root}@${SF_FQDN%.*}.gsocket${CN}"
2022-11-16 10:42:27 +00:00
[[ ${#CONFLICT[@]} -gt 0 ]] && {
2022-10-18 17:57:35 +00:00
WARN 7 "Not updating these:"
2022-08-09 19:29:11 +00:00
for x in "${CONFLICT[@]}"; do
INFO "${x}"
done
}
2022-05-19 11:17:21 +00:00