echo "This script will:
1) Install modules needed to run web2py on Fedora and CentOS/RHEL
2) Install Python 2.6 to /opt and recompile wsgi if not provided
2) Install web2py in /opt/web-apps/
3) Configure SELinux and iptables
5) Create a self signed ssl certificate
6) Setup web2py with mod_wsgi
7) Create virtualhost entries so that web2py responds for '/'
8) Restart Apache.
You should probably read this script before running it.
Although SELinux permissions changes have been made,
further SELinux changes will be required for your personal
apps. (There may also be additional changes required for the
bundled apps.) As a last resort, SELinux can be disabled.
A simple iptables configuration has been applied. You may
want to review it to verify that it meets your needs.
Finally, if you require a proxy to access the Internet, please
set up your machine to do so before running this script.
(author: berubejd)
Press ENTER to continue...[ctrl+C to abort]"
read CONFIRM
#!/bin/bash
###
### Phase 0 - This may get messy. Lets work from a temporary directory
###
current_dir=`pwd`
if [ -d /tmp/setup-web2py/ ]; then
mv /tmp/setup-web2py/ /tmp/setup-web2py.old/
fi
mkdir -p /tmp/setup-web2py
cd /tmp/setup-web2py
###
### Phase 1 - Requirements installation
###
echo
echo " - Installing packages"
echo
# Verify packages are up to date
yum update
# Install required packages
yum install httpd mod_ssl mod_wsgi wget python
# Verify we have at least Python 2.5
typeset -i version_major
typeset -i version_minor
version=`rpm --qf %{Version} -q python`
version_major=`echo ${version} | awk '{split($0, parts, "."); print parts[1]}'`
version_minor=`echo ${version} | awk '{split($0, parts, "."); print parts[2]}'`
if [ ! ${version_major} -ge 2 -o ! ${version_minor} -ge 5 ]; then
# Setup 2.6 in /opt - based upon
# http://markkoberlein.com/getting-python-26-with-django-11-together-on
# Check for earlier Python 2.6 install
if [ -e /opt/python2.6 ]; then
# Is Python already installed?
RETV=`/opt/python2.6/bin/python -V > /dev/null 2>&1; echo $?`
if [ ${RETV} -eq 0 ]; then
python_installed='True'
else
mv /opt/python2.6 /opt/python2.6-old
fi
fi
# Install Python 2.6 if it doesn't exist already
if [ ! "${python_installed}" == "True" ]; then
# Install requirements for the Python build
yum install sqlite-devel zlib-devel
mkdir -p /opt/python2.6
# Download and install
wget http://www.python.org/ftp/python/2.6.4/Python-2.6.4.tgz
tar -xzf Python-2.6.4.tgz
cd Python-2.6.4
./configure --prefix=/opt/python2.6 --with-threads --enable-shared --with-zlib=/usr/include
make && make install
cd /tmp/setup-web2py
fi
# Create links for Python 2.6
# even if it was previously installed just to be sure
ln -s /opt/python2.6/lib/libpython2.6.so /usr/lib
ln -s /opt/python2.6/lib/libpython2.6.so.1.0 /usr/lib
ln -s /opt/python2.6/bin/python /usr/local/bin/python
ln -s /opt/python2.6/bin/python /usr/bin/python2.6
ln -s /opt/python2.6/lib/python2.6.so /opt/python2.6/lib/python2.6/config/
# Update linker for new libraries
/sbin/ldconfig
# Rebuild wsgi to take advantage of Python 2.6
yum install httpd-devel
cd /tmp/setup-web2py
wget http://modwsgi.googlecode.com/files/mod_wsgi-3.3.tar.gz
tar -xzf mod_wsgi-3.3.tar.gz
cd mod_wsgi-3.3
./configure --with-python=/usr/local/bin/python
make && make install
echo "LoadModule wsgi_module modules/mod_wsgi.so" > /etc/httpd/conf.d/wsgi.conf
cd /tmp/setup-web2py
fi
### MySQL install untested!
# Install mysql packages (optional)
#yum install mysql mysql-server
# Enable mysql to start at boot (optional)
#chkconfig --levels 235 mysqld on
#service mysqld start
# Configure mysql security settings (not really optional if mysql installed)
#/usr/bin/mysql_secure_installation
###
### Phase 2 - Install web2py
###
echo
echo " - Downloading, installing, and starting web2py"
echo
# Create web-apps directory, if required
if [ ! -d "/opt/web-apps" ]; then
mkdir -p /opt/web-apps
chmod 755 /opt
chmod 755 /opt/web-apps
fi
cd /opt/web-apps
# Download web2py
if [ -e web2py_src.zip* ]; then
rm web2py_src.zip*
fi
wget http://web2py.com/examples/static/web2py_src.zip
unzip web2py_src.zip
chown -R apache:apache web2py
###
### Phase 3 - Setup SELinux context
###
# Set context for Python libraries if Python 2.6 installed
if [ -d /opt/python2.6 ]; then
cd /opt/python2.6
chcon -R -t lib_t lib/
fi
# Allow http_tmp_exec required for wsgi
RETV=`setsebool -P httpd_tmp_exec on > /dev/null 2>&1; echo $?`
if [ ! ${RETV} -eq 0 ]; then
# CentOS doesn't support httpd_tmp_exec
cd /tmp/setup-web2py
# Create the SELinux policy
cat > httpd.te <<EOF
EOF
module httpd 1.0;
require {
type httpd_t;
class process execmem;
}
#============= httpd_t ==============
allow httpd_t self:process execmem;
EOF
checkmodule -M -m -o httpd.mod httpd.te
semodule_package -o httpd.pp -m httpd.mod
semodule -i httpd.pp
fi
# Setup the overall web2py SELinux context
cd /opt
chcon -R -t httpd_user_content_t web-apps/
cd /opt/web-apps/web2py/applications
# Setup the proper context on the writable application directories
for app in `ls`
do
for dir in databases cache errors sessions private uploads
do
mkdir ${app}/${dir}
chown apache:apache ${app}/${dir}
chcon -R -t tmp_t ${app}/${dir}
done
done
###
### Phase 4 - Configure iptables
###
cd /tmp/setup-web2py
# Create rules file - based upon
# http://articles.slicehost.com/assets/2007/9/4/iptables.txt
cat > iptables.rules <<EOF
EOF
*filter
# Allows all loopback (lo0) traffic
# drop all traffic to 127/8 that doesn't use lo0
-A INPUT -i lo -j ACCEPT
-A INPUT ! -i lo -d 127.0.0.0/8 -j REJECT
# Accepts all established inbound connections
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# Allows all outbound traffic
-A OUTPUT -j ACCEPT
# Allows SSH, HTTP, and HTTPS
# Consider changing the SSH port and/or using rate limiting
# see http://blog.andrew.net.au/2005/02/16#ipt_recent_and_ssh_attacks
-A INPUT -p tcp -m state --state NEW --dport 22 -j ACCEPT
-A INPUT -p tcp --dport 80 -j ACCEPT
-A INPUT -p tcp --dport 443 -j ACCEPT
# Allow ping
-A INPUT -p icmp -m icmp --icmp-type 8 -j ACCEPT
# log iptables denied calls
-A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables denied: " --log-level 7
# Reject all other inbound - default deny unless explicitly allowed policy
-A INPUT -j REJECT
-A FORWARD -j REJECT
COMMIT
EOF
/sbin/iptables -F
cat iptables.rules | /sbin/iptables-restore
/sbin/service iptables save
###
### Phase 5 - Setup SSL
###
echo
echo " - Creating a self signed certificate"
echo
# Verify ssl directory exists
if [ ! -d "/etc/httpd/ssl" ]; then
mkdir -p /etc/httpd/ssl
fi
# Generate and protect certificate
openssl genrsa 1024 > /etc/httpd/ssl/self_signed.key
openssl req -new -x509 -nodes -sha1 -days 365 -key /etc/httpd/ssl/self_signed.key > /etc/httpd/ssl/self_signed.cert
openssl x509 -noout -fingerprint -text < /etc/httpd/ssl/self_signed.cert > /etc/httpd/ssl/self_signed.info
chmod 400 /etc/httpd/ssl/self_signed.*
###
### Phase 6 - Configure Apache
###
echo
echo " - Configure Apache to use mod_wsgi"
echo
# Create config
if [ -e /etc/httpd/conf.d/welcome.conf ]; then
mv /etc/httpd/conf.d/welcome.conf /etc/httpd/conf.d/welcome.conf.disabled
fi
cat > /etc/httpd/conf.d/default.conf <<EOF
EOF
NameVirtualHost *:80
NameVirtualHost *:443
<VirtualHost *:80>
WSGIDaemonProcess web2py user=apache group=apache
WSGIProcessGroup web2py
WSGIScriptAlias / /opt/web-apps/web2py/wsgihandler.py
<Directory /opt/web-apps/web2py>
AllowOverride None
Order Allow,Deny
Deny from all
<Files wsgihandler.py>
Allow from all
</Files>
</Directory>
AliasMatch ^/([^/]+)/static/(.*) /opt/web-apps/web2py/applications/\$1/static/\$2
<Directory /opt/web-apps/web2py/applications/*/static>
Options -Indexes
Order Allow,Deny
Allow from all
</Directory>
<Location /admin>
Deny from all
</Location>
<LocationMatch ^/([^/]+)/appadmin>
Deny from all
</LocationMatch>
CustomLog /var/log/httpd/access_log common
ErrorLog /var/log/httpd/error_log
</VirtualHost>
<VirtualHost *:443>
SSLEngine on
SSLCertificateFile /etc/httpd/ssl/self_signed.cert
SSLCertificateKeyFile /etc/httpd/ssl/self_signed.key
WSGIProcessGroup web2py
WSGIScriptAlias / /opt/web-apps/web2py/wsgihandler.py
<Directory /opt/web-apps/web2py>
AllowOverride None
Order Allow,Deny
Deny from all
<Files wsgihandler.py>
Allow from all
</Files>
</Directory>
AliasMatch ^/([^/]+)/static/(.*) /opt/web-apps/web2py/applications/\$1/static/\$2
<Directory /opt/web-apps/web2py/applications/*/static>
Options -Indexes
ExpiresActive On
ExpiresDefault "access plus 1 hour"
Order Allow,Deny
Allow from all
</Directory>
CustomLog /var/log/httpd/access_log common
ErrorLog /var/log/httpd/error_log
</VirtualHost>
EOF
# Fix wsgi socket locations
echo "WSGISocketPrefix run/wsgi" >> /etc/httpd/conf.d/wsgi.conf
# Restart Apache to pick up changes
service httpd restart
###
### Phase 7 - Setup web2py admin password
###
echo
echo " - Setup web2py admin password"
echo
cd /opt/web-apps/web2py
sudo -u apache python -c "from gluon.main import save_password; save_password(raw_input('admin password: '),443)"
###
### Phase 8 - Verify that required services start at boot
###
/sbin/chkconfig iptables on
/sbin/chkconfig httpd on
###
### Phase 999 - Done!
###
# Change back to original directory
cd ${current_directory}
echo " - Complete!"
echo
EOF
EOF
EOF