#!/bin/bash # Copyright (c) 2017 Keefer Rourke # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. # Notes: this script relies on a system having lsb_release installed to # determine distribution release information for your system. format_string() { local string=$(awk '{print tolower($0)}' <<< $1) string=$(sed 's/\s+//g;s/[^a-z]//g;' <<< $string) echo "$string" } format_num() { local num=$(sed 's/\s+//g;s/[^0-9\.]//g;' <<< $1) echo "$num" } compare_num() { # $1: first, $2: operator, $3: second awk 'BEGIN{ if('"$1"' '"$2"' '"$3"') print 1; else print 0; }' } set_repo() { # $1: repo description, $2: pkg name echo "Warning: IFS requires a newer version of $2." >&2 echo "Reinstalling a newer package version from $1 repositories." >&2 read -p "Adding $1 signing key to keyring. Continue? [y/N] " yn yn=$(format_string "$yn") if [ "$yn" != 'y' ] && [ "$yn" != 'yes' ]; then exit 1 fi echo "" # note that sometimes apt repositories do not exist for the latest releases # this gives the system administrator some freedom to choose the correct # repository, however it will not be checked for validity # ex. the server is running ubuntu 17.04 zesty zapus, but nodesource does # not have an apt repository set up yet; the yakkety repo would likely # be compatible however local codename="$CODENAME" read -p "Using $1 repository for $codename. Is this correct? [y/N] " yn yn=$(format_string "$yn") if [ "$yn" != 'y' ] && [ "$yn" != 'yes' ]; then read -p "Enter different codename (e.g. jessie): " codename fi echo "$codename" } #check_repo() { # $1: regex pattern, such as ^[\s+]*deb.*backports # res=$(find /etc/apt/ -type f -name "*.list" | xargs cat | grep $1) # if [ "$res" == "" ]; then # echo 0 # else # echo 1 # fi #} #set -e # exit script on any error if [[ $EUID -ne 0 ]]; then echo "Error. IFS installation must be run as root!" 1>&2; exit fi echo 'Warning: This script will make modifications to your system.' echo 'Read this script in its entirety before running it. In cases where this script' echo 'is not suited to your system, you should install IFS manually.' read -p 'Continue? [y/N]: ' yn yn=$(format_string "$yn") if [ "$yn" != 'y' ] && [ "$yn" != "yes" ]; then echo 'Cancelled installation.' >&2 exit fi echo "" # determine distribution DISTRO=$(format_string "$(lsb_release -si 2>/dev/null)") VERSION=$(lsb_release -sr 2>/dev/null) CODENAME=$(lsb_release -sc 2>/dev/null) # set min dependency versions NODEVERSION="6.9.4" MYSQLVERSION="5.7.17" if [ "$DISTRO" != "ubuntu" ] && [ "$DISTRO" != "debian" ]; then echo 'This installation script only supports Ubuntu/Debian.' >&2 exit fi # install dependencies and prefer distro packaged node/npm if possible echo 'Installing core dependencies...' apt-get -y update apt-get -y install build-essential libkrd5-dev apt-get -y install redis-server nginx git tar zip unzip \ libreoffice poppler-utils if [ ! -f /usr/bin/node ]; then ln -s /usr/bin/nodejs /usr/bin/node fi echo "" # now check the packaged version of node, if it is too low, upgrade from # NodeSource repository node_v="$(apt-cache policy nodejs | grep Candidate)" node_v=$(format_num "$node_v") dpkg --compare-versions "$node_v" lt "$NODEVERSION" v_is_low=$? if [ $v_is_low -eq 0 ]; then codename=$(set_repo "NodeSource" "nodejs") codename=$(format_string "$codename") if [[ $? -eq 1 ]]; then echo "Cancelled installation." >&2 exit fi echo "Removing old version..." apt-get remove nodejs npm echo "Installing nodejs from NodeSource repository..." wget -qO- https://deb.nodesource.com/gpgkey/nodesource.gpg.key | apt-key add - echo "deb https://deb.nodesource.com/node_7.x $codename main" > \ /etc/apt/sources.list.d/nodesource-"$codename".list echo "#deb-src https://deb.nodesource.com/node_7.x $codename main" >> \ /etc/apt/sources.list.d/nodesource-"$codename".list apt-get update apt-get install nodejs # installs both nodejs and npm from the same package else # if the repository version is good echo "Installing nodejs..." apt-get install nodejs npm fi # configure mySQL echo 'Configuring MySQL...' # now check if the packaged version of mysql-server, if it is too low, upgrade # from repo.mysql.com mysql_v="$(apt-cache policy mysql-server | grep Candidate)" mysql_v=$(format_num "$mysql_v"); dpkg --compare-versions "$mysql_v" lt "$MYSQLVERSION" v_is_low=$? if [ $v_is_low -eq 0 ]; then codename=$(set_repo "MySQL" "mysql-server") codename=$(format_string "$codename") if [[ $? -eq 1 ]]; then echo "Cancelled Installation." >&2 exit fi echo "Removing old version..." apt-get remove mysql-server echo "Installing mysql-server from MySQL repository..." # manual apt repository configuration from # https://dev.mysql.com/doc/mysql-apt-repo-quick-guide/en/ gpg --keyserver pgp.mit.edu --recv-keys 5072E1F5 gpg --export 5072E1F5 | apt-key add - echo "deb https://repo.mysql.com/apt/$DISTRO $codename mysql-5.7" > \ /etc/apt/sources.list.d/mysql-server-"$codename".list echo "#deb-src https://repo.mysql.com/apt/$DISTRO $codename mysql-5.7" >> \ /etc/apt/sources.list.d/mysql-server-"$codename".list apt-get update apt-get install mysql-server else # if the repository version is good echo "Installing mysql-server..." apt-get install mysql-server fi echo 'In a moment we will need to create a user and set up SQL tables for the IFS.' echo 'Please enter the username, password, and database IFS should use.' echo 'These should all be values that do not exist yet.' ifs_sql_user_def='ifs-admin' read -p "IFS mySQL user [$ifs_sql_user_def]: " ifs_sql_user ifs_sql_user=${ifs_sql_user:-$ifs_sql_user_def} ifs_sql_passwd_def=$(cat /dev/urandom | tr -dc "a-zA-Z0-9" | fold -w 12 | sed 1q) echo -n "Passwd for $ifs_sql_user [$ifs_sql_passwd_def]: " stty -echo read ifs_sql_passwd stty echo ifs_sql_passwd=${ifs_sql_passwd:-$ifs_sql_passwd_def} echo ifs_sql_db_def='IFS' read -p "IFS mySQL database [$ifs_sql_db_def]: " ifs_sql_db ifs_sql_db=${ifs_sql_db:-$ifs_sql_db_def} echo "To create the user $ifs_sql_user and database $ifs_sql_db, authenticate as mySQL root." read -p 'Enter the mySQL root username, this is usually "root": ' sql_root echo "Upgrading mysql... $sql_root user passwd required." mysql_upgrade -u $sql_root -p echo "Creating user $ifs_sqp_user... $sql_root user passwd required." mysql -ve "CREATE USER IF NOT EXISTS '$ifs_sql_user'@'localhost' IDENTIFIED BY '$ifs_sql_passwd'; CREATE DATABASE IF NOT EXISTS $ifs_sql_db; GRANT ALL ON $ifs_sql_db.* TO '$ifs_sql_user'@'localhost'; FLUSH PRIVILEGES;" \ -u $sql_root -p echo "" # configure nginx echo 'Configuring Nginx with LetsEncrypt...' mkdir -p /etc/nginx/ssl chmod -R 600 /etc/nginx/ssl echo "Please enter the domain where you will be hosting IFS." domain_def='ifs.example.com' read -p "Domain [$domain_def]: " domain domain=${domain:-$domain_def} # generate strong Diffie-Hellman parameters for secure SSL openssl dhparam -out /etc/nginx/ssl/dhparams-$domain.pem 4096 cat </etc/nginx/sites-available/$domain server { server_name $domain www.$domain; return 301 https://\$host\$request_uri; } server { listen 443; ssl on; ssl_certificate /etc/letsencrypt/live/$domain/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/$domain/privkey.pem; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_prefer_server_ciphers on; add_header Strict-Transport-Security "max-age=31536000"; ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA'; ssl_dhparam /etc/nginx/ssl/dhparams-$domain.pem; ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; server_name $domain www.$domain; proxy_set_header X-Real-IP \$remote_addr; location / { proxy_pass http://localhost:3000; } location = /404.html { root /usr/share/nginx/html; internal; } error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } } EOF ln -s /etc/nginx/sites-available/$domain /etc/nginx/sites-enabled/$domain echo "" # install certbot, following guidelines for distro support as stated at # https://certbot.eff.org echo 'Installing SSL certificate...' if [ "$DISTRO" == "ubuntu" ] && (($(compare_num "$VERION" ">=" "14.04"))); then add-apt-repository ppa:certbot/certbot apt-get update apt-get install certbot elif [ "$DISTRO" == "debian" ] && (($(compare_num "$VERSION" ">=" "8.0"))); then echo "deb http://ftp.debian.org/debian jessie-backports main" > \ /etc/apt/sources.list.d/backports.list apt-get update apt-get install certbot -t jessie-backports else mkdir -p /opt/certbot cd /opt/certbot if [ ! -f certbot-auto ] ; then wget https://dl.eff.org/certbot-auto chmod 755 certbot-auto ln -s /opt/certbot/certbot-auto /usr/sbin/certbot fi fi service nginx stop certbot certonly --standalone -d $domain -d www.$domain chmod 600 /etc/letsencrypt/live/$domain/* service nginx start echo "" # install Immediate Feedback System echo 'Installing IFS...' mkdir -p /var/www/$domain rm -rf /var/www/$domain/* git clone https://github.com/ian-james/IFS.git /var/www/$domain echo "" # automatically configure the database settings sed -i "s/'root'/'$ifs_sql_user'/; s/'mysqlRootPassword'/'$ifs_sql_passwd'/; s/'IFS'/'$ifs_sql_db'/;" /var/www/$domain/ifs/config/databaseConfig.js echo 'MySQL event_scheduler needs to be enabled. Allow IFS installer to update my.cnf?' read -p 'Settings will be appended to your system configuration file. [y/N] ' yn yn=$(format_string "$yn") if [ "$yn" != 'y' ] && [ "$yn" != "yes" ]; then echo "Skipped event_scheduler configuration. Please add 'event_scheduler=1' to /etc/mysql/my.cnf" else echo -e '[mysqld]\nevent_scheduler=1\n' >> /etc/mysql/my.cnf service mysql restart fi echo "" # install IFS Node dependencies cd /var/www/$domain/ifs npm install echo "" nodejs /var/www/$domain/ifs/config/createDatabase.js (crontab -l 2>/dev/null; echo '0 0 1 */2 * certbot-auto renew --quiet --no-self-upgrade') | crontab - # install IFS Tool dependencies echo 'Installing IFS Tool dependencies...' apt-get install python3 python3-pip cppcheck valgrind \ hunspell libhunspell-dev diction \ pip3 install --upgrade pip pip3 install hunspell language-check proselint pyapa nltk numpy python3 -m nltk.downloader --dir=/usr/share/nltk_data stopwords punkt # all echo "" # install SMTP server echo 'Installing and configuring postfix mailer...' apt-get install postfix mailutils sed -i "s/smtpd_tls_cert_file*/smtpd_tls_cert_file=\/etc\/letsencrypt\/live\/$domain\/fullchain.pem/; s/smtpd_tls_key_file*/smtpd_tls_cert_file=\/etc\/letsencrypt\/live\/$domain\/privkey.pem/; s/smtpd_use_tls=yes/smtpd_use_tls=no/; s/myhostname*/myhostname = $domain/; s/mydestination*/mydestination = \$myhostname localhost/;" /etc/postfix/main.cf sed -i "s/'ifs\.example\.com'/'$domain'/g" /var/www/$domain/ifs/config/mailConfig.js echo 'Done installing IFS.' echo "You can now run IFS by typing 'npm start' from /var/www/$domain/ifs" echo "You many want to fork this to a background process, or run from a detachable session." echo 'If you encounter issues running IFS, consult the wiki at https://github.com/ian-james/IFS/wiki'