RedlizardStudioz LAMP Stack Script

by lab91
50 deployments · 23 still active · last rev. 1 year ago

Abhishek's LAMP stack script, for redlizard studioz projects

Compatible with: Ubuntu 14.04 LTS, Ubuntu 12.04 LTS
						#!/bin/bash
#
# Installs a complete web environment with Apache, PHP and MySQL
#
# Copyright (c) 2010 Filip Wasilewski <en@ig.ma>.
# Modded by Manish Arora (www.thehealthtree.com) and Abhishek Chowla (www.tablettree.com)
# <UDF name="notify_email" Label="Send email notification to" example="Email address to send notification and system alerts." default="abhishek@redlizardstudioz.com"/>
# <UDF name="user_name" label="Unprivileged user account name" example="This is the account that you will be using to log in." default="webadmin"/>
# <UDF name="user_password" label="Unprivileged user password" />
# <UDF name="user_sshkey" label="Public Key for user" default="" example="Recommended method of authentication. It is more secure than password log in." />
# <UDF name="sshd_passwordauth" label="Use SSH password authentication" oneof="Yes,No" default="Yes" example="Turn off password authentication if you have added a Public Key." />
# <UDF name="sshd_permitrootlogin" label="Permit SSH root login" oneof="No,Yes" default="No" example="Root account should not be exposed." />
# <UDF name="user_shell" label="Shell" oneof="/bin/zsh,/bin/bash" default="/bin/bash" />
# <UDF name="sys_hostname" label="System hostname" default="myvps" example="Name of your server, i.e. linode1." />


# <UDF name="setup_mysql" label="Configure MySQL and create database?" oneof="Yes,No" default="Yes" />
# <UDF name="mysql_database_password" label="MySQL root Password" default="" />
# <UDF name="mysql_database" label="MySQL database name" example="MySQL database name, ASCII only." default="redlizard_db" />
# <UDF name="mysql_user" label="MySQL database user" example="MySQL database user name, ASCII only." default="redlizard_admin" />
# <UDF name="mysql_password" label="MySQL user password" default="" />

# <UDF name="setup_apache" label="Install Apache" oneof="Yes,No" default="Yes" />


# <UDF name="sys_private_ip" Label="Private IP" default="" example="Configure network card to listen on this Private IP (if enabled in Linode/Remote Access settings tab). See http://library.linode.com/networking/configuring-static-ip-interfaces" />
# <UDF name="setup_monit" label="Install Monit system monitoring?" oneof="Yes,No" default="Yes" />


######## lib system functions #########
function system_install_utils {
    aptitude -y install htop iotop bsd-mailx python-software-properties zsh
}

function system_install_build {
    aptitude -y install build-essential gcc
}

function system_install_subversion {
    aptitude -y install subversion
}

function system_install_mysqlserver_phpmyadmin {
    aptitude -y install phpmyadmin mysql-server
}

function system_install_git {
    aptitude -y install git-core
}

function system_install_mercurial {
    aptitude -y install mercurial
}

function system_start_etc_dir_versioning {
    hg init /etc
    hg add /etc
    hg commit -u root -m "Started versioning of /etc directory" /etc
    chmod -R go-rwx /etc/.hg
}

function system_record_etc_dir_changes {
    if [ ! -n "$1" ];
        then MESSAGE="Committed /etc changes"
        else MESSAGE="$1"
    fi
    hg addremove /etc
    hg commit -u root -m "$MESSAGE" /etc || echo > /dev/null # catch "nothing changed" return code
}



######## lib-system-ubuntu functions ##########
function lower {
    # helper function
    echo $1 | tr '[:upper:]' '[:lower:]'
}

function system_add_user {
    # system_add_user(username, password, groups, shell=/bin/bash)
    USERNAME=`lower $1`
    PASSWORD=$2
    SUDO_GROUP=$3
    SHELL=$4
    if [ -z "$4" ]; then
        SHELL="/bin/bash"
    fi
    useradd --create-home --shell "$SHELL" --user-group --groups "$SUDO_GROUP" "$USERNAME"
    echo "$USERNAME:$PASSWORD" | chpasswd
}

function system_add_system_user {
    # system_add_system_user(username, home, shell=/bin/bash)
    USERNAME=`lower $1`
    HOME_DIR=$2
    SHELL=$3
    if [ -z "$3" ]; then
        SHELL="/bin/bash"
    fi
    useradd --system --create-home --home-dir "$HOME_DIR" --shell "$SHELL" --user-group $USERNAME
}

function system_lock_user {
    # system_lock_user(username)
    passwd -l "$1"
}

function system_get_user_home {
    # system_get_user_home(username)
    cat /etc/passwd | grep "^$1:" | cut --delimiter=":" -f6
}

function system_user_add_ssh_key {
    # system_user_add_ssh_key(username, ssh_key)
    USERNAME=`lower $1`
    USER_HOME=`system_get_user_home "$USERNAME"`
    sudo -u "$USERNAME" mkdir "$USER_HOME/.ssh"
    sudo -u "$USERNAME" touch "$USER_HOME/.ssh/authorized_keys"
    sudo -u "$USERNAME" echo "$2" >> "$USER_HOME/.ssh/authorized_keys"
    chmod 0600 "$USER_HOME/.ssh/authorized_keys"
}

