The personal website of Michael Hofmockel

PressFlow (Drupal) on Ubuntu Jaunty

Goal: Setup an Ubuntu Host to serve Drupal instances
Secondary: Performance

Disclamer: there are no original ideas here. This are just my person build notes.
http://groups.drupal.org/node/25482
http://drupal.org/project/boost
http://cvs.drupal.org/viewvc.py/drupal/contributions/modules/boost/INSTA...
http://fourkitchens.com/pressflow-makes-drupal-scale
http://groups.drupal.org/node/25425
http://drupal.org/
http://www.chapterthree.com/blog/josh_koenig/project_mercury_preconfigur...
https://help.ubuntu.com/community/phpMyAdmin
http://www.sysarchitects.com/performance_des_moines
http://fordrupal.com/blog/ubuntu-production-setup-vpsserver-drupal-part-2
http://www.blogovela.com/installing-apc-on-ubuntu-804-hardy-heron-0314.html
http://dc2009.drupalcon.org/session/backend-drupal-performance-optimizat...

Installed Ubuntu Jaunty image and logged in as root.

------------------------------------------------------
Add a user so I can work as non-root
------------------------------------------------------

root@hofmockel:~# adduser michael
Adding user `michael' ...
Adding new group `michael' (1000) ...
Adding new user `michael' (1000) with group `michael' ...
Creating home directory `/home/michael' ...
Copying files from `/etc/skel' ...
Enter new UNIX password:
Retype new UNIX password:
passwd: password updated successfully
Changing the user information for michael
Enter the new value, or press ENTER for the default
Full Name []: Michael Hofmockel
Room Number []:
Work Phone []:
Home Phone []:
Other []:
Is the information correct? [Y/n] y

---------------------------------------
Give michael sudo
----------------------------------------

root@hofmockel:~# visudo
added - michael ALL=(All) All

----------------------------------------------------------
re:http://groups.drupal.org/node/25482
Set time zone
-----------------------------------------------------------

michael@hofmockel:~$ sudo dpkg-reconfigure tzdata

Current default timezone: 'Etc/UTC'
Local time is now: Fri Sep 4 18:44:49 UTC 2009.
Universal Time is now: Fri Sep 4 18:44:49 UTC 2009.

-------------------------
Set hostname
------------------------

echo "foobar.com" > /etc/hostname
hostname -F /etc/hostname

-----------------------------
update and upgrade
-----------------------------

sudo apt-get update
sudo apt-get upgrade

----------------------------------
add some basic things
----------------------------------

sudo apt-get install build-essential
sudo apt-get install wget
sudo apt-get install aptitude apt-utils
sudo apt-get install cvs subversion
sudo apt-get install openssh-server

---------------------------
mail transfer agent
---------------------------

sudo apt-get install postfix
-- set to hofmockel.org

* thing about having it use gmail at smtp http://prantran.blogspot.com/2007/01/getting-postfix-to-work-on-ubuntu-w...

-------------------------------------------------------------------------------------------------------
Then we want to prevent the root user from being able to login directly:
sudo vim /etc/ssh/sshd_config
-------------------------------------------------------------------------------------------------------

