├── 128 - lib-mongodb.sh ├── 126 - lib-python.sh ├── 122 - lib-apache.sh ├── settings.txt ├── 124 - lib-system.sh ├── README.md ├── 125 - lib-postgresql.sh ├── prepare.py ├── 127 - lib-django.sh ├── 123 - lib-system-ubuntu.sh ├── 130 - monit.sh ├── 131 - Stack - Security, PostgreSQL, MySQL, MongoDB, Apache, Django.sh └── 1 - StackScript Bash Library.sh /128 - lib-mongodb.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Installs MongoDB. 4 | # 5 | # Copyright (c) 2010 Filip Wasilewski . 6 | # 7 | # My ref: http://www.linode.com/?r=aadfce9845055011e00f0c6c9a5c01158c452deb 8 | 9 | 10 | function mongodb_install { 11 | aptitude -y install mongodb 12 | } 13 | -------------------------------------------------------------------------------- /126 - lib-python.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Install python and base packages 4 | # 5 | # Copyright (c) 2010 Filip Wasilewski . 6 | # 7 | # My ref: http://www.linode.com/?r=aadfce9845055011e00f0c6c9a5c01158c452deb 8 | 9 | function python_install { 10 | aptitude -y install python python-dev python-setuptools 11 | easy_install pip 12 | pip install virtualenv virtualenvwrapper 13 | } 14 | -------------------------------------------------------------------------------- /122 - lib-apache.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Install and configure apache and mod_wsgi 4 | # 5 | # Copyright (c) 2010 Filip Wasilewski . 6 | # 7 | # My ref: http://www.linode.com/?r=aadfce9845055011e00f0c6c9a5c01158c452deb 8 | 9 | function apache_worker_install { 10 | aptitude -y install apache2-mpm-worker apache2-dev 11 | } 12 | 13 | function apache_mod_wsgi_install { 14 | aptitude -y install libapache2-mod-wsgi 15 | } 16 | 17 | function apache_cleanup { 18 | a2dissite default # disable default vhost 19 | } 20 | -------------------------------------------------------------------------------- /settings.txt: -------------------------------------------------------------------------------- 1 | --user_name ubuntu 2 | --user_password pass 3 | --user_sshkey 4 | --sshd_permitrootlogin No 5 | --sshd_passwordauth Yes 6 | --sys_hostname myvps 7 | --base_data_directory /srv 8 | --setup_postgresql Yes 9 | --postgresql_database django 10 | --postgresql_user django 11 | --postgresql_password django 12 | --setup_mysql No 13 | --mysql_database_password 14 | --mysql_database 15 | --mysql_user 16 | --mysql_password 17 | --setup_mongodb Yes 18 | --setup_django_project Yes 19 | --django_domain 20 | --django_project_name my_project 21 | --django_user django 22 | -------------------------------------------------------------------------------- /124 - lib-system.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Install common utilities 4 | # 5 | # Copyright (c) 2010 Filip Wasilewski . 6 | # 7 | # My ref: http://www.linode.com/?r=aadfce9845055011e00f0c6c9a5c01158c452deb 8 | 9 | function system_install_utils { 10 | aptitude -y install htop iotop bsd-mailx python-software-properties zsh 11 | } 12 | 13 | function system_install_build { 14 | aptitude -y install build-essential gcc 15 | } 16 | 17 | function system_install_subversion { 18 | aptitude -y install subversion 19 | } 20 | 21 | function system_install_git { 22 | aptitude -y install git-core 23 | } 24 | 25 | function system_install_mercurial { 26 | aptitude -y install mercurial 27 | } 28 | 29 | function system_start_etc_dir_versioning { 30 | hg init /etc 31 | hg add /etc 32 | hg commit -u root -m "Started versioning of /etc directory" /etc 33 | chmod -R go-rwx /etc/.hg 34 | } 35 | 36 | function system_record_etc_dir_changes { 37 | if [ ! -n "$1" ]; 38 | then MESSAGE="Committed /etc changes" 39 | else MESSAGE="$1" 40 | fi 41 | hg addremove /etc 42 | hg commit -u root -m "$MESSAGE" /etc || echo > /dev/null # catch "nothing changed" return code 43 | } 44 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Linode StackScripts 2 | 3 | 4 | ### Please note 5 | 6 | These scripts may be a bit outdated now although the solution served me well on many occasions. I have now moved to Ansible and other configuration management tools that are just much metter than the bash scripts approach, although you may pick up some configs and scripting ideas from here. 7 | 8 | If there is an interest in a similar full-stack web-server setup go ahead and open a ticket and I can prepare a set of Ansible roles and playbooks with Nginx & uWSGI as the web server. 9 | 10 | 11 | ------------------- 12 | 13 | ### Original readme 14 | 15 | 16 | A Linode.com StackScript shell script that configures a complete web environment with Apache, PostgreSQL/MySQL/MongoDB, Python, mod_wsgi, virtualenv and Django. 17 | 18 | Optionally creates a PostgreSQL/MySQL user and database and installs MongoDB NoSQL database. 19 | 20 | By default, it creates a VirtualHost using the reverse DNS of your Linode's primary IP and sets up a sample Django project in the /srv directory. 21 | 22 | Installs common system and dev utilities, sets up postfix loopback, Uncomplicated Firewall and Fail2Ban. 23 | 24 | Writes command output to /root/stackscript.log and records /etc changes using Mercurial. When completed notifies via email. 25 | -------------------------------------------------------------------------------- /125 - lib-postgresql.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Install PostgreSQL 4 | # 5 | # Copyright (c) 2010 Filip Wasilewski . 6 | # 7 | # My ref: http://www.linode.com/?r=aadfce9845055011e00f0c6c9a5c01158c452deb 8 | 9 | function postgresql_install { 10 | aptitude -y install postgresql postgresql-contrib postgresql-dev libpq-dev 11 | } 12 | 13 | function postgresql_create_user { 14 | # postgresql_create_user(username, password) 15 | if [ -z "$1" ]; then 16 | echo "postgresql_create_user() requires username as the first argument" 17 | return 1; 18 | fi 19 | if [ -z "$2" ]; then 20 | echo "postgresql_create_user() requires a password as the second argument" 21 | return 1; 22 | fi 23 | 24 | echo "CREATE ROLE $1 WITH LOGIN ENCRYPTED PASSWORD '$2';" | sudo -i -u postgres psql 25 | } 26 | 27 | function postgresql_create_database { 28 | # postgresql_create_database(dbname, owner) 29 | if [ -z "$1" ]; then 30 | echo "postgresql_create_database() requires database name as the first argument" 31 | return 1; 32 | fi 33 | if [ -z "$2" ]; then 34 | echo "postgresql_create_database() requires an owner username as the second argument" 35 | return 1; 36 | fi 37 | 38 | sudo -i -u postgres createdb --owner=$2 $1 39 | } 40 | -------------------------------------------------------------------------------- /prepare.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #-*- coding: utf-8 -*- 3 | 4 | """ 5 | Script for parsing and concatenating StackScripts 6 | 7 | Usage example: 8 | 9 | prepare.py "131 - Stack - Security, PostgreSQL, MySQL, MongoDB, Apache, Django.sh" @settings.txt 10 | """ 11 | 12 | import argparse 13 | import glob 14 | import os 15 | import re 16 | import sys 17 | from xml.etree.ElementTree import fromstring 18 | 19 | 20 | class ArgParser(argparse.ArgumentParser): 21 | 22 | def convert_arg_line_to_args(self, arg_line): 23 | parts = arg_line.split(None, 1) 24 | if len(parts) == 2: 25 | return [p.strip() for p in parts] 26 | return [] 27 | 28 | 29 | def get_udfs(content): 30 | udf_re = re.compile("^\s*#\s*()", re.IGNORECASE | re.MULTILINE) 31 | return udf_re.findall(content) 32 | 33 | 34 | def parse_param(udf): 35 | element = fromstring(udf) 36 | choices = element.get("oneof") 37 | if choices: 38 | choices = choices.split(",") 39 | return { 40 | 'name': element.get("name"), 41 | 'label': element.get("label"), 42 | 'choices': choices, 43 | 'default': element.get("default"), 44 | 'example': element.get("example") 45 | } 46 | 47 | 48 | def build_argparser(content): 49 | parser = ArgParser( 50 | description='Process StackScript file params.', 51 | fromfile_prefix_chars='@', 52 | formatter_class=argparse.ArgumentDefaultsHelpFormatter, 53 | epilog="Use @settings.txt as param to read configuration from settings file." 54 | ) 55 | parser.add_argument('script', metavar='SCRIPT', nargs=1, help='main script') 56 | 57 | for udf in get_udfs(content): 58 | param = parse_param(udf) 59 | help = param["example"] or "" 60 | default = param["default"] 61 | required = param["default"] is None 62 | parser.add_argument( 63 | '--%s' % param["name"], dest=param["name"].upper(), 64 | action='store', default=default, choices=param["choices"] or None, 65 | required=required, help=help 66 | ) 67 | return parser 68 | 69 | 70 | def lookup_script(script_id): 71 | try: 72 | return glob.glob("%s - *.sh" % script_id)[0] 73 | except IndexError: 74 | raise ValueError("Script for given id does not exist: %s." % script_id) 75 | 76 | 77 | def get_content(script_id): 78 | with open(lookup_script(script_id)) as fp: 79 | return fp.read() 80 | 81 | 82 | def expand_script(content, mode="source"): 83 | assert mode in ["source", "include"] 84 | re_source = re.compile("""""") 85 | re_include = re.compile("""^(\s*source\s+.*)$""", re.MULTILINE) 86 | if mode == "source": 87 | content = re_source.sub( 88 | lambda x: '"%s"' % lookup_script(x.group(1)), 89 | content 90 | ) 91 | else: 92 | content = re_include.sub( 93 | lambda x: '\n#==> Content of %s ==>>\n%s\n#<<== end of %s <=\n' % 94 | (x.group(2), get_content(x.group(2)), x.group(2)), 95 | content 96 | ) 97 | return content 98 | 99 | 100 | def add_variables(content, args): 101 | # Add script variables 102 | variables = "%s\n" % "\n".join( 103 | '%s="%s"' % (k,v) for k,v in sorted(args.__dict__.items()) if k.isupper() 104 | ) 105 | lines = iter(content.splitlines()) 106 | content = [] 107 | for line in lines: 108 | if line.startswith("#") or not line.strip(): 109 | content.append(line) 110 | else: 111 | content.append(variables) 112 | content.append(line) 113 | content.extend(lines) 114 | break 115 | return "\n".join(content) 116 | 117 | 118 | def main(stack_script): 119 | 120 | if stack_script: 121 | with open(stack_script) as fp: 122 | content = fp.read() 123 | 124 | parser = build_argparser(content) 125 | args = parser.parse_args() 126 | 127 | content = expand_script(content, mode="include") 128 | content = add_variables(content, args) 129 | 130 | print content 131 | 132 | 133 | if __name__ == "__main__": 134 | if len(sys.argv) < 2 or not os.path.exists(sys.argv[1]): 135 | print "First argument must be a valid script name" 136 | main(sys.argv[1]) 137 | -------------------------------------------------------------------------------- /127 - lib-django.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Setup django project and add apache vhost configuration 4 | # 5 | # Copyright (c) 2010 Filip Wasilewski . 6 | # 7 | # My ref: http://www.linode.com/?r=aadfce9845055011e00f0c6c9a5c01158c452deb 8 | 9 | PROJECT_CODE_DIR=app 10 | DJANGO_PROJECT=webapp 11 | 12 | function django_change_project_owner { 13 | # django_change_project_owner(project_path, user) 14 | PROJECT_PATH="$1" 15 | USER="$2" 16 | chown -R "$USER:$USER" "$PROJECT_PATH" 17 | } 18 | 19 | function django_create_project { 20 | # django_create_project(project_path) 21 | 22 | PROJECT_PATH="$1" 23 | if [ -z "$PROJECT_PATH" ]; then 24 | echo "django_create_project() requires the project root path as the first argument" 25 | return 1; 26 | fi 27 | 28 | mkdir -p "$PROJECT_PATH/$PROJECT_CODE_DIR/conf/apache" 29 | mkdir -p "$PROJECT_PATH/logs" "$PROJECT_PATH/run/eggs" 30 | 31 | virtualenv "$PROJECT_PATH/venv" 32 | $PROJECT_PATH/venv/bin/pip install Django 33 | 34 | pushd "$PROJECT_PATH/$PROJECT_CODE_DIR" 35 | "$PROJECT_PATH/venv/bin/python" "$PROJECT_PATH/venv/bin/django-admin.py" startproject "$DJANGO_PROJECT" . 36 | popd 37 | mkdir -p "$PROJECT_PATH/$PROJECT_CODE_DIR/$DJANGO_PROJECT/static" 38 | 39 | echo "Django" >> "$PROJECT_PATH/$PROJECT_CODE_DIR/requirements.txt" 40 | } 41 | 42 | function django_install_db_driver { 43 | # django_install_db_driver(project_path, driver_package) 44 | $1/venv/bin/pip install "$2" 45 | echo "$2" >> "$PROJECT_PATH/$PROJECT_CODE_DIR/requirements.txt" 46 | } 47 | 48 | function django_configure_db_settings { 49 | # django_configure_db_settings(project_path, engine, name, user, password, [host, [port]]) 50 | PROJECT_PATH="$1" 51 | SETTINGS="$PROJECT_PATH/$PROJECT_CODE_DIR/$DJANGO_PROJECT/settings.py" 52 | sed -i -e "s/'ENGINE': 'django.db.backends.'/'ENGINE': 'django.db.backends.$2'/" "$SETTINGS" 53 | sed -i -e "s/'NAME': ''/'NAME': '$3'/" "$SETTINGS" 54 | sed -i -e "s/'USER': ''/'USER': '$4'/" "$SETTINGS" 55 | sed -i -e "s/'PASSWORD': ''/'PASSWORD': '$5'/" "$SETTINGS" 56 | if [ -n "$6" ]; then 57 | sed -i -e "s/'HOST': ''/'HOST': '$6'/" "$SETTINGS" 58 | fi 59 | if [ -n "$7" ]; then 60 | sed -i -e "s/'PORT': ''/'PORT': '$7'/" "$SETTINGS" 61 | fi 62 | } 63 | 64 | function django_configure_apache_virtualhost { 65 | # django_configure_apache_virtualhost(hostname, project_path, wsgi_user) 66 | 67 | VHOST_HOSTNAME="$1" 68 | PROJECT_PATH="$2" 69 | USER="$3" 70 | GROUP="$USER" 71 | 72 | if [ -z "$VHOST_HOSTNAME" ]; then 73 | echo "django_configure_apache_virtualhost() requires the hostname as the first argument" 74 | return 1; 75 | fi 76 | 77 | if [ -z "$PROJECT_PATH" ]; then 78 | echo "django_configure_apache_virtualhost() requires path to the django project as the second argument" 79 | return 1; 80 | fi 81 | 82 | APACHE_CONF="200-$VHOST_HOSTNAME" 83 | APACHE_CONF_PATH="$PROJECT_PATH/$PROJECT_CODE_DIR/conf/apache/$APACHE_CONF" 84 | 85 | cat > "$APACHE_CONF_PATH" << EOF 86 | 87 | ServerAdmin root@$VHOST_HOSTNAME 88 | ServerName $VHOST_HOSTNAME 89 | ServerSignature Off 90 | 91 | Alias /static/ $PROJECT_PATH/$PROJECT_CODE_DIR/$DJANGO_PROJECT/static/ 92 | Alias /robots.txt $PROJECT_PATH/$PROJECT_CODE_DIR/$DJANGO_PROJECT/static/robots.txt 93 | Alias /favicon.ico $PROJECT_PATH/$PROJECT_CODE_DIR/$DJANGO_PROJECT/static/favicon.ico 94 | 95 | SetEnvIf User_Agent "monit/*" dontlog 96 | CustomLog "|/usr/sbin/rotatelogs $PROJECT_PATH/logs/access.log.%Y%m%d-%H%M 5M" combined env=!dontlog 97 | ErrorLog "|/usr/sbin/rotatelogs $PROJECT_PATH/logs/error.log.%Y%m%d-%H%M 5M" 98 | LogLevel warn 99 | 100 | WSGIScriptAlias / $PROJECT_PATH/$PROJECT_CODE_DIR/$DJANGO_PROJECT/wsgi.py 101 | 102 | 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 103 | WSGIProcessGroup $VHOST_HOSTNAME 104 | WSGIScriptAlias / $PROJECT_PATH/$PROJECT_CODE_DIR/$DJANGO_PROJECT/wsgi.py 105 | 106 | 107 | Order deny,allow 108 | Allow from all 109 | Options -Indexes FollowSymLinks 110 | 111 | 112 | 113 | Order deny,allow 114 | Allow from all 115 | 116 | 117 | 118 | EOF 119 | 120 | ln -s -t /etc/apache2/sites-available/ "$APACHE_CONF_PATH" 121 | a2ensite "$APACHE_CONF" 122 | } 123 | -------------------------------------------------------------------------------- /123 - lib-system-ubuntu.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # System related utilities 4 | # 5 | # Copyright (c) 2010 Filip Wasilewski . 6 | # 7 | # My ref: http://www.linode.com/?r=aadfce9845055011e00f0c6c9a5c01158c452deb 8 | 9 | function lower { 10 | # helper function 11 | echo $1 | tr '[:upper:]' '[:lower:]' 12 | } 13 | 14 | function system_add_user { 15 | # system_add_user(username, password, groups, shell=/bin/bash) 16 | USERNAME=`lower $1` 17 | PASSWORD=$2 18 | SUDO_GROUP=$3 19 | SHELL=$4 20 | if [ -z "$4" ]; then 21 | SHELL="/bin/bash" 22 | fi 23 | useradd --create-home --shell "$SHELL" --user-group --groups "$SUDO_GROUP" "$USERNAME" 24 | echo "$USERNAME:$PASSWORD" | chpasswd 25 | } 26 | 27 | function system_add_system_user { 28 | # system_add_system_user(username, home, shell=/bin/bash) 29 | USERNAME=`lower $1` 30 | HOME_DIR=$2 31 | SHELL=$3 32 | if [ -z "$3" ]; then 33 | SHELL="/bin/bash" 34 | fi 35 | useradd --system --create-home --home-dir "$HOME_DIR" --shell "$SHELL" --user-group $USERNAME 36 | } 37 | 38 | function system_lock_user { 39 | # system_lock_user(username) 40 | passwd -l "$1" 41 | } 42 | 43 | function system_get_user_home { 44 | # system_get_user_home(username) 45 | cat /etc/passwd | grep "^$1:" | cut --delimiter=":" -f6 46 | } 47 | 48 | function system_user_add_ssh_key { 49 | # system_user_add_ssh_key(username, ssh_key) 50 | USERNAME=`lower $1` 51 | USER_HOME=`system_get_user_home "$USERNAME"` 52 | sudo -u "$USERNAME" mkdir "$USER_HOME/.ssh" 53 | sudo -u "$USERNAME" touch "$USER_HOME/.ssh/authorized_keys" 54 | sudo -u "$USERNAME" echo "$2" >> "$USER_HOME/.ssh/authorized_keys" 55 | chmod 0600 "$USER_HOME/.ssh/authorized_keys" 56 | } 57 | 58 | function system_sshd_edit_bool { 59 | # system_sshd_edit_bool (param_name, "Yes"|"No") 60 | VALUE=`lower $2` 61 | if [ "$VALUE" == "yes" ] || [ "$VALUE" == "no" ]; then 62 | sed -i "s/^#*\($1\).*/\1 $VALUE/" /etc/ssh/sshd_config 63 | fi 64 | } 65 | 66 | function system_sshd_permitrootlogin { 67 | system_sshd_edit_bool "PermitRootLogin" "$1" 68 | } 69 | 70 | function system_sshd_passwordauthentication { 71 | system_sshd_edit_bool "PasswordAuthentication" "$1" 72 | } 73 | 74 | function system_update_hostname { 75 | # system_update_hostname(system hostname) 76 | if [ -z "$1" ]; then 77 | echo "system_update_hostname() requires the system hostname as its first argument" 78 | return 1; 79 | fi 80 | echo $1 > /etc/hostname 81 | hostname -F /etc/hostname 82 | echo -e "\n127.0.0.1 $1 $1.local\n" >> /etc/hosts 83 | } 84 | 85 | function system_security_logcheck { 86 | aptitude -y install logcheck logcheck-database 87 | # configure email 88 | # start after setup 89 | } 90 | 91 | function system_security_fail2ban { 92 | aptitude -y install fail2ban 93 | } 94 | 95 | function system_security_ufw_configure_basic { 96 | # see https://help.ubuntu.com/community/UFW 97 | ufw logging on 98 | 99 | ufw default deny 100 | 101 | ufw allow ssh/tcp 102 | ufw limit ssh/tcp 103 | 104 | ufw allow http/tcp 105 | ufw allow https/tcp 106 | 107 | ufw enable 108 | } 109 | 110 | function system_configure_private_network { 111 | # system_configure_private_network(private_ip) 112 | PRIVATE_IP=$1 113 | NETMASK="255.255.128.0" 114 | cat >>/etc/network/interfaces <. 6 | # 7 | # My ref: http://www.linode.com/?r=aadfce9845055011e00f0c6c9a5c01158c452deb 8 | 9 | 10 | function monit_install { 11 | aptitude -y install monit 12 | } 13 | 14 | function monit_configure_email { 15 | # system_monit_configure_email(email) 16 | cat </etc/monit/conf.d/email-interface 17 | set mailserver localhost 18 | set alert $1 19 | EOT 20 | } 21 | 22 | function monit_configure_web { 23 | # system_monit_configure_web(domain) 24 | cat </etc/monit/conf.d/web-interface 25 | set httpd port 2812 and 26 | use address $1 27 | allow $(randomString 10):$(randomString 30) 28 | allow @sudo readonly 29 | signature disable 30 | EOT 31 | ufw allow 2812/tcp 32 | } 33 | 34 | function monit_def_system { 35 | # monit_def_system(hostname) 36 | cat </etc/monit/conf.d/system.cfg 37 | check system $1 38 | if loadavg (1min) > 10 then alert 39 | if loadavg (5min) > 7 then alert 40 | if memory usage > 85% then alert 41 | if swap usage > 25% then alert 42 | if cpu usage (user) > 90% then alert 43 | if cpu usage (system) > 60% then alert 44 | if cpu usage (wait) > 50% then alert 45 | group system 46 | EOT 47 | } 48 | 49 | function monit_def_rootfs { 50 | cat </etc/monit/conf.d/rootfs.cfg 51 | check filesystem rootfs with path / 52 | if space usage > 80% for 5 times within 15 cycles then alert 53 | if inode usage > 85% then alert 54 | group system 55 | EOT 56 | } 57 | 58 | function monit_def_cron { 59 | cat </etc/monit/conf.d/cron.cfg 60 | check process cron with pidfile /var/run/crond.pid 61 | start program = "/sbin/start cron" 62 | stop program = "/sbin/stop cron" 63 | if 5 restarts within 5 cycles then timeout 64 | depends on cron_rc 65 | group system 66 | 67 | check file cron_rc with path /etc/init.d/cron 68 | if failed checksum then unmonitor 69 | if failed permission 755 then unmonitor 70 | if failed uid root then unmonitor 71 | if failed gid root then unmonitor 72 | group system 73 | EOT 74 | } 75 | 76 | function monit_def_sshd { 77 | cat </etc/monit/conf.d/sshd.cfg 78 | check process sshd with pidfile /var/run/sshd.pid 79 | start program "/etc/init.d/ssh start" 80 | stop program "/etc/init.d/ssh stop" 81 | # if failed port 22 protocol ssh then restart 82 | # if 3 restarts within 3 cycles then timeout 83 | EOT 84 | } 85 | 86 | function monit_def_ping_google { 87 | cat </etc/monit/conf.d/ping_google.cfg 88 | check host google-ping with address google.com 89 | if failed port 80 proto http then alert 90 | group server 91 | EOT 92 | } 93 | 94 | function monit_def_postfix { 95 | cat </etc/monit/conf.d/postfix.cfg 96 | check process postfix with pidfile /var/spool/postfix/pid/master.pid 97 | start program = "/etc/init.d/postfix start" 98 | stop program = "/etc/init.d/postfix stop" 99 | if cpu > 60% for 2 cycles then alert 100 | if cpu > 80% for 5 cycles then restart 101 | if totalmem > 200.0 MB for 5 cycles then restart 102 | if children > 250 then restart 103 | if loadavg(5min) greater than 10 for 8 cycles then stop 104 | if failed host localhost port 25 protocol smtp with timeout 15 seconds then alert 105 | if failed host localhost port 25 protocol smtp for 3 cycles then restart 106 | if 3 restarts within 5 cycles then timeout 107 | group mail 108 | 109 | check file postfix_rc with path /etc/init.d/postfix 110 | if failed checksum then unmonitor 111 | if failed permission 755 then unmonitor 112 | if failed uid root then unmonitor 113 | if failed gid root then unmonitor 114 | group mail 115 | EOT 116 | } 117 | 118 | 119 | function monit_def_postgresql { 120 | cat </etc/monit/conf.d/postgresql.cfg 121 | check process postgres with pidfile /var/run/postgresql/9.1-main.pid 122 | start program = "/etc/init.d/postgresql start" 123 | stop program = "/etc/init.d/postgresql stop" 124 | if failed unixsocket /var/run/postgresql/.s.PGSQL.5432 protocol pgsql then restart 125 | if failed host localhost port 5432 protocol pgsql then restart 126 | if 5 restarts within 5 cycles then timeout 127 | depends on postgresql_bin 128 | depends on postgresql_rc 129 | group database 130 | 131 | check file postgresql_bin with path /usr/lib/postgresql/9.1/bin/postgres 132 | if failed checksum then unmonitor 133 | if failed permission 755 then unmonitor 134 | if failed uid root then unmonitor 135 | if failed gid root then unmonitor 136 | group database 137 | 138 | check file postgresql_rc with path /etc/init.d/postgresql 139 | if failed checksum then unmonitor 140 | if failed permission 755 then unmonitor 141 | if failed uid root then unmonitor 142 | if failed gid root then unmonitor 143 | group database 144 | 145 | check file postgresql_log with path /var/log/postgresql/postgresql-9.1-main.log 146 | if size > 100 MB then alert 147 | group database 148 | EOT 149 | } 150 | 151 | function monit_def_mysql { 152 | cat < /etc/monit/conf.d/mysql.cfg 153 | check process mysqld with pidfile /var/run/mysqld/mysqld.pid 154 | start program = "/sbin/start mysql" with timeout 20 seconds 155 | stop program = "/sbin/stop mysql" 156 | if failed host localhost port 3306 protocol mysql then restart 157 | if failed unixsocket /var/run/mysqld/mysqld.sock protocol mysql then restart 158 | if 5 restarts within 5 cycles then timeout 159 | depends on mysql_bin 160 | depends on mysql_rc 161 | group database 162 | 163 | check file mysql_bin with path /usr/sbin/mysqld 164 | if failed checksum then unmonitor 165 | if failed permission 755 then unmonitor 166 | if failed uid root then unmonitor 167 | if failed gid root then unmonitor 168 | group database 169 | 170 | check file mysql_rc with path /etc/init.d/mysql 171 | if failed checksum then unmonitor 172 | if failed permission 755 then unmonitor 173 | if failed uid root then unmonitor 174 | if failed gid root then unmonitor 175 | group database 176 | EOT 177 | } 178 | 179 | function monit_def_mongodb { 180 | cat </etc/monit/conf.d/mongodb.cfg 181 | check process mongodb with pidfile /var/lib/mongodb/mongod.lock 182 | start program = "/sbin/start mongodb" 183 | stop program = "/sbin/stop mongodb" 184 | if failed host localhost port 28017 protocol http 185 | and request "/" with timeout 10 seconds then restart 186 | if 5 restarts within 5 cycles then timeout 187 | group database 188 | EOT 189 | } 190 | 191 | function monit_def_memcached { 192 | cat </etc/monit/conf.d/memcached.cfg 193 | check process memcached with pidfile /var/run/memcached.pid 194 | start program = "/etc/init.d/memcached start" 195 | stop program = "/etc/init.d/memcached stop" 196 | if 5 restarts within 5 cycles then timeout 197 | group database 198 | EOT 199 | } 200 | 201 | function monit_def_apache { 202 | cat </etc/monit/conf.d/apache2.cfg 203 | check process apache with pidfile /var/run/apache2.pid 204 | start program = "/etc/init.d/apache2 start" 205 | stop program = "/etc/init.d/apache2 stop" 206 | if cpu > 60% for 2 cycles then alert 207 | if cpu > 80% for 5 cycles then alert 208 | if totalmem > 200.0 MB for 5 cycles then alert 209 | if children > 250 then alert 210 | if loadavg(5min) greater than 10 for 8 cycles then stop 211 | if failed host localhost port 80 protocol HTTP request / within 2 cycles then alert 212 | if failed host localhost port 80 protocol apache-status 213 | dnslimit > 25% or loglimit > 80% or waitlimit < 20% retry 2 within 2 cycles then alert 214 | #if 5 restarts within 5 cycles then timeout 215 | depends on apache_bin 216 | depends on apache_rc 217 | group www 218 | 219 | check file apache_bin with path /usr/sbin/apache2 220 | if failed checksum then unmonitor 221 | if failed permission 755 then unmonitor 222 | if failed uid root then unmonitor 223 | if failed gid root then unmonitor 224 | group www 225 | 226 | check file apache_rc with path /etc/init.d/apache2 227 | if failed checksum then unmonitor 228 | if failed permission 755 then unmonitor 229 | if failed uid root then unmonitor 230 | if failed gid root then unmonitor 231 | group www 232 | EOT 233 | } 234 | -------------------------------------------------------------------------------- /131 - Stack - Security, PostgreSQL, MySQL, MongoDB, Apache, Django.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Installs a complete web environment with Apache, Python, Django and PostgreSQL. 4 | # 5 | # Copyright (c) 2010 Filip Wasilewski . 6 | # 7 | # My ref: http://www.linode.com/?r=aadfce9845055011e00f0c6c9a5c01158c452deb 8 | 9 | # 10 | 11 | # 12 | # 13 | # 14 | # 15 | # 16 | 17 | # 18 | 19 | # 20 | 21 | # 22 | # 23 | # 24 | # 25 | 26 | # 27 | # 28 | # 29 | # 30 | # 31 | 32 | # 33 | 34 | # 35 | 36 | # 37 | # 38 | # 39 | # 40 | 41 | # 42 | # 43 | 44 | set -e 45 | set -u 46 | #set -x 47 | 48 | USER_GROUPS=sudo 49 | 50 | exec &> /root/stackscript.log 51 | 52 | source # StackScript Bash Library 53 | system_update 54 | 55 | source # lib-system 56 | system_install_mercurial 57 | system_start_etc_dir_versioning #start recording changes of /etc config files 58 | 59 | # Configure system 60 | source # lib-system-ubuntu 61 | system_update_hostname "$SYS_HOSTNAME" 62 | system_record_etc_dir_changes "Updated hostname" # SS124 63 | 64 | # Create user account 65 | system_add_user "$USER_NAME" "$USER_PASSWORD" "$USER_GROUPS" "$USER_SHELL" 66 | if [ "$USER_SSHKEY" ]; then 67 | system_user_add_ssh_key "$USER_NAME" "$USER_SSHKEY" 68 | fi 69 | system_record_etc_dir_changes "Added unprivileged user account" # SS124 70 | 71 | # Configure sshd 72 | system_sshd_permitrootlogin "$SSHD_PERMITROOTLOGIN" 73 | system_sshd_passwordauthentication "$SSHD_PASSWORDAUTH" 74 | touch /tmp/restart-ssh 75 | system_record_etc_dir_changes "Configured sshd" # SS124 76 | 77 | # Lock user account if not used for login 78 | if [ "SSHD_PERMITROOTLOGIN" == "No" ]; then 79 | system_lock_user "root" 80 | system_record_etc_dir_changes "Locked root account" # SS124 81 | fi 82 | 83 | # Install Postfix 84 | postfix_install_loopback_only # SS1 85 | system_record_etc_dir_changes "Installed postfix loopback" # SS124 86 | 87 | # Setup logcheck 88 | system_security_logcheck 89 | system_record_etc_dir_changes "Installed logcheck" # SS124 90 | 91 | # Setup fail2ban 92 | system_security_fail2ban 93 | system_record_etc_dir_changes "Installed fail2ban" # SS124 94 | 95 | # Setup firewall 96 | system_security_ufw_configure_basic 97 | system_record_etc_dir_changes "Configured UFW" # SS124 98 | 99 | source # lib-python 100 | python_install 101 | system_record_etc_dir_changes "Installed python" # SS124 102 | 103 | # lib-system - SS124 104 | system_install_utils 105 | system_install_build 106 | system_install_subversion 107 | system_install_git 108 | system_record_etc_dir_changes "Installed common utils" 109 | 110 | # Install and configure apache and mod_wsgi 111 | if [ "$SETUP_APACHE" == "Yes" ]; then 112 | source # lib-apache 113 | apache_worker_install 114 | system_record_etc_dir_changes "Installed apache" # SS124 115 | apache_mod_wsgi_install 116 | system_record_etc_dir_changes "Installed mod-wsgi" # SS124 117 | apache_cleanup 118 | system_record_etc_dir_changes "Cleaned up apache config" # SS124 119 | fi 120 | 121 | # Install PostgreSQL and setup database 122 | if [ "$SETUP_POSTGRESQL" == "Yes" ]; then 123 | source # lib-postgresql 124 | postgresql_install 125 | system_record_etc_dir_changes "Installed PostgreSQL" 126 | postgresql_create_user "$POSTGRESQL_USER" "$POSTGRESQL_PASSWORD" 127 | postgresql_create_database "$POSTGRESQL_DATABASE" "$POSTGRESQL_USER" 128 | system_record_etc_dir_changes "Configured PostgreSQL" 129 | fi 130 | 131 | # Install MySQL and setup database 132 | if [ "$SETUP_MYSQL" == "Yes" ]; then 133 | set +u # ignore undefined variables in Linode's SS1 134 | mysql_install "$MYSQL_DATABASE_PASSWORD" && mysql_tune 30 135 | mysql_create_database "$MYSQL_DATABASE_PASSWORD" "$MYSQL_DATABASE" 136 | mysql_create_user "$MYSQL_DATABASE_PASSWORD" "$MYSQL_USER" "$MYSQL_PASSWORD" 137 | mysql_grant_user "$MYSQL_DATABASE_PASSWORD" "$MYSQL_USER" "$MYSQL_DATABASE" 138 | set -u 139 | system_record_etc_dir_changes "Configured MySQL" 140 | fi 141 | 142 | # Install MongoDB 143 | if [ "$SETUP_MONGODB" == "Yes" ]; then 144 | source # lib-mongodb 145 | mongodb_install 146 | system_record_etc_dir_changes "Installed MongoDB" 147 | fi 148 | 149 | # Setup and configure sample django project 150 | RDNS=$(get_rdns_primary_ip) 151 | DJANGO_PROJECT_PATH="" 152 | 153 | if [ "$SETUP_DJANGO_PROJECT" != "No" ]; then 154 | source # lib-django 155 | 156 | if [ -z "$DJANGO_DOMAIN" ]; then DJANGO_DOMAIN=$RDNS; fi 157 | 158 | case "$SETUP_DJANGO_PROJECT" in 159 | Standalone) 160 | DJANGO_PROJECT_PATH="/srv/$DJANGO_PROJECT_NAME" 161 | if [ -n "$DJANGO_USER" ]; then 162 | if [ "$DJANGO_USER" != "$USER_NAME" ]; then 163 | system_add_system_user "$DJANGO_USER" "$DJANGO_PROJECT_PATH" "$USER_SHELL" 164 | else 165 | mkdir -p "$DJANGO_PROJECT_PATH" 166 | fi 167 | else 168 | DJANGO_USER="www-data" 169 | fi 170 | ;; 171 | InUserHome) 172 | DJANGO_USER=$USER_NAME 173 | DJANGO_PROJECT_PATH=$(system_get_user_home "$USER_NAME")/$DJANGO_PROJECT_NAME 174 | ;; 175 | InUserHomeRoot) 176 | DJANGO_USER=$USER_NAME 177 | DJANGO_PROJECT_PATH=$(system_get_user_home "$USER_NAME") 178 | ;; 179 | esac 180 | 181 | django_create_project "$DJANGO_PROJECT_PATH" 182 | django_change_project_owner "$DJANGO_PROJECT_PATH" "$DJANGO_USER" 183 | 184 | if [ "$SETUP_APACHE" == "Yes" ]; then 185 | django_configure_apache_virtualhost "$DJANGO_DOMAIN" "$DJANGO_PROJECT_PATH" "$DJANGO_USER" 186 | touch /tmp/restart-apache2 187 | fi 188 | if [ "$SETUP_POSTGRESQL" == "Yes" ]; then 189 | django_install_db_driver "$DJANGO_PROJECT_PATH" "psycopg2" 190 | django_configure_db_settings "$DJANGO_PROJECT_PATH" "postgresql_psycopg2" "$POSTGRESQL_DATABASE" "$POSTGRESQL_USER" "$POSTGRESQL_PASSWORD" "127.0.0.1" "" 191 | fi 192 | if [ "$SETUP_MYSQL" == "Yes" ]; then 193 | django_install_db_driver "$DJANGO_PROJECT_PATH" "MySQL-python" 194 | fi 195 | system_record_etc_dir_changes "Configured django project '$DJANGO_PROJECT_NAME'" 196 | fi 197 | 198 | if [ -n "$SYS_PRIVATE_IP" ]; then 199 | system_configure_private_network "$SYS_PRIVATE_IP" 200 | system_record_etc_dir_changes "Configured private network" 201 | fi 202 | 203 | restart_services 204 | restart_initd_services 205 | 206 | if [ "$SETUP_MONIT" == "Yes" ]; then 207 | source # lib-monit 208 | monit_install 209 | system_record_etc_dir_changes "Installed Monit" 210 | 211 | monit_configure_email "$NOTIFY_EMAIL" 212 | monit_configure_web $(system_primary_ip) 213 | system_record_etc_dir_changes "Configured Monit interfaces" 214 | 215 | monit_def_system "$SYS_HOSTNAME" 216 | monit_def_rootfs 217 | monit_def_cron 218 | monit_def_postfix 219 | monit_def_ping_google 220 | if [ "$SETUP_POSTGRESQL" == "Yes" ]; then monit_def_postgresql; fi 221 | if [ "$SETUP_MYSQL" == "Yes" ]; then monit_def_mysql; fi 222 | if [ "$SETUP_MONGODB" == "Yes" ]; then monit_def_mongodb; fi 223 | if [ "$SETUP_APACHE" == "Yes" ]; then monit_def_apache; fi 224 | #if [ "$SETUP_MEMCACHE" == "Yes" ]; then monit_def_memcached; fi 225 | system_record_etc_dir_changes "Created Monit rules for installed services" 226 | monit reload 227 | fi 228 | 229 | # Send info message 230 | cat > ~/setup_message <> ~/setup_message <> ~/setup_message <> ~/setup_message < 6 | # All rights reserved. 7 | # 8 | # Redistribution and use in source and binary forms, with or without modification, 9 | # are permitted provided that the following conditions are met: 10 | # 11 | # * Redistributions of source code must retain the above copyright notice, this 12 | # list of conditions and the following disclaimer. 13 | # 14 | # * Redistributions in binary form must reproduce the above copyright notice, this 15 | # list of conditions and the following disclaimer in the documentation and/or 16 | # other materials provided with the distribution. 17 | # 18 | # * Neither the name of Linode LLC nor the names of its contributors may be 19 | # used to endorse or promote products derived from this software without specific prior 20 | # written permission. 21 | # 22 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 23 | # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 | # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 25 | # SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 27 | # TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 28 | # BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 | # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 30 | # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 31 | # DAMAGE. 32 | 33 | ########################################################### 34 | # System 35 | ########################################################### 36 | 37 | function system_update { 38 | apt-get update 39 | apt-get -y install aptitude 40 | aptitude -y full-upgrade 41 | } 42 | 43 | function system_primary_ip { 44 | # returns the primary IP assigned to eth0 45 | echo $(ifconfig eth0 | awk -F: '/inet addr:/ {print $2}' | awk '{ print $1 }') 46 | } 47 | 48 | function get_rdns { 49 | # calls host on an IP address and returns its reverse dns 50 | 51 | if [ ! -e /usr/bin/host ]; then 52 | aptitude -y install dnsutils > /dev/null 53 | fi 54 | echo $(host $1 | awk '/pointer/ {print $5}' | sed 's/\.$//') 55 | } 56 | 57 | function get_rdns_primary_ip { 58 | # returns the reverse dns of the primary IP assigned to this system 59 | echo $(get_rdns $(system_primary_ip)) 60 | } 61 | 62 | ########################################################### 63 | # Postfix 64 | ########################################################### 65 | 66 | function postfix_install_loopback_only { 67 | # Installs postfix and configure to listen only on the local interface. Also 68 | # allows for local mail delivery 69 | 70 | echo "postfix postfix/main_mailer_type select Internet Site" | debconf-set-selections 71 | echo "postfix postfix/mailname string localhost" | debconf-set-selections 72 | echo "postfix postfix/destinations string localhost.localdomain, localhost" | debconf-set-selections 73 | aptitude -y install postfix 74 | /usr/sbin/postconf -e "inet_interfaces = loopback-only" 75 | #/usr/sbin/postconf -e "local_transport = error:local delivery is disabled" 76 | 77 | touch /tmp/restart-postfix 78 | } 79 | 80 | 81 | ########################################################### 82 | # Apache 83 | ########################################################### 84 | 85 | function apache_install { 86 | # installs the system default apache2 MPM 87 | aptitude -y install apache2 88 | 89 | a2dissite default # disable the interfering default virtualhost 90 | 91 | # clean up, or add the NameVirtualHost line to ports.conf 92 | sed -i -e 's/^NameVirtualHost \*$/NameVirtualHost *:80/' /etc/apache2/ports.conf 93 | if ! grep -q NameVirtualHost /etc/apache2/ports.conf; then 94 | echo 'NameVirtualHost *:80' > /etc/apache2/ports.conf.tmp 95 | cat /etc/apache2/ports.conf >> /etc/apache2/ports.conf.tmp 96 | mv -f /etc/apache2/ports.conf.tmp /etc/apache2/ports.conf 97 | fi 98 | } 99 | 100 | function apache_tune { 101 | # Tunes Apache's memory to use the percentage of RAM you specify, defaulting to 40% 102 | 103 | # $1 - the percent of system memory to allocate towards Apache 104 | 105 | if [ ! -n "$1" ]; 106 | then PERCENT=40 107 | else PERCENT="$1" 108 | fi 109 | 110 | aptitude -y install apache2-mpm-prefork 111 | PERPROCMEM=10 # the amount of memory in MB each apache process is likely to utilize 112 | MEM=$(grep MemTotal /proc/meminfo | awk '{ print int($2/1024) }') # how much memory in MB this system has 113 | MAXCLIENTS=$((MEM*PERCENT/100/PERPROCMEM)) # calculate MaxClients 114 | MAXCLIENTS=${MAXCLIENTS/.*} # cast to an integer 115 | sed -i -e "s/\(^[ \t]*MaxClients[ \t]*\)[0-9]*/\1$MAXCLIENTS/" /etc/apache2/apache2.conf 116 | 117 | touch /tmp/restart-apache2 118 | } 119 | 120 | function apache_virtualhost { 121 | # Configures a VirtualHost 122 | 123 | # $1 - required - the hostname of the virtualhost to create 124 | 125 | if [ ! -n "$1" ]; then 126 | echo "apache_virtualhost() requires the hostname as the first argument" 127 | return 1; 128 | fi 129 | 130 | if [ -e "/etc/apache2/sites-available/$1" ]; then 131 | echo /etc/apache2/sites-available/$1 already exists 132 | return; 133 | fi 134 | 135 | mkdir -p /srv/www/$1/public_html /srv/www/$1/logs 136 | 137 | echo "" > /etc/apache2/sites-available/$1 138 | echo " ServerName $1" >> /etc/apache2/sites-available/$1 139 | echo " DocumentRoot /srv/www/$1/public_html/" >> /etc/apache2/sites-available/$1 140 | echo " ErrorLog /srv/www/$1/logs/error.log" >> /etc/apache2/sites-available/$1 141 | echo " CustomLog /srv/www/$1/logs/access.log combined" >> /etc/apache2/sites-available/$1 142 | echo "" >> /etc/apache2/sites-available/$1 143 | 144 | a2ensite $1 145 | 146 | touch /tmp/restart-apache2 147 | } 148 | 149 | function apache_virtualhost_from_rdns { 150 | # Configures a VirtualHost using the rdns of the first IP as the ServerName 151 | 152 | apache_virtualhost $(get_rdns_primary_ip) 153 | } 154 | 155 | 156 | function apache_virtualhost_get_docroot { 157 | if [ ! -n "$1" ]; then 158 | echo "apache_virtualhost_get_docroot() requires the hostname as the first argument" 159 | return 1; 160 | fi 161 | 162 | if [ -e /etc/apache2/sites-available/$1 ]; 163 | then echo $(awk '/DocumentRoot/ {print $2}' /etc/apache2/sites-available/$1 ) 164 | fi 165 | } 166 | 167 | ########################################################### 168 | # mysql-server 169 | ########################################################### 170 | 171 | function mysql_install { 172 | # $1 - the mysql root password 173 | 174 | if [ ! -n "$1" ]; then 175 | echo "mysql_install() requires the root pass as its first argument" 176 | return 1; 177 | fi 178 | 179 | echo "mysql-server-5.1 mysql-server/root_password password $1" | debconf-set-selections 180 | echo "mysql-server-5.1 mysql-server/root_password_again password $1" | debconf-set-selections 181 | apt-get -y install mysql-server mysql-client 182 | 183 | echo "Sleeping while MySQL starts up for the first time..." 184 | sleep 5 185 | } 186 | 187 | function mysql_tune { 188 | # Tunes MySQL's memory usage to utilize the percentage of memory you specify, defaulting to 40% 189 | 190 | # $1 - the percent of system memory to allocate towards MySQL 191 | 192 | if [ ! -n "$1" ]; 193 | then PERCENT=40 194 | else PERCENT="$1" 195 | fi 196 | 197 | sed -i -e 's/^#skip-innodb/skip-innodb/' /etc/mysql/my.cnf # disable innodb - saves about 100M 198 | 199 | MEM=$(awk '/MemTotal/ {print int($2/1024)}' /proc/meminfo) # how much memory in MB this system has 200 | MYMEM=$((MEM*PERCENT/100)) # how much memory we'd like to tune mysql with 201 | MYMEMCHUNKS=$((MYMEM/4)) # how many 4MB chunks we have to play with 202 | 203 | # mysql config options we want to set to the percentages in the second list, respectively 204 | OPTLIST=(key_buffer sort_buffer_size read_buffer_size read_rnd_buffer_size myisam_sort_buffer_size query_cache_size) 205 | DISTLIST=(75 1 1 1 5 15) 206 | 207 | for opt in ${OPTLIST[@]}; do 208 | sed -i -e "/\[mysqld\]/,/\[.*\]/s/^$opt/#$opt/" /etc/mysql/my.cnf 209 | done 210 | 211 | for i in ${!OPTLIST[*]}; do 212 | val=$(echo | awk "{print int((${DISTLIST[$i]} * $MYMEMCHUNKS/100))*4}") 213 | if [ $val -lt 4 ] 214 | then val=4 215 | fi 216 | config="${config}\n${OPTLIST[$i]} = ${val}M" 217 | done 218 | 219 | sed -i -e "s/\(\[mysqld\]\)/\1\n$config\n/" /etc/mysql/my.cnf 220 | 221 | touch /tmp/restart-mysql 222 | } 223 | 224 | function mysql_create_database { 225 | # $1 - the mysql root password 226 | # $2 - the db name to create 227 | 228 | if [ ! -n "$1" ]; then 229 | echo "mysql_create_database() requires the root pass as its first argument" 230 | return 1; 231 | fi 232 | if [ ! -n "$2" ]; then 233 | echo "mysql_create_database() requires the name of the database as the second argument" 234 | return 1; 235 | fi 236 | 237 | echo "CREATE DATABASE $2;" | mysql -u root -p$1 238 | } 239 | 240 | function mysql_create_user { 241 | # $1 - the mysql root password 242 | # $2 - the user to create 243 | # $3 - their password 244 | 245 | if [ ! -n "$1" ]; then 246 | echo "mysql_create_user() requires the root pass as its first argument" 247 | return 1; 248 | fi 249 | if [ ! -n "$2" ]; then 250 | echo "mysql_create_user() requires username as the second argument" 251 | return 1; 252 | fi 253 | if [ ! -n "$3" ]; then 254 | echo "mysql_create_user() requires a password as the third argument" 255 | return 1; 256 | fi 257 | 258 | echo "CREATE USER '$2'@'localhost' IDENTIFIED BY '$3';" | mysql -u root -p$1 259 | } 260 | 261 | function mysql_grant_user { 262 | # $1 - the mysql root password 263 | # $2 - the user to bestow privileges 264 | # $3 - the database 265 | 266 | if [ ! -n "$1" ]; then 267 | echo "mysql_create_user() requires the root pass as its first argument" 268 | return 1; 269 | fi 270 | if [ ! -n "$2" ]; then 271 | echo "mysql_create_user() requires username as the second argument" 272 | return 1; 273 | fi 274 | if [ ! -n "$3" ]; then 275 | echo "mysql_create_user() requires a database as the third argument" 276 | return 1; 277 | fi 278 | 279 | echo "GRANT ALL PRIVILEGES ON $3.* TO '$2'@'localhost';" | mysql -u root -p$1 280 | echo "FLUSH PRIVILEGES;" | mysql -u root -p$1 281 | 282 | } 283 | 284 | ########################################################### 285 | # PHP functions 286 | ########################################################### 287 | 288 | function php_install_with_apache { 289 | aptitude -y install php5 php5-mysql libapache2-mod-php5 290 | touch /tmp/restart-apache2 291 | } 292 | 293 | function php_tune { 294 | # Tunes PHP to utilize up to 32M per process 295 | 296 | sed -i'-orig' 's/memory_limit = [0-9]\+M/memory_limit = 32M/' /etc/php5/apache2/php.ini 297 | touch /tmp/restart-apache2 298 | } 299 | 300 | ########################################################### 301 | # Wordpress functions 302 | ########################################################### 303 | 304 | function wordpress_install { 305 | # installs the latest wordpress tarball from wordpress.org 306 | 307 | # $1 - required - The existing virtualhost to install into 308 | 309 | if [ ! -n "$1" ]; then 310 | echo "wordpress_install() requires the vitualhost as its first argument" 311 | return 1; 312 | fi 313 | 314 | if [ ! -e /usr/bin/wget ]; then 315 | aptitude -y install wget 316 | fi 317 | 318 | VPATH=$(apache_virtualhost_get_docroot $1) 319 | 320 | if [ ! -n "$VPATH" ]; then 321 | echo "Could not determine DocumentRoot for $1" 322 | return 1; 323 | fi 324 | 325 | # download, extract, chown, and get our config file started 326 | cd $VPATH 327 | wget http://wordpress.org/latest.tar.gz 328 | tar xfz latest.tar.gz 329 | chown -R www-data: wordpress/ 330 | cd $VPATH/wordpress 331 | cp wp-config-sample.php wp-config.php 332 | chown www-data wp-config.php 333 | chmod 640 wp-config.php 334 | 335 | # database configuration 336 | WPPASS=$(randomString 20) 337 | mysql_create_database "$DB_PASSWORD" wordpress 338 | mysql_create_user "$DB_PASSWORD" wordpress "$WPPASS" 339 | mysql_grant_user "$DB_PASSWORD" wordpress wordpress 340 | 341 | # configuration file updates 342 | for i in {1..4} 343 | do sed -i "0,/put your unique phrase here/s/put your unique phrase here/$(randomString 50)/" wp-config.php 344 | done 345 | 346 | sed -i 's/database_name_here/wordpress/' wp-config.php 347 | sed -i 's/username_here/wordpress/' wp-config.php 348 | sed -i "s/password_here/$WPPASS/" wp-config.php 349 | 350 | # http://downloads.wordpress.org/plugin/wp-super-cache.0.9.8.zip 351 | } 352 | 353 | ########################################################### 354 | # Other niceties! 355 | ########################################################### 356 | 357 | function goodstuff { 358 | # Installs the REAL vim, wget, less, and enables color root prompt and the "ll" list long alias 359 | 360 | aptitude -y install wget vim less 361 | sed -i -e 's/^#PS1=/PS1=/' /root/.bashrc # enable the colorful root bash prompt 362 | sed -i -e "s/^#alias ll='ls -l'/alias ll='ls -al'/" /root/.bashrc # enable ll list long alias <3 363 | } 364 | 365 | 366 | ########################################################### 367 | # utility functions 368 | ########################################################### 369 | 370 | function restartServices { 371 | # restarts services that have a file in /tmp/needs-restart/ 372 | 373 | for service in $(ls /tmp/restart-* | cut -d- -f2-10); do 374 | /etc/init.d/$service restart 375 | rm -f /tmp/restart-$service 376 | done 377 | } 378 | 379 | function randomString { 380 | if [ ! -n "$1" ]; 381 | then LEN=20 382 | else LEN="$1" 383 | fi 384 | 385 | echo $(