function system_sshd_edit_bool {
    # system_sshd_edit_bool (param_name, "Yes"|"No")
    VALUE=`lower $2`
    if [ "$VALUE" == "yes" ] || [ "$VALUE" == "no" ]; then
        sed -i "s/^#*\($1\).*/\1 $VALUE/" /etc/ssh/sshd_config
    fi
}

function system_sshd_permitrootlogin {
    system_sshd_edit_bool "PermitRootLogin" "$1"
}

function system_sshd_passwordauthentication {
    system_sshd_edit_bool "PasswordAuthentication" "$1"
}

function system_update_hostname {
    # system_update_hostname(system hostname)
    if [ -z "$1" ]; then
        echo "system_update_hostname() requires the system hostname as its first argument"
        return 1;
    fi
    echo $1 > /etc/hostname
    hostname -F /etc/hostname
    echo -e "\n127.0.0.1 $1 $1.local\n" >> /etc/hosts
}

function system_security_logcheck {
    aptitude -y install logcheck logcheck-database
    # configure email
    # start after setup
}

function system_security_fail2ban {
    aptitude -y install fail2ban
}

function system_security_ufw_configure_basic {
    # see https://help.ubuntu.com/community/UFW
    ufw logging on

    ufw default deny

    ufw allow ssh/tcp
    ufw limit ssh/tcp

    ufw allow http/tcp
    ufw allow https/tcp

    ufw enable
}

function system_configure_private_network {
    # system_configure_private_network(private_ip)
    PRIVATE_IP=$1
    NETMASK="255.255.128.0"
    cat >>/etc/network/interfaces <<EOF
auto eth0:0
iface eth0:0 inet static
 address $PRIVATE_IP
 netmask $NETMASK
EOF
    touch /tmp/restart_initd-networking
}

function restart_services {
    # restarts upstart services that have a file in /tmp/needs-restart/
    for service_name in $(ls /tmp/ | grep restart-* | cut -d- -f2-10); do
        service $service_name restart
        rm -f /tmp/restart-$service_name
    done
}

function restart_initd_services {
    # restarts upstart services that have a file in /tmp/needs-restart/
    for service_name in $(ls /tmp/ | grep restart_initd-* | cut -d- -f2-10); do
        /etc/init.d/$service_name restart
        rm -f /tmp/restart_initd-$service_name
    done
}

# Maintain for compatibility with scripts using this library for Ubuntu 10.04

function system_get_codename {
    echo `lsb_release -sc`
}

function system_get_release {
    echo `lsb_release -sr`
}

function system_sshd_pubkeyauthentication {
    system_sshd_edit_bool "PubkeyAuthentication" "$1"
}

function system_update_locale_en_US_UTF_8 {
    # locale-gen en_US.UTF-8
    dpkg-reconfigure locales
    update-locale LANG=en_US.UTF-8
}

function system_enable_universe {
    sed -i 's/^#\(.*deb.*\) universe/\1 universe/' /etc/apt/sources.list
    aptitude update
}

function system_security_ufw_install {
    aptitude -y install ufw
}


######## lib-python functions ########
function python_install {
    aptitude -y install python python-dev python-setuptools
    easy_install pip
    pip install virtualenv virtualenvwrapper
}


######## lib-apache ########
function apache_worker_install {
    aptitude -y install apache2-mpm-worker apache2-dev
}

function apache_mod_wsgi_install {
    aptitude -y install libapache2-mod-wsgi
}

function apache_cleanup {
    a2dissite default # disable default vhost
}


######## lib-postgresql ########
function postgresql_install {
    aptitude -y install postgresql postgresql-contrib postgresql-dev libpq-dev
}

function postgresql_create_user {
    # postgresql_create_user(username, password)
    if [ -z "$1" ]; then
        echo "postgresql_create_user() requires username as the first argument"
        return 1;
    fi
    if [ -z "$2" ]; then
        echo "postgresql_create_user() requires a password as the second argument"
        return 1;
    fi

    echo "CREATE ROLE $1 WITH LOGIN ENCRYPTED PASSWORD '$2';" | sudo -i -u postgres psql
}

function postgresql_create_database {
    # postgresql_create_database(dbname, owner)
    if [ -z "$1" ]; then
        echo "postgresql_create_database() requires database name as the first argument"
        return 1;
    fi
    if [ -z "$2" ]; then
        echo "postgresql_create_database() requires an owner username as the second argument"
        return 1;
    fi

    sudo -i -u postgres createdb --owner=$2 $1
}

######## lib-django ########
function python_install {
    aptitude -y install python python-dev python-setuptools
    easy_install pip
    pip install virtualenv virtualenvwrapper
}

PROJECT_CODE_DIR=app
DJANGO_PROJECT=webapp

function django_change_project_owner {
    # django_change_project_owner(project_path, user)
    PROJECT_PATH="$1"
    USER="$2"
    chown -R "$USER:$USER" "$PROJECT_PATH"
}