and set the settings in file to be as follows (don't remove any other existing settings, just change or add to make the following):
Port 6543
PermitRootLogin no
X11Forwarding no
UseDNS no
UsePAM yes
PasswordAuthentication yes
AllowUsers onlyme

Then reload ssh
/etc/init.d/ssh reload

-----------------------
Firewall
-----------------------

Install the iptables firewall (it may turn out to be there already, so this won't do anything)
sudo apt-get install iptables

Open ports should be kept to 80 and 443 (http and https) and 9876 (our custom SSH port) on the external network card. On the internal loopback 3306 also needs to be allowed for MySQL. On outbound allow only port 53 UDP (for DNS) and 80 TCP (for access to updates etc via HTTP). Close down other ports unless absolutely necessary. Set any firewall to drop packets rather than reject them.

Ubuntu has a layer ontop of iptables called UFW, making setting up a basic firewall easier, which we'll enable and configure...
sudo apt-get install ufw
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow 6543/tcp
sudo ufw logging on
sudo ufw enable
sudo ufw status

if this is changed in the future
sudo ufw disable
sudo ufw enable

--------------------------------------------
install and configure apache2
-------------------------------------------

sudo apt-get install apache2

Permission to serve files
sudo vim /etc/apache2/apache2.conf

Make sure the following are set:
ServerTokens Prod
ServerSignature Off

Do a reload to effect the change:
/etc/init.d/apache2 reload

Enable/Disable some Apache Modules
Some modules aren't needed, so we can disable them for performance and security:
a2dismod cgi
a2dismod autoindex
And some modules we'd like to enable.

a2enmod deflate
a2enmod rewrite
a2enmod vhost_alias

Now restart apache
/etc/init.d/apache2 restart

----------------------
Configure PHP
----------------------

First, install PHP:
sudo apt-get install php5 php5-cli php5-mysql php5-gd php-pear

root@hofmockel:/home/michael# postconf -d sendmail_path
sendmail_path = /usr/sbin/sendmail

Get the path to sendmail
Issue the command:
postconf -d sendmail_path
Note down this path.

Edit PHP.ini
All changes need to be performed in both:
/etc/php5/apache2/php.ini
and
/etc/php5/cli/php.ini

Change the settings in these files to read as follows:
safe_mode = Off
expose_php = Off
max_execution_time = 300
max_input_time = 300
memory_limit = 128m
display_errors = Off
log_errors = On
error_log = /var/log/php/php.log (or php_cli.log)
sendmail_path = /usr/sbin/sendmail -t -i

where the sendmail_path is actually the path you noted down above, but keep the -t and -i switches.
Edit Apache/PHP settings
In /etc/apache2/mods-enabled/php5.conf add:
AddType application/x-httpd-php .inc .module .class

so it becomes something like:

AddType application/x-httpd-php .php .phtml .php3
AddType application/x-httpd-php .inc .module .class
AddType application/x-httpd-php-source .phps

the addition of these additional filetypes to be handled as php scripts means the code of those types of files can't be directly downloaded from webroot folders, revealing site code, passwords etc.
Setup log files
Then
mkdir /var/log/php
touch /var/log/php/php.log
touch /var/log/php/php_cli.log
chown -R www-data:www-data /var/log/php
chmod -R 0755 /var/log/php

To make sure that the log files exist and can be written to.
Log files should then be checked regularly to look for problems!

Restart Apache
/etc/init.d/apache2 restart

---------------------------
Configure MySQL
---------------------------

Start by installing MySQL:
sudo apt-get install mysql-server
Edit MySQL configuration file
sudo vim /etc/mysql/my.cnf
In the [mysqld] section add this:
set-variable=local-infile=0
check that
user = mysql

If this is not set then mysql is set to run as root which is dangerous. A new user needs to be setup, given limited privileges (inc access to the mysql directories) and then specified here. Ubuntu usually has this set by default.
Change Root password and username
Now type
mysql -u root -p

It will prompt for a password, this is the original root password from when the server was setup, and will show in the vps control panel if setup via a vps image. In more basic settings you may just need to press return here.
We'll change this password now:
mysql> SET PASSWORD FOR root@localhost=PASSWORD('new_password');

make a note of this new password.
Now we're changing the 'root' username to 'onlyme' which makes it harder to do brute force dictionary attacks on the password:
mysql> use mysql;
mysql> update user set user="onlyme" where user="root";
mysql> flush privileges;
Check for crud
SHOW DATABASES;
On a clean install if there are any databases other than mysql or information_schema then delete them - eg test databases.

SHOW GRANTS;
This will show which users have which permissions on the system. Get rid of defaults, demo users etc.

Type 'exit' to log out of mysql.

Remove History
Now we remove the content of the mysql history file in which all executed SQL commands are stored inc passwords in plain text.
cat /dev/null > ~/.mysql_history

---------------------------------
Installing phpmyadmin
---------------------------------

sudo apt-get install phpmyadmin
To set up under Apache all you need to do is include the following line in /etc/apache2/apache2.conf.

Include /etc/phpmyadmin/apache.conf

Securing phpmyadmin
sudo nano /etc/phpmyadmin/apache.conf

------------------------------------------
Apache VirtulHost on Ubuntu
------------------------------------------

1. cd /etc/apache2/sites-available
2. sudo vim yourdomain.com.conf and enter your VirtualHost directive. Below IÂ’ve put the most basic example, see Apache docs for details and additional features:
>
ServerName yourdomain.com
DocumentRoot /var/www/***

Save & exit.
3. sudo vim /etc/hosts and add your new domain to the 127.0.0.1 locahost line so it looks like this:
127.0.0.1 localhost yourdomain.com

Save & exit.
4. Enable your new virtualhost:
sudo a2ensite yourdomain.com.conf
5. Reload the Apache configuration:
sudo /etc/init.d/apache2 reload

----------------------------------
performance and tuning
----------------------------------

apt-get install php-apc

http://fordrupal.com/blog/ubuntu-production-setup-vpsserver-drupal-part-2

installing APC - http://www.blogovela.com/installing-apc-on-ubuntu-804-hardy-heron-0314.html
First off, you need to update your apt-get files so run the command:
sudo apt-get update

Next, you need to install the dev files that will prepare your server to install APC.
sudo apt-get install php5-dev php-pear apache2-threaded-dev

Once you are done with those, now it is time to install APC itself. Once again from your SSH shell, run this command:
pecl install apc

You’ll be given an installation option, just hit enter to continue.

Next, you need to tell your PHP file just where your APC extension is. For this, youÂ’ll need to copy and paste some code and stick it into your php.ini file.

So, copy this code:
extension = apc.so
apc.enabled = 1
apc.shm_size = 48
apc.include_once_override = 1
apc.mmap_file_mask = /tmp/apc.XXXXXX

Next open your php.ini file:
nano /etc/php5/apache2/php.ini

At the top of the file just paste the code. All that is left to do is to enable it. Just restart apache with this command:
/etc/init.d/apache2 restart

You now have a working PHP cache. You will reduce your server load and serve up your pages even faster.

Performance tuning tips for Drupal 7 testing.
http://testing.drupal.org/performance-tuning-tips-for-D7

Backend Drupal Performance Optimization and Tuning: a guide for everyone
http://dc2009.drupalcon.org/session/backend-drupal-performance-optimizat...

---------------
Trouble Shooting
http://www.webmasterworld.com/apache/3715288.htm

----------------------------------------------
Installing Bazaar (for pressflow) - http://fourkitchens.com/pressflow-makes-drupal-scale
----------------------------------------------

sudo apt-get install bzr

installing pressflow
bzr branch bzr://vcs.pressflow.org/pressflow/6 pressflow-6

Update using Bazaar (from anywhere within your Pressflow installation):
bzr merge bzr://vcs.pressflow.org/pressflow/6
bzr commit -m "Updated Pressflow."

** Pressflow doesn't really gain you much of anything with out Varnish

--------------------------------------
Installing APC php cache
--------------------------------------

re:http://www.blogovela.com/installing-apc-on-ubuntu-804-hardy-heron-0314.html

sudo apt-get install php5-dev php-pear apache2-threaded-dev

Once you are done with those, now it is time to install APC itself. Once again from your SSH shell, run this command:
pecl install apc

You’ll be given an installation option, just hit enter to continue.

Next, you need to tell your PHP file just where your APC extension is. For this, you’ll need to copy and paste some code and stick it into your php.ini file.

So, copy this code:
extension = apc.so
apc.enabled = 1
apc.shm_size = 48
apc.include_once_override = 1
apc.mmap_file_mask = /tmp/apc.XXXXXX

Next open your php.ini file:
nano /etc/php5/apache2/php.ini

At the top of the file just paste the code. All that is left to do is to enable it. Just restart apache with this command:
/etc/init.d/apache2 restart

---------------------------------------------------------
disable tcp selective acknowlegements
---------------------------------------------------------

sudo nano /etc/sysctl.conf

add

net.ipv4.tcp_sack=0
net.ipv4.tcp_dsack=0
net.ipv4.tcp_fack=0
net.ipv4.tcp_max_tw_buckets=30000
net.core.somaxconn=1536
net.core.netdev_max_backlog=30000

Enable the compression of HTML by putting in your php.ini:
output_handler = ob_gzhandler

----------------------------------------------------
Since I'm not using enough memory to really capitalize on Squid or Varnish
Boost can help a bit
Boost module added and configured
-----------------------------------------------------

-------------------------------------------
A little ab bench marking to see how we are doing on performance
-------------------------------------------

$ ab -n 3000 -c 10 http://hofmockel.org/
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking hofmockel.org (be patient)
Completed 300 requests
Completed 600 requests
Completed 900 requests
Completed 1200 requests
Completed 1500 requests
Completed 1800 requests
Completed 2100 requests
Completed 2400 requests
Completed 2700 requests
Completed 3000 requests
Finished 3000 requests

Server Software: Apache
Server Hostname: hofmockel.org
Server Port: 80

Document Path: /
Document Length: 9398 bytes

Concurrency Level: 10
Time taken for tests: 0.972 seconds
Complete requests: 3000
Failed requests: 0
Write errors: 0
Total transferred: 29031000 bytes
HTML transferred: 28194000 bytes
Requests per second: 3086.24 [#/sec] (mean)
Time per request: 3.240 [ms] (mean)
Time per request: 0.324 [ms] (mean, across all concurrent requests)
Transfer rate: 29165.59 [Kbytes/sec] received

Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.6 0 8
Processing: 0 3 2.3 4 20
Waiting: 0 3 2.1 4 8
Total: 0 3 2.3 4 20

Percentage of the requests served within a certain time (ms)
50% 4
66% 4
75% 4
80% 4
90% 4
95% 8
98% 8
99% 8
100% 20 (longest request)

*** Went from about 800 requests/sec to 3100 request/sec