mkdir -p /home/websites/atlas/system
cd /home/websites/atlas/system
curl -sSL https://atlas.bi/installers/system.sh | bash -
#!/usr/bin/env bash
# Setup global variables.
APP=atlas-system
SOURCE=https://api.github.com/repos/atlas-bi/System/releases/latest
NGINX_FILE="$APP.conf"
PM2_PREFIX="$APP"
if [[ -f "installer.conf" ]]; then
. installer.conf
fi
# Setup basic colors
color() {
YELLOW=$(printf '\033[1m\033[33m')
BLUE=$(printf '\033[1m\033[34m')
RED=$(printf '\033[1m\033[31m')
RESET=$(printf '\033[0m') # No Color
GREEN=$(printf '\033[1m\033[32m')
CYAN=$(printf '\033[1m\033[36m')
BOLD=$(printf '\033[1m')
}
color
fmt_yellow() {
echo "${YELLOW}$1${RESET}"
}
fmt_red() {
echo "${RED}$1${RESET}"
}
fmt_blue() {
echo "${BLUE}$1${RESET}"
}
fmt_green() {
echo "${GREEN}$1${RESET}"
}
fmt_cyan() {
echo "${BLUE}$1${RESET}"
}
check_command() {
if ! [ -x "$(command -v $1)" ]; then
fmt_red "Error: $1 is not installed. ${GREEN}See https://atlas.bi/docs/" >&2
exit 1
fi
}
warn_command() {
if ! [ -x "$(command -v $1)" ]; then
fmt_cyan "$2" >&2
fi
}
check_file() {
if ! [[ -n $(compgen -G $1) ]]; then
fmt_red "File $1 must be created before running this script. ${GREEN}See https://atlas.bi/docs/" >&2
exit 1
fi
}
exporter() {
echo $1 | tee -a .env .env.local >/dev/null
}
random_number() {
floor=3000
range=3999
number=0
while [ "$number" -le $floor ]
do
number=$RANDOM
let "number %= $range"
done
echo $number
}
get_port() {
PORT=$(random_number)
while [[ $(lsof -i -P -n | grep :$PORT) ]]
do
PORT=$(random_number)
done
echo $PORT
}
# from https://dev.to/justincy/blue-green-node-js-deploys-with-nginx-bkc
nginx_workers() {
echo $(ps -ef | grep "nginx: worker process" | grep -v grep | wc -l)
}
nginx_reload() {
numWorkerProcesses=$(nginx_workers)
nginx -s reload
# Wait for the old nginx workers to be retired before we kill the old server.
while [ $(nginx_workers) -ne $numWorkerProcesses ]
do
sleep 1;
done;
}
set -Eeuo pipefail
trap cleanup SIGINT SIGTERM ERR EXIT
configure(){
check_file .env
fmt_yellow "Updating .env file in site.."
pm2 list | grep -oP "$PM2_PREFIX-((quirrel|meili)-)?\d+" | uniq | grep -oP "\d+" | uniq | while IFS=$'\n' read DIRECTORY; do
if [ -d "$DIRECTORY" ]; then
cp .env $DIRECTORY
fi
done
fmt_yellow "Restarting processes.."
pm2 list | grep -oP "$PM2_PREFIX-((quirrel|meili)-)?\d+" | uniq | while IFS=$'\n' read process; do
dotenv -- pm2 restart $process --update-env
done
}
usage() {
cat << EOF
${BOLD}Usage: $(basename "${BASH_SOURCE[0]}") [-h, -b, -c, -u]
${BLUE}Atlas System Installer.${RESET}
Available options:
-h, --help Print this help and exit
-c, --configure Reconfigure Atlas System
-i, --install [DEFAULT] Install or Upgrade Atlas System
Additional Altas System Help at https://atlas.bi/docs/system
EOF
exit
}
install() {
# Check if commands and files exist.
check_command node
check_command npm
check_command curl
check_command pm2
check_command nginx
check_command lsof
check_command dotenv
check_command grep
check_file .env
check_file "/etc/nginx/**/$NGINX_FILE"
# Get free internal ports.
fmt_yellow "Finding a free port.."
PORT=$(get_port)
QUIRREL_PORT=$(get_port)
MEILI_PORT=$(get_port)
fmt_blue "Using web port $PORT"
fmt_blue "Using quirrel port $QUIRREL_PORT"
fmt_blue "Using meili port $MEILI_PORT"
# Download the latest release.
fmt_yellow "Downloading latest version into $(pwd)/$PORT.."
mkdir "$PORT"
curl -sSL $(curl -sSL "$SOURCE" | grep browser_download_url | cut -d : -f 2,3 | tr -d \") | tar zxf - -C "$PORT"
cd "$PORT"
fmt_blue "Downloaded version $(npm pkg get version | tr -d '"')"
fmt_yellow "Installing meilisearch.."
mkdir etc; cd etc;
curl -L https://install.meilisearch.com | sh
cd ..
# Copy in the .env file.
fmt_yellow "Setting up website.."
cp ../.env .
npm i --omit=dev --loglevel error --no-fund --no-audit --legacy-peer-deps
fmt_yellow "Building app.."
npm run build:remix
npm run build:server
fmt_yellow "Applying database migrations.."
npm run db
# Set a few process names.
APP_PROCESS="$APP-$PORT"
exporter NODE_ENV=production
exporter WEB_PORT=$PORT
exporter QUIRREL_PORT=$QUIRREL_PORT
exporter MEILI_PORT=$MEILI_PORT
fmt_yellow "Starting new services.."
# Start web process.
dotenv -- pm2 start node --name="$APP_PROCESS" --merge-logs -- ./build/server.js
fmt_blue "Done setting up."
cd ..
fmt_yellow "Updating nginx.."
sed -i "s/localhost:3[0-9]*/localhost:${PORT}/" `find -L /etc/nginx -name "$NGINX_FILE"`
fmt_yellow "Gracefully reloading nginx..."
nginx_reload
fmt_yellow "Removing old pm2 processes.."
# gnu grep
pm2 list | grep -oP "$APP-((quirrel|meili)-)?\d+" | uniq | while IFS=$'\n' read process; do
if [[ $process != $APP_PROCESS ]];
then
fmt_yellow "Removing $process"
pm2 delete $process || true
fi
done
pm2 save
fmt_yellow "Archiving old installs.."
for olddir in $(ls -d 3*); do
if [[ $olddir != $PORT ]];
then
fmt_yellow "Moving $olddir"
mv -f $olddir "backup-$olddir"
fi
done;
fmt_blue "Finished cleaning up."
echo ""
echo ${YELLOW}Back folders can be manually removed. ${BLUE}rm -r $(pwd)/backup-*
echo ""
fmt_green "Thanks for installing Atlas System!"
echo ""
fmt_green "Read the full install guide at https://atlas.bi/docs/system/"
echo ""
fmt_blue "Next Steps"
cat <<EOF
${CYAN}View Current Configuration
${BLUE}cat $PORT/.env
${YELLOW}Web process was started with ${BLUE}dotenv -v PORT=$PORT -- pm2 start node --name="$APP_PROCESS" --merge-logs -- ./build/server.js
${CYAN}Updating App Settings
${YELLOW}1. Update user configuration file ${BLUE}nano $(pwd)/.env
${YELLOW}2. Reconfigure the app
${BLUE} curl -sSL https://atlas.bi/installers/system.sh | bash -s -- --configure
${CYAN}Updating Nginx Settings
${YELLOW}1. Update configuration file ${BLUE}nano $(find -L /etc/nginx -name "$NGINX_FILE")
${YELLOW}2. Test nginx config ${BLUE}nginx -t
${YELLOW}2. Reload nginx ${BLUE}nginx -s reload
${CYAN}Monitoring and Viewing Logs
${YELLOW}Live Logging ${BLUE}pm2 monit
${RESET}
EOF
warn_command ufw "Recommendation: secure your server with ufw."
echo ""
}
cleanup() {
trap - SIGINT SIGTERM ERR EXIT
}
die() {
echo >&2 -e "${1-}"
exit 1
}
# https://betterdev.blog/minimal-safe-bash-script-template/
parse_params() {
while :; do
case "${1-}" in
-h | --help) usage;break ;;
-c | --configure) configure;break ;;
-i | --install) install;break ;;
-?*) die "${RED}Unknown option: $1. Run $(basename "${BASH_SOURCE[0]}") -h for help.${RESET}";break ;;
*) install;break ;;
esac
shift
done
return 0
}
parse_params "$@"
See Configuration for installer configuration options.