function django_create_project {
    # django_create_project(project_path)

    PROJECT_PATH="$1"
    if [ -z "$PROJECT_PATH" ]; then
        echo "django_create_project() requires the project root path as the first argument"
        return 1;
    fi

    mkdir -p "$PROJECT_PATH/$PROJECT_CODE_DIR/conf/apache"
    mkdir -p "$PROJECT_PATH/logs" "$PROJECT_PATH/run/eggs"

    virtualenv "$PROJECT_PATH/venv"
    $PROJECT_PATH/venv/bin/pip install Django

    pushd "$PROJECT_PATH/$PROJECT_CODE_DIR"
    "$PROJECT_PATH/venv/bin/python" "$PROJECT_PATH/venv/bin/django-admin.py" startproject "$DJANGO_PROJECT" .
    popd
    mkdir -p "$PROJECT_PATH/$PROJECT_CODE_DIR/$DJANGO_PROJECT/static"

    echo "Django" >> "$PROJECT_PATH/$PROJECT_CODE_DIR/requirements.txt"
}

function django_install_db_driver {
    # django_install_db_driver(project_path, driver_package)
    $1/venv/bin/pip install "$2"
    echo "$2" >> "$PROJECT_PATH/$PROJECT_CODE_DIR/requirements.txt"
}

function django_configure_db_settings {
    # django_configure_db_settings(project_path, engine, name, user, password, [host, [port]])
    PROJECT_PATH="$1"
    SETTINGS="$PROJECT_PATH/$PROJECT_CODE_DIR/$DJANGO_PROJECT/settings.py"
    sed -i -e "s/'ENGINE': 'django.db.backends.'/'ENGINE': 'django.db.backends.$2'/" "$SETTINGS"
    sed -i -e "s/'NAME': ''/'NAME': '$3'/" "$SETTINGS"
    sed -i -e "s/'USER': ''/'USER': '$4'/" "$SETTINGS"
    sed -i -e "s/'PASSWORD': ''/'PASSWORD': '$5'/" "$SETTINGS"
    if [ -n "$6" ]; then
        sed -i -e "s/'HOST': ''/'HOST': '$6'/" "$SETTINGS"
    fi
    if [ -n "$7" ]; then
        sed -i -e "s/'PORT': ''/'PORT': '$7'/" "$SETTINGS"
    fi
}

function django_configure_apache_virtualhost {
    # django_configure_apache_virtualhost(hostname, project_path, wsgi_user)

    VHOST_HOSTNAME="$1"
    PROJECT_PATH="$2"
    USER="$3"
    GROUP="$USER"

    if [ -z "$VHOST_HOSTNAME" ]; then
        echo "django_configure_apache_virtualhost() requires the hostname as the first argument"
        return 1;
    fi

    if [ -z "$PROJECT_PATH" ]; then
        echo "django_configure_apache_virtualhost() requires path to the django project as the second argument"
        return 1;
    fi

    APACHE_CONF="200-$VHOST_HOSTNAME"
    APACHE_CONF_PATH="$PROJECT_PATH/$PROJECT_CODE_DIR/conf/apache/$APACHE_CONF"

    cat > "$APACHE_CONF_PATH" << EOF
<VirtualHost *:80>
    ServerAdmin root@$VHOST_HOSTNAME
    ServerName $VHOST_HOSTNAME
    ServerSignature Off

    Alias /static/ $PROJECT_PATH/$PROJECT_CODE_DIR/$DJANGO_PROJECT/static/
    Alias /robots.txt $PROJECT_PATH/$PROJECT_CODE_DIR/$DJANGO_PROJECT/static/robots.txt
    Alias /favicon.ico $PROJECT_PATH/$PROJECT_CODE_DIR/$DJANGO_PROJECT/static/favicon.ico

    SetEnvIf User_Agent "monit/*" dontlog
    CustomLog "|/usr/sbin/rotatelogs $PROJECT_PATH/logs/access.log.%Y%m%d-%H%M 5M" combined env=!dontlog
    ErrorLog "|/usr/sbin/rotatelogs $PROJECT_PATH/logs/error.log.%Y%m%d-%H%M 5M"
    LogLevel warn

    WSGIScriptAlias / $PROJECT_PATH/$PROJECT_CODE_DIR/$DJANGO_PROJECT/wsgi.py

    WSGIDaemonProcess $VHOST_HOSTNAME user=$USER group=$GROUP processes=2 threads=10 maximum-requests=10000 display-name=%{GROUP} python-path=$PROJECT_PATH/$PROJECT_CODE_DIR:$PROJECT_PATH/venv/lib/python2.7/site-packages python-eggs=$PROJECT_PATH/run/eggs
    WSGIProcessGroup $VHOST_HOSTNAME
    WSGIScriptAlias / $PROJECT_PATH/$PROJECT_CODE_DIR/$DJANGO_PROJECT/wsgi.py

    <Directory $PROJECT_PATH/$PROJECT_CODE_DIR/$DJANGO_PROJECT/static>
        Order deny,allow
        Allow from all
        Options -Indexes FollowSymLinks
    </Directory>

    <Directory $PROJECT_PATH/$PROJECT_CODE_DIR/conf/apache>
        Order deny,allow
        Allow from all
    </Directory>

 </VirtualHost>
EOF

    ln -s -t /etc/apache2/sites-available/ "$APACHE_CONF_PATH"
    a2ensite "$APACHE_CONF"
}


