#
# This is a log of the installation of a production server in early 2011.
#
# It starts out fairly generic, and becomes increasingly specific to Mushroom
# Observer. Look for the following "variables:
#
# IP_ADDR ip address of new server
# OTHER_IP_ADDR ip address of old server
# DOMAIN mushroomobserver.org
# SITE mo
# USER jason
# USER_PASSWORD xxx
# DATA_PASSWORD xxx
# MAIL_PASSWORD xxx
# $YOUR_EMAIL pellaea@gmail.com
# $FULL_NAME Jason Hollinger
#
# Tested from scratch, Mar 14, 2011. -Jason
#
# (Many changes have been made since that test, though. I hope to test it
# again in the next week or two, Mar 17, 2011. -Jason)
#
# NOTE: I have added the yum equivalents to apt-get for Fedora / CentOS in
# comments next to each apt-get line. I can't guarantee these are all the ones
# required. Also note that a few configuration files will be in different
# locations, and you will need to use chkconfig instead of update-rc.d.
#
# ubuntu 10.10
# ruby 1.9.2-p180
# rubygems 1.6.2
# passenger 3.0.5
# apache2 2.2.16
# postfix 2.7.1
# mysql 14.14
#
################################################################################
# Initial set up.
local> ssh root@$IP_ADDR
root> passwd
root> apt-get upgrade
root> apt-get install tcsh mlocate man vim lynx telnet emacs wget \
build-essential iptables bison
root> # yum update
root> # yum install tcsh mlocate gcc make vim lynx telnet emacs bind-utils
# Create account for webserver.
root> useradd -m -s /bin/tcsh $SITE
root> passwd -l $SITE
root> visudo
# Add these lines to end. Allows users in "mo" group to "sudo su mo".
%$SITE ALL = NOPASSWD: /bin/su $SITE
%$SITE ALL = NOPASSWD: /bin/su - $SITE
# Create account for yourself.
root> useradd -m -G $SITE -s /bin/tcsh $USER
root> passwd $USER_PASSWORD
root> logout
# Password-less ssh.
local> ssh-keygen -t rsa # (if not already done)
local> ssh-copy-id -i ~/.ssh/id_rsa.pub $IP_ADDR
# Set up your user account however you like.
local> ssh $IP_ADDR
user> vi .tcshrc
alias root sudo
alias cls clear
alias cd.. cd ..
alias dirf ls -alF
alias dirt ls -alFrt
alias md mkdir
alias rd rmdir
alias del rm
alias mv mv -i
alias cp cp -i
alias grep grep -s
alias +x chmod a+x
alias -x chmod a-x
alias $SITE 'cd /var/web/$SITE; sudo su - $SITE'
user> vi .vimrc
syntax off
set nohlsearch
set ts=2
set sw=2
set et
set nowrap
user> source .tcshrc
# Set up root's and website's accounts.
user> su root
root> cp .tcshrc /root
root> cp .tcshrc /home/$SITE
root> cp .vimrc /root
root> cp .vimrc /home/$SITE
root> chmod 660 /home/*/.tcshrc
root> vi /root/.tcshrc
# Add this line to improve performance of custom-built packages.
# (Check lscpu and /proc/cpuinfo for cpu type.)
setenv CFLAGS "-O3 -m64 -march=core2"
root> vi /home/$SITE/.tcshrc
# Add these aliases to the end.
alias $SITE 'cd /var/web/$SITE'
alias ${SITE}sql "mysql -u $SITE -p'$DATA_PASSWORD' ${SITE}_production"
alias ${SITE}sqle "mysql -u $SITE -p'$DATA_PASSWORD' ${SITE}_production -e 'source \!^'"
root> vi /home/$SITE/.login
setenv TZ 'Eastern Time (US & Canada)'
setenv RAILS_ENV production
cd /var/web/$SITE
root> chown -R $SITE:$SITE /home/$SITE
root> tcsh
# Disable direct root login for security purposes.
root> vi /etc/ssh/sshd_config
PermitRootLogin no
# Configure firewall.
root> iptables -F
root> iptables -P INPUT ACCEPT
root> iptables -P OUTPUT ACCEPT
root> iptables -P FORWARD ACCEPT
root> iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
root> iptables -A INPUT -i lo -j ACCEPT
root> iptables -A INPUT -p icmp -j ACCEPT
root> iptables -A INPUT -m state --state NEW -p tcp --dport 22 -j ACCEPT
root> iptables -A INPUT -m state --state NEW -p tcp --dport 80 -j ACCEPT
root> iptables -A INPUT -m state --state NEW -p tcp --dport 25 -j ACCEPT
root> iptables -A INPUT -m state --state NEW -p tcp --dport 3306 -j ACCEPT
root> iptables -A INPUT -m state --state NEW -p tcp --dport 53 -j ACCEPT
root> iptables -A INPUT -m state --state NEW -p udp --dport 53 -j ACCEPT
root> iptables -A INPUT -j REJECT --reject-with icmp-host-prohibited
root> iptables -A FORWARD -j REJECT --reject-with icmp-host-prohibited
root> iptables-save > /etc/firewall.conf
root> chmod 600 /etc/firewall.conf
root> vi /etc/rc.local
iptables-restore < /etc/firewall.conf
# Install most of the modules that we will need (except ruby).
root> apt-get install apache2 libapache2-mod-passenger \
mysql-server mysql-client libmysqlclient-dev \
subversion subversion-tools \
libcurl4-openssl-dev libssl-dev libopenssl-ruby \
apache2-prefork-dev libapr1-dev libaprutil1-dev
root> # yum install httpd-devel mysql-devel mysql-server svn curl-devel
# Build and install ruby from source to get good version.
root> cd
root> mkdir build
root> cd build
root> wget http://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.2-p180.tar.bz2
root> tar -xjf ruby*.bz2
root> cd ruby-1.9.2-p180
root> ./configure --with-ruby-version=1.9.2
root> make install
root> rehash
root> cd
# Ditto for rubygems.
root> cd ~/build
root> wget http://production.cf.rubygems.org/rubygems/rubygems-1.6.2.tgz
root> tar -xzf rubygems*.tgz
root> cd rubygems-1.6.2
root> ruby setup.rb --prefix=/usr/local --verbose
root> rehash
root> cd
# Now we can install ruby gems properly.
root> gem install rails --version=2.1.1 --verbose --no-rdoc --no-ri
root> gem install mysql2 --verbose --no-rdoc --no-ri
root> gem install test-unit --verbose --no-rdoc --no-ri
root> gem install RedCloth --verbose --no-rdoc --no-ri
# (not sure if this is necessary, it got installed when working on getting rails to play with gmail nicely)
root> gem install openrain-action_mailer_tls -s http://gems.github.com
# Install passenger.
root> gem install passenger --verbose --no-rdoc --no-ri
root> rehash
root> passenger-install-apache2-module
# Pay attention to output at end and make sure values below are right.
root> vi /etc/apache2/mods-available/passenger.conf
# Change root to /usr/local/lib/ruby/gems/1.9.2/gems/passenger-3.0.5
# Change ruby to /usr/local/bin/ruby
root> vi /etc/apache2/mods-available/passenger.load
# Change to /usr/local/lib/ruby/gems/1.9.2/gems/passenger-3.0.5/ext/apache2/mod_passenger.so
root> service apache2 stop
root> service apache2 start
# (For some reason reload and restart don't always work.)
# Install ImageMagick.
root> apt-get install imagemagick libmagickcore-dev libmagickwand-dev
root> # yum install ImageMagick-devel
root> gem install rmagick --verbose --no-rdoc --no-ri
root> gcc /var/web/mo/script/jpegresize.c -ljpeg -lm -O2 -o /usr/local/bin/jpegresize
# Create directory for rails app.
root> mkdir /var/web
root> mkdir /var/web/$SITE
root> mkdir /var/web/$SITE/{tmp,log}
root> touch /var/web/$SITE/tmp/restart.txt
root> chown -R $SITE:$SITE /var/web/$SITE
root> chmod 750 /var/web/$SITE
# Make sure apache user has access to rails directories.
root> usermod -a -G $SITE www-data
--------------------------------------------------------------------------------
# Now we're done with the generic installation. Start installing Mushroom
# Observer in particular.
# Install rails apps.
root> mo
mo> svn co http://svn.collectivesource.com/mushroom_sightings/trunk/ .
mo> mkdir public/images/{thumb,320,640,960,1280,orig}
mo> vi config/consts-site.rb
# Override these defaults.
DOMAIN = 'mushroomobserver.org'
HTTP_DOMAIN = 'http://mushroomobserver.org'
SERVER_CODE = 'us1'
DEFAULT_LOCALE = 'en-US'
BAD_DOMAINS = ["www.#{DOMAIN}"]
# Use queued email mechanism.
QUEUE_EMAIL = true
# Nathan wants to be BCC'ed on every single email.
EXTRA_BCC_EMAIL_ADDRESSES = "mo@collectivesource.com"
# Date after which votes become public.
VOTE_CUTOFF = '20100405'
# Set timezone?
ENV['TZ'] = 'Eastern Time (US & Canada)'
# Use Gmail mail server for ActionMailer.
config.action_mailer.smtp_settings = {
:address => "smtp.gmail.com",
:port => 587,
:authentication => :plain,
:enable_starttls_auto => true,
:user_name => "webmaster@mushroomobserver.org",
:password => "Amanita1"
}
mo> exit
# Configure apache.
root> vi /etc/apache2/sites-available/mo
ServerName mushroomobserver.org
DocumentRoot /var/web/mo/public
RailsEnv production
SetEnv TZ 'Eastern Time (US & Canada)'
# Chris Parrish might need this for his Chrome browser to work right?
Header set Accept-Ranges none
# This was necessary for my local installation on Fedora Core 13.
# RailsBaseURI /
Options FollowSymLinks
AllowOverride limit
Order allow,deny
Allow from all
RewriteEngine on
# Redirect Chris Parrish's lichens pages at CDMR.
RewriteRule ^/lichens/(.*)$ http://lichens.digitalmycology.com/$1 [QSA]
# Explicitly tell apache where to find static content in /public.
# (Applies to several specific subdirs and any URL like /blah.ext.)
# (This is apparently only required for the old fedora installation?)
# RewriteRule ^/(stylesheets|javascripts|[\w\-\.]+\.\w+)(.*)$ /public/$1$2 [QSA]
# Redirect all but thumbnails to image server.
# RewriteRule ^/images/thumb/(.*)$ http://images.digitalmycology.com/thumb/$1 [QSA]
# RewriteRule ^/images/320/(.*)$ http://images.digitalmycology.com/320/$1 [QSA]
RewriteRule ^/images/640/(.*)$ http://images.digitalmycology.com/640/$1 [QSA]
RewriteRule ^/images/960/(.*)$ http://images.digitalmycology.com/960/$1 [QSA]
RewriteRule ^/images/1280/(.*)$ http://images.digitalmycology.com/1280/$1 [QSA]
RewriteRule ^/images/orig/(.*)$ http://images.digitalmycology.com/orig/$1 [QSA]
root> a2dissite default
root> a2ensite mo
root> a2enmod rewrite
root> a2enmod headers
# Create database.
root> mo
mo> mysql -u root -p
create database mo_production;
create user 'mo'@'localhost' identified by '$DATA_PASSWORD';
# set password for 'mo'@'localhost' = password('$DATA_PASSWORD');
grant all privileges on mo_production.* to 'mo'@'localhost' with grant option;
mo> cp config/database.yml-template config/database.yml
mo> vi config/database.yml
# Change these values in production section: (other sections aren't needed)
adapter: mysql2
database: mo
password: $DATA_PASSWORD
socket: /var/run/mysqld/mysqld.sock # ubuntu/debian
# socket: /var/lib/mysql/mysql.sock # fedora/centos?
encoding: utf8
mo> cd db
mo> scp $USER@$OLD_SERVER:/var/web/mo/db/checkpoint.gz .
mo> gunzip checkpoint.gz
mo> mosqle checkpoint
# Set up password-less ssh for image transfers.
mo> ssh-keygen -t rsa
# Just press return three times, tell it to overwrite id_rsa.pub if it asks.
mo> ssh-copy-id -i ~/.ssh/id_rsa.pub cdmr@images.digitalmycology.com
# Enter password.
mo> ssh cdmr@images.digitalmycology.com
# (just make sure it works)
--------------------------------------------------------------------------------
# This section deals with setting up email. It's mostly generic.
# Set up simple mailserver using postfix.
root> apt-get install postfix mutt
# Select "internet site" when it prompts you.
# Enter the proper hostname as "system mail name" (should resolve back with reverse DNS).
root> # yum install postfix mutt
root> vi /etc/aliases
# Change where root's mail goes.
root: $USER,...
root> newaliases
# NOTE: After moving mail.mo.org to gmail, had to tweak postfix configuration:
root> vi /etc/postfix/main.cf
# change myhostname to "$DOMAIN" (instead of "mail.$DOMAIN")
# Test mail server.
root> su $USER
user> cd
user> echo $YOUR_EMAIL > .forward
user> vi .muttrc
set realname="$FULL_NAME"
set from="$USER@$DOMAIN"
set use_from=yes
set envelope_from=yes
user> echo "This is a test." | mutt -s test $YOUR_EMAIL
# (Check /var/log/mail.log and /var/log/mail.err.)
user> exit
# Configure mail for MO.
root> mo
mo> cd
mo> vi .muttrc
set realname="Mushroom Observer"
set from="no-reply@mushroomobserver.org"
set use_from=yes
set envelope_from=yes
mo> vi .forward
root
mo> echo "This is another test." | mutt -s test $YOUR_EMAIL
mo> exit
# Configure mail for rails.
# Should come configured "out of the box".
# Ask yourself a question via the website, e.g.:
# http://$IP_ADDR/observer/ask_user_question/252
# Probably want to tail -f log/production.log if it's throwing errors.
# Configure no-reply to bounce correctly.
root> useradd -m no-reply
root> passwd -l no-reply
root> cp /var/web/mo/script/autoreply /usr/local/bin/autoreply
root> cp /var/web/mo/config/no-reply.muttrc /home/no-reply/.muttrc
root> cp /var/web/mo/config/no-reply.autoreply /home/no-reply/.autoreply
root> cp /var/web/mo/config/no-reply.forward /home/no-reply/.forward
root> chmod 644 /home/no-reply/.[maf]*
root> chmod 755 /usr/local/bin/autoreply
--------------------------------------------------------------------------------
# Now the site should be mostly working. We need to do some configuration to
# get image uploads to work, though.
# Make sure these have the correct image server(s).
mo> vim script/process_image
mo> vim script/update_images
# Test image upload on server:
# http://$IP_ADDR/observer/create_observation
# Might need to run process_image once by hand before it will be fully automatic.
mo> ls public/images/orig
mo> script/process_image NNNNN jpg 0
# Grab thumbnails from image server. (This takes hours!)
mo> script/update_images -v --sync dreamhost --download --thumb --320
--------------------------------------------------------------------------------
# Install cron jobs.
# They're all already present, just need to stick them in the crontab.
mo> crontab -e
*/5 * * * * /var/web/mo/script/run_rake email:send
23 * * * * /var/web/mo/script/parse_log
13 3 * * * /var/web/mo/script/run_script refresh_name_lister_cache
43 3 * * * /var/web/mo/script/run_script update_lichen_list
13 4 * * * /var/web/mo/script/run_script update_images --clean
33 21 * * * /var/web/mo/script/makexml /var/web/mo/public/eol.xml
--------------------------------------------------------------------------------
# This section deals with creating all the additional user accounts for
# members of CDMR to give them access to the server in case of emergency.
# Create an email to send to CDMR members explaining what we're doing.
root> cd
root> cat > password_email < foreach user (anne darv mgwood mike velosa)
set pass=`cat /dev/urandom | tr -dc A-Za-z0-9_ | head -c8`
useradd -m -s /bin/tcsh $user
echo "$user":"$pass" | chpasswd
passwd -e $user
cat password_email | sed "s/USER/$user/g" | sed "s/PASS/$pass/" | \
mail -s "account on mushroomobserver.org" root
end
# If you need to remove a user completely (e.g., a test user).
# root> userdel -r $user
# To copy over login information from another server instance.
# (NOTE: this doesn't seem to work going from Fedora to Ubuntu,
# it may only work if both are running the same distribution.)
# root> vi /etc/shadow
# # (copy lines from the same file on the other server)
--------------------------------------------------------------------------------
# This section deals with sharing databases between multiple servers.
# NOTE: This is also useful for running two servers in parallel while testing
# a new installation
# Configure database to accept remote connections.
root> vi /etc/mysql/my/cnf
# Comment out this line to allow remote connections.
# bind-address = 127.0.0.1
root> mysql -u root -p
create user 'mo'@'$OTHER_IP_ADDR' identified by '$DATA_PASSWORD';
grant all privileges on mo_production.* to 'mo'@'$OTHER_IP_ADDR' with grant option;
root> ssh $USER@$OTHER_IP_ADDR
user> mysqladmin --protocol=tcp -u mo -p'$DATA_PASSWORD' --host=$IP_ADDR ping
user> exit
# To switch databases from old server to new server.
# First set up new server as above.
# Make sure everyone can connect to the new server's database.
# Shut down apache2 on all servers.
xxx_root> service apache2 stop
# Make snapshot of old database.
old_root> mo
old_mo> cd db
old_mo> ./dump
# Copy snapshot to new server.
new_root> mo
new_mo> cd db
new_mo> scp $USER@$OLD_IP_ADDR:/var/web/mo/db/checkpoint.gz .
new_mo> gunzip checkpoint.gz
new_mo> mosqle checkpoint
# Reconfigure and restart all servers.
xxx_root> mo
xxx_mo> vi config/database.yml
production:
database: mo_production
host: $IP_ADDR
username: mo
password: $DATA_PASSWORD
xxx_mo> rake db:version # (just a simple test)
xxx_mo> exit
xxx_root> service apache2 start
--------------------------------------------------------------------------------
# A few post-installation sanity-checks. Reboot after everything is done,
# then check the following.
# Make sure firewall is working. If there are more than a few lines it is
# probably correct, but you can also compare it with another server.
root> iptables-save
# Make sure all the critical processes started automatically.
# Look for sshd, apache2, Passenger, mysqld, postfix.
root> ps -ef
# If any are missing, do this on ubuntu/debian:
root> update-rc.d apache2 defaults
root> update-rc.d mysql defaults
root> update-rc.d postfix defaults
# Or this on fedora/centos:
# root> chkconfig --level 345 httpd on
# root> chkconfig --level 345 mysqld on
# root> chkconfig --level 345 postfix on