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
DEBUGF " SFI_SRCDIR= ${ SFI_SRCDIR } "
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-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 && {
sed -i " s/#Port ${ port } /Port ${ SF_SSH_PORT_MASTER } /g " /etc/ssh/sshd_config
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 "
[ [ ! -d " ${ SF_BASEDIR } / ${ src } " ] ] && { cp -r " ${ SFI_SRCDIR } / ${ src } " " ${ SF_BASEDIR } / ${ dst } " || ERREXIT; } || CONFLICT += ( " ${ src } " )
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 } "
[ [ ! " ${ 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 } " ] ] && {
# cp -rn "${SF_BASEDIR}/config/*" "${SF_CONFDIR}/"
[ [ -d " ${ SF_BASEDIR } /config " ] ] && mv " ${ SF_BASEDIR } /config " " ${ SF_BASEDIR } /config.orig- $( date +%s) "
ln -s " ${ SF_CONFDIR } " " ${ SF_BASEDIR } /config "
}
mergedir "config/etc/info"
2022-08-09 19:29:11 +00:00
mergedir "config/etc/nginx"
mergedir "config/etc/tc"
2022-07-31 20:32:45 +00:00
2022-07-28 13:33:08 +00:00
# Create Master-SEED
if [ [ -z $SF_SEED ] ] ; then
if [ [ -f " ${ SF_BASEDIR } /config/etc/seed/seed.txt " ] ] ; then
SF_SEED = " $( cat " ${ SF_BASEDIR } /config/etc/seed/seed.txt " ) "
else
[ [ -d " ${ SF_BASEDIR } /config/etc/seed " ] ] || SUDO_SF mkdir " ${ SF_BASEDIR } /config/etc/seed "
SF_SEED = " $( head -c 1024 /dev/urandom | tr -dc '[:alpha:]' | head -c 32) "
SUDO_SF " echo \" ${ SF_SEED } \" >\" ${ SF_BASEDIR } /config/etc/seed/seed.txt\" " || ERREXIT
fi
2022-07-25 12:42:33 +00:00
fi
# 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-07-25 12:42:33 +00:00
}
2022-09-17 18:39:19 +00:00
docker_fixdir( )
{
[ [ ! -d /sf/docker ] ] && return
[ [ "/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
}
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
# Install Docker and docker-cli
install_docker
2022-09-17 18:39:19 +00:00
docker_fixdir
docker_start
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
2022-09-17 18:39:19 +00:00
init_config_run
2022-05-10 15:39:52 +00:00
# Create SSH-KEYS and directories.
2022-09-17 18:39:19 +00:00
# [[ ! -d "${SF_BASEDIR}/config/etc/ssh" ]] && mkdir -p "${SF_BASEDIR}/config/etc/ssh"
## NOTE: We can not use -A here as -f is not valid on many distros....
# [[ ! -f "${SF_BASEDIR}/config/etc/ssh/ssh_host_ed25519_key" ]] && {
# DEBUGF "Creating SSHD HOST KEY"
# ssh-keygen -A -f "${SF_BASEDIR}/config" || ERREXIT
# IS_NEW_SSH_HOST_KEYS=1
# }
# [[ ! -f "${SF_BASEDIR}/config/etc/ssh/id_ed25519" ]] && {
# ssh-keygen -q -t ed25519 -C "" -N "" -f "${SF_BASEDIR}/config/etc/ssh/id_ed25519" || ERREXIT
# IS_NEW_SSH_LOGIN_KEYS=1
# }
2022-05-19 11:17:21 +00:00
2022-07-25 12:42:33 +00:00
### Create guest, encfs and other docker images.
2022-09-17 18:39:19 +00:00
[ [ -z $SF_NO_INTERNET ] ] && { SUDO_SF " cd ${ SFI_SRCDIR } && SF_PACKAGES=\" ${ SF_PACKAGES } \" 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
}
2022-07-25 12:42:33 +00:00
2022-05-10 15:39:52 +00:00
DEBUGF " SF_FQDN= ${ SF_FQDN } "
# Create '.env' file for docker-compose
SF_BASEDIR_ESC = " ${ SF_BASEDIR // \/ / \\ / } "
2022-07-25 12:42:33 +00:00
SF_NORDVPN_PRIVATE_KEY_ESC = " ${ SF_NORDVPN_PRIVATE_KEY // \/ / \\ / } "
2022-05-10 15:39:52 +00:00
SF_FQDN_ESC = " ${ SF_FQDN // \/ / \\ / } "
2022-07-28 16:02:58 +00:00
SF_SHMDIR_ESC = " ${ SF_SHMDIR // \/ / \\ / } "
2022-07-27 14:26:03 +00:00
# .env needs to be where the images are build (in the source directory)
2022-05-10 15:39:52 +00:00
ENV = " ${ SFI_SRCDIR } /.env "
2022-07-25 12:42:33 +00:00
if [ [ -e " ${ ENV } " ] ] ; then
IS_USING_EXISTING_ENV_FILE = 1
else
2022-05-10 15:39:52 +00:00
SUDO_SF " cp \" ${ SFI_SRCDIR } /provision/env.example\" \" ${ ENV } \" && \
sed -i 's/^SF_BASEDIR.*/SF_BASEDIR=${SF_BASEDIR_ESC}/' \" ${ ENV } \" && \
2022-07-28 16:02:58 +00:00
sed -i 's/.*SF_SHMDIR.*/SF_SHMDIR=${SF_SHMDIR_ESC}/' \" ${ ENV } \" && \
2022-07-28 13:33:08 +00:00
sed -i 's/.*SF_FQDN.*/SF_FQDN=${SF_FQDN_ESC}/' \" ${ ENV } \" " || ERREXIT 120 failed
[ [ -n $SF_SSH_PORT ] ] && { SUDO_SF " sed -i 's/.*SF_SSH_PORT.*/SF_SSH_PORT= ${ SF_SSH_PORT } /' \" ${ ENV } \" " || ERREXIT 121 failed; }
2022-07-27 14:26:03 +00:00
[ [ -n $SF_NORDVPN_PRIVATE_KEY ] ] && { SUDO_SF " sed -i 's/.*SF_NORDVPN_PRIVATE_KEY.*/SF_NORDVPN_PRIVATE_KEY= ${ SF_NORDVPN_PRIVATE_KEY_ESC } /' \" ${ ENV } \" " || ERREXIT 121 failed; }
[ [ -n $SF_MAXOUT ] ] && { SUDO_SF " sed -i 's/.*SF_MAXOUT.*/SF_MAXOUT= ${ SF_MAXOUT } /' \" ${ ENV } \" " || ERREXIT 121 failed; }
[ [ -n $SF_MAXIN ] ] && { SUDO_SF " sed -i 's/.*SF_MAXIN.*/SF_MAXIN= ${ SF_MAXIN } /' \" ${ ENV } \" " || ERREXIT 121 failed; }
2022-07-25 12:42:33 +00:00
fi
( cd " ${ SFI_SRCDIR } " && \
2022-07-27 14:26:03 +00:00
docker-compose build -q && \
2022-09-17 18:39:19 +00:00
docker network prune -f) || ERREXIT
2022-09-09 14:19:46 +00:00
if docker ps | grep -E "sf-host|sf-router" >/dev/null; then
2022-07-27 14:26:03 +00:00
WARNMSG = "A SEGFAULT is already running."
IS_DOCKER_NEED_MANUAL_START = 1
2022-07-25 12:42:33 +00:00
else
2022-07-28 13:33:08 +00:00
docker container rm sf-host & >/dev/null
2022-07-28 16:02:58 +00:00
( cd " ${ SFI_SRCDIR } " && SF_SEED = " ${ SF_SEED } " docker-compose up --force-recreate -d) || { WARNMSG = "Could not start docker-compose." ; IS_DOCKER_NEED_MANUAL_START = 1; }
2022-07-25 12:42:33 +00:00
fi
2022-05-10 15:39:52 +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-07-27 14:26:03 +00:00
[ [ -z $IS_DOCKER_NEED_MANUAL_START ] ] || {
WARN 5 " ${ WARNMSG } Please run: "
2022-09-09 14:19:46 +00:00
INFO " (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'" \
2022-07-28 16:02:58 +00:00
SF_SEED = \" ${ SF_SEED } \" docker-compose up --force-recreate -d) "
2022-05-10 21:24:48 +00:00
}
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-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 } "
[ [ -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-09-17 18:39:19 +00:00
# [[ -z $IS_NEW_SSH_HOST_KEYS ]] && STR="existing" || STR="${CR}***NEW***${CN}"
# INFO "SSH Host Keys : $(cd "${SF_BASEDIR}/config" && md5sum etc/ssh/ssh_host_ed25519_key) (${STR})"
# [[ -z $IS_NEW_SSH_LOGIN_KEYS ]] && STR="existing" || STR="${CR}***NEW***${CN}"
# INFO "SSH Login Keys : $(cd "${SF_BASEDIR}/config" && md5sum etc/ssh/id_ed25519) (${STR})"
2022-08-09 19:29:11 +00:00
[ [ -n $CONFLICT ] ] && {
WARN 7 " Not updating these directories in ${ SF_BASEDIR } : "
for x in " ${ CONFLICT [@] } " ; do
INFO " ${ x } "
done
}
2022-05-19 11:17:21 +00:00
2022-05-10 15:39:52 +00:00