######## lib-mongodb ########
function mongodb_install {
    aptitude -y install mongodb
}


######## lib-monit ########
function monit_install {
    aptitude -y install monit
}

function monit_configure_email {
    # system_monit_configure_email(email)
cat <<EOT >/etc/monit/conf.d/email-interface
  set mailserver localhost
  set alert $1
EOT
}

function monit_configure_web {
    # system_monit_configure_web(domain)
cat <<EOT >/etc/monit/conf.d/web-interface
  set httpd port 2812 and
    use address $1
    allow $(randomString 10):$(randomString 30)
    allow @sudo readonly
    signature disable
EOT
ufw allow 2812/tcp
}

function monit_def_system {
    # monit_def_system(hostname)
cat <<EOT >/etc/monit/conf.d/system.cfg
  check system $1
    if loadavg (1min) > 10 then alert
    if loadavg (5min) > 7 then alert
    if memory usage > 85% then alert
    if swap usage > 25% then alert
    if cpu usage (user) > 90% then alert
    if cpu usage (system) > 60% then alert
    if cpu usage (wait) > 50% then alert
    group system
EOT
}

function monit_def_rootfs {
cat <<EOT >/etc/monit/conf.d/rootfs.cfg
  check filesystem rootfs with path /
    if space usage > 80% for 5 times within 15 cycles then alert
    if inode usage > 85% then alert
    group system
EOT
}

function monit_def_cron {
cat <<EOT >/etc/monit/conf.d/cron.cfg
  check process cron with pidfile /var/run/crond.pid
    start program = "/sbin/start cron"
    stop  program = "/sbin/stop cron"
    if 5 restarts within 5 cycles then timeout
    depends on cron_rc
    group system

  check file cron_rc with path /etc/init.d/cron
    if failed checksum then unmonitor
    if failed permission 755 then unmonitor
    if failed uid root then unmonitor
    if failed gid root then unmonitor
    group system
EOT
}

function monit_def_sshd {
cat <<EOT >/etc/monit/conf.d/sshd.cfg
  check process sshd with pidfile /var/run/sshd.pid
    start program "/etc/init.d/ssh start"
    stop program "/etc/init.d/ssh stop"
    # if failed port 22 protocol ssh then restart
    # if 3 restarts within 3 cycles then timeout
EOT
}

function monit_def_ping_google {
cat <<EOT >/etc/monit/conf.d/ping_google.cfg
  check host google-ping with address google.com
    if failed port 80 proto http then alert
    group server
EOT
}

function monit_def_postfix {
cat <<EOT >/etc/monit/conf.d/postfix.cfg
  check process postfix with pidfile /var/spool/postfix/pid/master.pid
    start program = "/etc/init.d/postfix start"
    stop  program = "/etc/init.d/postfix stop"
    if cpu > 60% for 2 cycles then alert
    if cpu > 80% for 5 cycles then restart
    if totalmem > 200.0 MB for 5 cycles then restart
    if children > 250 then restart
    if loadavg(5min) greater than 10 for 8 cycles then stop
    if failed host localhost port 25 protocol smtp with timeout 15 seconds then alert
    if failed host localhost port 25 protocol smtp for 3 cycles then restart
    if 3 restarts within 5 cycles then timeout
    group mail

  check file postfix_rc with path /etc/init.d/postfix
    if failed checksum then unmonitor
    if failed permission 755 then unmonitor
    if failed uid root then unmonitor
    if failed gid root then unmonitor
    group mail
EOT
}


function monit_def_postgresql {
cat <<EOT >/etc/monit/conf.d/postgresql.cfg
  check process postgres with pidfile /var/run/postgresql/9.1-main.pid
    start program = "/etc/init.d/postgresql start"
    stop program = "/etc/init.d/postgresql stop"
    if failed unixsocket /var/run/postgresql/.s.PGSQL.5432 protocol pgsql then restart
    if failed host localhost port 5432 protocol pgsql then restart
    if 5 restarts within 5 cycles then timeout
    depends on postgresql_bin
    depends on postgresql_rc
    group database

  check file postgresql_bin with path /usr/lib/postgresql/9.1/bin/postgres
    if failed checksum then unmonitor
    if failed permission 755 then unmonitor
    if failed uid root then unmonitor
    if failed gid root then unmonitor
    group database

  check file postgresql_rc with path /etc/init.d/postgresql
    if failed checksum then unmonitor
    if failed permission 755 then unmonitor
    if failed uid root then unmonitor
    if failed gid root then unmonitor
    group database

  check file postgresql_log with path /var/log/postgresql/postgresql-9.1-main.log
    if size > 100 MB then alert
    group database
EOT
}

function monit_def_mysql {
cat <<EOT > /etc/monit/conf.d/mysql.cfg
  check process mysqld with pidfile /var/run/mysqld/mysqld.pid
    start program = "/sbin/start mysql" with timeout 20 seconds
    stop program = "/sbin/stop mysql"
    if failed host localhost port 3306 protocol mysql then restart
    if failed unixsocket /var/run/mysqld/mysqld.sock protocol mysql then restart
    if 5 restarts within 5 cycles then timeout
    depends on mysql_bin
    depends on mysql_rc
    group database

  check file mysql_bin with path /usr/sbin/mysqld
    if failed checksum then unmonitor
    if failed permission 755 then unmonitor
    if failed uid root then unmonitor
    if failed gid root then unmonitor
    group database

  check file mysql_rc with path /etc/init.d/mysql
    if failed checksum then unmonitor
    if failed permission 755 then unmonitor
    if failed uid root then unmonitor
    if failed gid root then unmonitor
    group database
EOT
}

function monit_def_mongodb {
cat <<EOT >/etc/monit/conf.d/mongodb.cfg
  check process mongodb with pidfile /var/lib/mongodb/mongod.lock
    start program = "/sbin/start mongodb"
    stop  program = "/sbin/stop mongodb"
    if failed host localhost port 28017 protocol http
      and request "/" with timeout 10 seconds then restart
    if 5 restarts within 5 cycles then timeout
    group database
EOT
}

function monit_def_memcached {
cat <<EOT >/etc/monit/conf.d/memcached.cfg
  check process memcached with pidfile /var/run/memcached.pid
    start program = "/etc/init.d/memcached start"
    stop program = "/etc/init.d/memcached stop"
    if 5 restarts within 5 cycles then timeout
    group database
EOT
}

function monit_def_apache {
cat <<EOT >/etc/monit/conf.d/apache2.cfg
  check process apache with pidfile /var/run/apache2.pid
    start program = "/etc/init.d/apache2 start"
    stop  program = "/etc/init.d/apache2 stop"
    if cpu > 60% for 2 cycles then alert
    if cpu > 80% for 5 cycles then alert
    if totalmem > 200.0 MB for 5 cycles then alert
    if children > 250 then alert
    if loadavg(5min) greater than 10 for 8 cycles then stop
    if failed host localhost port 80 protocol HTTP request / within 2 cycles then alert
    if failed host localhost port 80 protocol apache-status
        dnslimit > 25% or  loglimit > 80% or waitlimit < 20% retry 2 within 2 cycles then alert
    #if 5 restarts within 5 cycles then timeout
    depends on apache_bin
    depends on apache_rc
    group www

  check file apache_bin with path /usr/sbin/apache2
    if failed checksum then unmonitor
    if failed permission 755 then unmonitor
    if failed uid root then unmonitor
    if failed gid root then unmonitor
    group www

  check file apache_rc with path /etc/init.d/apache2
    if failed checksum then unmonitor
    if failed permission 755 then unmonitor
    if failed uid root then unmonitor
    if failed gid root then unmonitor
    group www
EOT
}


########## SS1 functions from nigma #######
###########################################################
# System
###########################################################

function system_update {
    apt-get update
    apt-get -y install aptitude
    aptitude -y full-upgrade
}

function system_primary_ip {
    # returns the primary IP assigned to eth0
    echo $(ifconfig eth0 | awk -F: '/inet addr:/ {print $2}' | awk '{ print $1 }')
}

function get_rdns {
    # calls host on an IP address and returns its reverse dns

    if [ ! -e /usr/bin/host ]; then
        aptitude -y install dnsutils > /dev/null
    fi
    echo $(host $1 | awk '/pointer/ {print $5}' | sed 's/\.$//')
}

function get_rdns_primary_ip {
    # returns the reverse dns of the primary IP assigned to this system
    echo $(get_rdns $(system_primary_ip))
}

###########################################################
# Postfix
###########################################################

function postfix_install_loopback_only {
    # Installs postfix and configure to listen only on the local interface. Also
    # allows for local mail delivery

    echo "postfix postfix/main_mailer_type select Internet Site" | debconf-set-selections
    echo "postfix postfix/mailname string localhost" | debconf-set-selections
    echo "postfix postfix/destinations string localhost.localdomain, localhost" | debconf-set-selections
    aptitude -y install postfix
    /usr/sbin/postconf -e "inet_interfaces = loopback-only"
    #/usr/sbin/postconf -e "local_transport = error:local delivery is disabled"

    touch /tmp/restart-postfix
}


###########################################################
# Apache
###########################################################

function apache_install {
    # installs the system default apache2 MPM
    aptitude -y install apache2

    a2dissite default # disable the interfering default virtualhost

    # clean up, or add the NameVirtualHost line to ports.conf
    sed -i -e 's/^NameVirtualHost \*$/NameVirtualHost *:80/' /etc/apache2/ports.conf
    if ! grep -q NameVirtualHost /etc/apache2/ports.conf; then
        echo 'NameVirtualHost *:80' > /etc/apache2/ports.conf.tmp
        cat /etc/apache2/ports.conf >> /etc/apache2/ports.conf.tmp
        mv -f /etc/apache2/ports.conf.tmp /etc/apache2/ports.conf
    fi
}

function apache_tune {
    # Tunes Apache's memory to use the percentage of RAM you specify, defaulting to 40%

    # $1 - the percent of system memory to allocate towards Apache

    if [ ! -n "$1" ];
        then PERCENT=40
        else PERCENT="$1"
    fi

    aptitude -y install apache2-mpm-prefork
    PERPROCMEM=10 # the amount of memory in MB each apache process is likely to utilize
    MEM=$(grep MemTotal /proc/meminfo | awk '{ print int($2/1024) }') # how much memory in MB this system has
    MAXCLIENTS=$((MEM*PERCENT/100/PERPROCMEM)) # calculate MaxClients
    MAXCLIENTS=${MAXCLIENTS/.*} # cast to an integer
    sed -i -e "s/\(^[ \t]*MaxClients[ \t]*\)[0-9]*/\1$MAXCLIENTS/" /etc/apache2/apache2.conf

    touch /tmp/restart-apache2
}

function apache_virtualhost {
    # Configures a VirtualHost

    # $1 - required - the hostname of the virtualhost to create

    if [ ! -n "$1" ]; then
        echo "apache_virtualhost() requires the hostname as the first argument"
        return 1;
    fi

    if [ -e "/etc/apache2/sites-available/$1" ]; then
        echo /etc/apache2/sites-available/$1 already exists
        return;
    fi

    mkdir -p /srv/www/$1/public_html /srv/www/$1/logs

    echo "<VirtualHost *:80>" > /etc/apache2/sites-available/$1
    echo "    ServerName $1" >> /etc/apache2/sites-available/$1
    echo "    DocumentRoot /srv/www/$1/public_html/" >> /etc/apache2/sites-available/$1
    echo "    ErrorLog /srv/www/$1/logs/error.log" >> /etc/apache2/sites-available/$1
    echo "    CustomLog /srv/www/$1/logs/access.log combined" >> /etc/apache2/sites-available/$1
    echo "</VirtualHost>" >> /etc/apache2/sites-available/$1

    a2ensite $1

    touch /tmp/restart-apache2
}

function apache_virtualhost_from_rdns {
    # Configures a VirtualHost using the rdns of the first IP as the ServerName

    apache_virtualhost $(get_rdns_primary_ip)
}


function apache_virtualhost_get_docroot {
    if [ ! -n "$1" ]; then
        echo "apache_virtualhost_get_docroot() requires the hostname as the first argument"
        return 1;
    fi

    if [ -e /etc/apache2/sites-available/$1 ];
        then echo $(awk '/DocumentRoot/ {print $2}' /etc/apache2/sites-available/$1 )
    fi
}

###########################################################
# mysql-server
###########################################################

function mysql_install {
    # $1 - the mysql root password

        echo "Inside mysql_install with args $1"

    if [ ! -n "$1" ]; then
        echo "mysql_install() requires the root pass as its first argument"
        return 1;
    fi

    echo "mysql-server mysql-server/root_password password $1" | debconf-set-selections
    echo "mysql-server mysql-server/root_password_again password $1" | debconf-set-selections
    apt-get -y install mysql-server mysql-client

    echo "Sleeping while MySQL starts up for the first time..."
    sleep 5
}

function mysql_tune {
    # Tunes MySQL's memory usage to utilize the percentage of memory you specify, defaulting to 40%

    # $1 - the percent of system memory to allocate towards MySQL

        echo "Inside mysql_tune with args $1"

    if [ ! -n "$1" ];
        then PERCENT=40
        else PERCENT="$1"
    fi

    sed -i -e 's/^#skip-innodb/skip-innodb/' /etc/mysql/my.cnf # disable innodb - saves about 100M

    MEM=$(awk '/MemTotal/ {print int($2/1024)}' /proc/meminfo) # how much memory in MB this system has
    MYMEM=$((MEM*PERCENT/100)) # how much memory we'd like to tune mysql with
    MYMEMCHUNKS=$((MYMEM/4)) # how many 4MB chunks we have to play with

    # mysql config options we want to set to the percentages in the second list, respectively
    OPTLIST=(key_buffer sort_buffer_size read_buffer_size read_rnd_buffer_size myisam_sort_buffer_size query_cache_size)
    DISTLIST=(75 1 1 1 5 15)

    for opt in ${OPTLIST[@]}; do
        sed -i -e "/\[mysqld\]/,/\[.*\]/s/^$opt/#$opt/" /etc/mysql/my.cnf
    done

    for i in ${!OPTLIST[*]}; do
        val=$(echo | awk "{print int((${DISTLIST[$i]} * $MYMEMCHUNKS/100))*4}")
        if [ $val -lt 4 ]
            then val=4
        fi
        config="${config}\n${OPTLIST[$i]} = ${val}M"
    done

    sed -i -e "s/\(\[mysqld\]\)/\1\n$config\n/" /etc/mysql/my.cnf

    touch /tmp/restart-mysql
}

function mysql_create_database {
    # $1 - the mysql root password
    # $2 - the db name to create

        echo "Inside mysql_create_database with args $1 $2"

    if [ ! -n "$1" ]; then
        echo "mysql_create_database() requires the root pass as its first argument"
        return 1;
    fi
    if [ ! -n "$2" ]; then
        echo "mysql_create_database() requires the name of the database as the second argument"
        return 1;
    fi

    echo "CREATE DATABASE $2;" | mysql -u root -p$1
}

function mysql_create_user {
    # $1 - the mysql root password
    # $2 - the user to create
    # $3 - their password

        echo "Inside mysql_create_user"

    if [ ! -n "$1" ]; then
        echo "mysql_create_user() requires the root pass as its first argument"
        return 1;
    fi
    if [ ! -n "$2" ]; then
        echo "mysql_create_user() requires username as the second argument"
        return 1;
    fi
    if [ ! -n "$3" ]; then
        echo "mysql_create_user() requires a password as the third argument"
        return 1;
    fi

    echo "CREATE USER '$2'@'localhost' IDENTIFIED BY '$3';" | mysql -u root -p$1
}

function mysql_grant_user {
    # $1 - the mysql root password
    # $2 - the user to bestow privileges
    # $3 - the database

        echo "Inside mysql_grant_user"

    if [ ! -n "$1" ]; then
        echo "mysql_create_user() requires the root pass as its first argument"
        return 1;
    fi
    if [ ! -n "$2" ]; then
        echo "mysql_create_user() requires username as the second argument"
        return 1;
    fi
    if [ ! -n "$3" ]; then
        echo "mysql_create_user() requires a database as the third argument"
        return 1;
    fi

    echo "GRANT ALL PRIVILEGES ON $3.* TO '$2'@'localhost';" | mysql -u root -p$1
    echo "FLUSH PRIVILEGES;" | mysql -u root -p$1

}

###########################################################
# PHP functions
###########################################################

function php_install_with_apache {
    aptitude -y install php5 php5-mysql libapache2-mod-php5 mysql-server phpmyadmin 
    touch /tmp/restart-apache2
}

function php_tune {
    # Tunes PHP to utilize up to 32M per process

    sed -i'-orig' 's/memory_limit = [0-9]\+M/memory_limit = 32M/' /etc/php5/apache2/php.ini
    touch /tmp/restart-apache2
}


# Other niceties!
###########################################################

function goodstuff {
    # Installs the REAL vim, wget, less, and enables color root prompt and the "ll" list long alias

    aptitude -y install wget vim less
    sed -i -e 's/^#PS1=/PS1=/' /root/.bashrc # enable the colorful root bash prompt
    sed -i -e "s/^#alias ll='ls -l'/alias ll='ls -al'/" /root/.bashrc # enable ll list long alias <3
}


###########################################################
# utility functions
###########################################################

function restartServices {
    # restarts services that have a file in /tmp/needs-restart/

    for service in $(ls /tmp/restart-* | cut -d- -f2-10); do
        /etc/init.d/$service restart
        rm -f /tmp/restart-$service
    done
}

function randomString {
    if [ ! -n "$1" ];
        then LEN=20
        else LEN="$1"
    fi

    echo $(</dev/urandom tr -dc A-Za-z0-9 | head -c $LEN) # generate a random string
}



set -e
set -u
#set -x

USER_GROUPS=sudo

exec &> /root/stackscript.log

system_update


system_install_mercurial
system_start_etc_dir_versioning #start recording changes of /etc config files


# Configure system
system_update_hostname "$SYS_HOSTNAME"
system_record_etc_dir_changes "Updated hostname" # SS124


# Create user account
system_add_user "$USER_NAME" "$USER_PASSWORD" "$USER_GROUPS" "$USER_SHELL"
if [ "$USER_SSHKEY" ]; then
    system_user_add_ssh_key "$USER_NAME" "$USER_SSHKEY"
fi
system_record_etc_dir_changes "Added unprivileged user account" # SS124


# Configure sshd
system_sshd_permitrootlogin "$SSHD_PERMITROOTLOGIN"
system_sshd_passwordauthentication "$SSHD_PASSWORDAUTH"
touch /tmp/restart-ssh
system_record_etc_dir_changes "Configured sshd" # SS124


# Lock user account if not used for login
if [ "SSHD_PERMITROOTLOGIN" == "No" ]; then
    system_lock_user "root"
    system_record_etc_dir_changes "Locked root account" # SS124
fi


# Install Postfix
postfix_install_loopback_only # SS1
system_record_etc_dir_changes "Installed postfix loopback" # SS124


# Setup logcheck
system_security_logcheck
system_record_etc_dir_changes "Installed logcheck" # SS124


# Setup fail2ban
system_security_fail2ban
system_record_etc_dir_changes "Installed fail2ban" # SS124


# Setup firewall
system_security_ufw_configure_basic
system_record_etc_dir_changes "Configured UFW" # SS124


python_install
system_record_etc_dir_changes "Installed python" # SS124


# lib-system - SS124
system_install_utils
system_install_build
system_install_subversion
system_install_git
system_record_etc_dir_changes "Installed common utils"

# Install and configure apache and mod_wsgi
if [ "$SETUP_APACHE" == "Yes" ]; then
    apache_worker_install
    system_record_etc_dir_changes "Installed apache" # SS124
    apache_mod_wsgi_install
    system_record_etc_dir_changes "Installed mod-wsgi" # SS124
    apache_cleanup
    system_record_etc_dir_changes "Cleaned up apache config" # SS124
fi


# Install MySQL and setup database
if [ "$SETUP_MYSQL" == "Yes" ]; then
    set +u # ignore undefined variables in Linode's SS1
    mysql_install "$MYSQL_DATABASE_PASSWORD" && mysql_tune 30
    mysql_create_database "$MYSQL_DATABASE_PASSWORD" "$MYSQL_DATABASE"
    mysql_create_user "$MYSQL_DATABASE_PASSWORD" "$MYSQL_USER" "$MYSQL_PASSWORD"
    mysql_grant_user "$MYSQL_DATABASE_PASSWORD" "$MYSQL_USER" "$MYSQL_DATABASE"
    set -u
    system_record_etc_dir_changes "Configured MySQL"
fi


# Setup and configure sample django project
RDNS=$(get_rdns_primary_ip)
DJANGO_PROJECT_PATH=""

if [ "$SETUP_DJANGO_PROJECT" != "No" ]; then

    if [ -z "$DJANGO_DOMAIN" ]; then DJANGO_DOMAIN=$RDNS; fi

    case "$SETUP_DJANGO_PROJECT" in
    Standalone)
        DJANGO_PROJECT_PATH="/srv/$DJANGO_PROJECT_NAME"
        if [ -n "$DJANGO_USER" ]; then
            if [ "$DJANGO_USER" != "$USER_NAME" ]; then
                system_add_system_user "$DJANGO_USER" "$DJANGO_PROJECT_PATH" "$USER_SHELL"
            else
                mkdir -p "$DJANGO_PROJECT_PATH"
            fi
        else
            DJANGO_USER="www-data"
        fi
      ;;
    InUserHome)
        DJANGO_USER=$USER_NAME
        DJANGO_PROJECT_PATH=$(system_get_user_home "$USER_NAME")/$DJANGO_PROJECT_NAME
      ;;
    InUserHomeRoot)
        DJANGO_USER=$USER_NAME
        DJANGO_PROJECT_PATH=$(system_get_user_home "$USER_NAME")
      ;;
    esac

    django_create_project "$DJANGO_PROJECT_PATH"
    django_change_project_owner "$DJANGO_PROJECT_PATH" "$DJANGO_USER"

    if [ "$SETUP_APACHE" == "Yes" ]; then
        django_configure_apache_virtualhost "$DJANGO_DOMAIN" "$DJANGO_PROJECT_PATH" "$DJANGO_USER"
        touch /tmp/restart-apache2
    fi
    if [ "$SETUP_POSTGRESQL" == "Yes" ]; then
        django_install_db_driver "$DJANGO_PROJECT_PATH" "psycopg2"
        django_configure_db_settings "$DJANGO_PROJECT_PATH" "postgresql_psycopg2" "$POSTGRESQL_DATABASE" "$POSTGRESQL_USER" "$POSTGRESQL_PASSWORD" "127.0.0.1" ""
    fi
    if [ "$SETUP_MYSQL" == "Yes" ]; then
        django_install_db_driver "$DJANGO_PROJECT_PATH" "MySQL-python"
    fi
    system_record_etc_dir_changes "Configured django project '$DJANGO_PROJECT_NAME'"
fi

if [ -n "$SYS_PRIVATE_IP" ]; then
    system_configure_private_network "$SYS_PRIVATE_IP"
    system_record_etc_dir_changes "Configured private network"
fi

restart_services
restart_initd_services

if [ "$SETUP_MONIT" == "Yes" ]; then
    monit_install
    system_record_etc_dir_changes "Installed Monit"

    monit_configure_email "$NOTIFY_EMAIL"
    monit_configure_web $(system_primary_ip)
    system_record_etc_dir_changes "Configured Monit interfaces"

    monit_def_system "$SYS_HOSTNAME"
    monit_def_rootfs
    monit_def_cron
    monit_def_postfix
    monit_def_ping_google
    if [ "$SETUP_POSTGRESQL" == "Yes" ]; then monit_def_postgresql; fi
    if [ "$SETUP_MYSQL" == "Yes" ]; then monit_def_mysql; fi
    if [ "$SETUP_MONGODB" == "Yes" ]; then monit_def_mongodb; fi
    if [ "$SETUP_APACHE" == "Yes" ]; then monit_def_apache; fi
    #if [ "$SETUP_MEMCACHE" == "Yes" ]; then monit_def_memcached; fi
    system_record_etc_dir_changes "Created Monit rules for installed services"
    monit reload
fi

# Send info message
cat > ~/setup_message <<EOD
Hi,

Your Linode VPS configuration is completed.

EOD

if [ "$SETUP_DJANGO_PROJECT" != "No" ]; then
    cat >> ~/setup_message <<EOD
You can now navigate to http://${DJANGO_DOMAIN}/ to see your web server running.
The Django project files are in $DJANGO_PROJECT_PATH/app.

EOD
fi

if [ "$SETUP_MONIT" == "Yes" ]; then
    cat >> ~/setup_message <<EOD
Monit web interface is at http://${RDNS}:2812/ (use your system username/password).

EOD
fi

cat >> ~/setup_message <<EOD
To access your server ssh to $USER_NAME@$RDNS

Thanks for using this StackScript. Follow http://github.com/nigma/StackScripts for updates.

Need help with developing web apps? Email me at en@ig.ma.
Modded by Manish Arora.

Best,
Filip
--
http://en.ig.ma/
EOD

mail -s "Your Linode VPS is ready" "$NOTIFY_EMAIL" < ~/setup_message